mirror of https://github.com/dapr/cli.git
Compare commits
213 Commits
v1.9.0-rc.
...
master
Author | SHA1 | Date |
---|---|---|
|
edb70cf461 | |
|
22536a9640 | |
|
fff4c9158f | |
|
3198d9ca7e | |
|
b51eab0d84 | |
|
b31a9f2c56 | |
|
c939814420 | |
|
a85b8132db | |
|
5da3528524 | |
|
e7c1a322d7 | |
|
ce0b9fb4d9 | |
|
29f8962111 | |
|
16aeac5701 | |
|
16cc1d1b59 | |
|
ecc4ea4953 | |
|
4c1c26f2b6 | |
|
a0921c7820 | |
|
6c9bcc6dcf | |
|
42b93eaa7a | |
|
98b9da9699 | |
|
bd09c94b77 | |
|
06f38ed9bc | |
|
0cd0585b64 | |
|
728b329ce5 | |
|
a968b18f08 | |
|
ac6822ea69 | |
|
f8ee63c8f4 | |
|
8ce6b9fed9 | |
|
953c4a2a3f | |
|
c3f0fb2472 | |
|
3acfa7d7e4 | |
|
104849bc74 | |
|
17f4785906 | |
|
efe1d6c1e2 | |
|
dbbe022a8a | |
|
25d9ece42f | |
|
6d5e64d964 | |
|
8cd81b0477 | |
|
5446171840 | |
|
1152a1ef55 | |
|
d781b03002 | |
|
9bc96c2fa0 | |
|
376690b43e | |
|
086a3b9adb | |
|
1f080952a5 | |
|
002a223864 | |
|
db712e7eed | |
|
a3571c8464 | |
|
e08443b9b3 | |
|
aefcca1899 | |
|
aa0436ebe0 | |
|
027f5da3e1 | |
|
22059c399e | |
|
fecf47d752 | |
|
ad67ce58c4 | |
|
e72f95393c | |
|
16a513ba7a | |
|
30d888f4e6 | |
|
29d29ab549 | |
|
ddf43a5f55 | |
|
ad3442b252 | |
|
ed0d3af2d0 | |
|
762e2bb4ac | |
|
fd1d8e85bf | |
|
4881ca11d7 | |
|
619cd9cd84 | |
|
3ea5f9c6b2 | |
|
1da8760f11 | |
|
2380446870 | |
|
50e1dffec0 | |
|
f5eb4fda6c | |
|
c7e8612b11 | |
|
668bab451d | |
|
a339bdf491 | |
|
ac0a3cb06f | |
|
d55944ccec | |
|
02eec8bbc8 | |
|
1d60280de4 | |
|
0c1c275972 | |
|
bb2c3a7f66 | |
|
7a09fd6b9c | |
|
a08eebb5db | |
|
a38a44d27b | |
|
6a85f487e7 | |
|
df8f242fc8 | |
|
3fe6d8fffd | |
|
0ebded24f7 | |
|
504d4eadba | |
|
235f40cf81 | |
|
0c99afb4db | |
|
41f324016e | |
|
a15a3eb856 | |
|
6738eefe2b | |
|
4d586752bc | |
|
60f50e3497 | |
|
650fd6fe8d | |
|
31b9ea27ae | |
|
2751f5fa74 | |
|
a4f924f49d | |
|
7da8bd7b15 | |
|
fa2c99d8b0 | |
|
c41ea8a4d3 | |
|
35f324a09e | |
|
48cd76517f | |
|
2a50c8b59a | |
|
77fbc192ea | |
|
fae95a44f0 | |
|
ce97fe0d4b | |
|
c3f08b0679 | |
|
c65d816612 | |
|
96e225432a | |
|
36a13bc55a | |
|
af9030a383 | |
|
a59826c0a2 | |
|
337eab4079 | |
|
76bf893295 | |
|
90c8d960f2 | |
|
d3f54cf94b | |
|
81fd09b7d1 | |
|
9f67738e24 | |
|
7abf871ce0 | |
|
4e3ae81df5 | |
|
756b541ae4 | |
|
808defb16c | |
|
176fa0a663 | |
|
6eca34e727 | |
|
fff7e75762 | |
|
b60c541241 | |
|
45dcd5813d | |
|
72551c95af | |
|
5e3546a351 | |
|
55777da7bb | |
|
17124ebbe9 | |
|
398eb7e24a | |
|
56ba05982e | |
|
06a4c6bddc | |
|
211e57b915 | |
|
a6f8c7694d | |
|
a4aafbdfd4 | |
|
de997a9fda | |
|
8884bb977e | |
|
7e0d9dc45d | |
|
63f3fa0e29 | |
|
1cec708d88 | |
|
5ccd602262 | |
|
4fdec6b798 | |
|
23b37590e4 | |
|
fffa1dad13 | |
|
d3c3ac9bba | |
|
c8aa85b0e3 | |
|
25cc689143 | |
|
4dd43375e6 | |
|
78db061dac | |
|
c1c0ff5193 | |
|
72c988c476 | |
|
0c26e1c7a6 | |
|
84ba3aad24 | |
|
e82850a698 | |
|
8dbdbc5757 | |
|
20978a2b59 | |
|
a7f06c3b1b | |
|
55bc454ad9 | |
|
38c8f106df | |
|
50d5af4cd9 | |
|
a891cb09b3 | |
|
42f9519eb2 | |
|
17efdfd4a4 | |
|
778b2a5933 | |
|
b2daa8d220 | |
|
7e00eb4f03 | |
|
da38233cfc | |
|
1a9029ce71 | |
|
17dbe5bb13 | |
|
14c04f9a87 | |
|
61bf50cc4c | |
|
36893d9483 | |
|
b51eda4876 | |
|
9d18f86768 | |
|
44d8dcb752 | |
|
8b68de52da | |
|
37c2b34df5 | |
|
87b6f0ebc4 | |
|
c1f9627ed6 | |
|
d4654c065b | |
|
53dff409b4 | |
|
e253b91212 | |
|
abe9680b47 | |
|
1a980b6f9a | |
|
6c1bc5357c | |
|
63f14c36f9 | |
|
8a0936af9f | |
|
49a40657d8 | |
|
e926a0f739 | |
|
544c1d788a | |
|
194ce8a4af | |
|
13eed0eaf3 | |
|
db2ba58147 | |
|
f51aefb0ba | |
|
0008d46019 | |
|
0841faf2eb | |
|
bbcc0bd1c0 | |
|
7c302579d6 | |
|
da782d1e64 | |
|
3093641fcb | |
|
87645aaeee | |
|
eb1dd68a42 | |
|
07cf0553dc | |
|
1d0a566a45 | |
|
1a3e5d511e | |
|
e2f7e262f1 | |
|
8d79ef13ec | |
|
5785c1b59b | |
|
657310541a |
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"name": "Dapr CLI Dev Environment",
|
||||
// Update the container version when you publish dev-container
|
||||
"image": "ghcr.io/dapr/dapr-dev:0.1.8",
|
||||
// Replace with uncommented line below to build your own local copy of the image
|
||||
// "dockerFile": "../docker/Dockerfile-dev",
|
||||
"image": "ghcr.io/dapr/dapr-dev:latest",
|
||||
"containerEnv": {
|
||||
// Uncomment to overwrite devcontainer .kube/config and .minikube certs with the localhost versions
|
||||
// each time the devcontainer starts, if the respective .kube-localhost/config and .minikube-localhost
|
||||
|
@ -14,19 +12,19 @@
|
|||
// the localhost bind-mount /var/run/docker-host.sock.
|
||||
// "BIND_LOCALHOST_DOCKER": "true"
|
||||
},
|
||||
"extensions": [
|
||||
"davidanson.vscode-markdownlint",
|
||||
"golang.go",
|
||||
"ms-azuretools.vscode-dapr",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"ms-kubernetes-tools.vscode-kubernetes-tools"
|
||||
],
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/sshd:1": {},
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {},
|
||||
"ghcr.io/devcontainers/features/node": {
|
||||
"version": "lts"
|
||||
}
|
||||
},
|
||||
"mounts": [
|
||||
// Mount docker-in-docker library volume
|
||||
"type=volume,source=dind-var-lib-docker,target=/var/lib/docker",
|
||||
|
||||
// Bind mount docker socket under an alias to support docker-from-docker
|
||||
"type=bind,source=/var/run/docker.sock,target=/var/run/docker-host.sock",
|
||||
"type=bind,source=/var/run/docker.sock,target=/var/run/docker-host.sock"
|
||||
|
||||
// Uncomment to clone local .kube/config into devcontainer
|
||||
// "type=bind,source=${env:HOME}${env:USERPROFILE}/.kube,target=/home/dapr/.kube-localhost",
|
||||
|
@ -56,11 +54,28 @@
|
|||
// Run the entrypoint defined in container image.
|
||||
"--init"
|
||||
],
|
||||
"settings": {
|
||||
"go.toolsManagement.checkForUpdates": "local",
|
||||
"go.useLanguageServer": true,
|
||||
"go.gopath": "/go"
|
||||
"postCreateCommand": "npm install -g @devcontainers/cli",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"davidanson.vscode-markdownlint",
|
||||
"golang.go",
|
||||
"ms-azuretools.vscode-dapr",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"ms-kubernetes-tools.vscode-kubernetes-tools"
|
||||
],
|
||||
"settings": {
|
||||
"go.toolsManagement.checkForUpdates": "local",
|
||||
"go.useLanguageServer": true,
|
||||
"go.gopath": "/go",
|
||||
"go.buildTags": "e2e,perf,conftests,unit,integration_test,certtests,allcomponents",
|
||||
"git.alwaysSignOff": true,
|
||||
"terminal.integrated.env.linux": {
|
||||
"GOLANG_PROTOBUF_REGISTRATION_CONFLICT": "ignore"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspaceFolder": "/workspaces/cli",
|
||||
"workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/workspaces/cli",
|
||||
"workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/workspaces/cli"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
organization: dapr
|
||||
defaultSticker: clutq4bgp107990fl1h4m7jp3b
|
||||
stickers:
|
||||
-
|
||||
id: clutq4bgp107990fl1h4m7jp3b
|
||||
alias: cli-badge
|
|
@ -29,8 +29,7 @@ jobs:
|
|||
name: Build ${{ matrix.target_os }}_${{ matrix.target_arch }} binaries
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
GOVER: 1.19
|
||||
GOLANG_CI_LINT_VER: v1.49.0
|
||||
GOLANG_CI_LINT_VER: v1.61.0
|
||||
GOOS: ${{ matrix.target_os }}
|
||||
GOARCH: ${{ matrix.target_arch }}
|
||||
GOPROXY: https://proxy.golang.org
|
||||
|
@ -40,7 +39,7 @@ jobs:
|
|||
WIX_BIN_PATH: 'C:/Program Files (x86)/WiX Toolset v3.11/bin'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest, macOS-latest-large]
|
||||
target_arch: [arm, arm64, amd64]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
|
@ -49,6 +48,8 @@ jobs:
|
|||
target_os: windows
|
||||
- os: macOS-latest
|
||||
target_os: darwin
|
||||
- os: macOS-latest-large
|
||||
target_os: darwin
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
target_arch: arm
|
||||
|
@ -56,13 +57,28 @@ jobs:
|
|||
target_arch: arm64
|
||||
- os: macOS-latest
|
||||
target_arch: arm
|
||||
- os: macOS-latest
|
||||
target_arch: amd64
|
||||
- os: macOS-latest-large
|
||||
target_arch: arm
|
||||
- os: macOS-latest-large
|
||||
target_arch: arm64
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GOVER }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GOVER }}
|
||||
- name: Prepare Go's bin location - MacOS
|
||||
if: matrix.target_os == 'darwin'
|
||||
run: |
|
||||
export PATH=$HOME/bin:$PATH
|
||||
echo "$HOME/bin" >> $GITHUB_PATH
|
||||
|
||||
echo "GOBIN=$HOME/bin" >> $GITHUB_ENV
|
||||
mkdir -p $HOME/bin
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
id: setup-go
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
- name: Run golangci-lint
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
|
@ -72,11 +88,6 @@ jobs:
|
|||
- name: Run make modtidy check-diff
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
run: make modtidy check-diff
|
||||
- name: Run Go Vulnerability Check
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
run: |
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
govulncheck ./...
|
||||
- name: Parse release version and set REL_VERSION
|
||||
run: python ./.github/scripts/get_release_version.py
|
||||
- name: Setup test output
|
||||
|
@ -91,7 +102,7 @@ jobs:
|
|||
run: make test
|
||||
- name: Codecov
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
- name: Run make release to build and archive binaries
|
||||
run: |
|
||||
mkdir -p ${{ env.ARCHIVE_OUTDIR }}
|
||||
|
@ -107,14 +118,14 @@ jobs:
|
|||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
run: |
|
||||
[ ! -z "${{ env.REL_VERSION }}" ] && echo "${{ env.REL_VERSION }}" > "${{ env.ARCHIVE_OUTDIR }}/release_version.txt"
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
- name: upload artifacts ## Following migration guide in https://github.com/actions/upload-artifact/blob/main/docs/MIGRATION.md
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cli_drop
|
||||
name: cli_drop-${{ matrix.target_os }}_${{ matrix.target_arch }}
|
||||
path: ${{ env.ARCHIVE_OUTDIR }}
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target_os }}_${{ matrix.target_arch }}_test_unit.json
|
||||
path: ${{ env.TEST_OUTPUT_FILE }}
|
||||
|
@ -127,9 +138,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: download artifacts
|
||||
uses: actions/download-artifact@master
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cli_drop
|
||||
pattern: cli_drop-*
|
||||
merge-multiple: true
|
||||
path: ${{ env.ARTIFACT_DIR }}
|
||||
- name: Set Release Version
|
||||
run: |
|
||||
|
@ -144,18 +156,34 @@ jobs:
|
|||
- name: publish binaries to github
|
||||
if: startswith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
echo "installing github-release-cli..."
|
||||
sudo npm install --silent --no-progress -g github-release-cli@1.3.1
|
||||
# Get the list of files
|
||||
RELEASE_ARTIFACT=(${ARTIFACT_DIR}/*)
|
||||
# Parse repository to get owner and repo names
|
||||
OWNER_NAME="${GITHUB_REPOSITORY%%/*}"
|
||||
REPO_NAME="${GITHUB_REPOSITORY#*/}"
|
||||
export GITHUB_TOKEN=${{ secrets.DAPR_BOT_TOKEN }}
|
||||
echo "Uploading Dapr CLI Binaries to GitHub Release"
|
||||
github-release upload \
|
||||
--owner $OWNER_NAME --repo $REPO_NAME \
|
||||
--tag "v${REL_VERSION}" \
|
||||
--name "Dapr CLI v${REL_VERSION}" \
|
||||
--prerelease true \
|
||||
gh release create \
|
||||
"v${REL_VERSION}" \
|
||||
--title "Dapr CLI v${REL_VERSION}" \
|
||||
--repo $GITHUB_REPOSITORY \
|
||||
--prerelease \
|
||||
${RELEASE_ARTIFACT[*]}
|
||||
publish-winget:
|
||||
name: Publish to winget-pkgs
|
||||
needs: publish
|
||||
if: startswith(github.ref, 'refs/tags/v')
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Parse release version and set REL_VERSION
|
||||
run: python ./.github/scripts/get_release_version.py
|
||||
- name: Update winget manifests
|
||||
shell: pwsh
|
||||
run: |
|
||||
$url = "https://github.com/dapr/cli/releases/download/v${{ env.REL_VERSION }}/dapr.msi"
|
||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||
if("${{ env.REL_VERSION }}".Contains("-rc.")){
|
||||
$PackageIdentifier="Dapr.CLI.Preview"
|
||||
} else{
|
||||
$PackageIdentifier="Dapr.CLI"
|
||||
}
|
||||
.\wingetcreate.exe update "$PackageIdentifier" --submit --urls "$url|x64" --version "${{ env.REL_VERSION }}" --token "${{ secrets.DAPR_BOT_TOKEN }}"
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
name: "Release dev container features & Generate Documentation"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Publish Features"
|
||||
uses: devcontainers/action@v1
|
||||
with:
|
||||
publish-features: "true"
|
||||
base-path-to-features: "./dev-container-feature/src"
|
||||
generate-docs: "true"
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create PR for Documentation
|
||||
id: push_image_info
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
echo "Start."
|
||||
# Configure git and Push updates
|
||||
git config --global user.email github-actions@github.com
|
||||
git config --global user.name github-actions
|
||||
git config pull.rebase false
|
||||
branch=automated-documentation-update-$GITHUB_RUN_ID
|
||||
git checkout -b $branch
|
||||
message='Automated documentation update'
|
||||
# Add / update and commit
|
||||
git add */**/README.md
|
||||
git commit -m 'Automated documentation update [skip ci]' || export NO_UPDATES=true
|
||||
# Push
|
||||
if [ "$NO_UPDATES" != "true" ] ; then
|
||||
git push origin "$branch"
|
||||
gh pr create --title "$message" --body "$message"
|
||||
fi
|
|
@ -0,0 +1,62 @@
|
|||
name: "CI - Test Features"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
paths:
|
||||
- "dev-container-feature/**"
|
||||
- .github/workflows/dev_container_feature**
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-autogenerated:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
features:
|
||||
- dapr-cli
|
||||
baseImage:
|
||||
- debian:latest
|
||||
- ubuntu:latest
|
||||
- mcr.microsoft.com/devcontainers/base:ubuntu
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install latest devcontainer CLI"
|
||||
run: npm install -g @devcontainers/cli
|
||||
|
||||
- name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
|
||||
run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} ./dev-container-feature
|
||||
|
||||
|
||||
test-scenarios:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
features:
|
||||
- dapr-cli
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install latest devcontainer CLI"
|
||||
run: npm install -g @devcontainers/cli
|
||||
|
||||
- name: "Generating tests for '${{ matrix.features }}' scenarios"
|
||||
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated ./dev-container-feature
|
||||
|
||||
|
||||
test-global:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install latest devcontainer CLI"
|
||||
run: npm install -g @devcontainers/cli
|
||||
|
||||
- name: "Testing global scenarios"
|
||||
run: devcontainer features test --global-scenarios-only ./dev-container-feature
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
name: "Validate devcontainer-feature.json files"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- "dev-container-feature/**"
|
||||
- .github/workflows/dev_container_feature**
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Validate devcontainer-feature.json files"
|
||||
uses: devcontainers/action@v1
|
||||
with:
|
||||
validate-only: "true"
|
||||
base-path-to-features: "./dev-container-feature/src"
|
|
@ -34,15 +34,16 @@ jobs:
|
|||
FOSSA_API_KEY: b88e1f4287c3108c8751bf106fb46db6 # This is a push-only token that is safe to be exposed.
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Run FOSSA Scan"
|
||||
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
|
||||
uses: fossas/fossa-action@v1.3.1 # Use a specific version if locking is preferred
|
||||
with:
|
||||
api-key: ${{ env.FOSSA_API_KEY }}
|
||||
|
||||
- name: "Run FOSSA Test"
|
||||
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
|
||||
with:
|
||||
api-key: ${{ env.FOSSA_API_KEY }}
|
||||
run-tests: true
|
||||
# Disable fossa test due to a bug on fossa side.
|
||||
# - name: "Run FOSSA Test"
|
||||
# uses: fossas/fossa-action@v1.3.1 # Use a specific version if locking is preferred
|
||||
# with:
|
||||
# api-key: ${{ env.FOSSA_API_KEY }}
|
||||
# run-tests: true
|
||||
|
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install Dapr
|
||||
- name: Install DAPR CLI
|
||||
|
|
|
@ -50,53 +50,43 @@ jobs:
|
|||
name: E2E tests for K8s (KinD)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOVER: 1.19
|
||||
DAPR_RUNTIME_VERSION: 1.9.0-rc.3
|
||||
DAPR_DASHBOARD_VERSION: 0.10.0
|
||||
DAPR_TGZ: dapr-1.9.0-rc.3.tgz
|
||||
DAPR_RUNTIME_PINNED_VERSION: 1.14.4
|
||||
DAPR_DASHBOARD_PINNED_VERSION: 0.14.0
|
||||
DAPR_RUNTIME_LATEST_STABLE_VERSION:
|
||||
DAPR_DASHBOARD_LATEST_STABLE_VERSION:
|
||||
strategy:
|
||||
fail-fast: false # Keep running if one leg fails.
|
||||
matrix:
|
||||
k8s-version:
|
||||
- v1.21.14
|
||||
- v1.22.13
|
||||
- v1.23.10
|
||||
- v1.24.4
|
||||
- v1.23.12
|
||||
- v1.24.6
|
||||
- v1.25.2
|
||||
mode:
|
||||
- ha
|
||||
- non-ha
|
||||
# Map between K8s and KinD versions.
|
||||
# This is attempting to make it a bit clearer what's being tested.
|
||||
# See: https://github.com/kubernetes-sigs/kind/releases/tag/v0.15.0
|
||||
# See: https://github.com/kubernetes-sigs/kind/releases/tag/v0.16.0
|
||||
include:
|
||||
- k8s-version: v1.21.14
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:f9b4d3d1112f24a7254d2ee296f177f628f9b4c1b32f0006567af11b91c1f301
|
||||
- k8s-version: v1.22.13
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:4904eda4d6e64b402169797805b8ec01f50133960ad6c19af45173a27eadf959
|
||||
- k8s-version: v1.23.10
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:f047448af6a656fae7bc909e2fab360c18c487ef3edc93f06d78cdfd864b2d12
|
||||
- k8s-version: v1.24.4
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:adfaebada924a26c2c9308edd53c6e33b3d4e453782c0063dc0028bdebaddf98
|
||||
exclude:
|
||||
- k8s-version: v1.21.14
|
||||
mode: non-ha
|
||||
- k8s-version: v1.21.14
|
||||
mode: non-ha
|
||||
- k8s-version: v1.22.13
|
||||
mode: non-ha
|
||||
- k8s-version: v1.23.12
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:9402cf1330bbd3a0d097d2033fa489b2abe40d479cc5ef47d0b6a6960613148a
|
||||
- k8s-version: v1.24.6
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:97e8d00bc37a7598a0b32d1fabd155a96355c49fa0d4d4790aab0f161bf31be1
|
||||
- k8s-version: v1.25.2
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:9be91e9e9cdf116809841fc77ebdb8845443c4c72fe5218f3ae9eb57fdb4bace
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GOVER }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GOVER }}
|
||||
- name: Check out code onto GOPATH
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ./src/github.com/dapr/cli
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
id: setup-go
|
||||
with:
|
||||
go-version-file: './src/github.com/dapr/cli/go.mod'
|
||||
|
||||
- name: Configure KinD
|
||||
# Generate a KinD configuration file that uses:
|
||||
|
@ -124,7 +114,7 @@ jobs:
|
|||
# Log the generated kind.yaml for easy reference.
|
||||
cat kind.yaml
|
||||
- name: Create KinD Cluster
|
||||
uses: helm/kind-action@v1.0.0
|
||||
uses: helm/kind-action@v1.3.0
|
||||
with:
|
||||
config: kind.yaml
|
||||
cluster_name: kind
|
||||
|
@ -143,16 +133,36 @@ jobs:
|
|||
- name: Determine latest Dapr Runtime version including Pre-releases
|
||||
if: github.base_ref == 'master'
|
||||
run: |
|
||||
helm repo add dapr https://dapr.github.io/helm-charts/ && helm repo update && export RUNTIME_VERSION=$(helm search repo dapr/dapr --devel --versions | awk '/dapr\/dapr/ {print $3; exit}' )
|
||||
echo "DAPR_RUNTIME_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
echo "Found $RUNTIME_VERSION"
|
||||
export RUNTIME_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dapr/releases | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
if [[ -z "$RUNTIME_VERSION" ]]; then
|
||||
echo "Could not fetch the latest Dapr Runtime version. Using pinned version $DAPR_RUNTIME_PINNED_VERSION"
|
||||
else
|
||||
echo "Found $RUNTIME_VERSION"
|
||||
echo "DAPR_RUNTIME_PINNED_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
- name: Determine latest Dapr Dashboard version including Pre-releases
|
||||
if: github.base_ref == 'master'
|
||||
run: |
|
||||
curl -L -o dapr.tgz https://github.com/dapr/helm-charts/raw/master/$DAPR_TGZ && tar -xzf dapr.tgz && export DASHBOARD_VERSION=$(cat ./dapr/charts/dapr_dashboard/Chart.yaml | grep version | awk '{ print $2; exit }') && rm -rf dapr
|
||||
echo "DAPR_DASHBOARD_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
echo "Found $DASHBOARD_VERSION"
|
||||
export DASHBOARD_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dashboard/releases | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
if [[ -z "$DASHBOARD_VERSION" ]]; then
|
||||
echo "Could not fetch the latest Dapr Dashboard version. Using pinned version $DAPR_DASHBOARD_PINNED_VERSION"
|
||||
else
|
||||
echo "Found $DASHBOARD_VERSION"
|
||||
echo "DAPR_DASHBOARD_PINNED_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
- name: Determine latest stable Dapr Runtime version
|
||||
run: |
|
||||
export LATEST_STABLE_RUNTIME_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dapr/releases/latest | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
echo "Found $LATEST_STABLE_RUNTIME_VERSION"
|
||||
echo "DAPR_RUNTIME_LATEST_STABLE_VERSION=$LATEST_STABLE_RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Determine latest stable Dapr Dashboard version
|
||||
run: |
|
||||
export LATEST_STABLE_DASHBOARD_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dashboard/releases/latest | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
echo "Found $LATEST_STABLE_DASHBOARD_VERSION"
|
||||
echo "DAPR_DASHBOARD_LATEST_STABLE_VERSION=$LATEST_STABLE_DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Run tests with GHCR
|
||||
# runs every 6hrs
|
||||
|
@ -163,6 +173,7 @@ jobs:
|
|||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-kind.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
|
||||
export TEST_DAPR_HA_MODE=${{ matrix.mode }}
|
||||
make e2e-build-run-k8s
|
||||
shell: bash
|
||||
- name: Run tests with Docker hub
|
||||
|
@ -171,11 +182,12 @@ jobs:
|
|||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-kind.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
|
||||
export TEST_DAPR_HA_MODE=${{ matrix.mode }}
|
||||
make e2e-build-run-k8s
|
||||
shell: bash
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.k8s-version }}_${{ matrix.mode }}_e2e_k8s.json
|
||||
path: ${{ env.TEST_OUTPUT_FILE }}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ------------------------------------------------------------
|
||||
|
||||
name: E2E - Self-hosted
|
||||
|
||||
on:
|
||||
|
@ -19,39 +18,44 @@ on:
|
|||
- master
|
||||
- release-*
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- "**.md"
|
||||
schedule:
|
||||
- cron: '0 */3 * * *'
|
||||
- cron: '0 */6 * * *'
|
||||
- cron: "0 */3 * * *"
|
||||
- cron: "0 */6 * * *"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- 'release-*'
|
||||
- "release-*"
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
self-hosted-e2e:
|
||||
name: Run Self-Hosted E2E tests in ${{ matrix.target_os }}_${{ matrix.target_arch }}_${{ matrix.dapr_install_mode }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
GOVER: 1.19
|
||||
GOOS: ${{ matrix.target_os }}
|
||||
GOARCH: ${{ matrix.target_arch }}
|
||||
GOPROXY: https://proxy.golang.org
|
||||
ARCHIVE_OUTDIR: dist/archives
|
||||
DAPR_RUNTIME_VERSION: "1.9.0-rc.3"
|
||||
DAPR_DASHBOARD_VERSION: 0.10.0
|
||||
DAPR_TGZ: dapr-1.9.0-rc.3.tgz
|
||||
DAPR_RUNTIME_PINNED_VERSION: "1.14.4"
|
||||
DAPR_DASHBOARD_PINNED_VERSION: 0.14.0
|
||||
DAPR_RUNTIME_LATEST_STABLE_VERSION: ""
|
||||
DAPR_DASHBOARD_LATEST_STABLE_VERSION: ""
|
||||
GOLANG_PROTOBUF_REGISTRATION_CONFLICT: warn
|
||||
PODMAN_VERSION: 5.4.0
|
||||
strategy:
|
||||
# TODO: Remove this when our E2E tests are stable for podman on MacOS.
|
||||
fail-fast: false # Keep running if one leg fails.
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
# See https://github.com/actions/runner-images
|
||||
os: [macos-latest-large, ubuntu-latest, windows-latest]
|
||||
target_arch: [amd64]
|
||||
dapr_install_mode: [slim, complete]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target_os: linux
|
||||
- os: macOS-latest
|
||||
- os: macos-latest-large
|
||||
target_os: darwin
|
||||
- os: windows-latest
|
||||
target_os: windows
|
||||
|
@ -59,38 +63,75 @@ jobs:
|
|||
- os: windows-latest
|
||||
dapr_install_mode: complete
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GOVER }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GOVER }}
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Install podman - MacOS
|
||||
if: matrix.os == 'macos-latest' && matrix.dapr_install_mode == 'complete'
|
||||
- name: Prepare Go's bin location - MacOS
|
||||
if: matrix.os == 'macos-latest-large'
|
||||
run: |
|
||||
sudo rm -rf `brew --cache`
|
||||
brew upgrade
|
||||
brew install podman
|
||||
which podman-mac-helper
|
||||
podman_helper=$(which podman-mac-helper)
|
||||
sudo ${podman_helper} install
|
||||
podman machine init
|
||||
podman machine start
|
||||
export PATH=$HOME/bin:$PATH
|
||||
echo "$HOME/bin" >> $GITHUB_PATH
|
||||
|
||||
echo "GOBIN=$HOME/bin" >> $GITHUB_ENV
|
||||
mkdir -p $HOME/bin
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
id: setup-go
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
- name: Install podman - MacOS
|
||||
timeout-minutes: 15
|
||||
if: matrix.os == 'macos-latest-large' && matrix.dapr_install_mode == 'complete'
|
||||
run: |
|
||||
# Install podman
|
||||
curl -sL -o podman.pkg https://github.com/containers/podman/releases/download/v${{ env.PODMAN_VERSION }}/podman-installer-macos-amd64.pkg
|
||||
sudo installer -pkg podman.pkg -target /
|
||||
export PATH=/opt/podman/bin:$PATH
|
||||
echo "/opt/podman/bin" >> $GITHUB_PATH
|
||||
|
||||
# Start podman machine
|
||||
sudo podman-mac-helper install
|
||||
podman machine init -v $HOME:$HOME --memory 16384 --cpus 12
|
||||
podman machine start --log-level debug
|
||||
podman machine ssh sudo sysctl -w kernel.keys.maxkeys=20000
|
||||
podman info
|
||||
echo "CONTAINER_RUNTIME=podman" >> $GITHUB_ENV
|
||||
- name: Determine latest Dapr Runtime version including Pre-releases
|
||||
if: github.base_ref == 'master'
|
||||
run: |
|
||||
helm repo add dapr https://dapr.github.io/helm-charts/ && helm repo update && export RUNTIME_VERSION=$(helm search repo dapr/dapr --devel --versions | awk '/dapr\/dapr/ {print $3; exit}' )
|
||||
echo "DAPR_RUNTIME_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
echo "Found $RUNTIME_VERSION"
|
||||
export RUNTIME_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dapr/releases | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
if [[ -z "$RUNTIME_VERSION" ]]; then
|
||||
echo "Could not fetch the latest Dapr Runtime version. Using pinned version $DAPR_RUNTIME_PINNED_VERSION"
|
||||
else
|
||||
echo "Found $RUNTIME_VERSION"
|
||||
echo "DAPR_RUNTIME_PINNED_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
- name: Determine latest Dapr Dashboard version including Pre-releases
|
||||
if: github.base_ref == 'master'
|
||||
run: |
|
||||
curl -L -o dapr.tgz https://github.com/dapr/helm-charts/raw/master/$DAPR_TGZ && tar -xzf dapr.tgz && export DASHBOARD_VERSION=$(cat ./dapr/charts/dapr_dashboard/Chart.yaml | grep version | awk '{ print $2; exit }') && rm -rf dapr
|
||||
echo "DAPR_DASHBOARD_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
echo "Found $DASHBOARD_VERSION"
|
||||
export DASHBOARD_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dashboard/releases | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
if [[ -z "$DASHBOARD_VERSION" ]]; then
|
||||
echo "Could not fetch the latest Dapr Dashboard version. Using pinned version $DAPR_DASHBOARD_PINNED_VERSION"
|
||||
else
|
||||
echo "Found $DASHBOARD_VERSION"
|
||||
echo "DAPR_DASHBOARD_PINNED_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
- name: Determine latest stable Dapr Runtime version
|
||||
run: |
|
||||
export LATEST_STABLE_RUNTIME_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dapr/releases/latest | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
echo "Found $LATEST_STABLE_RUNTIME_VERSION"
|
||||
echo "DAPR_RUNTIME_LATEST_STABLE_VERSION=$LATEST_STABLE_RUNTIME_VERSION" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Determine latest stable Dapr Dashboard version
|
||||
run: |
|
||||
export LATEST_STABLE_DASHBOARD_VERSION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/dapr/dashboard/releases/latest | grep tag_name | awk -F':' '{print $2}' | tr -d '", ' | sed '/-/! s/$/_/' | sort -V | sed 's/_$//' | tr -d 'v' | tail -1)
|
||||
echo "Found $LATEST_STABLE_DASHBOARD_VERSION"
|
||||
echo "DAPR_DASHBOARD_LATEST_STABLE_VERSION=$LATEST_STABLE_DASHBOARD_VERSION" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Set the test timeout - MacOS
|
||||
if: matrix.os == 'macos-latest-large'
|
||||
run: echo "E2E_SH_TEST_TIMEOUT=30m" >> $GITHUB_ENV
|
||||
- name: Run E2E tests with GHCR
|
||||
# runs every 6hrs
|
||||
if: github.event.schedule == '0 */6 * * *'
|
||||
|
@ -98,6 +139,7 @@ jobs:
|
|||
DAPR_DEFAULT_IMAGE_REGISTRY: ghcr
|
||||
DAPR_E2E_INIT_SLIM: ${{ contains(matrix.os, 'windows-latest') || contains(matrix.dapr_install_mode, 'slim') }}
|
||||
CONTAINER_RUNTIME: ${{ env.CONTAINER_RUNTIME }}
|
||||
E2E_SH_TEST_TIMEOUT: ${{ env.E2E_SH_TEST_TIMEOUT }}
|
||||
run: |
|
||||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-standalone.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
|
@ -109,6 +151,7 @@ jobs:
|
|||
env:
|
||||
DAPR_E2E_INIT_SLIM: ${{ contains(matrix.os, 'windows-latest') || contains(matrix.dapr_install_mode, 'slim') }}
|
||||
CONTAINER_RUNTIME: ${{ env.CONTAINER_RUNTIME }}
|
||||
E2E_SH_TEST_TIMEOUT: ${{ env.E2E_SH_TEST_TIMEOUT }}
|
||||
run: |
|
||||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-standalone.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
|
@ -117,8 +160,7 @@ jobs:
|
|||
shell: bash
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target_os }}_${{ matrix.target_arch }}_e2e_standalone.json
|
||||
name: ${{ matrix.target_os }}_${{ matrix.target_arch }}_${{ matrix.dapr_install_mode }}_e2e_standalone.json
|
||||
path: ${{ env.TEST_OUTPUT_FILE }}
|
||||
|
||||
|
|
|
@ -49,51 +49,39 @@ jobs:
|
|||
kubernetes-e2e:
|
||||
name: Upgrade path tests (KinD)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOVER: 1.19
|
||||
strategy:
|
||||
fail-fast: false # Keep running if one leg fails.
|
||||
matrix:
|
||||
k8s-version:
|
||||
- v1.21.14
|
||||
- v1.22.13
|
||||
- v1.23.10
|
||||
- v1.24.4
|
||||
- v1.23.12
|
||||
- v1.24.6
|
||||
- v1.25.2
|
||||
mode:
|
||||
- ha
|
||||
- non-ha
|
||||
# Map between K8s and KinD versions.
|
||||
# This is attempting to make it a bit clearer what's being tested.
|
||||
# See: https://github.com/kubernetes-sigs/kind/releases/tag/v0.15.0
|
||||
# See: https://github.com/kubernetes-sigs/kind/releases/tag/v0.16.0
|
||||
include:
|
||||
- k8s-version: v1.21.14
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:f9b4d3d1112f24a7254d2ee296f177f628f9b4c1b32f0006567af11b91c1f301
|
||||
- k8s-version: v1.22.13
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:4904eda4d6e64b402169797805b8ec01f50133960ad6c19af45173a27eadf959
|
||||
- k8s-version: v1.23.10
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:f047448af6a656fae7bc909e2fab360c18c487ef3edc93f06d78cdfd864b2d12
|
||||
- k8s-version: v1.24.4
|
||||
kind-version: v0.15.0
|
||||
kind-image-sha: sha256:adfaebada924a26c2c9308edd53c6e33b3d4e453782c0063dc0028bdebaddf98
|
||||
exclude:
|
||||
- k8s-version: v1.21.14
|
||||
mode: non-ha
|
||||
- k8s-version: v1.21.14
|
||||
mode: non-ha
|
||||
- k8s-version: v1.22.13
|
||||
mode: non-ha
|
||||
- k8s-version: v1.23.12
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:9402cf1330bbd3a0d097d2033fa489b2abe40d479cc5ef47d0b6a6960613148a
|
||||
- k8s-version: v1.24.6
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:97e8d00bc37a7598a0b32d1fabd155a96355c49fa0d4d4790aab0f161bf31be1
|
||||
- k8s-version: v1.25.2
|
||||
kind-version: v0.16.0
|
||||
kind-image-sha: sha256:9be91e9e9cdf116809841fc77ebdb8845443c4c72fe5218f3ae9eb57fdb4bace
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GOVER }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GOVER }}
|
||||
- name: Check out code onto GOPATH
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ./src/github.com/dapr/cli
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
id: setup-go
|
||||
with:
|
||||
go-version-file: './src/github.com/dapr/cli/go.mod'
|
||||
|
||||
- name: Configure KinD
|
||||
# Generate a KinD configuration file that uses:
|
||||
|
@ -123,7 +111,7 @@ jobs:
|
|||
cat kind.yaml
|
||||
|
||||
- name: Create KinD Cluster
|
||||
uses: helm/kind-action@v1.0.0
|
||||
uses: helm/kind-action@v1.3.0
|
||||
with:
|
||||
config: kind.yaml
|
||||
cluster_name: kind
|
||||
|
@ -149,6 +137,7 @@ jobs:
|
|||
run: |
|
||||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-upgrade-kind.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
export TEST_DAPR_HA_MODE=${{ matrix.mode }}
|
||||
make e2e-build-run-upgrade
|
||||
|
||||
- name: Run tests with Docker hub
|
||||
|
@ -156,11 +145,12 @@ jobs:
|
|||
run: |
|
||||
export TEST_OUTPUT_FILE=$GITHUB_WORKSPACE/test-e2e-upgrade-kind.json
|
||||
echo "TEST_OUTPUT_FILE=$TEST_OUTPUT_FILE" >> $GITHUB_ENV
|
||||
export TEST_DAPR_HA_MODE=${{ matrix.mode }}
|
||||
make e2e-build-run-upgrade
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@master
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.k8s-version }}_${{ matrix.mode }}_e2e_upgrade_k8s.json
|
||||
path: ${{ env.TEST_OUTPUT_FILE }}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
*.dylib
|
||||
cli
|
||||
|
||||
# Handy directory to keep local scripts and help files.
|
||||
.local/
|
||||
|
||||
# Mac's metadata folder
|
||||
.DS_Store
|
||||
|
||||
|
@ -24,6 +27,10 @@ cli
|
|||
|
||||
# CLI's auto-generated components directory
|
||||
**/components
|
||||
# Auto generated deploy dir inside .dapr directory
|
||||
**/.dapr/deploy
|
||||
# Auto generated logs dir inside .dapr directory
|
||||
**/.dapr/logs
|
||||
|
||||
test_output.json
|
||||
|
||||
|
@ -33,4 +40,4 @@ go.work
|
|||
#Wix files
|
||||
*.wixobj
|
||||
*.wixpdb
|
||||
*.msi
|
||||
*.msi
|
||||
|
|
103
.golangci.yml
103
.golangci.yml
|
@ -4,7 +4,7 @@ run:
|
|||
concurrency: 4
|
||||
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
deadline: 10m
|
||||
timeout: 10m
|
||||
|
||||
# exit code when at least one issue was found, default is 1
|
||||
issues-exit-code: 1
|
||||
|
@ -16,27 +16,22 @@ run:
|
|||
#build-tags:
|
||||
# - mytag
|
||||
|
||||
issues:
|
||||
# which dirs to skip: they won't be analyzed;
|
||||
# can use regexp here: generated.*, regexp is applied on full path;
|
||||
# default value is empty list, but next dirs are always skipped independently
|
||||
# from this option's value:
|
||||
# third_party$, testdata$, examples$, Godeps$, builtin$
|
||||
skip-dirs:
|
||||
exclude-dirs:
|
||||
- ^pkg.*client.*clientset.*versioned.*
|
||||
- ^pkg.*client.*informers.*externalversions.*
|
||||
|
||||
# which files to skip: they will be analyzed, but issues from them
|
||||
# won't be reported. Default value is empty list, but there is
|
||||
# no need to include all autogenerated files, we confidently recognize
|
||||
# autogenerated files. If it's not please let us know.
|
||||
skip-files: []
|
||||
# - ".*\\.my\\.go$"
|
||||
# - lib/bad.go
|
||||
- pkg.*mod.*k8s.io.*
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
|
||||
format: tab
|
||||
formats:
|
||||
- format: tab
|
||||
|
||||
# print lines of code with issue, default is true
|
||||
print-issued-lines: true
|
||||
|
@ -70,9 +65,6 @@ linters-settings:
|
|||
statements: 40
|
||||
|
||||
govet:
|
||||
# report about shadowed variables
|
||||
check-shadowing: true
|
||||
|
||||
# settings per analyzer
|
||||
settings:
|
||||
printf: # analyzer name, run `go tool vet help` to see all analyzers
|
||||
|
@ -81,13 +73,18 @@ linters-settings:
|
|||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||
- github.com/dapr/cli/pkg/print.FailureStatusEvent
|
||||
- github.com/dapr/cli/pkg/print.SuccessStatusEvent
|
||||
- github.com/dapr/cli/pkg/print.WarningStatusEvent
|
||||
- github.com/dapr/cli/pkg/print.InfoStatusEvent
|
||||
- github.com/dapr/cli/pkg/print.StatusEvent
|
||||
- github.com/dapr/cli/pkg/print.Spinner
|
||||
|
||||
# enable or disable analyzers by name
|
||||
enable:
|
||||
- atomicalign
|
||||
enable-all: false
|
||||
disable:
|
||||
- shadow
|
||||
enable-all: false
|
||||
disable-all: false
|
||||
revive:
|
||||
# linting errors below this confidence will be ignored, default is 0.8
|
||||
|
@ -105,9 +102,6 @@ linters-settings:
|
|||
gocognit:
|
||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||
min-complexity: 10
|
||||
maligned:
|
||||
# print struct with more effective memory layout or not, false by default
|
||||
suggest-new: true
|
||||
dupl:
|
||||
# tokens count to trigger issue, 150 by default
|
||||
threshold: 100
|
||||
|
@ -117,13 +111,11 @@ linters-settings:
|
|||
# minimal occurrences count to trigger, 3 by default
|
||||
min-occurrences: 5
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
include-go-root: false
|
||||
packages:
|
||||
- github.com/Sirupsen/logrus
|
||||
packages-with-error-messages:
|
||||
# specify an error message to output when a blacklisted package is used
|
||||
github.com/Sirupsen/logrus: "must use github.com/sirupsen/logrus"
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- pkg: "github.com/Sirupsen/logrus"
|
||||
desc: "must use github.com/sirupsen/logrus"
|
||||
misspell:
|
||||
# Correct spellings using locale preferences for US or UK.
|
||||
# Default is to use a neutral variety of English.
|
||||
|
@ -142,7 +134,7 @@ linters-settings:
|
|||
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
|
||||
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
|
||||
# with golangci-lint call it on a directory with the changed file.
|
||||
check-exported: false
|
||||
exported-fields-are-used: false
|
||||
unparam:
|
||||
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
|
||||
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
|
||||
|
@ -215,15 +207,19 @@ linters-settings:
|
|||
# Allow multiline assignments to be cuddled. Default is true.
|
||||
allow-multiline-assign: true
|
||||
# Allow case blocks to end with a whitespace.
|
||||
allow-case-traling-whitespace: true
|
||||
# Allow declarations (var) to be cuddled.
|
||||
allow-cuddle-declarations: false
|
||||
testifylint:
|
||||
disable:
|
||||
- require-error
|
||||
|
||||
|
||||
linters:
|
||||
fast: false
|
||||
enable-all: true
|
||||
disable:
|
||||
# TODO Enforce the below linters later
|
||||
- musttag
|
||||
- dupl
|
||||
- errcheck
|
||||
- funlen
|
||||
|
@ -232,33 +228,48 @@ linters:
|
|||
- gocyclo
|
||||
- gocognit
|
||||
- godox
|
||||
- interfacer
|
||||
- lll
|
||||
- maligned
|
||||
- scopelint
|
||||
- unparam
|
||||
- wsl
|
||||
- gomnd
|
||||
- testpackage
|
||||
- nestif
|
||||
- goerr113
|
||||
- nlreturn
|
||||
- exhaustive
|
||||
- gci
|
||||
- noctx
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- gomoddirectives
|
||||
- paralleltest
|
||||
- noctx
|
||||
- gci
|
||||
- tparallel
|
||||
- wastedassign
|
||||
- cyclop
|
||||
- forbidigo
|
||||
- tagliatelle
|
||||
- thelper
|
||||
- paralleltest
|
||||
- wrapcheck
|
||||
- varnamelen
|
||||
- forcetypeassert
|
||||
- tagliatelle
|
||||
- ireturn
|
||||
- golint
|
||||
- nosnakecase
|
||||
- errchkjson
|
||||
- contextcheck
|
||||
- gomoddirectives
|
||||
- godot
|
||||
- cyclop
|
||||
- varnamelen
|
||||
- errorlint
|
||||
- forcetypeassert
|
||||
- maintidx
|
||||
- nilnil
|
||||
- predeclared
|
||||
- tenv
|
||||
- thelper
|
||||
- wastedassign
|
||||
- containedctx
|
||||
- gosimple
|
||||
- nonamedreturns
|
||||
- asasalint
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- inamedparam
|
||||
- tagalign
|
||||
- mnd
|
||||
- canonicalheader
|
||||
- exportloopref
|
||||
- execinquery
|
||||
- err113
|
||||
- fatcontext
|
||||
- forbidigo
|
||||
|
|
|
@ -40,7 +40,7 @@ Before you file an issue, make sure you've checked the following:
|
|||
- 👎 down-vote
|
||||
1. For bugs
|
||||
- Check it's not an environment issue. For example, if running on Kubernetes, make sure prerequisites are in place. (state stores, bindings, etc.)
|
||||
- You have as much data as possible. This usually comes in the form of logs and/or stacktrace. If running on Kubernetes or other environment, look at the logs of the Dapr services (runtime, operator, placement service). More details on how to get logs can be found [here](https://docs.dapr.io/operations/troubleshooting/logs-troubleshooting/).
|
||||
- You have as much data as possible. This usually comes in the form of logs and/or stacktrace. If running on Kubernetes or other environment, look at the logs of the Dapr services (runtime, operator, placement, scheduler service). More details on how to get logs can be found [here](https://docs.dapr.io/operations/troubleshooting/logs-troubleshooting/).
|
||||
1. For proposals
|
||||
- Many changes to the Dapr runtime may require changes to the API. In that case, the best place to discuss the potential feature is the main [Dapr repo](https://github.com/dapr/dapr).
|
||||
- Other examples could include bindings, state stores or entirely new components.
|
||||
|
|
|
@ -1,991 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:80004fcc5cf64e591486b3e11b406f1e0d17bf85d475d64203c8494f5da4fcd1"
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["compute/metadata"]
|
||||
pruneopts = "UT"
|
||||
revision = "8c41231e01b2085512d98153bcffb847ff9b4b9f"
|
||||
version = "v0.38.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6b1426cad7057b717351eacf5b6fe70f053f11aac1ce254bbf2fd72c031719eb"
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "dcb33c7f3b7cfe67e8a2cea10207ede1b7c40764"
|
||||
version = "v0.4.12"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b88fe174accff6609eee9dc7e4ec9f828cbda83e3646111538dbcc7f762f1a56"
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = [
|
||||
"autorest",
|
||||
"autorest/adal",
|
||||
"autorest/azure",
|
||||
"autorest/date",
|
||||
"logger",
|
||||
"tracing",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f29a2eccaa178b367df0405778cd85e0af7b4225"
|
||||
version = "v12.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d5e752c67b445baa5b6cb6f8aa706775c2aa8e41aca95a0c651520ff2c80361a"
|
||||
name = "github.com/Microsoft/go-winio"
|
||||
packages = [
|
||||
".",
|
||||
"pkg/guid",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "6c72808b55902eae4c5943626030429ff20f3b63"
|
||||
version = "v0.4.14"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:174cfc45f3f3e0f24f4bc3d2c80d8bcd4c02e274f9a0c4e7fcb6ff3273c0eeee"
|
||||
name = "github.com/Pallinder/sillyname-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "97aeae9e6ba11ec62a40cf8b6b4bc42116c0a303"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:04457f9f6f3ffc5fea48e71d62f2ca256637dee0a04d710288e27e05c8b41976"
|
||||
name = "github.com/Sirupsen/logrus"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "839c75faf7f98a33d445d181f3018b5c3409a45e"
|
||||
version = "v1.4.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:937ce6e0cd5ccfec205f444a0d9c74f5680cbb68cd0a992b000559bf964ea20b"
|
||||
name = "github.com/briandowns/spinner"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e3fb08e7443c496a847cb2eef48e3883f3e12c38"
|
||||
version = "v1.6.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c1100fc71e23b6a32b2c68a5202a848fd13811d5a10b12edb8019c3667d1cd9a"
|
||||
name = "github.com/cenkalti/backoff"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "4b4cebaf850ec58f1bb1fec5bdebdf8501c2bc3f"
|
||||
version = "v3.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fdb4ed936abeecb46a8c27dcac83f75c05c87a46d9ec7711411eb785c213fa02"
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = [
|
||||
"gen-go/agent/common/v1",
|
||||
"gen-go/agent/metrics/v1",
|
||||
"gen-go/agent/trace/v1",
|
||||
"gen-go/metrics/v1",
|
||||
"gen-go/resource/v1",
|
||||
"gen-go/trace/v1",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "a105b96453fe85139acc07b68de48f2cbdd71249"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95ea6524ccf5526a5f57fa634f2789266684ae1c15ce1a0cab3ae68e7ea3c4d0"
|
||||
name = "github.com/dapr/dapr"
|
||||
packages = [
|
||||
"pkg/apis/components",
|
||||
"pkg/apis/components/v1alpha1",
|
||||
"pkg/components",
|
||||
"pkg/config/modes",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c75b111b7d2258ce7339f6b40c6d1af5b0b6de22"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "UT"
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4ddc17aeaa82cb18c5f0a25d7c253a10682f518f4b2558a82869506eec223d76"
|
||||
name = "github.com/docker/distribution"
|
||||
packages = [
|
||||
"digestset",
|
||||
"reference",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "2461543d988979529609e8cb6fca9ca190dc48da"
|
||||
version = "v2.7.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c4c7064c2c67a0a00815918bae489dd62cd88d859d24c95115d69b00b3d33334"
|
||||
name = "github.com/docker/docker"
|
||||
packages = [
|
||||
"api/types",
|
||||
"api/types/blkiodev",
|
||||
"api/types/container",
|
||||
"api/types/events",
|
||||
"api/types/filters",
|
||||
"api/types/mount",
|
||||
"api/types/network",
|
||||
"api/types/reference",
|
||||
"api/types/registry",
|
||||
"api/types/strslice",
|
||||
"api/types/swarm",
|
||||
"api/types/time",
|
||||
"api/types/versions",
|
||||
"api/types/volume",
|
||||
"client",
|
||||
"pkg/tlsconfig",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "092cba3727bb9b4a2f0e922cd6c0f93ea270e363"
|
||||
version = "v1.13.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:811c86996b1ca46729bad2724d4499014c4b9effd05ef8c71b852aad90deb0ce"
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = [
|
||||
"nat",
|
||||
"sockets",
|
||||
"tlsconfig",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e95ef557dc3120984bb66b385ae01b4bb8ff56bcde28e7b0d1beed0cccc4d69f"
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "519db1ee28dcc9fd2474ae59fca29a810482bfb1"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
|
||||
name = "github.com/ghodss/yaml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:adddf11eb27039a3afcc74c5e3d13da84e189012ec37acfc2c70385f25edbe0f"
|
||||
name = "github.com/gocarina/gocsv"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2fc85fcf0c07e8bb9123b2104e84cfc2a5b53724"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d02824a56d268f74a6b6fdd944b20b58a77c3d70e81008b3ee0c4f1a6777340"
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"sortkeys",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:489a99067cd08971bd9c1ee0055119ba8febc1429f9200ab0bec68d35e8c4833"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"jsonpb",
|
||||
"proto",
|
||||
"protoc-gen-go/descriptor",
|
||||
"protoc-gen-go/generator",
|
||||
"protoc-gen-go/generator/internal/remap",
|
||||
"protoc-gen-go/plugin",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/struct",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a6181aca1fd5e27103f9a920876f29ac72854df7345a39f3b01e61c8c94cc8af"
|
||||
name = "github.com/google/gofuzz"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f140a6486e521aad38f5917de355cbf147cc0496"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
|
||||
name = "github.com/google/uuid"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
|
||||
name = "github.com/googleapis/gnostic"
|
||||
packages = [
|
||||
"OpenAPIv2",
|
||||
"compiler",
|
||||
"extensions",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c7810b83a74c6ec1d14d16d4b950c09abce6fbe9cc660ac2cde5b57efa8cc12e"
|
||||
name = "github.com/gophercloud/gophercloud"
|
||||
packages = [
|
||||
".",
|
||||
"openstack",
|
||||
"openstack/identity/v2/tenants",
|
||||
"openstack/identity/v2/tokens",
|
||||
"openstack/identity/v3/tokens",
|
||||
"openstack/utils",
|
||||
"pagination",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c2d73b246b48e239d3f03c455905e06fe26e33c3"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4f30fff718a459f9be272e7aa87463cdf4ba27bb8bd7f586ac34c36d670aada4"
|
||||
name = "github.com/grpc-ecosystem/grpc-gateway"
|
||||
packages = [
|
||||
"internal",
|
||||
"runtime",
|
||||
"utilities",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "cddead4ec1d10cc62f08e1fd6f8591fbe71cfff9"
|
||||
version = "v1.9.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:67474f760e9ac3799f740db2c489e6423a4cde45520673ec123ac831ad849cb8"
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = ["simplelru"]
|
||||
pruneopts = "UT"
|
||||
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
|
||||
version = "v0.5.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a0cefd27d12712af4b5018dc7046f245e1e3b5760e2e848c30b171b570708f9b"
|
||||
name = "github.com/imdario/mergo"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "7c29201646fa3de8506f701213473dd407f19646"
|
||||
version = "v0.3.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f5a2051c55d05548d2d4fd23d244027b59fbd943217df8aa3b5e170ac2fd6e1b"
|
||||
name = "github.com/json-iterator/go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29"
|
||||
version = "v1.1.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fa4b4bfa0edfb83c4690d8746ea25bc2447ad0c20063ba72adcb5725f54acde0"
|
||||
name = "github.com/klauspost/compress"
|
||||
packages = [
|
||||
"flate",
|
||||
"gzip",
|
||||
"zlib",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "4e96aec082898e4dad17d8aca1a7e2d01362ff6c"
|
||||
version = "v1.9.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5a0ef768465592efca0412f7e838cdc0826712f8447e70e6ccc52eb441e9ab13"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "de8848e004dd33dc07a2947b3d76f618a7fc7ef1"
|
||||
version = "v1.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e150b5fafbd7607e2d638e4e5cf43aa4100124e5593385147b0a74e2733d8b0d"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2a7a6ca930a4cd0bc33a3f298eb71960732a3a7"
|
||||
version = "v0.0.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7"
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:56aff9bb73896906956fee6927207393212bfaa732c1aab4feaf29de4b1418e9"
|
||||
name = "github.com/mitchellh/go-ps"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "621e5597135b1d14a7d9c2bfc7bc312e7c58463c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||
version = "1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
|
||||
name = "github.com/modern-go/reflect2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6491080aa184f88c2bb8e2f6056e5e0e9a578b2d8666efbd6e97bc37a0c41e72"
|
||||
name = "github.com/nightlyone/lockfile"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0ad87eef1443f64d3d8c50da647e2b1552851124"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abcdbf03ca6ca13d3697e2186edc1f33863bbdac2b3a44dfa39015e8903f7409"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e6d60cf7ba1f42d86d54cdf5508611c4aafb3970"
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d"
|
||||
name = "github.com/opencontainers/go-digest"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||
version = "v1.0.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6eea828983c70075ca297bb915ffbcfd3e34c5a50affd94428a65df955c0ff9c"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "903d9455db9ff1d7ac1ab199062eca7266dd11a3"
|
||||
version = "v1.6.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7413525ee648f20b4181be7fe8103d0cb98be9e141926a03ee082dc207061e4e"
|
||||
name = "github.com/phayes/freeport"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "b8543db493a5ed890c5499e935e2cad7504f3a04"
|
||||
version = "1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bb495ec276ab82d3dd08504bbc0594a65de8c3b22c6f2aaa92d05b73fbf3a82e"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "588a75ec4f32903aa5e39a2619ba6a4631e28424"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1b753ec16506f5864d26a28b43703c58831255059644351bbcb019b843950900"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0b60fc944fb6a7b6c985832bd341bdb7ed8fe894fea330414e7774bb24652962"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "72b022eb357a56469725dcd03918449e2278d02e"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f4b32291cad5efac2bfdba89ccde6aa04618b62ce06c1a571da2dc4f3f2677fb"
|
||||
name = "github.com/subosito/gotenv"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2ef7124db659d49edac6aa459693a15ae36c671a"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59"
|
||||
name = "github.com/valyala/bytebufferpool"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:15ad8a80098fcc7a194b9db6b26d74072a852e4faa957848c8118193d3c69230"
|
||||
name = "github.com/valyala/fasthttp"
|
||||
packages = [
|
||||
".",
|
||||
"fasthttputil",
|
||||
"stackless",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "e5f51c11919d4f66400334047b897ef0a94c6f3c"
|
||||
version = "v20180529"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4c93890bbbb5016505e856cb06b5c5a2ff5b7217584d33f2a9071ebef4b5d473"
|
||||
name = "go.opencensus.io"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
"internal/tagencoding",
|
||||
"metric/metricdata",
|
||||
"metric/metricproducer",
|
||||
"plugin/ocgrpc",
|
||||
"plugin/ochttp",
|
||||
"plugin/ochttp/propagation/b3",
|
||||
"plugin/ochttp/propagation/tracecontext",
|
||||
"resource",
|
||||
"stats",
|
||||
"stats/internal",
|
||||
"stats/view",
|
||||
"tag",
|
||||
"trace",
|
||||
"trace/internal",
|
||||
"trace/propagation",
|
||||
"trace/tracestate",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "43463a80402d8447b7fce0d2c58edf1687ff0b58"
|
||||
version = "v0.19.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bbe51412d9915d64ffaa96b51d409e070665efc5194fcf145c4a27d4133107a4"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
pruneopts = "UT"
|
||||
revision = "e1dfcc566284e143ba8f9afbb3fa563f2a0d212b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:01a2f697724170f98739b5261ec830eafc626f56b6786c730578dabcce47649c"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"context/ctxhttp",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/socks",
|
||||
"internal/timeseries",
|
||||
"proxy",
|
||||
"trace",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "a4d6f7feada510cc50e69a37b484cb0fdc6b7876"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:645cb780e4f3177111b40588f0a7f5950efcfb473e7ff41d8d81b2ba5eaa6ed5"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [
|
||||
".",
|
||||
"google",
|
||||
"internal",
|
||||
"jws",
|
||||
"jwt",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "9f3314589c9a9136388751d9adae6b0ed400978a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:382bb5a7fb4034db3b6a2d19e5a4a6bcf52f4750530603c01ca18a172fa3089b"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
pruneopts = "UT"
|
||||
revision = "112230192c580c3556b8cee6403af37a4fc5f28c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:656ce95b4cdf841c00825f4cb94f6e0e1422d7d6faaf3094e94cd18884a32251"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "a129542de9ae0895210abff9c95d67a1f33cb93d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8d8faad6b12a3a4c819a3f9618cb6ee1fa1cfc33253abeeea8b55336721e3405"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/language",
|
||||
"internal/language/compact",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
|
||||
version = "v0.3.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
pruneopts = "UT"
|
||||
revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643"
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
pruneopts = "UT"
|
||||
revision = "aac82e61c0c8fe133c297b4b59316b9f481e1f0a"
|
||||
version = "v0.6.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:04f2ff15fc59e1ddaf9900ad0e19e5b19586b31f9dafd4d592b617642b239d8f"
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
"internal/app_identity",
|
||||
"internal/base",
|
||||
"internal/datastore",
|
||||
"internal/log",
|
||||
"internal/modules",
|
||||
"internal/remote_api",
|
||||
"internal/urlfetch",
|
||||
"urlfetch",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:3565a93b7692277a5dea355bc47bd6315754f3246ed07a224be6aec28972a805"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = [
|
||||
"googleapis/api/httpbody",
|
||||
"googleapis/rpc/status",
|
||||
"protobuf/field_mask",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "a7e196e89fd3a3c4d103ca540bd5dac3a736e375"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e8800ddadd6bce3bc0c5ffd7bc55dbdddc6e750956c10cc10271cade542fccbe"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"binarylog/grpc_binarylog_v1",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"credentials/internal",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/balancerload",
|
||||
"internal/binarylog",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/grpcsync",
|
||||
"internal/syscall",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "501c41df7f472c740d0674ff27122f3f48c80ce7"
|
||||
version = "v1.21.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
||||
version = "v0.9.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:86ad5797d1189de342ed6988fbb76b92dc0429a4d677ad69888d6137efa5712e"
|
||||
name = "k8s.io/api"
|
||||
packages = [
|
||||
"admissionregistration/v1beta1",
|
||||
"apps/v1",
|
||||
"apps/v1beta1",
|
||||
"apps/v1beta2",
|
||||
"auditregistration/v1alpha1",
|
||||
"authentication/v1",
|
||||
"authentication/v1beta1",
|
||||
"authorization/v1",
|
||||
"authorization/v1beta1",
|
||||
"autoscaling/v1",
|
||||
"autoscaling/v2beta1",
|
||||
"autoscaling/v2beta2",
|
||||
"batch/v1",
|
||||
"batch/v1beta1",
|
||||
"batch/v2alpha1",
|
||||
"certificates/v1beta1",
|
||||
"coordination/v1",
|
||||
"coordination/v1beta1",
|
||||
"core/v1",
|
||||
"events/v1beta1",
|
||||
"extensions/v1beta1",
|
||||
"networking/v1",
|
||||
"networking/v1beta1",
|
||||
"node/v1alpha1",
|
||||
"node/v1beta1",
|
||||
"policy/v1beta1",
|
||||
"rbac/v1",
|
||||
"rbac/v1alpha1",
|
||||
"rbac/v1beta1",
|
||||
"scheduling/v1",
|
||||
"scheduling/v1alpha1",
|
||||
"scheduling/v1beta1",
|
||||
"settings/v1alpha1",
|
||||
"storage/v1",
|
||||
"storage/v1alpha1",
|
||||
"storage/v1beta1",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "6e4e0e4f393bf5e8bbff570acd13217aa5a770cd"
|
||||
version = "kubernetes-1.14.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78f6a824d205c6cb0d011cce241407646b773cb57ee27e8c7e027753b4111075"
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/errors",
|
||||
"pkg/api/meta",
|
||||
"pkg/api/resource",
|
||||
"pkg/apis/meta/v1",
|
||||
"pkg/apis/meta/v1/unstructured",
|
||||
"pkg/apis/meta/v1beta1",
|
||||
"pkg/conversion",
|
||||
"pkg/conversion/queryparams",
|
||||
"pkg/fields",
|
||||
"pkg/labels",
|
||||
"pkg/runtime",
|
||||
"pkg/runtime/schema",
|
||||
"pkg/runtime/serializer",
|
||||
"pkg/runtime/serializer/json",
|
||||
"pkg/runtime/serializer/protobuf",
|
||||
"pkg/runtime/serializer/recognizer",
|
||||
"pkg/runtime/serializer/streaming",
|
||||
"pkg/runtime/serializer/versioning",
|
||||
"pkg/selection",
|
||||
"pkg/types",
|
||||
"pkg/util/clock",
|
||||
"pkg/util/errors",
|
||||
"pkg/util/framer",
|
||||
"pkg/util/intstr",
|
||||
"pkg/util/json",
|
||||
"pkg/util/naming",
|
||||
"pkg/util/net",
|
||||
"pkg/util/runtime",
|
||||
"pkg/util/sets",
|
||||
"pkg/util/validation",
|
||||
"pkg/util/validation/field",
|
||||
"pkg/util/yaml",
|
||||
"pkg/version",
|
||||
"pkg/watch",
|
||||
"third_party/forked/golang/reflect",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "6a84e37a896db9780c75367af8d2ed2bb944022e"
|
||||
version = "kubernetes-1.14.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:37f699391265222af7da4bf8e443ca03dd834ce362fbb4b19b4d67492ff06781"
|
||||
name = "k8s.io/client-go"
|
||||
packages = [
|
||||
"discovery",
|
||||
"kubernetes",
|
||||
"kubernetes/scheme",
|
||||
"kubernetes/typed/admissionregistration/v1beta1",
|
||||
"kubernetes/typed/apps/v1",
|
||||
"kubernetes/typed/apps/v1beta1",
|
||||
"kubernetes/typed/apps/v1beta2",
|
||||
"kubernetes/typed/auditregistration/v1alpha1",
|
||||
"kubernetes/typed/authentication/v1",
|
||||
"kubernetes/typed/authentication/v1beta1",
|
||||
"kubernetes/typed/authorization/v1",
|
||||
"kubernetes/typed/authorization/v1beta1",
|
||||
"kubernetes/typed/autoscaling/v1",
|
||||
"kubernetes/typed/autoscaling/v2beta1",
|
||||
"kubernetes/typed/autoscaling/v2beta2",
|
||||
"kubernetes/typed/batch/v1",
|
||||
"kubernetes/typed/batch/v1beta1",
|
||||
"kubernetes/typed/batch/v2alpha1",
|
||||
"kubernetes/typed/certificates/v1beta1",
|
||||
"kubernetes/typed/coordination/v1",
|
||||
"kubernetes/typed/coordination/v1beta1",
|
||||
"kubernetes/typed/core/v1",
|
||||
"kubernetes/typed/events/v1beta1",
|
||||
"kubernetes/typed/extensions/v1beta1",
|
||||
"kubernetes/typed/networking/v1",
|
||||
"kubernetes/typed/networking/v1beta1",
|
||||
"kubernetes/typed/node/v1alpha1",
|
||||
"kubernetes/typed/node/v1beta1",
|
||||
"kubernetes/typed/policy/v1beta1",
|
||||
"kubernetes/typed/rbac/v1",
|
||||
"kubernetes/typed/rbac/v1alpha1",
|
||||
"kubernetes/typed/rbac/v1beta1",
|
||||
"kubernetes/typed/scheduling/v1",
|
||||
"kubernetes/typed/scheduling/v1alpha1",
|
||||
"kubernetes/typed/scheduling/v1beta1",
|
||||
"kubernetes/typed/settings/v1alpha1",
|
||||
"kubernetes/typed/storage/v1",
|
||||
"kubernetes/typed/storage/v1alpha1",
|
||||
"kubernetes/typed/storage/v1beta1",
|
||||
"pkg/apis/clientauthentication",
|
||||
"pkg/apis/clientauthentication/v1alpha1",
|
||||
"pkg/apis/clientauthentication/v1beta1",
|
||||
"pkg/version",
|
||||
"plugin/pkg/client/auth",
|
||||
"plugin/pkg/client/auth/azure",
|
||||
"plugin/pkg/client/auth/exec",
|
||||
"plugin/pkg/client/auth/gcp",
|
||||
"plugin/pkg/client/auth/oidc",
|
||||
"plugin/pkg/client/auth/openstack",
|
||||
"rest",
|
||||
"rest/watch",
|
||||
"third_party/forked/golang/template",
|
||||
"tools/auth",
|
||||
"tools/clientcmd",
|
||||
"tools/clientcmd/api",
|
||||
"tools/clientcmd/api/latest",
|
||||
"tools/clientcmd/api/v1",
|
||||
"tools/metrics",
|
||||
"tools/reference",
|
||||
"transport",
|
||||
"util/cert",
|
||||
"util/connrotation",
|
||||
"util/flowcontrol",
|
||||
"util/homedir",
|
||||
"util/jsonpath",
|
||||
"util/keyutil",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "1a26190bd76a9017e289958b9fba936430aa3704"
|
||||
version = "kubernetes-1.14.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c696379ad201c1e86591785579e16bf6cf886c362e9a7534e8eb0d1028b20582"
|
||||
name = "k8s.io/klog"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e531227889390a39d9533dde61f590fe9f4b0035"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8b40227d4bf8b431fdab4f9026e6e346f00ac3be5662af367a183f78c57660b3"
|
||||
name = "k8s.io/utils"
|
||||
packages = ["integer"]
|
||||
pruneopts = "UT"
|
||||
revision = "8fab8cb257d50c8cf94ec9771e74826edbb68fb5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
|
||||
name = "sigs.k8s.io/yaml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
|
||||
version = "v1.1.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/Pallinder/sillyname-go",
|
||||
"github.com/briandowns/spinner",
|
||||
"github.com/dapr/dapr/pkg/components",
|
||||
"github.com/dapr/dapr/pkg/config/modes",
|
||||
"github.com/docker/docker/client",
|
||||
"github.com/fatih/color",
|
||||
"github.com/gocarina/gocsv",
|
||||
"github.com/google/uuid",
|
||||
"github.com/mitchellh/go-ps",
|
||||
"github.com/nightlyone/lockfile",
|
||||
"github.com/olekukonko/tablewriter",
|
||||
"github.com/phayes/freeport",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/viper",
|
||||
"gopkg.in/yaml.v2",
|
||||
"k8s.io/api/core/v1",
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"k8s.io/client-go/kubernetes",
|
||||
"k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"k8s.io/client-go/plugin/pkg/client/auth/gcp",
|
||||
"k8s.io/client-go/tools/clientcmd",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
54
Gopkg.toml
54
Gopkg.toml
|
@ -1,54 +0,0 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/color"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/viper"
|
||||
version = "1.5.0"
|
||||
|
||||
[[override]]
|
||||
version = "kubernetes-1.14.1"
|
||||
name = "k8s.io/apimachinery"
|
||||
|
||||
[[override]]
|
||||
version = "kubernetes-1.14.1"
|
||||
name = "k8s.io/api"
|
||||
|
||||
[[override]]
|
||||
version = "kubernetes-1.14.1"
|
||||
name = "k8s.io/client-go"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
37
Makefile
37
Makefile
|
@ -59,6 +59,7 @@ ifeq ($(LOCAL_OS),Linux)
|
|||
else ifeq ($(LOCAL_OS),Darwin)
|
||||
TARGET_OS_LOCAL = darwin
|
||||
GOLANGCI_LINT:=golangci-lint
|
||||
PATH := $(PATH):$(HOME)/go/bin/darwin_$(GOARCH)
|
||||
export ARCHIVE_EXT = .tar.gz
|
||||
else
|
||||
TARGET_OS_LOCAL ?= windows
|
||||
|
@ -71,6 +72,11 @@ export BINARY_EXT ?= $(BINARY_EXT_LOCAL)
|
|||
|
||||
TEST_OUTPUT_FILE ?= test_output.json
|
||||
|
||||
# Set the default timeout for tests to 10 minutes
|
||||
ifndef E2E_SH_TEST_TIMEOUT
|
||||
override E2E_SH_TEST_TIMEOUT := 10m
|
||||
endif
|
||||
|
||||
# Use the variable H to add a header (equivalent to =>) to informational output
|
||||
H = $(shell printf "\033[34;1m=>\033[0m")
|
||||
|
||||
|
@ -148,7 +154,14 @@ test: test-deps
|
|||
################################################################################
|
||||
.PHONY: test-e2e-k8s
|
||||
test-e2e-k8s: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 20m -count=1 -tags=e2e ./tests/e2e/kubernetes/...
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 25m -count=1 -tags=e2e ./tests/e2e/kubernetes/...
|
||||
|
||||
################################################################################
|
||||
# E2E Tests for K8s Template exec #
|
||||
################################################################################
|
||||
.PHONY: test-e2e-k8s-template
|
||||
test-e2e-k8s-template: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 25m -count=1 -tags=templatek8s ./tests/e2e/kubernetes/...
|
||||
|
||||
################################################################################
|
||||
# Build, E2E Tests for Kubernetes #
|
||||
|
@ -161,7 +174,7 @@ e2e-build-run-k8s: build test-e2e-k8s
|
|||
################################################################################
|
||||
.PHONY: test-e2e-upgrade
|
||||
test-e2e-upgrade: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 30m -count=1 -tags=e2e ./tests/e2e/upgrade/...
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 60m -count=1 -tags=e2e ./tests/e2e/upgrade/...
|
||||
|
||||
################################################################################
|
||||
# Build, E2E Tests for Kubernetes Upgrade #
|
||||
|
@ -170,12 +183,19 @@ test-e2e-upgrade: test-deps
|
|||
e2e-build-run-upgrade: build test-e2e-upgrade
|
||||
|
||||
|
||||
################################################################################
|
||||
# E2E Tests for Self-Hosted Template exec #
|
||||
################################################################################
|
||||
.PHONY: test-e2e-sh-template
|
||||
test-e2e-sh-template: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout $(E2E_SH_TEST_TIMEOUT) -count=1 -tags=template ./tests/e2e/standalone/...
|
||||
|
||||
################################################################################
|
||||
# E2E Tests for Self-Hosted #
|
||||
################################################################################
|
||||
.PHONY: test-e2e-sh
|
||||
test-e2e-sh: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -count=1 -tags=e2e ./tests/e2e/standalone/...
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout $(E2E_SH_TEST_TIMEOUT) -count=1 -tags=e2e ./tests/e2e/standalone/...
|
||||
|
||||
################################################################################
|
||||
# Build, E2E Tests for Self-Hosted #
|
||||
|
@ -188,7 +208,7 @@ e2e-build-run-sh: build test-e2e-sh
|
|||
################################################################################
|
||||
.PHONY: modtidy
|
||||
modtidy:
|
||||
go mod tidy -compat=1.19
|
||||
go mod tidy -compat=1.21
|
||||
|
||||
################################################################################
|
||||
# Target: check-diff #
|
||||
|
@ -196,3 +216,12 @@ modtidy:
|
|||
.PHONY: check-diff
|
||||
check-diff:
|
||||
git diff --exit-code ./go.mod # check no changes
|
||||
|
||||
################################################################################
|
||||
# Target: vuln-check #
|
||||
################################################################################
|
||||
.PHONY: vuln-check
|
||||
vuln-check:
|
||||
@echo "Checking for vulnerabilities..."
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
govulncheck ./...
|
||||
|
|
73
README.md
73
README.md
|
@ -68,7 +68,7 @@ Install windows Dapr CLI using MSI package.
|
|||
|
||||
### Install Dapr on your local machine (self-hosted)
|
||||
|
||||
In self-hosted mode, dapr can be initialized using the CLI with the placement, redis and zipkin containers enabled by default(recommended) or without them which also does not require docker to be available in the environment.
|
||||
In self-hosted mode, dapr can be initialized using the CLI with the placement, scheduler, redis, and zipkin containers enabled by default(recommended) or without them which also does not require docker to be available in the environment.
|
||||
|
||||
#### Initialize Dapr
|
||||
|
||||
|
@ -89,17 +89,18 @@ Output should look like so:
|
|||
✅ Downloaded binaries and completed components set up.
|
||||
ℹ️ daprd binary has been installed to $HOME/.dapr/bin.
|
||||
ℹ️ dapr_placement container is running.
|
||||
ℹ️ dapr_scheduler container is running.
|
||||
ℹ️ dapr_redis container is running.
|
||||
ℹ️ dapr_zipkin container is running.
|
||||
ℹ️ Use `docker ps` to check running containers.
|
||||
✅ Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started
|
||||
✅ Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started
|
||||
```
|
||||
|
||||
> Note: To see that Dapr has been installed successfully, from a command prompt run the `docker ps` command and check that the `daprio/dapr:latest`, `dapr_redis` and `dapr_zipkin` container images are all running.
|
||||
|
||||
This step creates the following defaults:
|
||||
|
||||
1. components folder which is later used during `dapr run` unless the `--components-path` option is provided. For Linux/MacOS, the default components folder path is `$HOME/.dapr/components` and for Windows it is `%USERPROFILE%\.dapr\components`.
|
||||
1. components folder which is later used during `dapr run` unless the `--resources-path` (`--components-path` is deprecated and will be removed in future releases) option is provided. For Linux/MacOS, the default components folder path is `$HOME/.dapr/components` and for Windows it is `%USERPROFILE%\.dapr\components`.
|
||||
2. component files in the components folder called `pubsub.yaml` and `statestore.yaml`.
|
||||
3. default config file `$HOME/.dapr/config.yaml` for Linux/MacOS or for Windows at `%USERPROFILE%\.dapr\config.yaml` to enable tracing on `dapr init` call. Can be overridden with the `--config` flag on `dapr run`.
|
||||
|
||||
|
@ -118,10 +119,11 @@ Output should look like so:
|
|||
✅ Downloaded binaries and completed components set up.
|
||||
ℹ️ daprd binary has been installed to $HOME/.dapr/bin.
|
||||
ℹ️ placement binary has been installed.
|
||||
✅ Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started
|
||||
ℹ️ scheduler binary has been installed.
|
||||
✅ Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started
|
||||
```
|
||||
|
||||
>Note: When initializing Dapr with the `--slim` flag only the Dapr runtime binary and the placement service binary are installed. An empty default components folder is created with no default configuration files. During `dapr run` user should use `--components-path` to point to a components directory with custom configurations files or alternatively place these files in the default directory. For Linux/MacOS, the default components directory path is `$HOME/.dapr/components` and for Windows it is `%USERPROFILE%\.dapr\components`.
|
||||
>Note: When initializing Dapr with the `--slim` flag only the Dapr runtime, placement, and scheduler service binaries are installed. An empty default components folder is created with no default configuration files. During `dapr run` user should use `--resources-path` (`--components-path` is deprecated and will be removed in future releases) to point to a components directory with custom configurations files or alternatively place these files in the default directory. For Linux/MacOS, the default components directory path is `$HOME/.dapr/components` and for Windows it is `%USERPROFILE%\.dapr\components`.
|
||||
|
||||
#### Install a specific runtime version
|
||||
|
||||
|
@ -139,7 +141,7 @@ Runtime version: v1.0.0
|
|||
|
||||
#### Install with mariner images
|
||||
|
||||
You can install Dapr Runtime using mariner images using the `--image-variant` flag.
|
||||
You can install Dapr Runtime using mariner images using the `--image-variant` flag.
|
||||
|
||||
```bash
|
||||
# Installing Dapr with Mariner images
|
||||
|
@ -156,6 +158,17 @@ You can install Dapr runtime by pulling docker images from a given private regis
|
|||
dapr init --image-registry example.io/<username>
|
||||
```
|
||||
|
||||
#### Install with a custom scheduler host and port
|
||||
|
||||
You can install Dapr runtime with a custom scheduler host and port by using `--scheduler-override-broadcast-host-port` flag.
|
||||
|
||||
```bash
|
||||
dapr init --scheduler-override-broadcast-host-port 192.168.42.42:50006
|
||||
```
|
||||
|
||||
> Note: The default host is `localhost`.
|
||||
|
||||
|
||||
#### Install in airgap environment
|
||||
|
||||
You can install Dapr runtime in airgap (offline) environment using a pre-downloaded [installer bundle](https://github.com/dapr/installer-bundle/releases). You need to download the archived bundle for your OS beforehand (e.g., daprbundle_linux_amd64.tar.gz,) and unpack it. Thereafter use the local Dapr CLI binary in the bundle with `--from-dir` flag in the init command to point to the extracted bundle location to initialize Dapr.
|
||||
|
@ -171,14 +184,14 @@ Move to the bundle directory and run the following command:
|
|||
|
||||
> If you are not running the above command from the bundle directory, provide the full path to bundle directory as input. For example, assuming the bundle directory path is $HOME/daprbundle, run `$HOME/daprbundle/dapr init --from-dir $HOME/daprbundle` to have the same behavior.
|
||||
|
||||
> Note: Dapr Installer bundle just contains the placement container apart from the binaries and so `zipkin` and `redis` are not enabled by default. You can pull the images locally either from network or private registry and run as follows:
|
||||
> Note: Dapr Installer bundle just contains the placement and scheduler containers apart from the binaries and so `zipkin` and `redis` are not enabled by default. You can pull the images locally either from network or private registry and run as follows:
|
||||
|
||||
```bash
|
||||
docker run --name "dapr_zipkin" --restart always -d -p 9411:9411 openzipkin/zipkin
|
||||
docker run --name "dapr_redis" --restart always -d -p 6379:6379 redis
|
||||
```
|
||||
|
||||
Alternatively to the above, you can also have slim installation as well to install dapr without running any Docker containers in airgap mode.
|
||||
Alternatively to the above, you can also have slim installation as well to install dapr without running any Docker containers in airgap mode.
|
||||
|
||||
```bash
|
||||
./dapr init --slim --from-dir .
|
||||
|
@ -199,6 +212,9 @@ dapr init --network dapr-network
|
|||
> Note: When installed to a specific Docker network, you will need to add the `--placement-host-address` arguments to `dapr run` commands run in any containers within that network.
|
||||
> The format of `--placement-host-address` argument is either `<hostname>` or `<hostname>:<port>`. If the port is omitted, the default port `6050` for Windows and `50005` for Linux/MacOS applies.
|
||||
|
||||
> Note: When installed to a specific Docker network, you will need to add the `--scheduler-host-address` arguments to `dapr run` commands run in any containers within that network.
|
||||
> The format of `--scheduler-host-address` argument is either `<hostname>` or `<hostname>:<port>`. If the port is omitted, the default port `6060` for Windows and `50006` for Linux/MacOS applies.
|
||||
|
||||
#### Install with a specific container runtime
|
||||
|
||||
You can install the Dapr runtime using a specific container runtime
|
||||
|
@ -212,9 +228,23 @@ $ dapr init --container-runtime podman
|
|||
|
||||
> Note: The default container runtime is Docker.
|
||||
|
||||
#### In a dev container or GitHub Codespace
|
||||
|
||||
To install the Dapr CLI in a dev container or GitHub Codespace, add the following to your `devcontainer.json` file:
|
||||
|
||||
```jsonc
|
||||
"features": {
|
||||
"ghcr.io/dapr/cli/dapr-cli:0": {}
|
||||
}
|
||||
```
|
||||
|
||||
Restart your dev container or GitHub Codespace and run `dapr init` to initialize Dapr.
|
||||
|
||||
For more details, see the docs for dev containers with [Visual Studio Code](https://code.visualstudio.com/docs/devcontainers/containers#_dev-container-features) and [GitHub Codespaces](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/configuring-dev-containers/adding-features-to-a-devcontainer-file).
|
||||
|
||||
### Uninstall Dapr in a standalone mode
|
||||
|
||||
Uninstalling will remove daprd binary and the placement container (if installed with Docker or the placement binary if not).
|
||||
Uninstalling will remove daprd binary along with the placement and scheduler containers (if installed with Docker or the placement and scheduler binaries if not).
|
||||
|
||||
|
||||
```bash
|
||||
|
@ -223,7 +253,7 @@ dapr uninstall
|
|||
|
||||
> For Linux users, if you run your docker cmds with sudo, you need to use "**sudo dapr uninstall**" to remove the containers.
|
||||
|
||||
The command above won't remove the redis or zipkin containers by default in case you were using it for other purposes. It will also not remove the default dapr folder that was created on `dapr init`. To remove all the containers (placement, redis, zipkin) and also the default dapr folder created on init run:
|
||||
The command above won't remove the redis or zipkin containers by default in case you were using it for other purposes. It will also not remove the default dapr folder that was created on `dapr init`. To remove all the containers (placement, scheduler, redis, zipkin) and also the default dapr folder created on init run:
|
||||
|
||||
```bash
|
||||
dapr uninstall --all
|
||||
|
@ -231,7 +261,7 @@ dapr uninstall --all
|
|||
|
||||
The above command can also be run when Dapr has been installed in a non-docker environment, it will only remove the installed binaries and the default dapr folder in that case.
|
||||
|
||||
> NB: The `dapr uninstall` command will always try to remove the placement binary/service and will throw an error is not able to.
|
||||
> NB: The `dapr uninstall` command will always try to remove the placement and scheduler binaries/services and will throw an error is not able to.
|
||||
|
||||
**You should always run a `dapr uninstall` before running another `dapr init`.**
|
||||
|
||||
|
@ -270,7 +300,7 @@ Output should look like as follows:
|
|||
ℹ️ Note: To install Dapr using Helm, see here: https://docs.dapr.io/getting-started/install-dapr/#install-with-helm-advanced
|
||||
|
||||
✅ Deploying the Dapr control plane to your cluster...
|
||||
✅ Success! Dapr has been installed to namespace dapr-system. To verify, run "dapr status -k" in your terminal. To get started, go here: https://aka.ms/dapr-getting-started
|
||||
✅ Success! Dapr has been installed to namespace dapr-system. To verify, run "dapr status -k" in your terminal. To get started, go here: https://docs.dapr.io/getting-started
|
||||
```
|
||||
|
||||
#### Supplying Helm values
|
||||
|
@ -278,7 +308,7 @@ Output should look like as follows:
|
|||
All available [Helm Chart values](https://github.com/dapr/dapr/tree/master/charts/dapr#configuration) can be set by using the `--set` flag:
|
||||
|
||||
```bash
|
||||
dapr init -k --set global.tag=1.0.0 --set dapr_operator.logLevel=error
|
||||
dapr init -k --set global.tag=1.0.0 --set dapr_operator.logLevel=error
|
||||
```
|
||||
|
||||
#### Installing to a custom namespace
|
||||
|
@ -337,12 +367,14 @@ dapr upgrade -k --runtime-version=1.0.0
|
|||
|
||||
The example above shows how to upgrade from your current version to version `1.0.0`.
|
||||
|
||||
*Note: `dapr upgrade` will retry up to 5 times upon failure*
|
||||
|
||||
#### Supplying Helm values
|
||||
|
||||
All available [Helm Chart values](https://github.com/dapr/dapr/tree/master/charts/dapr#configuration) can be set by using the `--set` flag:
|
||||
|
||||
```bash
|
||||
dapr upgrade -k --runtime-version=1.0.0 --set global.tag=my-tag --set dapr_operator.logLevel=error
|
||||
dapr upgrade -k --runtime-version=1.0.0 --set global.tag=my-tag --set dapr_operator.logLevel=error
|
||||
```
|
||||
|
||||
*Note: do not use the `dapr upgrade` command if you're upgrading from 0.x versions of Dapr*
|
||||
|
@ -391,7 +423,7 @@ dapr init --network dapr-network
|
|||
dapr run --app-id nodeapp --placement-host-address dapr_placement node app.js
|
||||
```
|
||||
|
||||
> Note: When in a specific Docker network, the Redis, Zipkin and placement service containers are given specific network aliases, `dapr_redis`, `dapr_zipkin` and `dapr_placement`, respectively. The default configuration files reflect the network alias rather than `localhost` when a docker network is specified.
|
||||
> Note: When in a specific Docker network, the Redis, Zipkin and placement and scheduler service containers are given specific network aliases, `dapr_redis`, `dapr_zipkin`, `dapr_placement`, and `dapr_scheduler`, respectively. The default configuration files reflect the network alias rather than `localhost` when a docker network is specified.
|
||||
|
||||
### Use gRPC
|
||||
|
||||
|
@ -444,7 +476,7 @@ Launch Dapr and your app:
|
|||
dapr run --app-id nodeapp --app-port 3000 node app.js
|
||||
```
|
||||
|
||||
Note: To choose a non-default components folder, use the --components-path option.
|
||||
Note: To choose a non-default components folder, use the --resources-path(--components-path is deprecated) option.
|
||||
|
||||
Invoke your app:
|
||||
|
||||
|
@ -537,6 +569,10 @@ Use user provided ca.crt, issuer.crt and issuer.key
|
|||
```bash
|
||||
dapr mtls renew-certificate -k --ca-root-certificate <ca.crt> --issuer-private-key <issuer.key> --issuer-public-certificate <issuer.crt> --restart
|
||||
```
|
||||
#### To view the complete list of flags and their combination, run below command:
|
||||
```bash
|
||||
dapr mtls renew-certificate -h
|
||||
```
|
||||
|
||||
### List Components
|
||||
|
||||
|
@ -557,7 +593,8 @@ dapr components --kubernetes --namespace target-namespace
|
|||
To use a custom path for component definitions
|
||||
|
||||
```bash
|
||||
dapr run --components-path [custom path]
|
||||
dapr run --resources-path [custom path]
|
||||
> Note: --components-path flag is deprecated. It will continue to work until it is removed completely.
|
||||
```
|
||||
|
||||
|
||||
|
@ -723,7 +760,9 @@ See the [Reference Guide](https://docs.dapr.io/reference/cli/) for more informat
|
|||
## Contributing to Dapr CLI
|
||||
|
||||
See the [Development Guide](https://github.com/dapr/cli/blob/master/docs/development/development.md) to get started with building and developing.
|
||||
## Release process for Dapr CLI
|
||||
|
||||
See the [Release Guide](https://github.com/dapr/cli/blob/master/docs/development/release.md) for complete release process for Dapr CLI.
|
||||
## Code of Conduct
|
||||
|
||||
Please refer to our [Dapr Community Code of Conduct](https://github.com/dapr/community/blob/master/CODE-OF-CONDUCT.md)
|
||||
|
|
|
@ -21,6 +21,11 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/dapr/dapr/pkg/runtime"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
@ -60,8 +65,8 @@ var (
|
|||
annotateReadinessProbeThreshold int
|
||||
annotateDaprImage string
|
||||
annotateAppSSL bool
|
||||
annotateMaxRequestBodySize int
|
||||
annotateReadBufferSize int
|
||||
annotateMaxRequestBodySize string
|
||||
annotateReadBufferSize string
|
||||
annotateHTTPStreamRequestBody bool
|
||||
annotateGracefulShutdownSeconds int
|
||||
annotateEnableAPILogging bool
|
||||
|
@ -221,7 +226,6 @@ func readInputsFromFS(path string) ([]io.Reader, error) {
|
|||
inputs = append(inputs, file)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -319,12 +323,23 @@ func getOptionsFromFlags() kubernetes.AnnotateOptions {
|
|||
if annotateAppSSL {
|
||||
o = append(o, kubernetes.WithAppSSL())
|
||||
}
|
||||
if annotateMaxRequestBodySize != -1 {
|
||||
o = append(o, kubernetes.WithMaxRequestBodySize(annotateMaxRequestBodySize))
|
||||
if annotateMaxRequestBodySize != "-1" {
|
||||
if q, err := resource.ParseQuantity(annotateMaxRequestBodySize); err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "error parsing value of max-body-size: %s, error: %s", annotateMaxRequestBodySize, err.Error())
|
||||
os.Exit(1)
|
||||
} else {
|
||||
o = append(o, kubernetes.WithMaxRequestBodySize(int(q.Value())))
|
||||
}
|
||||
}
|
||||
if annotateReadBufferSize != -1 {
|
||||
o = append(o, kubernetes.WithReadBufferSize(annotateReadBufferSize))
|
||||
if annotateReadBufferSize != "-1" {
|
||||
if q, err := resource.ParseQuantity(annotateReadBufferSize); err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "error parsing value of read-buffer-size: %s, error: %s", annotateMaxRequestBodySize, err.Error())
|
||||
os.Exit(1)
|
||||
} else {
|
||||
o = append(o, kubernetes.WithReadBufferSize(int(q.Value())))
|
||||
}
|
||||
}
|
||||
|
||||
if annotateHTTPStreamRequestBody {
|
||||
o = append(o, kubernetes.WithHTTPStreamRequestBody())
|
||||
}
|
||||
|
@ -359,7 +374,7 @@ func init() {
|
|||
AnnotateCmd.Flags().StringVarP(&annotateAppID, "app-id", "a", "", "The app id to annotate")
|
||||
AnnotateCmd.Flags().IntVarP(&annotateAppPort, "app-port", "p", -1, "The port to expose the app on")
|
||||
AnnotateCmd.Flags().StringVarP(&annotateConfig, "config", "c", "", "The config file to annotate")
|
||||
AnnotateCmd.Flags().StringVar(&annotateAppProtocol, "app-protocol", "", "The protocol to use for the app")
|
||||
AnnotateCmd.Flags().StringVar(&annotateAppProtocol, "app-protocol", "", "The protocol to use for the app. Allowed values http, https, h2c, grpc, grpcs")
|
||||
AnnotateCmd.Flags().BoolVar(&annotateEnableProfile, "enable-profile", false, "Enable profiling")
|
||||
AnnotateCmd.Flags().StringVar(&annotateLogLevel, "log-level", "", "The log level to use")
|
||||
AnnotateCmd.Flags().StringVar(&annotateAPITokenSecret, "api-token-secret", "", "The secret to use for the API token")
|
||||
|
@ -385,8 +400,9 @@ func init() {
|
|||
AnnotateCmd.Flags().IntVar(&annotateReadinessProbeThreshold, "readiness-probe-threshold", -1, "The threshold to use for the readiness probe")
|
||||
AnnotateCmd.Flags().StringVar(&annotateDaprImage, "dapr-image", "", "The image to use for the dapr sidecar container")
|
||||
AnnotateCmd.Flags().BoolVar(&annotateAppSSL, "app-ssl", false, "Enable SSL for the app")
|
||||
AnnotateCmd.Flags().IntVar(&annotateMaxRequestBodySize, "max-request-body-size", -1, "The maximum request body size to use")
|
||||
AnnotateCmd.Flags().IntVar(&annotateReadBufferSize, "http-read-buffer-size", -1, "The maximum size of HTTP header read buffer in kilobytes")
|
||||
AnnotateCmd.Flags().MarkDeprecated("app-ssl", "This flag is deprecated and will be removed in a future release. Use \"app-protocol\" flag with https or grpcs instead")
|
||||
AnnotateCmd.Flags().StringVar(&annotateMaxRequestBodySize, "max-body-size", strconv.Itoa(runtime.DefaultMaxRequestBodySize>>20)+"Mi", "The maximum request body size to use")
|
||||
AnnotateCmd.Flags().StringVar(&annotateReadBufferSize, "read-buffer-size", strconv.Itoa(runtime.DefaultReadBufferSize>>10)+"Ki", "The maximum size of HTTP header read buffer in kilobytes")
|
||||
AnnotateCmd.Flags().BoolVar(&annotateHTTPStreamRequestBody, "http-stream-request-body", false, "Enable streaming request body for HTTP")
|
||||
AnnotateCmd.Flags().IntVar(&annotateGracefulShutdownSeconds, "graceful-shutdown-seconds", -1, "The number of seconds to wait for the app to shutdown")
|
||||
AnnotateCmd.Flags().BoolVar(&annotateEnableAPILogging, "enable-api-logging", false, "Enable API logging for the Dapr sidecar")
|
||||
|
|
|
@ -15,9 +15,11 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
|
@ -29,7 +31,12 @@ var BuildInfoCmd = &cobra.Command{
|
|||
dapr build-info
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(standalone.GetBuildInfo(RootCmd.Version))
|
||||
out, err := standalone.GetBuildInfo(daprRuntimePath, cliVersion)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error getting build info: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(out)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,12 @@ var completionExample = `
|
|||
# Set the dapr completion code for zsh[1] to autoload on startup
|
||||
dapr completion zsh > "${fpath[1]}/_dapr"
|
||||
|
||||
# Installing fish completion on Linux
|
||||
## Load the dapr completion code for fish into the current shell
|
||||
dapr completion fish | source
|
||||
# Set the dapr completion code for fish[1] to autoload on startup
|
||||
dapr completion fish > $HOME/.config/fish/completions/dapr.fish
|
||||
|
||||
# Installing powershell completion on Windows
|
||||
## Create $PROFILE if it not exists
|
||||
if (!(Test-Path -Path $PROFILE )){ New-Item -Type File -Path $PROFILE -Force }
|
||||
|
@ -77,6 +83,7 @@ func newCompletionCmd() *cobra.Command {
|
|||
cmd.AddCommand(
|
||||
newCompletionBashCmd(),
|
||||
newCompletionZshCmd(),
|
||||
newCompletionFishCmd(),
|
||||
newCompletionPowerShellCmd(),
|
||||
)
|
||||
|
||||
|
@ -112,6 +119,19 @@ func newCompletionZshCmd() *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func newCompletionFishCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "fish",
|
||||
Short: "Generates fish completion scripts",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
RootCmd.GenFishCompletion(os.Stdout, true)
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newCompletionPowerShellCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "powershell",
|
||||
|
|
56
cmd/dapr.go
56
cmd/dapr.go
|
@ -30,15 +30,22 @@ var RootCmd = &cobra.Command{
|
|||
Use: "dapr",
|
||||
Short: "Dapr CLI",
|
||||
Long: `
|
||||
__
|
||||
__
|
||||
____/ /___ _____ _____
|
||||
/ __ / __ '/ __ \/ ___/
|
||||
/ /_/ / /_/ / /_/ / /
|
||||
\__,_/\__,_/ .___/_/
|
||||
/_/
|
||||
|
||||
/ /_/ / /_/ / /_/ / /
|
||||
\__,_/\__,_/ .___/_/
|
||||
/_/
|
||||
|
||||
===============================
|
||||
Distributed Application Runtime`,
|
||||
Run: func(cmd *cobra.Command, _ []string) {
|
||||
if versionFlag {
|
||||
printVersion()
|
||||
} else {
|
||||
cmd.Help()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
type daprVersion struct {
|
||||
|
@ -46,40 +53,51 @@ type daprVersion struct {
|
|||
RuntimeVersion string `json:"Runtime version"`
|
||||
}
|
||||
|
||||
type osType string
|
||||
|
||||
const (
|
||||
windowsOsType osType = "windows"
|
||||
)
|
||||
|
||||
var (
|
||||
daprVer daprVersion
|
||||
logAsJSON bool
|
||||
cliVersion string
|
||||
versionFlag bool
|
||||
daprVer daprVersion
|
||||
logAsJSON bool
|
||||
daprRuntimePath string
|
||||
)
|
||||
|
||||
// Execute adds all child commands to the root command.
|
||||
func Execute(version, apiVersion string) {
|
||||
RootCmd.Version = version
|
||||
// Need to be set here as it is accessed in initConfig.
|
||||
cliVersion = version
|
||||
api.RuntimeAPIVersion = apiVersion
|
||||
|
||||
daprVer = daprVersion{
|
||||
CliVersion: version,
|
||||
RuntimeVersion: strings.ReplaceAll(standalone.GetRuntimeVersion(), "\n", ""),
|
||||
}
|
||||
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
setVersion()
|
||||
|
||||
if err := RootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
func setVersion() {
|
||||
template := fmt.Sprintf(cliVersionTemplateString, daprVer.CliVersion, daprVer.RuntimeVersion)
|
||||
RootCmd.SetVersionTemplate(template)
|
||||
func printVersion() {
|
||||
fmt.Printf(cliVersionTemplateString, daprVer.CliVersion, daprVer.RuntimeVersion)
|
||||
}
|
||||
|
||||
// Function is called as a preRun initializer for each command executed.
|
||||
func initConfig() {
|
||||
if logAsJSON {
|
||||
print.EnableJSONFormat()
|
||||
}
|
||||
// err intentionally ignored since daprd may not yet be installed.
|
||||
runtimeVer, _ := standalone.GetRuntimeVersion(daprRuntimePath)
|
||||
|
||||
daprVer = daprVersion{
|
||||
// Set in Execute() method in this file before initConfig() is called by cmd.Execute().
|
||||
CliVersion: cliVersion,
|
||||
RuntimeVersion: strings.ReplaceAll(runtimeVer, "\n", ""),
|
||||
}
|
||||
|
||||
viper.SetEnvPrefix("dapr")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
@ -87,5 +105,7 @@ func initConfig() {
|
|||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "version for dapr")
|
||||
RootCmd.PersistentFlags().StringVarP(&daprRuntimePath, "runtime-path", "", "", "The path to the dapr runtime installation directory")
|
||||
RootCmd.PersistentFlags().BoolVarP(&logAsJSON, "log-as-json", "", false, "Log output in JSON format")
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -62,11 +63,14 @@ var DashboardCmd = &cobra.Command{
|
|||
# Start dashboard locally
|
||||
dapr dashboard
|
||||
|
||||
# Start dashboard locally in a specified port
|
||||
# Start dashboard locally in a specified port
|
||||
dapr dashboard -p 9999
|
||||
|
||||
# Port forward to dashboard in Kubernetes
|
||||
dapr dashboard -k
|
||||
# Start dashboard locally on a random port which is free.
|
||||
dapr dashboard -p 0
|
||||
|
||||
# Port forward to dashboard in Kubernetes
|
||||
dapr dashboard -k
|
||||
|
||||
# Port forward to dashboard in Kubernetes on all addresses in a specified port
|
||||
dapr dashboard -k -p 9999 -a 0.0.0.0
|
||||
|
@ -79,7 +83,13 @@ dapr dashboard -k -p 0
|
|||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if dashboardVersionCmd {
|
||||
fmt.Println(standalone.GetDashboardVersion())
|
||||
dashboardVer, err := standalone.GetDashboardVersion(daprRuntimePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(dashboardVer)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
@ -93,6 +103,12 @@ dapr dashboard -k -p 0
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := utils.CheckIfPortAvailable(dashboardLocalPort); err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Please select a different port with %q flag: %s", "-p", err)
|
||||
print.InfoStatusEvent(os.Stdout, "You can also use port 0 to select a random free port.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if kubernetesMode {
|
||||
config, client, err := kubernetes.GetKubeConfigClient()
|
||||
if err != nil {
|
||||
|
@ -165,9 +181,9 @@ dapr dashboard -k -p 0
|
|||
}()
|
||||
|
||||
// url for dashboard after port forwarding.
|
||||
var webURL string = net.JoinHostPort(dashboardHost, fmt.Sprint(portForward.LocalPort))
|
||||
webURL := "http://" + net.JoinHostPort(dashboardHost, strconv.Itoa(portForward.LocalPort))
|
||||
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Dapr dashboard found in namespace:\t%s", foundNamespace))
|
||||
print.InfoStatusEvent(os.Stdout, "Dapr dashboard found in namespace:\t"+foundNamespace)
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Dapr dashboard available at:\t%s\n", webURL))
|
||||
|
||||
err = browser.OpenURL(webURL)
|
||||
|
@ -179,9 +195,14 @@ dapr dashboard -k -p 0
|
|||
<-portForward.GetStop()
|
||||
} else {
|
||||
// Standalone mode.
|
||||
err := standalone.NewDashboardCmd(dashboardLocalPort).Run()
|
||||
dashboardCmd, err := standalone.NewDashboardCmd(daprRuntimePath, dashboardLocalPort)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Dapr dashboard not found. Is Dapr installed?")
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
|
||||
} else {
|
||||
err = dashboardCmd.Run()
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Dapr dashboard failed to run: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -199,5 +220,6 @@ func init() {
|
|||
DashboardCmd.Flags().IntVarP(&dashboardLocalPort, "port", "p", defaultLocalPort, "The local port on which to serve Dapr dashboard")
|
||||
DashboardCmd.Flags().StringVarP(&dashboardNamespace, "namespace", "n", daprSystemNamespace, "The namespace where Dapr dashboard is running")
|
||||
DashboardCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
|
||||
RootCmd.AddCommand(DashboardCmd)
|
||||
}
|
||||
|
|
155
cmd/init.go
155
cmd/init.go
|
@ -14,6 +14,7 @@ limitations under the License.
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -24,24 +25,28 @@ import (
|
|||
"github.com/dapr/cli/pkg/kubernetes"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/dapr/cli/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
kubernetesMode bool
|
||||
wait bool
|
||||
timeout uint
|
||||
slimMode bool
|
||||
runtimeVersion string
|
||||
dashboardVersion string
|
||||
allNamespaces bool
|
||||
initNamespace string
|
||||
resourceNamespace string
|
||||
enableMTLS bool
|
||||
enableHA bool
|
||||
values []string
|
||||
fromDir string
|
||||
containerRuntime string
|
||||
imageVariant string
|
||||
kubernetesMode bool
|
||||
wait bool
|
||||
timeout uint
|
||||
slimMode bool
|
||||
devMode bool
|
||||
runtimeVersion string
|
||||
dashboardVersion string
|
||||
allNamespaces bool
|
||||
initNamespace string
|
||||
resourceNamespace string
|
||||
enableMTLS bool
|
||||
enableHA bool
|
||||
values []string
|
||||
fromDir string
|
||||
containerRuntime string
|
||||
imageVariant string
|
||||
schedulerVolume string
|
||||
schedulerOverrideBroadcastHostPort string
|
||||
)
|
||||
|
||||
var InitCmd = &cobra.Command{
|
||||
|
@ -50,18 +55,25 @@ var InitCmd = &cobra.Command{
|
|||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("network", cmd.Flags().Lookup("network"))
|
||||
viper.BindPFlag("image-registry", cmd.Flags().Lookup("image-registry"))
|
||||
|
||||
runtimeVersion = getConfigurationValue("runtime-version", cmd)
|
||||
dashboardVersion = getConfigurationValue("dashboard-version", cmd)
|
||||
containerRuntime = getConfigurationValue("container-runtime", cmd)
|
||||
},
|
||||
Example: `
|
||||
# Initialize Dapr in self-hosted mode
|
||||
dapr init
|
||||
|
||||
# Initialize Dapr in self-hosted mode with a provided docker image registry. Image looked up as <registry-url>/<image>.
|
||||
# Check docs or README for more information on the format of the image path that is required.
|
||||
# Check docs or README for more information on the format of the image path that is required.
|
||||
dapr init --image-registry <registry-url>
|
||||
|
||||
# Initialize Dapr in Kubernetes
|
||||
dapr init -k
|
||||
|
||||
# Initialize Dapr in Kubernetes in dev mode
|
||||
dapr init -k --dev
|
||||
|
||||
# Initialize Dapr in Kubernetes and wait for the installation to complete (default timeout is 300s/5m)
|
||||
dapr init -k --wait --timeout 600
|
||||
|
||||
|
@ -80,6 +92,10 @@ dapr init --from-dir <path-to-directory>
|
|||
# Initialize dapr with a particular image variant. Allowed values: "mariner"
|
||||
dapr init --image-variant <variant>
|
||||
|
||||
# Initialize Dapr inside a ".dapr" directory present in a non-default location
|
||||
# Folder .dapr will be created in folder pointed to by <path-to-install-directory>
|
||||
dapr init --runtime-path <path-to-install-directory>
|
||||
|
||||
# See more at: https://docs.dapr.io/getting-started/
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
@ -91,6 +107,11 @@ dapr init --image-variant <variant>
|
|||
imageRegistryURI := ""
|
||||
var err error
|
||||
|
||||
if len(strings.TrimSpace(daprRuntimePath)) != 0 {
|
||||
print.FailureStatusEvent(os.Stderr, "--runtime-path is only valid for self-hosted mode")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(imageRegistryFlag) != 0 {
|
||||
warnForPrivateRegFeat()
|
||||
imageRegistryURI = imageRegistryFlag
|
||||
|
@ -101,23 +122,33 @@ dapr init --image-variant <variant>
|
|||
print.FailureStatusEvent(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
if err = verifyCustomCertFlags(cmd); err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
config := kubernetes.InitConfiguration{
|
||||
Namespace: initNamespace,
|
||||
Version: runtimeVersion,
|
||||
EnableMTLS: enableMTLS,
|
||||
EnableHA: enableHA,
|
||||
Args: values,
|
||||
Wait: wait,
|
||||
Timeout: timeout,
|
||||
ImageRegistryURI: imageRegistryURI,
|
||||
ImageVariant: imageVariant,
|
||||
Namespace: initNamespace,
|
||||
Version: runtimeVersion,
|
||||
DashboardVersion: dashboardVersion,
|
||||
EnableMTLS: enableMTLS,
|
||||
EnableHA: enableHA,
|
||||
EnableDev: devMode,
|
||||
Args: values,
|
||||
Wait: wait,
|
||||
Timeout: timeout,
|
||||
ImageRegistryURI: imageRegistryURI,
|
||||
ImageVariant: imageVariant,
|
||||
RootCertificateFilePath: strings.TrimSpace(caRootCertificateFile),
|
||||
IssuerCertificateFilePath: strings.TrimSpace(issuerPublicCertificateFile),
|
||||
IssuerPrivateKeyFilePath: strings.TrimSpace(issuerPrivateKeyFile),
|
||||
}
|
||||
err = kubernetes.Init(config)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("Success! Dapr has been installed to namespace %s. To verify, run `dapr status -k' in your terminal. To get started, go here: https://aka.ms/dapr-getting-started", config.Namespace))
|
||||
print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("Success! Dapr has been installed to namespace %s. To verify, run `dapr status -k' in your terminal. To get started, go here: https://docs.dapr.io/getting-started", config.Namespace))
|
||||
} else {
|
||||
dockerNetwork := ""
|
||||
imageRegistryURI := ""
|
||||
|
@ -136,48 +167,88 @@ dapr init --image-variant <variant>
|
|||
if len(imageRegistryURI) != 0 {
|
||||
warnForPrivateRegFeat()
|
||||
}
|
||||
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant)
|
||||
|
||||
if !utils.IsValidContainerRuntime(containerRuntime) {
|
||||
print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
schedulerHostPort := &schedulerOverrideBroadcastHostPort
|
||||
if schedulerOverrideBroadcastHostPort == "" {
|
||||
schedulerHostPort = nil
|
||||
}
|
||||
|
||||
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath, &schedulerVolume, schedulerHostPort)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
print.SuccessStatusEvent(os.Stdout, "Success! Dapr is up and running. To get started, go here: https://aka.ms/dapr-getting-started")
|
||||
print.SuccessStatusEvent(os.Stdout, "Success! Dapr is up and running. To get started, go here: https://docs.dapr.io/getting-started")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func verifyCustomCertFlags(cmd *cobra.Command) error {
|
||||
ca := cmd.Flags().Lookup("ca-root-certificate")
|
||||
issuerKey := cmd.Flags().Lookup("issuer-private-key")
|
||||
issuerCert := cmd.Flags().Lookup("issuer-public-certificate")
|
||||
|
||||
if ca.Changed && len(strings.TrimSpace(ca.Value.String())) == 0 {
|
||||
return errors.New("non empty value of --ca-root-certificate must be provided")
|
||||
}
|
||||
if issuerKey.Changed && len(strings.TrimSpace(issuerKey.Value.String())) == 0 {
|
||||
return errors.New("non empty value of --issuer-private-key must be provided")
|
||||
}
|
||||
if issuerCert.Changed && len(strings.TrimSpace(issuerCert.Value.String())) == 0 {
|
||||
return errors.New("non empty value of --issuer-public-certificate must be provided")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func warnForPrivateRegFeat() {
|
||||
print.WarningStatusEvent(os.Stdout, "Flag --image-registry is a preview feature and is subject to change.")
|
||||
}
|
||||
|
||||
func init() {
|
||||
defaultRuntimeVersion := "latest"
|
||||
viper.BindEnv("runtime_version_override", "DAPR_RUNTIME_VERSION")
|
||||
runtimeVersionEnv := viper.GetString("runtime_version_override")
|
||||
if runtimeVersionEnv != "" {
|
||||
defaultRuntimeVersion = runtimeVersionEnv
|
||||
}
|
||||
defaultDashboardVersion := "latest"
|
||||
viper.BindEnv("dashboard_version_override", "DAPR_DASHBOARD_VERSION")
|
||||
dashboardVersionEnv := viper.GetString("dashboard_version_override")
|
||||
if dashboardVersionEnv != "" {
|
||||
defaultDashboardVersion = dashboardVersionEnv
|
||||
}
|
||||
defaultContainerRuntime := string(utils.DOCKER)
|
||||
|
||||
InitCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Deploy Dapr to a Kubernetes cluster")
|
||||
InitCmd.Flags().BoolVarP(&devMode, "dev", "", false, "Use Dev mode. Deploy Redis, Zipkin also in the Kubernetes cluster")
|
||||
InitCmd.Flags().BoolVarP(&wait, "wait", "", false, "Wait for Kubernetes initialization to complete")
|
||||
InitCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The wait timeout for the Kubernetes installation")
|
||||
InitCmd.Flags().BoolVarP(&slimMode, "slim", "s", false, "Exclude placement service, Redis and Zipkin containers from self-hosted installation")
|
||||
InitCmd.Flags().BoolVarP(&slimMode, "slim", "s", false, "Exclude placement service, scheduler service, Redis and Zipkin containers from self-hosted installation")
|
||||
InitCmd.Flags().StringVarP(&runtimeVersion, "runtime-version", "", defaultRuntimeVersion, "The version of the Dapr runtime to install, for example: 1.0.0")
|
||||
InitCmd.Flags().StringVarP(&dashboardVersion, "dashboard-version", "", defaultDashboardVersion, "The version of the Dapr dashboard to install, for example: 1.0.0")
|
||||
InitCmd.Flags().StringVarP(&dashboardVersion, "dashboard-version", "", defaultDashboardVersion, "The version of the Dapr dashboard to install, for example: 0.13.0")
|
||||
InitCmd.Flags().StringVarP(&initNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to install Dapr in")
|
||||
InitCmd.Flags().BoolVarP(&enableMTLS, "enable-mtls", "", true, "Enable mTLS in your cluster")
|
||||
InitCmd.Flags().BoolVarP(&enableHA, "enable-ha", "", false, "Enable high availability (HA) mode")
|
||||
InitCmd.Flags().String("network", "", "The Docker network on which to deploy the Dapr runtime")
|
||||
InitCmd.Flags().StringVarP(&fromDir, "from-dir", "", "", "Use Dapr artifacts from local directory for self-hosted installation")
|
||||
InitCmd.Flags().StringVarP(&imageVariant, "image-variant", "", "", "The image variant to use for the Dapr runtime, for example: mariner")
|
||||
InitCmd.Flags().StringVarP(&schedulerVolume, "scheduler-volume", "", "dapr_scheduler", "Self-hosted only. Specify a volume for the scheduler service data directory.")
|
||||
InitCmd.Flags().StringVarP(&schedulerOverrideBroadcastHostPort, "scheduler-override-broadcast-host-port", "", "", "Self-hosted only. Specify the scheduler broadcast host and port, for example: 192.168.42.42:50006. If not specified, it uses localhost:50006 (6060 for Windows).")
|
||||
InitCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
InitCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
|
||||
InitCmd.Flags().String("image-registry", "", "Custom/Private docker image repository url")
|
||||
InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use (defaults to docker)")
|
||||
InitCmd.Flags().String("image-registry", "", "Custom/private docker image repository URL")
|
||||
InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", defaultContainerRuntime, "The container runtime to use. Supported values are docker (default) and podman")
|
||||
InitCmd.Flags().StringVarP(&caRootCertificateFile, "ca-root-certificate", "", "", "The root certificate file")
|
||||
InitCmd.Flags().StringVarP(&issuerPrivateKeyFile, "issuer-private-key", "", "", "The issuer certificate private key")
|
||||
InitCmd.Flags().StringVarP(&issuerPublicCertificateFile, "issuer-public-certificate", "", "", "The issuer certificate")
|
||||
InitCmd.MarkFlagsRequiredTogether("ca-root-certificate", "issuer-private-key", "issuer-public-certificate")
|
||||
|
||||
RootCmd.AddCommand(InitCmd)
|
||||
}
|
||||
|
||||
// getConfigurationValue returns the value for a given configuration key.
|
||||
// The value is retrieved from the following sources, in order:
|
||||
// Default value
|
||||
// Environment variable (respecting registered prefixes)
|
||||
// Command line flag
|
||||
// Value is returned as a string.
|
||||
func getConfigurationValue(n string, cmd *cobra.Command) string {
|
||||
viper.BindEnv(n)
|
||||
viper.BindPFlag(n, cmd.Flags().Lookup(n))
|
||||
return viper.GetString(n)
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET
|
|||
|
||||
// TODO(@daixiang0): add Windows support.
|
||||
if invokeSocket != "" {
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == string(windowsOsType) {
|
||||
print.FailureStatusEvent(os.Stderr, "The unix-domain-socket option is not supported on Windows")
|
||||
os.Exit(1)
|
||||
} else {
|
||||
|
|
|
@ -67,7 +67,7 @@ dapr mtls export -o ./certs
|
|||
}
|
||||
|
||||
dir, _ := filepath.Abs(exportPath)
|
||||
print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("Trust certs successfully exported to %s", dir))
|
||||
print.SuccessStatusEvent(os.Stdout, "Trust certs successfully exported to "+dir)
|
||||
},
|
||||
PostRun: func(cmd *cobra.Command, args []string) {
|
||||
kubernetes.CheckForCertExpiry()
|
||||
|
|
|
@ -69,7 +69,7 @@ dapr publish --publish-app-id myapp --pubsub target --topic sample --data '{"key
|
|||
client := standalone.NewClient()
|
||||
// TODO(@daixiang0): add Windows support.
|
||||
if publishSocket != "" {
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == string(windowsOsType) {
|
||||
print.FailureStatusEvent(os.Stderr, "The unix-domain-socket option is not supported on Windows")
|
||||
os.Exit(1)
|
||||
} else {
|
||||
|
|
|
@ -14,9 +14,11 @@ limitations under the License.
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -37,8 +39,9 @@ var (
|
|||
|
||||
func RenewCertificateCmd() *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "renew-certificate",
|
||||
Short: "Rotates Dapr root certificate of your kubernetes cluster",
|
||||
Use: "renew-certificate",
|
||||
Aliases: []string{"renew-cert", "rnc"},
|
||||
Short: "Rotates the Dapr root certificate on your Kubernetes cluster",
|
||||
|
||||
Example: `
|
||||
# Generates new root and issuer certificates for kubernetes cluster
|
||||
|
@ -50,6 +53,13 @@ dapr mtls renew-certificate -k --private-key myprivatekey.key --valid-until <no
|
|||
# Rotates certificate of your kubernetes cluster with provided ca.cert, issuer.crt and issuer.key file path
|
||||
dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private-key <issuer.key> --issuer-public-certificate <issuer.pem> --restart
|
||||
|
||||
# Generates new root and issuer certificates for kubernetes cluster with provided image variant
|
||||
dapr mtls renew-certificate -k --valid-until <no of days> --image-variant mariner --restart
|
||||
|
||||
# Use alias to renew certificate command
|
||||
dapr mtls rnc -k --valid-until <no of days> --restart
|
||||
dapr mtls renew-cert -k --valid-until <no of days> --restart
|
||||
|
||||
# See more at: https://docs.dapr.io/getting-started/
|
||||
`,
|
||||
|
||||
|
@ -62,6 +72,10 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
|
||||
if kubernetesMode {
|
||||
print.PendingStatusEvent(os.Stdout, "Starting certificate rotation")
|
||||
err = utils.ValidateImageVariant(imageVariant)
|
||||
if err != nil {
|
||||
logErrorAndExit(err)
|
||||
}
|
||||
if rootcertFlag || issuerKeyFlag || issuerCertFlag {
|
||||
flagArgsEmpty := checkReqFlagArgsEmpty(caRootCertificateFile, issuerPrivateKeyFile, issuerPublicCertificateFile)
|
||||
if flagArgsEmpty {
|
||||
|
@ -75,6 +89,7 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
IssuerCertificateFilePath: issuerPublicCertificateFile,
|
||||
IssuerPrivateKeyFilePath: issuerPrivateKeyFile,
|
||||
Timeout: timeout,
|
||||
ImageVariant: imageVariant,
|
||||
})
|
||||
if err != nil {
|
||||
logErrorAndExit(err)
|
||||
|
@ -88,8 +103,9 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
print.InfoStatusEvent(os.Stdout, "Using password file to generate root certificate")
|
||||
err = kubernetes.RenewCertificate(kubernetes.RenewCertificateParams{
|
||||
RootPrivateKeyFilePath: privateKey,
|
||||
ValidUntil: time.Hour * time.Duration(validUntil*24),
|
||||
ValidUntil: time.Hour * time.Duration(validUntil*24), //nolint:gosec
|
||||
Timeout: timeout,
|
||||
ImageVariant: imageVariant,
|
||||
})
|
||||
if err != nil {
|
||||
logErrorAndExit(err)
|
||||
|
@ -97,8 +113,9 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
} else {
|
||||
print.InfoStatusEvent(os.Stdout, "generating fresh certificates")
|
||||
err = kubernetes.RenewCertificate(kubernetes.RenewCertificateParams{
|
||||
ValidUntil: time.Hour * time.Duration(validUntil*24),
|
||||
Timeout: timeout,
|
||||
ValidUntil: time.Hour * time.Duration(validUntil*24), //nolint:gosec
|
||||
Timeout: timeout,
|
||||
ImageVariant: imageVariant,
|
||||
})
|
||||
if err != nil {
|
||||
logErrorAndExit(err)
|
||||
|
@ -112,7 +129,7 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
logErrorAndExit(err)
|
||||
}
|
||||
print.SuccessStatusEvent(os.Stdout,
|
||||
fmt.Sprintf("Certificate rotation is successful! Your new certicate is valid through %s", expiry.Format(time.RFC1123)))
|
||||
"Certificate rotation is successful! Your new certicate is valid through "+expiry.Format(time.RFC1123))
|
||||
|
||||
if restartDaprServices {
|
||||
restartControlPlaneService()
|
||||
|
@ -132,6 +149,7 @@ dapr mtls renew-certificate -k --ca-root-certificate <root.pem> --issuer-private
|
|||
command.Flags().UintVarP(&validUntil, "valid-until", "", 365, "Max days before certificate expires")
|
||||
command.Flags().BoolVarP(&restartDaprServices, "restart", "", false, "Restart Dapr control plane services")
|
||||
command.Flags().UintVarP(&timeout, "timeout", "", 300, "The timeout for the certificate renewal")
|
||||
command.Flags().StringVarP(&imageVariant, "image-variant", "", "", "The image variant to use for the Dapr runtime, for example: mariner")
|
||||
command.MarkFlagRequired("kubernetes")
|
||||
return command
|
||||
}
|
||||
|
@ -152,22 +170,43 @@ func logErrorAndExit(err error) {
|
|||
}
|
||||
|
||||
func restartControlPlaneService() error {
|
||||
controlPlaneServices := []string{"deploy/dapr-sentry", "deploy/dapr-operator", "statefulsets/dapr-placement-server"}
|
||||
controlPlaneServices := []string{
|
||||
"deploy/dapr-sentry",
|
||||
"deploy/dapr-sidecar-injector",
|
||||
"deploy/dapr-operator",
|
||||
"statefulsets/dapr-placement-server",
|
||||
}
|
||||
namespace, err := kubernetes.GetDaprNamespace()
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stdout, "Failed to fetch Dapr namespace")
|
||||
}
|
||||
for _, name := range controlPlaneServices {
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Restarting %s..", name))
|
||||
_, err := utils.RunCmdAndWait("kubectl", "rollout", "restart", name, "-n", namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in restarting deployment %s. Error is %w", name, err)
|
||||
}
|
||||
_, err = utils.RunCmdAndWait("kubectl", "rollout", "status", name, "-n", namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in checking status for deployment %s. Error is %w", name, err)
|
||||
}
|
||||
|
||||
errs := make([]error, len(controlPlaneServices))
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(controlPlaneServices))
|
||||
for i, name := range controlPlaneServices {
|
||||
go func(i int, name string) {
|
||||
defer wg.Done()
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Restarting %s..", name))
|
||||
_, err := utils.RunCmdAndWait("kubectl", "rollout", "restart", "-n", namespace, name)
|
||||
if err != nil {
|
||||
errs[i] = fmt.Errorf("error in restarting deployment %s. Error is %w", name, err)
|
||||
return
|
||||
}
|
||||
_, err = utils.RunCmdAndWait("kubectl", "rollout", "status", "-n", namespace, name)
|
||||
if err != nil {
|
||||
errs[i] = fmt.Errorf("error in checking status for deployment %s. Error is %w", name, err)
|
||||
return
|
||||
}
|
||||
}(i, name)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if err := errors.Join(errs...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.SuccessStatusEvent(os.Stdout, "All control plane services have restarted successfully!")
|
||||
return nil
|
||||
}
|
||||
|
|
836
cmd/run.go
836
cmd/run.go
|
@ -16,46 +16,79 @@ package cmd
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
daprRuntime "github.com/dapr/dapr/pkg/runtime"
|
||||
|
||||
"github.com/dapr/cli/pkg/kubernetes"
|
||||
"github.com/dapr/cli/pkg/metadata"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
runExec "github.com/dapr/cli/pkg/runexec"
|
||||
"github.com/dapr/cli/pkg/runfileconfig"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
daprsyscall "github.com/dapr/cli/pkg/syscall"
|
||||
"github.com/dapr/cli/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
appPort int
|
||||
profilePort int
|
||||
appID string
|
||||
configFile string
|
||||
port int
|
||||
grpcPort int
|
||||
internalGRPCPort int
|
||||
maxConcurrency int
|
||||
enableProfiling bool
|
||||
logLevel string
|
||||
protocol string
|
||||
componentsPath string
|
||||
appSSL bool
|
||||
metricsPort int
|
||||
maxRequestBodySize int
|
||||
readBufferSize int
|
||||
unixDomainSocket string
|
||||
enableAPILogging bool
|
||||
appPort int
|
||||
profilePort int
|
||||
appID string
|
||||
configFile string
|
||||
port int
|
||||
grpcPort int
|
||||
internalGRPCPort int
|
||||
maxConcurrency int
|
||||
enableProfiling bool
|
||||
logLevel string
|
||||
protocol string
|
||||
componentsPath string
|
||||
resourcesPaths []string
|
||||
appSSL bool
|
||||
metricsPort int
|
||||
maxRequestBodySize string
|
||||
readBufferSize string
|
||||
unixDomainSocket string
|
||||
enableAppHealth bool
|
||||
appHealthPath string
|
||||
appHealthInterval int
|
||||
appHealthTimeout int
|
||||
appHealthThreshold int
|
||||
enableAPILogging bool
|
||||
apiListenAddresses string
|
||||
schedulerHostAddress string
|
||||
runFilePath string
|
||||
appChannelAddress string
|
||||
enableRunK8s bool
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRunTemplateFileName = "dapr.yaml"
|
||||
runtimeWaitTimeoutInSeconds = 60
|
||||
)
|
||||
|
||||
// Flags that are compatible with --run-file
|
||||
var runFileCompatibleFlags = []string{
|
||||
"kubernetes",
|
||||
"help",
|
||||
"version",
|
||||
"runtime-path",
|
||||
"log-as-json",
|
||||
}
|
||||
|
||||
var RunCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run Dapr and (optionally) your application side by side. Supported platforms: Self-hosted",
|
||||
|
@ -77,19 +110,74 @@ dapr run --app-id myapp
|
|||
|
||||
# Run a gRPC application written in Go (listening on port 3000)
|
||||
dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
||||
|
||||
# Run a gRPC application written in Go (listening on port 3000) with a different app channel address
|
||||
dapr run --app-id myapp --app-port 3000 --app-channel-address localhost --app-protocol grpc -- go run main.go
|
||||
|
||||
|
||||
# Run sidecar only specifying dapr runtime installation directory
|
||||
dapr run --app-id myapp --runtime-path /usr/local/dapr
|
||||
|
||||
# Run multiple apps by providing path of a run config file
|
||||
dapr run --run-file dapr.yaml
|
||||
|
||||
# Run multiple apps by providing a directory path containing the run config file(dapr.yaml)
|
||||
dapr run --run-file /path/to/directory
|
||||
|
||||
# Run multiple apps by providing config via stdin
|
||||
cat dapr.template.yaml | envsubst | dapr run --run-file -
|
||||
|
||||
# Run multiple apps in Kubernetes by proficing path of a run config file
|
||||
dapr run --run-file dapr.yaml -k
|
||||
|
||||
# Run multiple apps in Kubernetes by providing a directory path containing the run config file(dapr.yaml)
|
||||
dapr run --run-file /path/to/directory -k
|
||||
`,
|
||||
Args: cobra.MinimumNArgs(0),
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("placement-host-address", cmd.Flags().Lookup("placement-host-address"))
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(runFilePath) > 0 {
|
||||
// Check for incompatible flags
|
||||
incompatibleFlags := detectIncompatibleFlags(cmd)
|
||||
if len(incompatibleFlags) > 0 {
|
||||
// Print warning message about incompatible flags
|
||||
warningMsg := "The following flags are ignored when using --run-file and should be configured in the run file instead: " + strings.Join(incompatibleFlags, ", ")
|
||||
print.WarningStatusEvent(os.Stdout, warningMsg)
|
||||
}
|
||||
|
||||
runConfigFilePath, err := getRunFilePath(runFilePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to get run file path: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
executeRunWithAppsConfigFile(runConfigFilePath, enableRunK8s)
|
||||
return
|
||||
}
|
||||
if len(args) == 0 {
|
||||
fmt.Println(print.WhiteBold("WARNING: no application command found."))
|
||||
}
|
||||
|
||||
daprDirPath, err := standalone.GetDaprRuntimePath(daprRuntimePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fallback to default config file if not specified.
|
||||
if configFile == "" {
|
||||
configFile = standalone.GetDaprConfigPath(daprDirPath)
|
||||
}
|
||||
|
||||
// Fallback to default components directory if not specified.
|
||||
if componentsPath == "" {
|
||||
componentsPath = standalone.GetDaprComponentsPath(daprDirPath)
|
||||
}
|
||||
|
||||
if unixDomainSocket != "" {
|
||||
// TODO(@daixiang0): add Windows support.
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == string(windowsOsType) {
|
||||
print.FailureStatusEvent(os.Stderr, "The unix-domain-socket option is not supported on Windows")
|
||||
os.Exit(1)
|
||||
} else {
|
||||
|
@ -100,35 +188,49 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
}
|
||||
}
|
||||
|
||||
output, err := standalone.Run(&standalone.RunConfig{
|
||||
AppID: appID,
|
||||
AppPort: appPort,
|
||||
HTTPPort: port,
|
||||
GRPCPort: grpcPort,
|
||||
ConfigFile: configFile,
|
||||
Arguments: args,
|
||||
EnableProfiling: enableProfiling,
|
||||
ProfilePort: profilePort,
|
||||
LogLevel: logLevel,
|
||||
MaxConcurrency: maxConcurrency,
|
||||
Protocol: protocol,
|
||||
PlacementHostAddr: viper.GetString("placement-host-address"),
|
||||
ComponentsPath: componentsPath,
|
||||
AppSSL: appSSL,
|
||||
MetricsPort: metricsPort,
|
||||
MaxRequestBodySize: maxRequestBodySize,
|
||||
HTTPReadBufferSize: readBufferSize,
|
||||
UnixDomainSocket: unixDomainSocket,
|
||||
EnableAPILogging: enableAPILogging,
|
||||
InternalGRPCPort: internalGRPCPort,
|
||||
sharedRunConfig := &standalone.SharedRunConfig{
|
||||
ConfigFile: configFile,
|
||||
EnableProfiling: enableProfiling,
|
||||
LogLevel: logLevel,
|
||||
MaxConcurrency: maxConcurrency,
|
||||
AppProtocol: protocol,
|
||||
PlacementHostAddr: viper.GetString("placement-host-address"),
|
||||
ComponentsPath: componentsPath,
|
||||
ResourcesPaths: resourcesPaths,
|
||||
AppSSL: appSSL,
|
||||
MaxRequestBodySize: maxRequestBodySize,
|
||||
HTTPReadBufferSize: readBufferSize,
|
||||
EnableAppHealth: enableAppHealth,
|
||||
AppHealthPath: appHealthPath,
|
||||
AppHealthInterval: appHealthInterval,
|
||||
AppHealthTimeout: appHealthTimeout,
|
||||
AppHealthThreshold: appHealthThreshold,
|
||||
EnableAPILogging: enableAPILogging,
|
||||
APIListenAddresses: apiListenAddresses,
|
||||
SchedulerHostAddress: schedulerHostAddress,
|
||||
DaprdInstallPath: daprRuntimePath,
|
||||
}
|
||||
output, err := runExec.NewOutput(&standalone.RunConfig{
|
||||
AppID: appID,
|
||||
AppChannelAddress: appChannelAddress,
|
||||
AppPort: appPort,
|
||||
HTTPPort: port,
|
||||
GRPCPort: grpcPort,
|
||||
ProfilePort: profilePort,
|
||||
Command: args,
|
||||
MetricsPort: metricsPort,
|
||||
UnixDomainSocket: unixDomainSocket,
|
||||
InternalGRPCPort: internalGRPCPort,
|
||||
SharedRunConfig: *sharedRunConfig,
|
||||
})
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
// TODO: In future release replace following logic with the refactored functions seen below.
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
setupShutdownNotify(sigCh)
|
||||
daprsyscall.SetupShutdownNotify(sigCh)
|
||||
|
||||
daprRunning := make(chan bool, 1)
|
||||
appRunning := make(chan bool, 1)
|
||||
|
@ -148,6 +250,15 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
output.DaprHTTPPort,
|
||||
output.DaprGRPCPort)
|
||||
}
|
||||
|
||||
if (daprVer.RuntimeVersion != "edge") && (semver.Compare(fmt.Sprintf("v%v", daprVer.RuntimeVersion), "v1.14.0-rc.1") == -1) {
|
||||
print.InfoStatusEvent(os.Stdout, "The scheduler is only compatible with dapr runtime 1.14 onwards.")
|
||||
for i, arg := range output.DaprCMD.Args {
|
||||
if strings.HasPrefix(arg, "--scheduler-host-address") {
|
||||
output.DaprCMD.Args[i] = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, startInfo)
|
||||
|
||||
output.DaprCMD.Stdout = os.Stdout
|
||||
|
@ -229,14 +340,14 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
|
||||
stdErrPipe, pipeErr := output.AppCMD.StderrPipe()
|
||||
if pipeErr != nil {
|
||||
print.FailureStatusEvent(os.Stderr, fmt.Sprintf("Error creating stderr for App: %s", err.Error()))
|
||||
print.FailureStatusEvent(os.Stderr, "Error creating stderr for App: "+err.Error())
|
||||
appRunning <- false
|
||||
return
|
||||
}
|
||||
|
||||
stdOutPipe, pipeErr := output.AppCMD.StdoutPipe()
|
||||
if pipeErr != nil {
|
||||
print.FailureStatusEvent(os.Stderr, fmt.Sprintf("Error creating stdout for App: %s", err.Error()))
|
||||
print.FailureStatusEvent(os.Stderr, "Error creating stdout for App: "+err.Error())
|
||||
appRunning <- false
|
||||
return
|
||||
}
|
||||
|
@ -245,13 +356,13 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
outScanner := bufio.NewScanner(stdOutPipe)
|
||||
go func() {
|
||||
for errScanner.Scan() {
|
||||
fmt.Println(print.Blue(fmt.Sprintf("== APP == %s", errScanner.Text())))
|
||||
fmt.Println(print.Blue("== APP == " + errScanner.Text()))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for outScanner.Scan() {
|
||||
fmt.Println(print.Blue(fmt.Sprintf("== APP == %s", outScanner.Text())))
|
||||
fmt.Println(print.Blue("== APP == " + outScanner.Text()))
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -290,15 +401,23 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
}
|
||||
|
||||
// Metadata API is only available if app has started listening to port, so wait for app to start before calling metadata API.
|
||||
err = metadata.Put(output.DaprHTTPPort, "cliPID", strconv.Itoa(os.Getpid()), appID, unixDomainSocket)
|
||||
err = metadata.Put(output.DaprHTTPPort, "cliPID", strconv.Itoa(os.Getpid()), output.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stdout, "Could not update sidecar metadata for cliPID: %s", err.Error())
|
||||
}
|
||||
|
||||
if output.AppCMD != nil {
|
||||
if output.AppCMD.Process != nil {
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Updating metadata for appPID: %d", output.AppCMD.Process.Pid))
|
||||
err = metadata.Put(output.DaprHTTPPort, "appPID", strconv.Itoa(output.AppCMD.Process.Pid), output.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stdout, "Could not update sidecar metadata for appPID: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
appCommand := strings.Join(args, " ")
|
||||
print.InfoStatusEvent(os.Stdout, fmt.Sprintf("Updating metadata for app command: %s", appCommand))
|
||||
err = metadata.Put(output.DaprHTTPPort, "appCommand", appCommand, appID, unixDomainSocket)
|
||||
print.InfoStatusEvent(os.Stdout, "Updating metadata for app command: "+appCommand)
|
||||
err = metadata.Put(output.DaprHTTPPort, "appCommand", appCommand, output.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stdout, "Could not update sidecar metadata for appCommand: %s", err.Error())
|
||||
} else {
|
||||
|
@ -354,7 +473,7 @@ dapr run --app-id myapp --app-port 3000 --app-protocol grpc -- go run main.go
|
|||
func init() {
|
||||
RunCmd.Flags().IntVarP(&appPort, "app-port", "p", -1, "The port your application is listening on")
|
||||
RunCmd.Flags().StringVarP(&appID, "app-id", "a", "", "The id for your application, used for service discovery")
|
||||
RunCmd.Flags().StringVarP(&configFile, "config", "c", standalone.DefaultConfigFilePath(), "Dapr configuration file")
|
||||
RunCmd.Flags().StringVarP(&configFile, "config", "c", "", "Dapr configuration file")
|
||||
RunCmd.Flags().IntVarP(&port, "dapr-http-port", "H", -1, "The HTTP port for Dapr to listen on")
|
||||
RunCmd.Flags().IntVarP(&grpcPort, "dapr-grpc-port", "G", -1, "The gRPC port for Dapr to listen on")
|
||||
RunCmd.Flags().IntVarP(&internalGRPCPort, "dapr-internal-grpc-port", "I", -1, "The gRPC port for the Dapr internal API to listen on")
|
||||
|
@ -362,16 +481,625 @@ func init() {
|
|||
RunCmd.Flags().IntVarP(&profilePort, "profile-port", "", -1, "The port for the profile server to listen on")
|
||||
RunCmd.Flags().StringVarP(&logLevel, "log-level", "", "info", "The log verbosity. Valid values are: debug, info, warn, error, fatal, or panic")
|
||||
RunCmd.Flags().IntVarP(&maxConcurrency, "app-max-concurrency", "", -1, "The concurrency level of the application, otherwise is unlimited")
|
||||
RunCmd.Flags().StringVarP(&protocol, "app-protocol", "P", "http", "The protocol (gRPC or HTTP) Dapr uses to talk to the application")
|
||||
RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", standalone.DefaultComponentsDirPath(), "The path for components directory")
|
||||
RunCmd.Flags().StringVarP(&protocol, "app-protocol", "P", "http", "The protocol (grpc, grpcs, http, https, h2c) Dapr uses to talk to the application")
|
||||
RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", "", "The path for components directory. Default is $HOME/.dapr/components or %USERPROFILE%\\.dapr\\components")
|
||||
RunCmd.Flags().StringSliceVarP(&resourcesPaths, "resources-path", "", []string{}, "The path for resources directory")
|
||||
// TODO: Remove below line once the flag is removed in the future releases.
|
||||
// By marking this as deprecated, the flag will be hidden from the help menu, but will continue to work. It will show a warning message when used.
|
||||
RunCmd.Flags().MarkDeprecated("components-path", "This flag is deprecated and will be removed in the future releases. Use \"resources-path\" flag instead")
|
||||
RunCmd.Flags().String("placement-host-address", "localhost", "The address of the placement service. Format is either <hostname> for default port or <hostname>:<port> for custom port")
|
||||
RunCmd.Flags().StringVarP(&schedulerHostAddress, "scheduler-host-address", "", "localhost", "The address of the scheduler service. Format is either <hostname> for default port or <hostname>:<port> for custom port")
|
||||
// TODO: Remove below flag once the flag is removed in runtime in future release.
|
||||
RunCmd.Flags().BoolVar(&appSSL, "app-ssl", false, "Enable https when Dapr invokes the application")
|
||||
RunCmd.Flags().MarkDeprecated("app-ssl", "This flag is deprecated and will be removed in the future releases. Use \"app-protocol\" flag with https or grpcs values instead")
|
||||
RunCmd.Flags().IntVarP(&metricsPort, "metrics-port", "M", -1, "The port of metrics on dapr")
|
||||
RunCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
RunCmd.Flags().IntVarP(&maxRequestBodySize, "dapr-http-max-request-size", "", -1, "Max size of request body in MB")
|
||||
RunCmd.Flags().IntVarP(&readBufferSize, "dapr-http-read-buffer-size", "", -1, "HTTP header read buffer in KB")
|
||||
RunCmd.Flags().StringVarP(&maxRequestBodySize, "max-body-size", "", strconv.Itoa(daprRuntime.DefaultMaxRequestBodySize>>20)+"Mi", "Max size of request body in MB")
|
||||
RunCmd.Flags().StringVarP(&readBufferSize, "read-buffer-size", "", strconv.Itoa(daprRuntime.DefaultReadBufferSize>>10)+"Ki", "HTTP header read buffer in KB")
|
||||
RunCmd.Flags().StringVarP(&unixDomainSocket, "unix-domain-socket", "u", "", "Path to a unix domain socket dir. If specified, Dapr API servers will use Unix Domain Sockets")
|
||||
RunCmd.Flags().BoolVar(&enableAppHealth, "enable-app-health-check", false, "Enable health checks for the application using the protocol defined with app-protocol")
|
||||
RunCmd.Flags().StringVar(&appHealthPath, "app-health-check-path", "", "Path used for health checks; HTTP only")
|
||||
RunCmd.Flags().IntVar(&appHealthInterval, "app-health-probe-interval", 0, "Interval to probe for the health of the app in seconds")
|
||||
RunCmd.Flags().IntVar(&appHealthTimeout, "app-health-probe-timeout", 0, "Timeout for app health probes in milliseconds")
|
||||
RunCmd.Flags().IntVar(&appHealthThreshold, "app-health-threshold", 0, "Number of consecutive failures for the app to be considered unhealthy")
|
||||
RunCmd.Flags().BoolVar(&enableAPILogging, "enable-api-logging", false, "Log API calls at INFO verbosity. Valid values are: true or false")
|
||||
|
||||
RunCmd.Flags().BoolVarP(&enableRunK8s, "kubernetes", "k", false, "Run the multi-app run template against Kubernetes environment.")
|
||||
RunCmd.Flags().StringVar(&apiListenAddresses, "dapr-listen-addresses", "", "Comma separated list of IP addresses that sidecar will listen to")
|
||||
RunCmd.Flags().StringVarP(&runFilePath, "run-file", "f", "", "Path to the run template file for the list of apps to run")
|
||||
RunCmd.Flags().StringVarP(&appChannelAddress, "app-channel-address", "", utils.DefaultAppChannelAddress, "The network address the application listens on")
|
||||
RootCmd.AddCommand(RunCmd)
|
||||
}
|
||||
|
||||
func executeRun(runTemplateName, runFilePath string, apps []runfileconfig.App) (bool, error) {
|
||||
var exitWithError bool
|
||||
|
||||
// setup shutdown notify channel.
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
daprsyscall.SetupShutdownNotify(sigCh)
|
||||
|
||||
runStates := make([]*runExec.RunExec, 0, len(apps))
|
||||
|
||||
// Creates a separate process group ID for current process i.e. "dapr run -f".
|
||||
// All the subprocess and their grandchildren inherit this PGID.
|
||||
// This is done to provide a better grouping, which can be used to control all the proceses started by "dapr run -f".
|
||||
daprsyscall.CreateProcessGroupID()
|
||||
|
||||
for _, app := range apps {
|
||||
print.StatusEvent(os.Stdout, print.LogInfo, "Validating config and starting app %q", app.RunConfig.AppID)
|
||||
// Set defaults if zero value provided in config yaml.
|
||||
app.RunConfig.SetDefaultFromSchema()
|
||||
|
||||
app.RunConfig.SchedulerHostAddress = validateSchedulerHostAddress(daprVer.RuntimeVersion, app.RunConfig.SchedulerHostAddress)
|
||||
|
||||
// Validate validates the configs and modifies the ports to free ports, appId etc.
|
||||
err := app.RunConfig.Validate()
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error validating run config for app %q present in %s: %s", app.RunConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
// Get Run Config for different apps.
|
||||
runConfig := app.RunConfig
|
||||
err = app.CreateDaprdLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting daprd log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
// Combined multiwriter for logs.
|
||||
var appDaprdWriter io.Writer
|
||||
// appLogWriter is used when app command is present.
|
||||
var appLogWriter io.Writer
|
||||
// A custom writer used for trimming ASCII color codes from logs when writing to files.
|
||||
var customAppLogWriter io.Writer
|
||||
|
||||
daprdLogWriterCloser := runfileconfig.GetLogWriter(app.DaprdLogWriteCloser, app.DaprdLogDestination)
|
||||
|
||||
if len(runConfig.Command) == 0 {
|
||||
print.StatusEvent(os.Stdout, print.LogWarning, "No application command found for app %q present in %s", runConfig.AppID, runFilePath)
|
||||
appDaprdWriter = runExec.GetAppDaprdWriter(app, true)
|
||||
appLogWriter = app.DaprdLogWriteCloser
|
||||
} else {
|
||||
err = app.CreateAppLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting app log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
appDaprdWriter = runExec.GetAppDaprdWriter(app, false)
|
||||
appLogWriter = runfileconfig.GetLogWriter(app.AppLogWriteCloser, app.AppLogDestination)
|
||||
}
|
||||
customAppLogWriter = print.CustomLogWriter{W: appLogWriter}
|
||||
runState, err := startDaprdAndAppProcesses(&runConfig, app.AppDirPath, sigCh,
|
||||
daprdLogWriterCloser, daprdLogWriterCloser, customAppLogWriter, customAppLogWriter)
|
||||
if err != nil {
|
||||
print.StatusEvent(appDaprdWriter, print.LogFailure, "Error starting Dapr and app (%q): %s", app.AppID, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
// Store runState in an array.
|
||||
runStates = append(runStates, runState)
|
||||
|
||||
// Metadata API is only available if app has started listening to port, so wait for app to start before calling metadata API.
|
||||
putCLIProcessIDInMeta(runState, os.Getpid())
|
||||
|
||||
// Update extended metadata with run file path.
|
||||
putRunFilePathInMeta(runState, runFilePath)
|
||||
|
||||
// Update extended metadata with run file path.
|
||||
putRunTemplateNameInMeta(runState, runTemplateName)
|
||||
|
||||
// Update extended metadata with app log file path.
|
||||
if app.AppLogDestination != standalone.Console {
|
||||
putAppLogFilePathInMeta(runState, app.AppLogFileName)
|
||||
}
|
||||
|
||||
// Update extended metadata with daprd log file path.
|
||||
if app.DaprdLogDestination != standalone.Console {
|
||||
putDaprLogFilePathInMeta(runState, app.DaprdLogFileName)
|
||||
}
|
||||
|
||||
if runState.AppCMD.Command != nil {
|
||||
putAppCommandInMeta(runConfig, runState)
|
||||
|
||||
if runState.AppCMD.Command.Process != nil {
|
||||
putAppProcessIDInMeta(runState)
|
||||
// Attach a windows job object to the app process.
|
||||
utils.AttachJobObjectToProcess(strconv.Itoa(os.Getpid()), runState.AppCMD.Command.Process)
|
||||
}
|
||||
}
|
||||
|
||||
print.StatusEvent(runState.DaprCMD.OutputWriter, print.LogSuccess, "You're up and running! Dapr logs will appear here.\n")
|
||||
logInformationalStatusToStdout(app)
|
||||
}
|
||||
// If all apps have been started and there are no errors in starting the apps wait for signal from sigCh.
|
||||
if !exitWithError {
|
||||
// After all apps started wait for sigCh.
|
||||
<-sigCh
|
||||
// To add a new line in Stdout.
|
||||
fmt.Println()
|
||||
print.InfoStatusEvent(os.Stdout, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
|
||||
}
|
||||
|
||||
// Stop daprd and app processes for each runState.
|
||||
closeError := gracefullyShutdownAppsAndCloseResources(runStates, apps)
|
||||
|
||||
for _, app := range apps {
|
||||
runConfig := app.RunConfig
|
||||
if runConfig.UnixDomainSocket != "" {
|
||||
for _, s := range []string{"http", "grpc"} {
|
||||
os.Remove(utils.GetSocket(runConfig.UnixDomainSocket, runConfig.AppID, s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exitWithError, closeError
|
||||
}
|
||||
|
||||
func logInformationalStatusToStdout(app runfileconfig.App) {
|
||||
print.InfoStatusEvent(os.Stdout, "Started Dapr with app id %q. HTTP Port: %d. gRPC Port: %d",
|
||||
app.AppID, app.RunConfig.HTTPPort, app.RunConfig.GRPCPort)
|
||||
print.InfoStatusEvent(os.Stdout, "Writing log files to directory : %s", app.GetLogsDir())
|
||||
}
|
||||
|
||||
func gracefullyShutdownAppsAndCloseResources(runState []*runExec.RunExec, apps []runfileconfig.App) error {
|
||||
for _, s := range runState {
|
||||
stopDaprdAndAppProcesses(s)
|
||||
}
|
||||
var err error
|
||||
// close log file resources.
|
||||
for _, app := range apps {
|
||||
hasErr := app.CloseAppLogFile()
|
||||
if err == nil && hasErr != nil {
|
||||
err = hasErr
|
||||
}
|
||||
hasErr = app.CloseDaprdLogFile()
|
||||
if err == nil && hasErr != nil {
|
||||
err = hasErr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func executeRunWithAppsConfigFile(runFilePath string, k8sEnabled bool) {
|
||||
config, apps, err := getRunConfigFromRunFile(runFilePath)
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stdout, print.LogFailure, "Error getting apps from config file: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(apps) == 0 {
|
||||
print.StatusEvent(os.Stdout, print.LogFailure, "No apps to run")
|
||||
os.Exit(1)
|
||||
}
|
||||
var exitWithError bool
|
||||
var closeErr error
|
||||
if !k8sEnabled {
|
||||
exitWithError, closeErr = executeRun(config.Name, runFilePath, apps)
|
||||
} else {
|
||||
exitWithError, closeErr = kubernetes.Run(runFilePath, config)
|
||||
}
|
||||
if exitWithError {
|
||||
if closeErr != nil {
|
||||
print.StatusEvent(os.Stdout, print.LogFailure, "Error closing resources: %s", closeErr)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// populate the scheduler host address based on the dapr version.
|
||||
func validateSchedulerHostAddress(version, address string) string {
|
||||
// If no SchedulerHostAddress is supplied, set it to default value.
|
||||
if semver.Compare(fmt.Sprintf("v%v", version), "v1.15.0-rc.0") == 1 {
|
||||
if address == "" {
|
||||
return "localhost"
|
||||
}
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
func getRunConfigFromRunFile(runFilePath string) (runfileconfig.RunFileConfig, []runfileconfig.App, error) {
|
||||
config := runfileconfig.RunFileConfig{}
|
||||
apps, err := config.GetApps(runFilePath)
|
||||
return config, apps, err
|
||||
}
|
||||
|
||||
// startDaprdAndAppProcesses is a function to start the App process and the associated Daprd process.
|
||||
// This should be called as a blocking function call.
|
||||
func startDaprdAndAppProcesses(runConfig *standalone.RunConfig, commandDir string, sigCh chan os.Signal,
|
||||
daprdOutputWriter io.Writer, daprdErrorWriter io.Writer,
|
||||
appOutputWriter io.Writer, appErrorWriter io.Writer,
|
||||
) (*runExec.RunExec, error) {
|
||||
daprRunning := make(chan bool, 1)
|
||||
appRunning := make(chan bool, 1)
|
||||
|
||||
daprCMD, err := runExec.GetDaprCmdProcess(runConfig)
|
||||
if err != nil {
|
||||
print.StatusEvent(daprdErrorWriter, print.LogFailure, "Error getting daprd command with args : %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if strings.TrimSpace(commandDir) != "" {
|
||||
daprCMD.Command.Dir = commandDir
|
||||
}
|
||||
daprCMD.WithOutputWriter(daprdOutputWriter)
|
||||
daprCMD.WithErrorWriter(daprdErrorWriter)
|
||||
daprCMD.SetStdout()
|
||||
daprCMD.SetStderr()
|
||||
|
||||
appCmd, err := runExec.GetAppCmdProcess(runConfig)
|
||||
if err != nil {
|
||||
print.StatusEvent(appErrorWriter, print.LogFailure, "Error getting app command with args : %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if appCmd.Command != nil {
|
||||
// If an app is being run, set the command directory for that app.
|
||||
// appCmd does not need to call SetStdout and SetStderr since output is being read processed and then written
|
||||
// to the output and error writers for an app.
|
||||
appCmd.WithOutputWriter(appOutputWriter)
|
||||
appCmd.WithErrorWriter(appErrorWriter)
|
||||
if strings.TrimSpace(commandDir) != "" {
|
||||
appCmd.Command.Dir = commandDir
|
||||
}
|
||||
}
|
||||
|
||||
runState := runExec.New(runConfig, daprCMD, appCmd)
|
||||
|
||||
startErrChan := make(chan error, 1)
|
||||
|
||||
// Start daprd process.
|
||||
go startDaprdProcess(runConfig, runState, daprRunning, sigCh, startErrChan)
|
||||
|
||||
// Wait for daprRunning channel output.
|
||||
if daprStarted := <-daprRunning; !daprStarted {
|
||||
startErr := <-startErrChan
|
||||
print.StatusEvent(daprdErrorWriter, print.LogFailure, "Error starting daprd process: %s", startErr.Error())
|
||||
return nil, startErr
|
||||
}
|
||||
|
||||
// No application command is present.
|
||||
if appCmd.Command == nil {
|
||||
print.StatusEvent(appOutputWriter, print.LogWarning, "No application command present")
|
||||
return runState, nil
|
||||
}
|
||||
|
||||
// Start App process.
|
||||
go startAppProcess(runConfig, runState, appRunning, sigCh, startErrChan)
|
||||
|
||||
// Wait for appRunnning channel output.
|
||||
if appStarted := <-appRunning; !appStarted {
|
||||
startErr := <-startErrChan
|
||||
print.StatusEvent(appErrorWriter, print.LogFailure, "Error starting app process: %s", startErr.Error())
|
||||
// Start App failed so try to stop daprd process.
|
||||
err = killDaprdProcess(runState)
|
||||
if err != nil {
|
||||
print.StatusEvent(daprdErrorWriter, print.LogFailure, "Error stopping daprd process: %s", err.Error())
|
||||
print.StatusEvent(appErrorWriter, print.LogFailure, "Error stopping daprd process: %s", err.Error())
|
||||
}
|
||||
// Return the error from starting the app process.
|
||||
return nil, startErr
|
||||
}
|
||||
return runState, nil
|
||||
}
|
||||
|
||||
// stopDaprdAndAppProcesses is a function to stop the App process and the associated Daprd process
|
||||
// This should be called as a blocking function call.
|
||||
func stopDaprdAndAppProcesses(runState *runExec.RunExec) bool {
|
||||
var err error
|
||||
print.StatusEvent(runState.DaprCMD.OutputWriter, print.LogInfo, "\ntermination signal received: shutting down")
|
||||
// Only if app command is present and
|
||||
// if two different output writers are present run the following print statement.
|
||||
if runState.AppCMD.Command != nil && runState.AppCMD.OutputWriter != runState.DaprCMD.OutputWriter {
|
||||
print.StatusEvent(runState.AppCMD.OutputWriter, print.LogInfo, "\ntermination signal received: shutting down")
|
||||
}
|
||||
|
||||
exitWithError := false
|
||||
|
||||
daprErr := runState.DaprCMD.CommandErr
|
||||
|
||||
if daprErr != nil {
|
||||
exitWithError = true
|
||||
print.StatusEvent(runState.DaprCMD.ErrorWriter, print.LogFailure, "Error exiting Dapr: %s", daprErr)
|
||||
} else if runState.DaprCMD.Command.ProcessState == nil || !runState.DaprCMD.Command.ProcessState.Exited() {
|
||||
err = killDaprdProcess(runState)
|
||||
if err != nil {
|
||||
exitWithError = true
|
||||
}
|
||||
}
|
||||
appErr := runState.AppCMD.CommandErr
|
||||
|
||||
if appErr != nil {
|
||||
exitWithError = true
|
||||
print.StatusEvent(runState.AppCMD.ErrorWriter, print.LogFailure, "Error exiting App: %s", appErr)
|
||||
} else if runState.AppCMD.Command != nil && (runState.AppCMD.Command.ProcessState == nil || !runState.AppCMD.Command.ProcessState.Exited()) {
|
||||
err = killAppProcess(runState)
|
||||
if err != nil {
|
||||
exitWithError = true
|
||||
}
|
||||
}
|
||||
return exitWithError
|
||||
}
|
||||
|
||||
// startAppsProcess, starts the App process and calls wait in a goroutine
|
||||
// This function should be called as a goroutine.
|
||||
func startAppProcess(runConfig *standalone.RunConfig, runE *runExec.RunExec,
|
||||
appRunning chan bool, sigCh chan os.Signal, errorChan chan error,
|
||||
) {
|
||||
if runE.AppCMD.Command == nil {
|
||||
appRunning <- true
|
||||
return
|
||||
}
|
||||
|
||||
stdErrPipe, pipeErr := runE.AppCMD.Command.StderrPipe()
|
||||
if pipeErr != nil {
|
||||
print.StatusEvent(runE.AppCMD.ErrorWriter, print.LogFailure, "Error creating stderr for App %q : %s", runE.AppID, pipeErr.Error())
|
||||
errorChan <- pipeErr
|
||||
appRunning <- false
|
||||
return
|
||||
}
|
||||
|
||||
stdOutPipe, pipeErr := runE.AppCMD.Command.StdoutPipe()
|
||||
if pipeErr != nil {
|
||||
print.StatusEvent(runE.AppCMD.ErrorWriter, print.LogFailure, "Error creating stdout for App %q : %s", runE.AppID, pipeErr.Error())
|
||||
errorChan <- pipeErr
|
||||
appRunning <- false
|
||||
return
|
||||
}
|
||||
|
||||
errScanner := bufio.NewScanner(stdErrPipe)
|
||||
outScanner := bufio.NewScanner(stdOutPipe)
|
||||
go func() {
|
||||
for errScanner.Scan() {
|
||||
fmt.Fprintln(runE.AppCMD.ErrorWriter, print.Blue(fmt.Sprintf("== APP - %s == %s", runE.AppID,
|
||||
errScanner.Text())))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for outScanner.Scan() {
|
||||
fmt.Fprintln(runE.AppCMD.OutputWriter, print.Blue(fmt.Sprintf("== APP - %s == %s", runE.AppID, outScanner.Text())))
|
||||
}
|
||||
}()
|
||||
|
||||
err := runE.AppCMD.Command.Start()
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.AppCMD.ErrorWriter, print.LogFailure, err.Error())
|
||||
errorChan <- err
|
||||
appRunning <- false
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
appErr := runE.AppCMD.Command.Wait()
|
||||
|
||||
if appErr != nil {
|
||||
runE.AppCMD.CommandErr = appErr
|
||||
print.StatusEvent(runE.AppCMD.ErrorWriter, print.LogFailure, "The App process exited with error code: %s", appErr.Error())
|
||||
} else {
|
||||
print.StatusEvent(runE.AppCMD.OutputWriter, print.LogSuccess, "Exited App successfully")
|
||||
}
|
||||
}()
|
||||
|
||||
appRunning <- true
|
||||
}
|
||||
|
||||
// startDaprdProcess, starts the Daprd process and calls wait in a goroutine
|
||||
// This function should be called as a goroutine.
|
||||
func startDaprdProcess(runConfig *standalone.RunConfig, runE *runExec.RunExec,
|
||||
daprRunning chan bool, sigCh chan os.Signal, errorChan chan error,
|
||||
) {
|
||||
var startInfo string
|
||||
if runConfig.UnixDomainSocket != "" {
|
||||
startInfo = fmt.Sprintf(
|
||||
"Starting Dapr with id %s. HTTP Socket: %v. gRPC Socket: %v.",
|
||||
runE.AppID,
|
||||
utils.GetSocket(unixDomainSocket, runE.AppID, "http"),
|
||||
utils.GetSocket(unixDomainSocket, runE.AppID, "grpc"))
|
||||
} else {
|
||||
startInfo = fmt.Sprintf(
|
||||
"Starting Dapr with id %s. HTTP Port: %v. gRPC Port: %v",
|
||||
runE.AppID,
|
||||
runE.DaprHTTPPort,
|
||||
runE.DaprGRPCPort)
|
||||
}
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, startInfo)
|
||||
|
||||
err := runE.DaprCMD.Command.Start()
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
daprRunning <- false
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
daprdErr := runE.DaprCMD.Command.Wait()
|
||||
if daprdErr != nil {
|
||||
runE.DaprCMD.CommandErr = daprdErr
|
||||
print.StatusEvent(runE.DaprCMD.ErrorWriter, print.LogFailure, "The daprd process exited with error code: %s", daprdErr.Error())
|
||||
} else {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogSuccess, "Exited Dapr successfully")
|
||||
}
|
||||
}()
|
||||
|
||||
if runConfig.AppPort <= 0 {
|
||||
// If app does not listen to port, we can check for Dapr's sidecar health before starting the app.
|
||||
// Otherwise, it creates a deadlock.
|
||||
sidecarUp := true
|
||||
|
||||
if runConfig.UnixDomainSocket != "" {
|
||||
httpSocket := utils.GetSocket(runConfig.UnixDomainSocket, runE.AppID, "http")
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Checking if Dapr sidecar is listening on HTTP socket %v", httpSocket)
|
||||
err = utils.IsDaprListeningOnSocket(httpSocket, time.Duration(runtimeWaitTimeoutInSeconds)*time.Second)
|
||||
if err != nil {
|
||||
sidecarUp = false
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Dapr sidecar is not listening on HTTP socket: %s", err.Error())
|
||||
}
|
||||
|
||||
grpcSocket := utils.GetSocket(runConfig.UnixDomainSocket, runE.AppID, "grpc")
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Checking if Dapr sidecar is listening on GRPC socket %v", grpcSocket)
|
||||
err = utils.IsDaprListeningOnSocket(grpcSocket, time.Duration(runtimeWaitTimeoutInSeconds)*time.Second)
|
||||
if err != nil {
|
||||
sidecarUp = false
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Dapr sidecar is not listening on GRPC socket: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Checking if Dapr sidecar is listening on HTTP port %v", runE.DaprHTTPPort)
|
||||
err = utils.IsDaprListeningOnPort(runE.DaprHTTPPort, time.Duration(runtimeWaitTimeoutInSeconds)*time.Second)
|
||||
if err != nil {
|
||||
sidecarUp = false
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Dapr sidecar is not listening on HTTP port: %s", err.Error())
|
||||
}
|
||||
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Checking if Dapr sidecar is listening on GRPC port %v", runE.DaprGRPCPort)
|
||||
err = utils.IsDaprListeningOnPort(runE.DaprGRPCPort, time.Duration(runtimeWaitTimeoutInSeconds)*time.Second)
|
||||
if err != nil {
|
||||
sidecarUp = false
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Dapr sidecar is not listening on GRPC port: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if sidecarUp {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Dapr sidecar is up and running.")
|
||||
} else {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Dapr sidecar might not be responding.")
|
||||
}
|
||||
}
|
||||
daprRunning <- true
|
||||
}
|
||||
|
||||
// killDaprdProcess is used to kill the Daprd process and return error on failure.
|
||||
func killDaprdProcess(runE *runExec.RunExec) error {
|
||||
err := runE.DaprCMD.Command.Process.Kill()
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.ErrorWriter, print.LogFailure, "Error exiting Dapr: %s", err)
|
||||
return err
|
||||
}
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogSuccess, "Exited Dapr successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// killAppProcess is used to kill the App process and return error on failure.
|
||||
func killAppProcess(runE *runExec.RunExec) error {
|
||||
if runE.AppCMD.Command == nil {
|
||||
return nil
|
||||
}
|
||||
err := runE.AppCMD.Command.Process.Kill()
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.ErrorWriter, print.LogFailure, "Error exiting App: %s", err)
|
||||
return err
|
||||
}
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogSuccess, "Exited App successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// putCLIProcessIDInMeta puts the CLI process ID in metadata so that it can be used by the CLI to stop the CLI process.
|
||||
func putCLIProcessIDInMeta(runE *runExec.RunExec, pid int) {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Updating metadata for cliPID: %d", pid)
|
||||
err := metadata.Put(runE.DaprHTTPPort, "cliPID", strconv.Itoa(pid), runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for cliPID: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func putAppProcessIDInMeta(runE *runExec.RunExec) {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Updating metadata for appPID: %d", runE.AppCMD.Command.Process.Pid)
|
||||
err := metadata.Put(runE.DaprHTTPPort, "appPID", strconv.Itoa(runE.AppCMD.Command.Process.Pid), runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for appPID: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// putAppCommandInMeta puts the app command in metadata so that it can be used by the CLI to stop the app.
|
||||
func putAppCommandInMeta(runConfig standalone.RunConfig, runE *runExec.RunExec) {
|
||||
appCommand := strings.Join(runConfig.Command, " ")
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogInfo, "Updating metadata for app command: %s", appCommand)
|
||||
err := metadata.Put(runE.DaprHTTPPort, "appCommand", appCommand, runE.AppID, runConfig.UnixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for appCommand: %s", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// putRunFilePathInMeta puts the absolute path of run file in metadata so that it can be used by the CLI to stop all apps started by this run file.
|
||||
func putRunFilePathInMeta(runE *runExec.RunExec, runFilePath string) {
|
||||
runFilePath, err := filepath.Abs(runFilePath)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not get absolute path for run file: %s", err.Error())
|
||||
return
|
||||
}
|
||||
err = metadata.Put(runE.DaprHTTPPort, "runTemplatePath", runFilePath, runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for run file path: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// putRunTemplateNameInMeta puts the name of the run file in metadata so that it can be used by the CLI to stop all apps started by this run file.
|
||||
func putRunTemplateNameInMeta(runE *runExec.RunExec, runTemplateName string) {
|
||||
err := metadata.Put(runE.DaprHTTPPort, "runTemplateName", runTemplateName, runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for run template name: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// putAppLogFilePathInMeta puts the absolute path of app log file in metadata so that it can be used by the CLI to stop the app.
|
||||
func putAppLogFilePathInMeta(runE *runExec.RunExec, appLogFilePath string) {
|
||||
err := metadata.Put(runE.DaprHTTPPort, "appLogPath", appLogFilePath, runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for app log file path: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// putDaprLogFilePathInMeta puts the absolute path of Dapr log file in metadata so that it can be used by the CLI to stop the app.
|
||||
func putDaprLogFilePathInMeta(runE *runExec.RunExec, daprLogFilePath string) {
|
||||
err := metadata.Put(runE.DaprHTTPPort, "daprdLogPath", daprLogFilePath, runE.AppID, unixDomainSocket)
|
||||
if err != nil {
|
||||
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for dapr log file path: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// getRunFilePath returns the path to the run file.
|
||||
// If the provided path is a path to a YAML file then return the same.
|
||||
// Else it returns the path of "dapr.yaml" in the provided directory.
|
||||
func getRunFilePath(path string) (string, error) {
|
||||
if path == "-" {
|
||||
return path, nil // will be read from stdin later.
|
||||
}
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error getting file info for %s: %w", path, err)
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
filePath, err := utils.FindFileInDir(path, defaultRunTemplateFileName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filePath, nil
|
||||
}
|
||||
hasYAMLExtension := strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")
|
||||
if !hasYAMLExtension {
|
||||
return "", fmt.Errorf("file %q is not a YAML file", path)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// getConflictingFlags checks if any flags are set other than the ones passed in the excludedFlags slice.
|
||||
// Used for logic or notifications when any of the flags are conflicting and should not be used together.
|
||||
func getConflictingFlags(cmd *cobra.Command, excludedFlags ...string) []string {
|
||||
var conflictingFlags []string
|
||||
cmd.Flags().Visit(func(f *pflag.Flag) {
|
||||
if !slices.Contains(excludedFlags, f.Name) {
|
||||
conflictingFlags = append(conflictingFlags, f.Name)
|
||||
}
|
||||
})
|
||||
return conflictingFlags
|
||||
}
|
||||
|
||||
// detectIncompatibleFlags checks if any incompatible flags are used with --run-file
|
||||
// and returns a slice of the flag names that were used
|
||||
func detectIncompatibleFlags(cmd *cobra.Command) []string {
|
||||
if runFilePath == "" {
|
||||
return nil // No run file specified, so no incompatibilities
|
||||
}
|
||||
|
||||
// Get all flags that are not in the compatible list
|
||||
return getConflictingFlags(cmd, append(runFileCompatibleFlags, "run-file")...)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateSchedulerHostAddress(t *testing.T) {
|
||||
t.Run("test scheduler host address - v1.14.0-rc.0", func(t *testing.T) {
|
||||
address := validateSchedulerHostAddress("1.14.0-rc.0", "")
|
||||
assert.Equal(t, "", address)
|
||||
})
|
||||
|
||||
t.Run("test scheduler host address - v1.15.0-rc.0", func(t *testing.T) {
|
||||
address := validateSchedulerHostAddress("1.15.0", "")
|
||||
assert.Equal(t, "localhost:50006", address)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDetectIncompatibleFlags(t *testing.T) {
|
||||
// Setup a temporary run file path to trigger the incompatible flag check
|
||||
originalRunFilePath := runFilePath
|
||||
runFilePath = "some/path"
|
||||
defer func() {
|
||||
// Restore the original runFilePath
|
||||
runFilePath = originalRunFilePath
|
||||
}()
|
||||
|
||||
t.Run("detect incompatible flags", func(t *testing.T) {
|
||||
// Create a test command with flags
|
||||
cmd := &cobra.Command{Use: "test"}
|
||||
cmd.Flags().String("app-id", "", "")
|
||||
cmd.Flags().String("dapr-http-port", "", "")
|
||||
cmd.Flags().String("kubernetes", "", "") // Compatible flag
|
||||
cmd.Flags().String("runtime-path", "", "") // Compatible flag
|
||||
cmd.Flags().String("log-as-json", "", "") // Compatible flag
|
||||
|
||||
// Mark flags as changed
|
||||
cmd.Flags().Set("app-id", "myapp")
|
||||
cmd.Flags().Set("dapr-http-port", "3500")
|
||||
cmd.Flags().Set("kubernetes", "true")
|
||||
cmd.Flags().Set("runtime-path", "/path/to/runtime")
|
||||
cmd.Flags().Set("log-as-json", "true")
|
||||
|
||||
// Test detection
|
||||
incompatibleFlags := detectIncompatibleFlags(cmd)
|
||||
assert.Len(t, incompatibleFlags, 2)
|
||||
assert.Contains(t, incompatibleFlags, "app-id")
|
||||
assert.Contains(t, incompatibleFlags, "dapr-http-port")
|
||||
assert.NotContains(t, incompatibleFlags, "kubernetes")
|
||||
assert.NotContains(t, incompatibleFlags, "runtime-path")
|
||||
assert.NotContains(t, incompatibleFlags, "log-as-json")
|
||||
})
|
||||
|
||||
t.Run("no incompatible flags when run file not specified", func(t *testing.T) {
|
||||
// Create a test command with flags
|
||||
cmd := &cobra.Command{Use: "test"}
|
||||
cmd.Flags().String("app-id", "", "")
|
||||
cmd.Flags().String("dapr-http-port", "", "")
|
||||
|
||||
// Mark flags as changed
|
||||
cmd.Flags().Set("app-id", "myapp")
|
||||
cmd.Flags().Set("dapr-http-port", "3500")
|
||||
|
||||
// Temporarily clear runFilePath
|
||||
originalRunFilePath := runFilePath
|
||||
runFilePath = ""
|
||||
defer func() {
|
||||
runFilePath = originalRunFilePath
|
||||
}()
|
||||
|
||||
// Test detection
|
||||
incompatibleFlags := detectIncompatibleFlags(cmd)
|
||||
assert.Nil(t, incompatibleFlags)
|
||||
})
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2021 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
)
|
||||
|
||||
func setupShutdownNotify(sigCh chan os.Signal) {
|
||||
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
|
||||
|
||||
// Unlike Linux/Mac, you can't just send a SIGTERM from another process.
|
||||
// In order for 'dapr stop' to be able to signal gracefully we must use a named event in Windows.
|
||||
go func() {
|
||||
eventName, _ := syscall.UTF16FromString(fmt.Sprintf("dapr_cli_%v", os.Getpid()))
|
||||
eventHandle, _ := windows.CreateEvent(nil, 0, 0, &eventName[0])
|
||||
_, err := windows.WaitForSingleObject(eventHandle, windows.INFINITE)
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stdout, "Unable to wait for shutdown event. 'dapr stop' will not work. Error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
sigCh <- os.Interrupt
|
||||
}()
|
||||
}
|
63
cmd/stop.go
63
cmd/stop.go
|
@ -14,15 +14,21 @@ limitations under the License.
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/dapr/cli/pkg/kubernetes"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
var stopAppID string
|
||||
var (
|
||||
stopAppID string
|
||||
stopK8s bool
|
||||
)
|
||||
|
||||
var StopCmd = &cobra.Command{
|
||||
Use: "stop",
|
||||
|
@ -30,13 +36,56 @@ var StopCmd = &cobra.Command{
|
|||
Example: `
|
||||
# Stop Dapr application
|
||||
dapr stop --app-id <ID>
|
||||
|
||||
# Stop multiple apps by providing a run config file
|
||||
dapr stop --run-file dapr.yaml
|
||||
|
||||
# Stop multiple apps by providing a directory path containing the run config file(dapr.yaml)
|
||||
dapr stop --run-file /path/to/directory
|
||||
|
||||
# Stop and delete Kubernetes deployment of multiple apps by providing a run config file
|
||||
dapr stop --run-file dapr.yaml -k
|
||||
|
||||
# Stop and delete Kubernetes deployment of multiple apps by providing a directory path containing the run config file(dapr.yaml)
|
||||
dapr stop --run-file /path/to/directory -k
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
if len(runFilePath) > 0 {
|
||||
runFilePath, err = getRunFilePath(runFilePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to get run file path: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if !stopK8s {
|
||||
err = executeStopWithRunFile(runFilePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to stop Dapr and app processes: %s", err)
|
||||
} else {
|
||||
print.SuccessStatusEvent(os.Stdout, "Dapr and app processes stopped successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
config, _, cErr := getRunConfigFromRunFile(runFilePath)
|
||||
if cErr != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to parse run template file %q: %s", runFilePath, cErr.Error())
|
||||
}
|
||||
err = kubernetes.Stop(runFilePath, config)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error stopping deployments from multi-app run template: %v", err)
|
||||
}
|
||||
}
|
||||
if stopAppID != "" {
|
||||
args = append(args, stopAppID)
|
||||
}
|
||||
apps, err := standalone.List()
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "failed to get list of apps started by dapr : %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cliPIDToNoOfApps := standalone.GetCLIPIDCountMap(apps)
|
||||
for _, appID := range args {
|
||||
err := standalone.Stop(appID)
|
||||
err = standalone.Stop(appID, cliPIDToNoOfApps, apps)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "failed to stop app id %s: %s", appID, err)
|
||||
} else {
|
||||
|
@ -48,6 +97,16 @@ dapr stop --app-id <ID>
|
|||
|
||||
func init() {
|
||||
StopCmd.Flags().StringVarP(&stopAppID, "app-id", "a", "", "The application id to be stopped")
|
||||
StopCmd.Flags().StringVarP(&runFilePath, "run-file", "f", "", "Path to the run template file for the list of apps to stop")
|
||||
StopCmd.Flags().BoolVarP(&stopK8s, "kubernetes", "k", false, "Stop deployments in Kubernetes based on multi-app run file")
|
||||
StopCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
RootCmd.AddCommand(StopCmd)
|
||||
}
|
||||
|
||||
func executeStopWithRunFile(runFilePath string) error {
|
||||
absFilePath, err := filepath.Abs(runFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get absolute file path for %s: %w", runFilePath, err)
|
||||
}
|
||||
return standalone.StopAppsWithRunFile(absFilePath)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -23,11 +24,13 @@ import (
|
|||
"github.com/dapr/cli/pkg/kubernetes"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/dapr/cli/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
uninstallNamespace string
|
||||
uninstallKubernetes bool
|
||||
uninstallDev bool
|
||||
uninstallAll bool
|
||||
uninstallContainerRuntime string
|
||||
)
|
||||
|
@ -40,11 +43,24 @@ var UninstallCmd = &cobra.Command{
|
|||
# Uninstall from self-hosted mode
|
||||
dapr uninstall
|
||||
|
||||
# Uninstall from self-hosted mode and remove .dapr directory, Redis, Placement and Zipkin containers
|
||||
# Uninstall from self-hosted mode and remove .dapr directory, Redis, Placement, Scheduler, and Zipkin containers
|
||||
dapr uninstall --all
|
||||
|
||||
# Uninstall from Kubernetes
|
||||
dapr uninstall -k
|
||||
|
||||
# Uninstall from Kubernetes and remove CRDs
|
||||
dapr uninstall -k --all
|
||||
|
||||
# Uninstall from Kubernetes remove dev deployments of Redis, Zipkin
|
||||
dapr uninstall -k --dev
|
||||
|
||||
# Uninstall from Kubernetes remove dev deployments of Redis, Zipkin and CRDs
|
||||
dapr uninstall -k --dev --all
|
||||
|
||||
# Uninstall Dapr from non-default install directory
|
||||
# This will remove the .dapr directory present in the path <path-to-install-directory>
|
||||
dapr uninstall --runtime-path <path-to-install-directory>
|
||||
`,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("network", cmd.Flags().Lookup("network"))
|
||||
|
@ -54,12 +70,21 @@ dapr uninstall -k
|
|||
var err error
|
||||
|
||||
if uninstallKubernetes {
|
||||
if len(strings.TrimSpace(daprRuntimePath)) != 0 {
|
||||
print.FailureStatusEvent(os.Stderr, "--runtime-path is only valid for self-hosted mode")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your cluster...")
|
||||
err = kubernetes.Uninstall(uninstallNamespace, uninstallAll, timeout)
|
||||
err = kubernetes.Uninstall(uninstallNamespace, uninstallAll, uninstallDev, timeout)
|
||||
} else {
|
||||
if !utils.IsValidContainerRuntime(uninstallContainerRuntime) {
|
||||
print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.")
|
||||
os.Exit(1)
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...")
|
||||
dockerNetwork := viper.GetString("network")
|
||||
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime)
|
||||
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime, daprRuntimePath)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -72,11 +97,12 @@ dapr uninstall -k
|
|||
|
||||
func init() {
|
||||
UninstallCmd.Flags().BoolVarP(&uninstallKubernetes, "kubernetes", "k", false, "Uninstall Dapr from a Kubernetes cluster")
|
||||
UninstallCmd.Flags().BoolVarP(&uninstallDev, "dev", "", false, "Uninstall Dapr Redis and Zipking installations from Kubernetes cluster")
|
||||
UninstallCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The timeout for the Kubernetes uninstall")
|
||||
UninstallCmd.Flags().BoolVar(&uninstallAll, "all", false, "Remove .dapr directory, Redis, Placement and Zipkin containers on local machine, and CRDs on a Kubernetes cluster")
|
||||
UninstallCmd.Flags().BoolVar(&uninstallAll, "all", false, "Remove .dapr directory, Redis, Placement, Scheduler (and default volume in self-hosted mode), and Zipkin containers on local machine, and CRDs on a Kubernetes cluster")
|
||||
UninstallCmd.Flags().String("network", "", "The Docker network from which to remove the Dapr runtime")
|
||||
UninstallCmd.Flags().StringVarP(&uninstallNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to uninstall Dapr from")
|
||||
UninstallCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use (defaults to docker)")
|
||||
UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman")
|
||||
RootCmd.AddCommand(UninstallCmd)
|
||||
}
|
||||
|
|
|
@ -25,8 +25,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
upgradeRuntimeVersion string
|
||||
upgradeImageVariant string
|
||||
upgradeRuntimeVersion string
|
||||
upgradeImageVariant string
|
||||
upgradeDashboardVersion string
|
||||
)
|
||||
|
||||
var UpgradeCmd = &cobra.Command{
|
||||
|
@ -58,6 +59,7 @@ dapr upgrade -k
|
|||
}
|
||||
err = kubernetes.Upgrade(kubernetes.UpgradeConfig{
|
||||
RuntimeVersion: upgradeRuntimeVersion,
|
||||
DashboardVersion: upgradeDashboardVersion,
|
||||
Args: values,
|
||||
Timeout: timeout,
|
||||
ImageRegistryURI: imageRegistryURI,
|
||||
|
@ -78,6 +80,7 @@ func init() {
|
|||
UpgradeCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Upgrade or downgrade Dapr in a Kubernetes cluster")
|
||||
UpgradeCmd.Flags().UintVarP(&timeout, "timeout", "", 300, "The timeout for the Kubernetes upgrade")
|
||||
UpgradeCmd.Flags().StringVarP(&upgradeRuntimeVersion, "runtime-version", "", "", "The version of the Dapr runtime to upgrade or downgrade to, for example: 1.0.0")
|
||||
UpgradeCmd.Flags().StringVarP(&upgradeDashboardVersion, "dashboard-version", "", "", "The version of the Dapr dashboard to upgrade or downgrade to, for example: 0.13.0")
|
||||
UpgradeCmd.Flags().BoolP("help", "h", false, "Print this help message")
|
||||
UpgradeCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
|
||||
UpgradeCmd.Flags().String("image-registry", "", "Custom/Private docker image repository URL")
|
||||
|
|
|
@ -29,7 +29,7 @@ var output string
|
|||
|
||||
var VersionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print Dapr runtime and Cli version.",
|
||||
Short: "Print the Dapr runtime and CLI version",
|
||||
Example: `
|
||||
# Version for Dapr
|
||||
dapr version --output json
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
## Using with `docker-in-docker` feature
|
||||
|
||||
Since the Dapr CLI requires Docker, an easy way to get started is to use the `docker-in-docker` feature. This will install a separate Docker daemon inside the container for `dapr` to use:
|
||||
|
||||
```jsonc
|
||||
"features": {
|
||||
// Install the Dapr CLI
|
||||
"ghcr.io/dapr/cli/dapr-cli:0": {},
|
||||
// Enable Docker (via Docker-in-Docker)
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
|
||||
// Alternatively, use Docker-outside-of-Docker (uses Docker in the host)
|
||||
//"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
|
||||
}
|
||||
```
|
||||
|
||||
For more details on setting up a Dev Container with Dapr, see the [Developing Dapr applications with Dev Containers docs](https://docs.dapr.io/developing-applications/local-development/ides/vscode/vscode-remote-dev-containers/).
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
# dapr-cli (dapr-cli)
|
||||
|
||||
Install the Dapr CLI
|
||||
|
||||
## Example Usage
|
||||
|
||||
```json
|
||||
"features": {
|
||||
"ghcr.io/dapr/cli/dapr-cli:0": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Options Id | Description | Type | Default Value |
|
||||
|-----|-----|-----|-----|
|
||||
| version | Version of the Dapr CLI to install (or "latest") | string | latest |
|
||||
|
||||
## Using with `docker-in-docker` feature
|
||||
|
||||
Since the Dapr CLI requires Docker, an easy way to get started is to use the `docker-in-docker` feature. This will install a separate Docker daemon inside the container for `dapr` to use:
|
||||
|
||||
```jsonc
|
||||
"features": {
|
||||
// Install the Dapr CLI
|
||||
"ghcr.io/dapr/cli/dapr-cli:0": {},
|
||||
// Enable Docker (via Docker-in-Docker)
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
|
||||
// Alternatively, use Docker-outside-of-Docker (uses Docker in the host)
|
||||
//"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
|
||||
}
|
||||
```
|
||||
|
||||
For more details on setting up a Dev Container with Dapr, see the [Developing Dapr applications with Dev Containers docs](https://docs.dapr.io/developing-applications/local-development/ides/vscode/vscode-remote-dev-containers/).
|
||||
|
||||
---
|
||||
|
||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/dapr/cli/blob/master/dev-container-feature/src/dapr-cli/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "dapr-cli",
|
||||
"id": "dapr-cli",
|
||||
"version": "0.1.0",
|
||||
"description": "Install the Dapr CLI",
|
||||
"options": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"proposals": [
|
||||
"latest"
|
||||
],
|
||||
"default": "latest",
|
||||
"description": "Version of the Dapr CLI to install (or \"latest\")"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
|
||||
###################
|
||||
# Helper Functions
|
||||
###################
|
||||
|
||||
# Re-used from https://github.com/devcontainers/features/blob/4a9929f96485061e3778b35848e21d7c3c193480/src/dotnet/install.sh#L74
|
||||
|
||||
apt_get_update()
|
||||
{
|
||||
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||
echo "Running apt-get update..."
|
||||
apt-get update -y
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if packages are installed and installs them if not.
|
||||
check_packages() {
|
||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||
apt_get_update
|
||||
apt-get -y install --no-install-recommends "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
get_latest_release() {
|
||||
curl --silent "https://api.github.com/repos/dapr/cli/releases/latest" |
|
||||
grep '"tag_name":' | sed -E "s/.*\"v([^\"]+)\".*/\1/"
|
||||
}
|
||||
|
||||
###################
|
||||
# Install Dapr CLI
|
||||
###################
|
||||
echo "Activating feature 'dapr-cli'"
|
||||
|
||||
check_packages curl ca-certificates
|
||||
|
||||
VERSION=${VERSION:-"latest"}
|
||||
|
||||
if [ "${VERSION}" = "latest" ]; then
|
||||
VERSION=$(get_latest_release)
|
||||
fi
|
||||
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
armv7*) ARCH="arm";;
|
||||
aarch64) ARCH="arm64";;
|
||||
x86_64) ARCH="amd64";;
|
||||
esac
|
||||
|
||||
curl -SsL "https://github.com/dapr/cli/releases/download/v${VERSION}/dapr_linux_${ARCH}.tar.gz" | \
|
||||
tar -zx -C /usr/local/bin dapr
|
||||
|
||||
dapr --version
|
||||
|
||||
## Write bash completion code to a file and source it from .bash_profile
|
||||
mkdir -p $_REMOTE_USER_HOME/.dapr
|
||||
dapr completion bash > $_REMOTE_USER_HOME/.dapr/completion.bash.inc
|
||||
printf "
|
||||
## dapr shell completion
|
||||
source '$_REMOTE_USER_HOME/.dapr/completion.bash.inc'
|
||||
" >> $_REMOTE_USER_HOME/.bashrc
|
||||
chown -R $_REMOTE_USER:$_REMOTE_USER $_REMOTE_USER_HOME/.dapr
|
||||
chown $_REMOTE_USER:$_REMOTE_USER $_REMOTE_USER_HOME/.bashrc
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This test file will be executed against an auto-generated devcontainer.json that
|
||||
# includes the 'dapr-cli' Feature with no options.
|
||||
#
|
||||
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
|
||||
#
|
||||
# Eg:
|
||||
# {
|
||||
# "image": "<..some-base-image...>",
|
||||
# "features": {
|
||||
# "dapr-cli": {}
|
||||
# },
|
||||
# "remoteUser": "root"
|
||||
# }
|
||||
#
|
||||
# Thus, the value of all options will fall back to the default value in
|
||||
# the Feature's 'devcontainer-feature.json'.
|
||||
#
|
||||
# These scripts are run as 'root' by default. Although that can be changed
|
||||
# with the '--remote-user' flag.
|
||||
#
|
||||
# This test can be run with the following command (from the repo root folder):
|
||||
#
|
||||
# devcontainer features test \
|
||||
# --features dapr-cli \
|
||||
# --remote-user root \
|
||||
# --skip-scenarios \
|
||||
# --base-image mcr.microsoft.com/devcontainers/base:ubuntu \
|
||||
# --project-folder dev-container-feature
|
||||
|
||||
set -e
|
||||
|
||||
# Optional: Import test library bundled with the devcontainer CLI
|
||||
# Provides the 'check' and 'reportResults' commands.
|
||||
source dev-container-features-test-lib
|
||||
|
||||
# Feature-specific tests
|
||||
# The 'check' command comes from the dev-container-features-test-lib.
|
||||
check "execute command" bash -c "dapr --help | grep 'Distributed Application Runtime'"
|
||||
|
||||
# Report results
|
||||
# If any of the checks above exited with a non-zero exit code, the test will fail.
|
||||
reportResults
|
|
@ -7,7 +7,7 @@ This document helps you get started developing Dapr CLI. If you find any problem
|
|||
|
||||
### Linux and MacOS
|
||||
|
||||
1. The Go language environment `1.19` [(instructions)](https://golang.org/doc/install#tarball).
|
||||
1. The Go language environment `1.21` [(instructions)](https://golang.org/doc/install#tarball).
|
||||
* Make sure that your GOPATH and PATH are configured correctly
|
||||
```bash
|
||||
export GOPATH=~/go
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
# Release Guide
|
||||
|
||||
This document describes how to release Dapr CLI along with associated artifacts.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Only the repository maintainers and release team are allowed to execute the below steps.
|
||||
|
||||
## Pre-release build
|
||||
|
||||
Pre-release build will be built from `release-<major>.<minor>` branch and versioned by git version tag suffix e.g. `-rc.0`, `-rc.1`, etc. This build is not released to users who use the latest stable version.
|
||||
**Pre-release process**
|
||||
1. Create a PR to update the `Dapr runtime` and `Dapr dashboard` pre-release versions in workflow and tests files wherever applicable, and merge the PR to master branch. For example, please take a look at this PR - https://github.com/dapr/cli/pull/1019. Please note that this PR is just for reference and only reflects the absolute minimum number of file changes. These versions update could lead to some other changes also.
|
||||
|
||||
2. Create branch `release-<major>.<minor>` from master and push the branch. e.g. `release-1.11`. You can use the github web UI to create the branch or use the following command.
|
||||
|
||||
```sh
|
||||
$ git checkout master && git reset --hard upstream/master && git pull upstream master
|
||||
$ git checkout -b release-1.11
|
||||
$ git push upstream release-1.11
|
||||
```
|
||||
3. Add pre-release version tag (with suffix -rc.0 e.g. v1.11.0-rc.0) and push the tag.
|
||||
|
||||
```sh
|
||||
$ git tag "v1.11.0-rc.0" -m "v1.11.0-rc.0"
|
||||
$ git push upstream v1.11.0-rc.0
|
||||
|
||||
```
|
||||
4. CI creates the new build artifacts.
|
||||
5. Test and validate the functionalities with the specific version.
|
||||
6. If there are regressions and bugs, fix them in release-* branch. e.g `release-1.11` branch.
|
||||
7. Create new pre-release version tag (with suffix -rc.1, -rc.2, etc).
|
||||
8. Repeat from 5 to 7 until all bugs are fixed.
|
||||
|
||||
|
||||
## Release the stable version to users
|
||||
|
||||
> **Note**: Make sure stable versions of `dapr runtime` and `dapr dashboard` are released before releasing the CLI and update their references in workflow and tests files wherever applicable.
|
||||
|
||||
Once all bugs are fixed, stable version can be released. Create a new git version tag (without the suffix -rc.x e.g. v1.11.0) and push the tag. CI will create the new build artifacts and release them.
|
||||
|
||||
## Release Patch version
|
||||
|
||||
Work on the existing `release-<major>.<minor>` branch to release a patch version. Once all bugs are fixed, create a new patch version tag, such as `v1.11.1-rc.0`. After verifying the fixes on this pre-release, create a new git version tag such as `v1.11.1` and push the tag. CI will create the new build artifacts and release them.
|
373
go.mod
373
go.mod
|
@ -1,230 +1,245 @@
|
|||
module github.com/dapr/cli
|
||||
|
||||
go 1.19
|
||||
go 1.23.5
|
||||
|
||||
require (
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/Masterminds/semver/v3 v3.3.0
|
||||
github.com/Pallinder/sillyname-go v0.0.0-20130730142914-97aeae9e6ba1
|
||||
github.com/briandowns/spinner v1.6.1
|
||||
github.com/dapr/dapr v1.9.0-rc.3
|
||||
github.com/dapr/go-sdk v1.5.1-0.20221001032816-7bcbf27f5152
|
||||
github.com/docker/docker v20.10.17+incompatible
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/gocarina/gocsv v0.0.0-20190426105157-2fc85fcf0c07
|
||||
github.com/hashicorp/go-retryablehttp v0.5.4
|
||||
github.com/hashicorp/go-version v1.3.0
|
||||
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b
|
||||
github.com/nightlyone/lockfile v0.0.0-20180618180623-0ad87eef1443
|
||||
github.com/briandowns/spinner v1.19.0
|
||||
github.com/dapr/dapr v1.15.0-rc.3.0.20250107220753-e073759df4c1
|
||||
github.com/dapr/go-sdk v1.11.0
|
||||
github.com/dapr/kit v0.13.1-0.20241127165251-30e2c24840b4
|
||||
github.com/docker/docker v25.0.6+incompatible
|
||||
github.com/evanphx/json-patch/v5 v5.9.0
|
||||
github.com/fatih/color v1.17.0
|
||||
github.com/gocarina/gocsv v0.0.0-20220927221512-ad3251f9fa25
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/kolesnikovae/go-winjob v1.0.0
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/nightlyone/lockfile v1.0.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/spf13/viper v1.10.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.13.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/mod v0.22.0
|
||||
golang.org/x/sys v0.28.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
helm.sh/helm/v3 v3.9.4
|
||||
k8s.io/api v0.24.2
|
||||
k8s.io/apiextensions-apiserver v0.24.2
|
||||
k8s.io/apimachinery v0.24.2
|
||||
k8s.io/cli-runtime v0.24.2
|
||||
k8s.io/client-go v0.24.2
|
||||
helm.sh/helm/v3 v3.17.1
|
||||
k8s.io/api v0.32.1
|
||||
k8s.io/apiextensions-apiserver v0.32.1
|
||||
k8s.io/apimachinery v0.32.1
|
||||
k8s.io/cli-runtime v0.32.1
|
||||
k8s.io/client-go v0.32.1
|
||||
k8s.io/helm v2.16.10+incompatible
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require github.com/evanphx/json-patch v4.12.0+incompatible
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.5.0 // indirect
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.1 // indirect
|
||||
github.com/AdhityaRamadhanus/fasthttpcors v0.0.0-20170121111917-d4c07198763a // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.0.0 // indirect
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
|
||||
cel.dev/expr v0.18.0 // indirect
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/Code-Hex/go-generics-cache v1.3.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.3 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/PuerkitoBio/purell v1.2.1 // indirect
|
||||
github.com/aavaz-ai/pii-scrubber v0.0.0-20220812094047-3fa450ab6973 // indirect
|
||||
github.com/alphadose/haxmap v1.4.0 // indirect
|
||||
github.com/anshal21/go-worker v1.1.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||
github.com/containerd/containerd v1.6.6 // indirect
|
||||
github.com/containerd/continuity v0.2.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/dapr/components-contrib v1.9.0-rc.1 // indirect
|
||||
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/cli v20.10.17+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bufbuild/protocompile v0.6.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/chebyrash/promise v0.0.0-20230709133807-42ec49ba1459 // indirect
|
||||
github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.14.0 // indirect
|
||||
github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect
|
||||
github.com/containerd/containerd v1.7.24 // indirect
|
||||
github.com/containerd/errdefs v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/dapr/components-contrib v1.15.0-rc.1.0.20241216170750-aca5116d95c9 // indirect
|
||||
github.com/dapr/durabletask-go v0.5.1-0.20241216172832-16da3e7c3530 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
github.com/docker/cli v25.0.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fasthttp/router v1.4.12 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.4.0 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||
github.com/go-kit/log v0.2.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
|
||||
github.com/go-chi/chi/v5 v5.1.0 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/cel-go v0.10.1 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/cel-go v0.22.0 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jhump/protoreflect v1.13.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jhump/protoreflect v1.15.3 // indirect
|
||||
github.com/jmoiron/sqlx v1.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/klauspost/compress v1.17.10 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lib/pq v1.10.6 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httprc v1.0.5 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.21 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/marusama/semaphore/v2 v2.5.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/runc v1.1.2 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.2 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.8.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.12.2 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.35.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/statsd_exporter v0.22.3 // indirect
|
||||
github.com/rubenv/sql-migrate v1.1.1 // indirect
|
||||
github.com/russross/blackfriday v2.0.0+incompatible // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/pkoukk/tiktoken-go v0.1.6 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.4 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.59.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/statsd_exporter v0.22.7 // indirect
|
||||
github.com/rubenv/sql-migrate v1.7.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sony/gobreaker v0.5.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/stretchr/objx v0.4.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.40.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.7 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tmc/langchaingo v0.1.12 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f // indirect
|
||||
google.golang.org/grpc v1.48.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
||||
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.26.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
|
||||
google.golang.org/grpc v1.68.1 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiserver v0.24.2 // indirect
|
||||
k8s.io/component-base v0.24.2 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect
|
||||
k8s.io/kubectl v0.24.2 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
oras.land/oras-go v1.2.0 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.11.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.11.4 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/Azure/go-autorest => github.com/Azure/go-autorest v14.2.0+incompatible
|
||||
|
||||
github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
|
||||
github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
|
||||
github.com/russross/blackfriday => github.com/russross/blackfriday v1.5.2
|
||||
k8s.io/client => github.com/kubernetes-client/go v0.0.0-20190928040339-c757968c4c36
|
||||
k8s.io/apiserver v0.32.1 // indirect
|
||||
k8s.io/component-base v0.32.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
k8s.io/kubectl v0.32.1 // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
oras.land/oras-go v1.2.5 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.19.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
)
|
||||
|
|
|
@ -141,7 +141,7 @@ if (!(Test-Path $zipFilePath -PathType Leaf)) {
|
|||
Write-Output "Extracting $zipFilePath..."
|
||||
Microsoft.Powershell.Archive\Expand-Archive -Force -Path $zipFilePath -DestinationPath $DaprRoot
|
||||
if (!(Test-Path $DaprCliFilePath -PathType Leaf)) {
|
||||
throw "Failed to download Dapr Cli archieve - $zipFilePath"
|
||||
throw "Failed to download Dapr Cli archive - $zipFilePath"
|
||||
}
|
||||
|
||||
# Check the Dapr CLI version
|
||||
|
|
|
@ -180,6 +180,7 @@ installFile() {
|
|||
runAsRoot rm "$DAPR_CLI_FILE"
|
||||
fi
|
||||
chmod o+x $tmp_root_dapr_cli
|
||||
mkdir -p $DAPR_INSTALL_DIR
|
||||
runAsRoot cp "$tmp_root_dapr_cli" "$DAPR_INSTALL_DIR"
|
||||
|
||||
if [ -f "$DAPR_CLI_FILE" ]; then
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
|
@ -19,7 +19,7 @@ import (
|
|||
yamlDecoder "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/dapr/dapr/pkg/injector/sidecar"
|
||||
"github.com/dapr/dapr/pkg/injector/patcher"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -55,8 +55,8 @@ const (
|
|||
daprReadinessProbeThresholdKey = "dapr.io/sidecar-readiness-probe-threshold"
|
||||
daprImageKey = "dapr.io/sidecar-image"
|
||||
daprAppSSLKey = "dapr.io/app-ssl"
|
||||
daprMaxRequestBodySizeKey = "dapr.io/http-max-request-size"
|
||||
daprReadBufferSizeKey = "dapr.io/http-read-buffer-size"
|
||||
daprMaxRequestBodySizeKey = "dapr.io/max-body-size"
|
||||
daprReadBufferSizeKey = "dapr.io/read-buffer-size"
|
||||
daprHTTPStreamRequestBodyKey = "dapr.io/http-stream-request-body"
|
||||
daprGracefulShutdownSecondsKey = "dapr.io/graceful-shutdown-seconds"
|
||||
daprEnableAPILoggingKey = "dapr.io/enable-api-logging"
|
||||
|
@ -82,7 +82,7 @@ const (
|
|||
)
|
||||
|
||||
type Annotator interface {
|
||||
Annotate(io.Reader, io.Writer) error
|
||||
Annotate(io.Reader, io.Writer) error //nolint: inamedparam
|
||||
}
|
||||
|
||||
type K8sAnnotator struct {
|
||||
|
@ -341,12 +341,8 @@ func (p *K8sAnnotator) annotateYAML(input []byte, config AnnotateOptions) ([]byt
|
|||
}
|
||||
|
||||
// Create a patch operation for the annotations.
|
||||
patchOps := []sidecar.PatchOperation{}
|
||||
patchOps = append(patchOps, sidecar.PatchOperation{
|
||||
Op: "add",
|
||||
Path: path,
|
||||
Value: annotations,
|
||||
})
|
||||
var patchOps []jsonpatch.Operation
|
||||
patchOps = append(patchOps, patcher.NewPatchOperation("add", path, annotations))
|
||||
patchBytes, err := json.Marshal(patchOps)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
|
|
|
@ -2,11 +2,11 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -333,7 +333,7 @@ func TestAnnotate(t *testing.T) {
|
|||
|
||||
for i := range expectedDocs {
|
||||
if tt.printOutput {
|
||||
t.Logf(outDocs[i])
|
||||
t.Logf(outDocs[i]) //nolint:govet
|
||||
}
|
||||
assert.YAMLEq(t, expectedDocs[i], outDocs[i])
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ func TestGetDaprAnnotations(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "true", annotations[daprEnabledKey])
|
||||
assert.Equal(t, appID, annotations[daprAppIDKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", appPort), annotations[daprAppPortKey])
|
||||
assert.Equal(t, strconv.Itoa(appPort), annotations[daprAppPortKey])
|
||||
assert.Equal(t, config, annotations[daprConfigKey])
|
||||
assert.Equal(t, appProtocol, annotations[daprAppProtocolKey])
|
||||
assert.Equal(t, "true", annotations[daprEnableProfilingKey])
|
||||
|
@ -431,31 +431,31 @@ func TestGetDaprAnnotations(t *testing.T) {
|
|||
assert.Equal(t, apiTokenSecret, annotations[daprAPITokenSecretKey])
|
||||
assert.Equal(t, appTokenSecret, annotations[daprAppTokenSecretKey])
|
||||
assert.Equal(t, "true", annotations[daprLogAsJSONKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", appMaxConcurrency), annotations[daprAppMaxConcurrencyKey])
|
||||
assert.Equal(t, strconv.Itoa(appMaxConcurrency), annotations[daprAppMaxConcurrencyKey])
|
||||
assert.Equal(t, "true", annotations[daprEnableMetricsKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", metricsPort), annotations[daprMetricsPortKey])
|
||||
assert.Equal(t, strconv.Itoa(metricsPort), annotations[daprMetricsPortKey])
|
||||
assert.Equal(t, "true", annotations[daprEnableDebugKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", debugPort), annotations[daprDebugPortKey])
|
||||
assert.Equal(t, strconv.Itoa(debugPort), annotations[daprDebugPortKey])
|
||||
assert.Equal(t, env, annotations[daprEnvKey])
|
||||
assert.Equal(t, cpuLimit, annotations[daprCPULimitKey])
|
||||
assert.Equal(t, memoryLimit, annotations[daprMemoryLimitKey])
|
||||
assert.Equal(t, cpuRequest, annotations[daprCPURequestKey])
|
||||
assert.Equal(t, memoryRequest, annotations[daprMemoryRequestKey])
|
||||
assert.Equal(t, listenAddresses, annotations[daprListenAddressesKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", livenessProbeDelay), annotations[daprLivenessProbeDelayKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", livenessProbeTimeout), annotations[daprLivenessProbeTimeoutKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", livenessProbePeriod), annotations[daprLivenessProbePeriodKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", livenessProbeThreshold), annotations[daprLivenessProbeThresholdKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", readinessProbeDelay), annotations[daprReadinessProbeDelayKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", readinessProbeTimeout), annotations[daprReadinessProbeTimeoutKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", readinessProbePeriod), annotations[daprReadinessProbePeriodKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", readinessProbeThreshold), annotations[daprReadinessProbeThresholdKey])
|
||||
assert.Equal(t, strconv.Itoa(livenessProbeDelay), annotations[daprLivenessProbeDelayKey])
|
||||
assert.Equal(t, strconv.Itoa(livenessProbeTimeout), annotations[daprLivenessProbeTimeoutKey])
|
||||
assert.Equal(t, strconv.Itoa(livenessProbePeriod), annotations[daprLivenessProbePeriodKey])
|
||||
assert.Equal(t, strconv.Itoa(livenessProbeThreshold), annotations[daprLivenessProbeThresholdKey])
|
||||
assert.Equal(t, strconv.Itoa(readinessProbeDelay), annotations[daprReadinessProbeDelayKey])
|
||||
assert.Equal(t, strconv.Itoa(readinessProbeTimeout), annotations[daprReadinessProbeTimeoutKey])
|
||||
assert.Equal(t, strconv.Itoa(readinessProbePeriod), annotations[daprReadinessProbePeriodKey])
|
||||
assert.Equal(t, strconv.Itoa(readinessProbeThreshold), annotations[daprReadinessProbeThresholdKey])
|
||||
assert.Equal(t, daprImage, annotations[daprImageKey])
|
||||
assert.Equal(t, "true", annotations[daprAppSSLKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", maxRequestBodySize), annotations[daprMaxRequestBodySizeKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", readBufferSize), annotations[daprReadBufferSizeKey])
|
||||
assert.Equal(t, strconv.Itoa(maxRequestBodySize), annotations[daprMaxRequestBodySizeKey])
|
||||
assert.Equal(t, strconv.Itoa(readBufferSize), annotations[daprReadBufferSizeKey])
|
||||
assert.Equal(t, "true", annotations[daprHTTPStreamRequestBodyKey])
|
||||
assert.Equal(t, fmt.Sprintf("%d", gracefulShutdownSeconds), annotations[daprGracefulShutdownSecondsKey])
|
||||
assert.Equal(t, strconv.Itoa(gracefulShutdownSeconds), annotations[daprGracefulShutdownSecondsKey])
|
||||
assert.Equal(t, "true", annotations[daprEnableAPILoggingKey])
|
||||
assert.Equal(t, unixDomainSocketPath, annotations[daprUnixDomainSocketPathKey])
|
||||
assert.Equal(t, volumeMountsReadOnly, annotations[daprVolumeMountsReadOnlyKey])
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"sync"
|
||||
|
||||
k8s "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
scheme "github.com/dapr/dapr/pkg/client/clientset/versioned"
|
||||
|
@ -30,10 +31,6 @@ import (
|
|||
|
||||
// oidc auth
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||
|
||||
// openstack auth
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -15,6 +15,7 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/dapr/cli/utils"
|
||||
|
@ -51,9 +52,14 @@ func GetDaprHelmChartName(helmConf *helm.Configuration) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(releases) == 0 {
|
||||
return "", fmt.Errorf("could not find release name %q in your helm releases", daprReleaseName)
|
||||
}
|
||||
var chart string
|
||||
for _, r := range releases {
|
||||
if r.Chart != nil && strings.Contains(r.Chart.Name(), "dapr") {
|
||||
if r.Chart != nil &&
|
||||
strings.Contains(r.Chart.Name(), daprReleaseName) &&
|
||||
!strings.Contains(r.Chart.Name(), dashboardReleaseName) {
|
||||
chart = r.Name
|
||||
break
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/dapr/cli/pkg/age"
|
||||
"github.com/dapr/cli/utils"
|
||||
v1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
|
||||
"github.com/dapr/dapr/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
// ComponentsOutput represent a Dapr component.
|
||||
|
@ -46,21 +47,37 @@ func PrintComponents(name, namespace, outputFormat string) error {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
list, err := client.ComponentsV1alpha1().Components(namespace).List(meta_v1.ListOptions{})
|
||||
// This means that the Dapr Components CRD is not installed and
|
||||
// therefore no component items exist.
|
||||
if apierrors.IsNotFound(err) {
|
||||
list = &v1alpha1.ComponentList{
|
||||
Items: []v1alpha1.Component{},
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
return listComponents(client, namespace)
|
||||
}, name, outputFormat)
|
||||
}
|
||||
|
||||
func listComponents(client versioned.Interface, namespace string) (*v1alpha1.ComponentList, error) {
|
||||
list, err := client.ComponentsV1alpha1().Components(namespace).List(meta_v1.ListOptions{})
|
||||
// This means that the Dapr Components CRD is not installed and
|
||||
// therefore no component items exist.
|
||||
if apierrors.IsNotFound(err) {
|
||||
list = &v1alpha1.ComponentList{
|
||||
Items: []v1alpha1.Component{},
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func getComponent(client versioned.Interface, namespace string, componentName string) (*v1alpha1.Component, error) {
|
||||
c, err := client.ComponentsV1alpha1().Components(namespace).Get(componentName, meta_v1.GetOptions{})
|
||||
// This means that the Dapr Components CRD is not installed and
|
||||
// therefore no component items exist.
|
||||
if apierrors.IsNotFound(err) {
|
||||
return &v1alpha1.Component{}, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
func writeComponents(writer io.Writer, getConfigFunc func() (*v1alpha1.ComponentList, error), name, outputFormat string) error {
|
||||
confs, err := getConfigFunc()
|
||||
if err != nil {
|
||||
|
|
|
@ -15,7 +15,7 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -139,7 +139,7 @@ func TestComponents(t *testing.T) {
|
|||
name: "Yaml one config",
|
||||
configName: "",
|
||||
outputFormat: "yaml",
|
||||
expectedOutput: "name: appConfig\nnamespace: \"\"\nspec:\n type: state.redis\n version: v1\n ignoreerrors: false\n metadata: []\n inittimeout: \"\"\n",
|
||||
expectedOutput: "- name: appConfig\n namespace: \"\"\n spec:\n type: state.redis\n version: v1\n ignoreerrors: false\n metadata: []\n inittimeout: \"\"\n",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Component{
|
||||
|
@ -189,7 +189,7 @@ func TestComponents(t *testing.T) {
|
|||
name: "Json one config",
|
||||
configName: "",
|
||||
outputFormat: "json",
|
||||
expectedOutput: "{\n \"name\": \"appConfig\",\n \"namespace\": \"\",\n \"spec\": {\n \"type\": \"state.redis\",\n \"version\": \"v1\",\n \"ignoreErrors\": false,\n \"metadata\": null,\n \"initTimeout\": \"\"\n }\n}",
|
||||
expectedOutput: "[\n {\n \"name\": \"appConfig\",\n \"namespace\": \"\",\n \"spec\": {\n \"type\": \"state.redis\",\n \"version\": \"v1\",\n \"ignoreErrors\": false,\n \"metadata\": null,\n \"initTimeout\": \"\"\n }\n }\n]",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Component{
|
||||
|
@ -242,7 +242,7 @@ func TestComponents(t *testing.T) {
|
|||
err := writeComponents(&buff,
|
||||
func() (*v1alpha1.ComponentList, error) {
|
||||
if len(tc.errString) > 0 {
|
||||
return nil, fmt.Errorf(tc.errString)
|
||||
return nil, errors.New(tc.errString)
|
||||
}
|
||||
|
||||
return &v1alpha1.ComponentList{Items: tc.k8sConfig}, nil
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/dapr/cli/utils"
|
||||
v1alpha1 "github.com/dapr/dapr/pkg/apis/configuration/v1alpha1"
|
||||
"github.com/dapr/kit/ptr"
|
||||
)
|
||||
|
||||
func GetDefaultConfiguration() v1alpha1.Configuration {
|
||||
|
@ -28,10 +29,10 @@ func GetDefaultConfiguration() v1alpha1.Configuration {
|
|||
Name: "daprsystem",
|
||||
},
|
||||
Spec: v1alpha1.ConfigurationSpec{
|
||||
MTLSSpec: v1alpha1.MTLSSpec{
|
||||
Enabled: true,
|
||||
WorkloadCertTTL: "24h",
|
||||
AllowedClockSkew: "15m",
|
||||
MTLSSpec: &v1alpha1.MTLSSpec{
|
||||
Enabled: ptr.Of(true),
|
||||
WorkloadCertTTL: ptr.Of("24h"),
|
||||
AllowedClockSkew: ptr.Of("15m"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ func GetDaprControlPlaneCurrentConfig() (*v1alpha1.Configuration, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output, err := utils.RunCmdAndWait("kubectl", "get", "configurations/daprsystem", "-n", namespace, "-o", "json")
|
||||
output, err := utils.RunCmdAndWait("kubectl", "get", "configurations.dapr.io/daprsystem", "-n", namespace, "-o", "json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/dapr/cli/pkg/age"
|
||||
"github.com/dapr/cli/utils"
|
||||
v1alpha1 "github.com/dapr/dapr/pkg/apis/configuration/v1alpha1"
|
||||
"github.com/dapr/dapr/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
type configurationsOutput struct {
|
||||
|
@ -66,6 +67,18 @@ func PrintConfigurations(name, namespace, outputFormat string) error {
|
|||
}, name, outputFormat)
|
||||
}
|
||||
|
||||
func getDaprConfiguration(client versioned.Interface, namespace string, configurationName string) (*v1alpha1.Configuration, error) {
|
||||
c, err := client.ConfigurationV1alpha1().Configurations(namespace).Get(configurationName, meta_v1.GetOptions{})
|
||||
// This means that the Dapr Configurations CRD is not installed and
|
||||
// therefore no configuration items exist.
|
||||
if apierrors.IsNotFound(err) {
|
||||
return &v1alpha1.Configuration{}, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
func writeConfigurations(writer io.Writer, getConfigFunc func() (*v1alpha1.ConfigurationList, error), name, outputFormat string) error {
|
||||
confs, err := getConfigFunc()
|
||||
if err != nil {
|
||||
|
@ -104,11 +117,15 @@ func writeConfigurations(writer io.Writer, getConfigFunc func() (*v1alpha1.Confi
|
|||
func printConfigurationList(writer io.Writer, list []v1alpha1.Configuration) error {
|
||||
co := []configurationsOutput{}
|
||||
for _, c := range list {
|
||||
var metricsEnabled bool
|
||||
if c.Spec.MetricSpec != nil {
|
||||
metricsEnabled = *c.Spec.MetricSpec.Enabled
|
||||
}
|
||||
co = append(co, configurationsOutput{
|
||||
TracingEnabled: tracingEnabled(c.Spec.TracingSpec),
|
||||
Name: c.GetName(),
|
||||
Namespace: c.GetNamespace(),
|
||||
MetricsEnabled: c.Spec.MetricSpec.Enabled,
|
||||
MetricsEnabled: metricsEnabled,
|
||||
Created: c.CreationTimestamp.Format("2006-01-02 15:04.05"),
|
||||
Age: age.GetAge(c.CreationTimestamp.Time),
|
||||
})
|
||||
|
@ -121,7 +138,10 @@ func printConfigurationList(writer io.Writer, list []v1alpha1.Configuration) err
|
|||
return utils.MarshalAndWriteTable(writer, co)
|
||||
}
|
||||
|
||||
func tracingEnabled(spec v1alpha1.TracingSpec) bool {
|
||||
func tracingEnabled(spec *v1alpha1.TracingSpec) bool {
|
||||
if spec == nil {
|
||||
return false
|
||||
}
|
||||
sr, err := strconv.ParseFloat(spec.SamplingRate, 32)
|
||||
if err != nil {
|
||||
return false
|
||||
|
|
|
@ -15,7 +15,7 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -24,6 +24,7 @@ import (
|
|||
v1alpha1 "github.com/dapr/dapr/pkg/apis/configuration/v1alpha1"
|
||||
)
|
||||
|
||||
//nolint:dupword
|
||||
func TestConfigurations(t *testing.T) {
|
||||
now := meta_v1.Now()
|
||||
formattedNow := now.Format("2006-01-02 15:04.05")
|
||||
|
@ -129,7 +130,7 @@ func TestConfigurations(t *testing.T) {
|
|||
name: "Yaml one config",
|
||||
configName: "",
|
||||
outputFormat: "yaml",
|
||||
expectedOutput: "name: appConfig\nnamespace: default\nspec:\n apphttppipelinespec:\n handlers: []\n httppipelinespec:\n handlers: []\n tracingspec:\n samplingrate: \"\"\n stdout: false\n zipkin:\n endpointaddresss: \"\"\n otel:\n protocol: \"\"\n endpointAddress: \"\"\n isSecure: false\n metricspec:\n enabled: false\n mtlsspec:\n enabled: false\n workloadcertttl: \"\"\n allowedclockskew: \"\"\n secrets:\n scopes: []\n accesscontrolspec:\n defaultAction: \"\"\n trustDomain: \"\"\n policies: []\n nameresolutionspec:\n component: \"\"\n version: \"\"\n configuration:\n json:\n raw: []\n features: []\n apispec:\n allowed: []\n componentsspec: {}\n",
|
||||
expectedOutput: "- name: appConfig\n namespace: default\n spec:\n apphttppipelinespec: null\n httppipelinespec: null\n tracingspec: null\n metricspec: null\n metricsspec: null\n mtlsspec: null\n secrets: null\n accesscontrolspec: null\n nameresolutionspec: null\n features: []\n apispec: null\n componentsspec: null\n loggingspec: null\n wasmspec: null\n workflowspec: null\n",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Configuration{
|
||||
|
@ -147,7 +148,7 @@ func TestConfigurations(t *testing.T) {
|
|||
name: "Yaml two configs",
|
||||
configName: "",
|
||||
outputFormat: "yaml",
|
||||
expectedOutput: "- name: appConfig1\n namespace: default\n spec:\n apphttppipelinespec:\n handlers: []\n httppipelinespec:\n handlers: []\n tracingspec:\n samplingrate: \"\"\n stdout: false\n zipkin:\n endpointaddresss: \"\"\n otel:\n protocol: \"\"\n endpointAddress: \"\"\n isSecure: false\n metricspec:\n enabled: false\n mtlsspec:\n enabled: false\n workloadcertttl: \"\"\n allowedclockskew: \"\"\n secrets:\n scopes: []\n accesscontrolspec:\n defaultAction: \"\"\n trustDomain: \"\"\n policies: []\n nameresolutionspec:\n component: \"\"\n version: \"\"\n configuration:\n json:\n raw: []\n features: []\n apispec:\n allowed: []\n componentsspec: {}\n- name: appConfig2\n namespace: default\n spec:\n apphttppipelinespec:\n handlers: []\n httppipelinespec:\n handlers: []\n tracingspec:\n samplingrate: \"\"\n stdout: false\n zipkin:\n endpointaddresss: \"\"\n otel:\n protocol: \"\"\n endpointAddress: \"\"\n isSecure: false\n metricspec:\n enabled: false\n mtlsspec:\n enabled: false\n workloadcertttl: \"\"\n allowedclockskew: \"\"\n secrets:\n scopes: []\n accesscontrolspec:\n defaultAction: \"\"\n trustDomain: \"\"\n policies: []\n nameresolutionspec:\n component: \"\"\n version: \"\"\n configuration:\n json:\n raw: []\n features: []\n apispec:\n allowed: []\n componentsspec: {}\n",
|
||||
expectedOutput: "- name: appConfig1\n namespace: default\n spec:\n apphttppipelinespec: null\n httppipelinespec: null\n tracingspec: null\n metricspec: null\n metricsspec: null\n mtlsspec: null\n secrets: null\n accesscontrolspec: null\n nameresolutionspec: null\n features: []\n apispec: null\n componentsspec: null\n loggingspec: null\n wasmspec: null\n workflowspec: null\n- name: appConfig2\n namespace: default\n spec:\n apphttppipelinespec: null\n httppipelinespec: null\n tracingspec: null\n metricspec: null\n metricsspec: null\n mtlsspec: null\n secrets: null\n accesscontrolspec: null\n nameresolutionspec: null\n features: []\n apispec: null\n componentsspec: null\n loggingspec: null\n wasmspec: null\n workflowspec: null\n",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Configuration{
|
||||
|
@ -173,7 +174,7 @@ func TestConfigurations(t *testing.T) {
|
|||
name: "Json one config",
|
||||
configName: "",
|
||||
outputFormat: "json",
|
||||
expectedOutput: "{\n \"name\": \"appConfig\",\n \"namespace\": \"default\",\n \"spec\": {\n \"appHttpPipeline\": {\n \"handlers\": null\n },\n \"httpPipeline\": {\n \"handlers\": null\n },\n \"tracing\": {\n \"samplingRate\": \"\",\n \"stdout\": false,\n \"zipkin\": {\n \"endpointAddress\": \"\"\n },\n \"otel\": {\n \"protocol\": \"\",\n \"endpointAddress\": \"\",\n \"isSecure\": false\n }\n },\n \"metric\": {\n \"enabled\": false\n },\n \"mtls\": {\n \"enabled\": false,\n \"workloadCertTTL\": \"\",\n \"allowedClockSkew\": \"\"\n },\n \"secrets\": {\n \"scopes\": null\n },\n \"accessControl\": {\n \"defaultAction\": \"\",\n \"trustDomain\": \"\",\n \"policies\": null\n },\n \"nameResolution\": {\n \"component\": \"\",\n \"version\": \"\",\n \"configuration\": null\n },\n \"api\": {},\n \"components\": {}\n }\n}",
|
||||
expectedOutput: "[\n {\n \"name\": \"appConfig\",\n \"namespace\": \"default\",\n \"spec\": {}\n }\n]",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Configuration{
|
||||
|
@ -191,7 +192,7 @@ func TestConfigurations(t *testing.T) {
|
|||
name: "Json two configs",
|
||||
configName: "",
|
||||
outputFormat: "json",
|
||||
expectedOutput: "[\n {\n \"name\": \"appConfig1\",\n \"namespace\": \"default\",\n \"spec\": {\n \"appHttpPipeline\": {\n \"handlers\": null\n },\n \"httpPipeline\": {\n \"handlers\": null\n },\n \"tracing\": {\n \"samplingRate\": \"\",\n \"stdout\": false,\n \"zipkin\": {\n \"endpointAddress\": \"\"\n },\n \"otel\": {\n \"protocol\": \"\",\n \"endpointAddress\": \"\",\n \"isSecure\": false\n }\n },\n \"metric\": {\n \"enabled\": false\n },\n \"mtls\": {\n \"enabled\": false,\n \"workloadCertTTL\": \"\",\n \"allowedClockSkew\": \"\"\n },\n \"secrets\": {\n \"scopes\": null\n },\n \"accessControl\": {\n \"defaultAction\": \"\",\n \"trustDomain\": \"\",\n \"policies\": null\n },\n \"nameResolution\": {\n \"component\": \"\",\n \"version\": \"\",\n \"configuration\": null\n },\n \"api\": {},\n \"components\": {}\n }\n },\n {\n \"name\": \"appConfig2\",\n \"namespace\": \"default\",\n \"spec\": {\n \"appHttpPipeline\": {\n \"handlers\": null\n },\n \"httpPipeline\": {\n \"handlers\": null\n },\n \"tracing\": {\n \"samplingRate\": \"\",\n \"stdout\": false,\n \"zipkin\": {\n \"endpointAddress\": \"\"\n },\n \"otel\": {\n \"protocol\": \"\",\n \"endpointAddress\": \"\",\n \"isSecure\": false\n }\n },\n \"metric\": {\n \"enabled\": false\n },\n \"mtls\": {\n \"enabled\": false,\n \"workloadCertTTL\": \"\",\n \"allowedClockSkew\": \"\"\n },\n \"secrets\": {\n \"scopes\": null\n },\n \"accessControl\": {\n \"defaultAction\": \"\",\n \"trustDomain\": \"\",\n \"policies\": null\n },\n \"nameResolution\": {\n \"component\": \"\",\n \"version\": \"\",\n \"configuration\": null\n },\n \"api\": {},\n \"components\": {}\n }\n }\n]",
|
||||
expectedOutput: "[\n {\n \"name\": \"appConfig1\",\n \"namespace\": \"default\",\n \"spec\": {}\n },\n {\n \"name\": \"appConfig2\",\n \"namespace\": \"default\",\n \"spec\": {}\n }\n]",
|
||||
errString: "",
|
||||
errorExpected: false,
|
||||
k8sConfig: []v1alpha1.Configuration{
|
||||
|
@ -220,7 +221,7 @@ func TestConfigurations(t *testing.T) {
|
|||
err := writeConfigurations(&buff,
|
||||
func() (*v1alpha1.ConfigurationList, error) {
|
||||
if len(tc.errString) > 0 {
|
||||
return nil, fmt.Errorf(tc.errString)
|
||||
return nil, errors.New(tc.errString)
|
||||
}
|
||||
|
||||
return &v1alpha1.ConfigurationList{Items: tc.k8sConfig}, nil
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2021 The Dapr Authors
|
||||
Copyright 2023 The Dapr 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
|
||||
|
@ -14,14 +11,23 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
import "github.com/Masterminds/semver/v3"
|
||||
|
||||
func setupShutdownNotify(sigCh chan os.Signal) {
|
||||
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
|
||||
const daprHelmChartWithDashboard = "<= 1.10.x"
|
||||
|
||||
// IsDashboardIncluded returns true if dashboard is included in Helm chart version for Dapr.
|
||||
func IsDashboardIncluded(runtimeVersion string) (bool, error) {
|
||||
c, err := semver.NewConstraint(daprHelmChartWithDashboard)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion(runtimeVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return c.Check(v), nil
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDashboardChart(t *testing.T) {
|
||||
testCases := []struct {
|
||||
runtimeVersion string
|
||||
expectDashboard bool
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
runtimeVersion: "1.9.6",
|
||||
expectDashboard: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.10.7",
|
||||
expectDashboard: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.10.99",
|
||||
expectDashboard: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.11.0",
|
||||
expectDashboard: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.11.0",
|
||||
expectDashboard: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.12.7",
|
||||
expectDashboard: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "1.13.0",
|
||||
expectDashboard: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
runtimeVersion: "Bad Version",
|
||||
expectDashboard: false,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run("Validating version "+tc.runtimeVersion, func(t *testing.T) {
|
||||
hasDashboard, err := IsDashboardIncluded(tc.runtimeVersion)
|
||||
if tc.expectError {
|
||||
assert.Error(t, err, "expected an error")
|
||||
} else {
|
||||
assert.NoError(t, err, "expected an error")
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expectDashboard, hasDashboard, "dashboard expectation")
|
||||
})
|
||||
}
|
||||
}
|
|
@ -33,37 +33,117 @@ import (
|
|||
"github.com/dapr/cli/pkg/print"
|
||||
cli_ver "github.com/dapr/cli/pkg/version"
|
||||
"github.com/dapr/cli/utils"
|
||||
"github.com/dapr/dapr/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
const (
|
||||
daprReleaseName = "dapr"
|
||||
daprHelmRepo = "https://dapr.github.io/helm-charts"
|
||||
latestVersion = "latest"
|
||||
daprReleaseName = "dapr"
|
||||
dashboardReleaseName = "dapr-dashboard"
|
||||
latestVersion = "latest"
|
||||
bitnamiStableVersion = "17.14.5"
|
||||
|
||||
// dev mode constants.
|
||||
thirdPartyDevNamespace = "default"
|
||||
zipkinChartName = "zipkin"
|
||||
redisChartName = "redis"
|
||||
zipkinReleaseName = "dapr-dev-zipkin"
|
||||
redisReleaseName = "dapr-dev-redis"
|
||||
redisVersion = "6.2.11"
|
||||
bitnamiHelmRepo = "https://charts.bitnami.com/bitnami"
|
||||
daprHelmRepo = "https://dapr.github.io/helm-charts"
|
||||
zipkinHelmRepo = "https://openzipkin.github.io/zipkin"
|
||||
stateStoreComponentName = "statestore"
|
||||
pubsubComponentName = "pubsub"
|
||||
zipkingConfigurationName = "appconfig"
|
||||
)
|
||||
|
||||
type InitConfiguration struct {
|
||||
Version string
|
||||
Namespace string
|
||||
EnableMTLS bool
|
||||
EnableHA bool
|
||||
Args []string
|
||||
Wait bool
|
||||
Timeout uint
|
||||
ImageRegistryURI string
|
||||
ImageVariant string
|
||||
Version string
|
||||
DashboardVersion string
|
||||
Namespace string
|
||||
EnableMTLS bool
|
||||
EnableHA bool
|
||||
EnableDev bool
|
||||
Args []string
|
||||
Wait bool
|
||||
Timeout uint
|
||||
ImageRegistryURI string
|
||||
ImageVariant string
|
||||
RootCertificateFilePath string
|
||||
IssuerCertificateFilePath string
|
||||
IssuerPrivateKeyFilePath string
|
||||
}
|
||||
|
||||
// Init deploys the Dapr operator using the supplied runtime version.
|
||||
func Init(config InitConfiguration) error {
|
||||
msg := "Deploying the Dapr control plane to your cluster..."
|
||||
|
||||
stopSpinning := print.Spinner(os.Stdout, msg)
|
||||
defer stopSpinning(print.Failure)
|
||||
if err := install(config); err != nil {
|
||||
helmRepoDapr := utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo)
|
||||
err := installWithConsole(daprReleaseName, config.Version, helmRepoDapr, "Dapr control plane", config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stopSpinning(print.Success)
|
||||
for _, dashboardClusterRole := range []string{"dashboard-reader", "dapr-dashboard"} {
|
||||
// Detect Dapr Dashboard using a cluster-level resource (not dependent on namespace).
|
||||
_, err = utils.RunCmdAndWait("kubectl", "describe", "clusterrole", dashboardClusterRole)
|
||||
if err == nil {
|
||||
// No need to install Dashboard since it is already present.
|
||||
// Charts for versions < 1.11 contain Dashboard already.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
err = installWithConsole(dashboardReleaseName, config.DashboardVersion, helmRepoDapr, "Dapr dashboard", config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.EnableDev {
|
||||
redisChartVals := []string{
|
||||
"image.tag=" + redisVersion,
|
||||
"replica.replicaCount=0",
|
||||
}
|
||||
|
||||
err = installThirdPartyWithConsole(redisReleaseName, redisChartName, bitnamiStableVersion, bitnamiHelmRepo, "Dapr Redis", redisChartVals, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = installThirdPartyWithConsole(zipkinReleaseName, zipkinChartName, latestVersion, zipkinHelmRepo, "Dapr Zipkin", []string{}, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = initDevConfigs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func installThirdPartyWithConsole(releaseName, chartName, releaseVersion, helmRepo string, prettyName string, chartValues []string, config InitConfiguration) error {
|
||||
installSpinning := print.Spinner(os.Stdout, "Deploying the "+prettyName+" with "+releaseVersion+" version to your cluster...")
|
||||
defer installSpinning(print.Failure)
|
||||
|
||||
// releaseVersion of chart will always be latest version.
|
||||
err := installThirdParty(releaseName, chartName, releaseVersion, helmRepo, chartValues, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
installSpinning(print.Success)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installWithConsole(releaseName, releaseVersion, helmRepo string, prettyName string, config InitConfiguration) error {
|
||||
installSpinning := print.Spinner(os.Stdout, "Deploying the "+prettyName+" with "+releaseVersion+" version to your cluster...")
|
||||
defer installSpinning(print.Failure)
|
||||
|
||||
err := install(releaseName, releaseVersion, helmRepo, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
installSpinning(print.Success)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -93,16 +173,23 @@ func helmConfig(namespace string) (*helm.Configuration, error) {
|
|||
return &ac, err
|
||||
}
|
||||
|
||||
func getVersion(version string) (string, error) {
|
||||
func getVersion(releaseName string, version string) (string, error) {
|
||||
actualVersion := version
|
||||
if version == latestVersion {
|
||||
var err error
|
||||
version, err = cli_ver.GetDaprVersion()
|
||||
if releaseName == daprReleaseName {
|
||||
actualVersion, err = cli_ver.GetDaprVersion()
|
||||
} else if releaseName == dashboardReleaseName {
|
||||
actualVersion, err = cli_ver.GetDashboardVersion()
|
||||
} else {
|
||||
return "", fmt.Errorf("cannot get latest version for unknown chart: %s", releaseName)
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot get the latest release version: %w", err)
|
||||
}
|
||||
version = strings.TrimPrefix(version, "v")
|
||||
actualVersion = strings.TrimPrefix(actualVersion, "v")
|
||||
}
|
||||
return version, nil
|
||||
return actualVersion, nil
|
||||
}
|
||||
|
||||
func createTempDir() (string, error) {
|
||||
|
@ -121,15 +208,15 @@ func locateChartFile(dirPath string) (string, error) {
|
|||
return filepath.Join(dirPath, files[0].Name()), nil
|
||||
}
|
||||
|
||||
func daprChart(version string, config *helm.Configuration) (*chart.Chart, error) {
|
||||
func getHelmChart(version, releaseName, helmRepo string, config *helm.Configuration) (*chart.Chart, error) {
|
||||
pull := helm.NewPullWithOpts(helm.WithConfig(config))
|
||||
pull.RepoURL = utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo)
|
||||
pull.RepoURL = helmRepo
|
||||
pull.Username = utils.GetEnv("DAPR_HELM_REPO_USERNAME", "")
|
||||
pull.Password = utils.GetEnv("DAPR_HELM_REPO_PASSWORD", "")
|
||||
|
||||
pull.Settings = &cli.EnvSettings{}
|
||||
|
||||
if version != latestVersion {
|
||||
if version != latestVersion && (releaseName == daprReleaseName || releaseName == dashboardReleaseName || releaseName == redisChartName) {
|
||||
pull.Version = chartVersion(version)
|
||||
}
|
||||
|
||||
|
@ -141,7 +228,7 @@ func daprChart(version string, config *helm.Configuration) (*chart.Chart, error)
|
|||
|
||||
pull.DestDir = dir
|
||||
|
||||
_, err = pull.Run(daprReleaseName)
|
||||
_, err = pull.Run(releaseName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -153,23 +240,38 @@ func daprChart(version string, config *helm.Configuration) (*chart.Chart, error)
|
|||
return loader.Load(chartPath)
|
||||
}
|
||||
|
||||
func chartValues(config InitConfiguration) (map[string]interface{}, error) {
|
||||
func daprChartValues(config InitConfiguration, version string) (map[string]interface{}, error) {
|
||||
chartVals := map[string]interface{}{}
|
||||
err := utils.ValidateImageVariant(config.ImageVariant)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
globalVals := []string{
|
||||
helmVals := []string{
|
||||
fmt.Sprintf("global.ha.enabled=%t", config.EnableHA),
|
||||
fmt.Sprintf("global.mtls.enabled=%t", config.EnableMTLS),
|
||||
fmt.Sprintf("global.tag=%s", utils.GetVariantVersion(config.Version, config.ImageVariant)),
|
||||
"global.tag=" + utils.GetVariantVersion(version, config.ImageVariant),
|
||||
}
|
||||
if len(config.ImageRegistryURI) != 0 {
|
||||
globalVals = append(globalVals, fmt.Sprintf("global.registry=%s", config.ImageRegistryURI))
|
||||
helmVals = append(helmVals, "global.registry="+config.ImageRegistryURI)
|
||||
}
|
||||
globalVals = append(globalVals, config.Args...)
|
||||
helmVals = append(helmVals, config.Args...)
|
||||
|
||||
for _, v := range globalVals {
|
||||
if config.RootCertificateFilePath != "" && config.IssuerCertificateFilePath != "" && config.IssuerPrivateKeyFilePath != "" {
|
||||
rootCertBytes, issuerCertBytes, issuerKeyBytes, err := parseCertificateFiles(
|
||||
config.RootCertificateFilePath,
|
||||
config.IssuerCertificateFilePath,
|
||||
config.IssuerPrivateKeyFilePath,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
helmVals = append(helmVals, "dapr_sentry.tls.root.certPEM="+string(rootCertBytes),
|
||||
"dapr_sentry.tls.issuer.certPEM="+string(issuerCertBytes),
|
||||
"dapr_sentry.tls.issuer.keyPEM="+string(issuerKeyBytes),
|
||||
)
|
||||
}
|
||||
|
||||
for _, v := range helmVals {
|
||||
if err := strvals.ParseInto(v, chartVals); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -177,7 +279,7 @@ func chartValues(config InitConfiguration) (map[string]interface{}, error) {
|
|||
return chartVals, nil
|
||||
}
|
||||
|
||||
func install(config InitConfiguration) error {
|
||||
func install(releaseName, releaseVersion, helmRepo string, config InitConfiguration) error {
|
||||
err := createNamespace(config.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -188,28 +290,30 @@ func install(config InitConfiguration) error {
|
|||
return err
|
||||
}
|
||||
|
||||
daprChart, err := daprChart(config.Version, helmConf)
|
||||
daprChart, err := getHelmChart(releaseVersion, releaseName, helmRepo, helmConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
version, err := getVersion(config.Version)
|
||||
version, err := getVersion(releaseName, releaseVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = applyCRDs(fmt.Sprintf("v%s", version))
|
||||
if err != nil {
|
||||
return err
|
||||
if releaseName == daprReleaseName {
|
||||
err = applyCRDs("v" + version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
installClient := helm.NewInstall(helmConf)
|
||||
installClient.ReleaseName = daprReleaseName
|
||||
installClient.ReleaseName = releaseName
|
||||
installClient.Namespace = config.Namespace
|
||||
installClient.Wait = config.Wait
|
||||
installClient.Timeout = time.Duration(config.Timeout) * time.Second
|
||||
installClient.Timeout = time.Duration(config.Timeout) * time.Second //nolint:gosec
|
||||
|
||||
values, err := chartValues(config)
|
||||
values, err := daprChartValues(config, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -217,15 +321,48 @@ func install(config InitConfiguration) error {
|
|||
if _, err = installClient.Run(daprChart, values); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installThirdParty(releaseName, chartName, releaseVersion, helmRepo string, chartVals []string, config InitConfiguration) error {
|
||||
helmConf, err := helmConfig(thirdPartyDevNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
helmChart, err := getHelmChart(releaseVersion, chartName, helmRepo, helmConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
installClient := helm.NewInstall(helmConf)
|
||||
installClient.ReleaseName = releaseName
|
||||
installClient.Namespace = thirdPartyDevNamespace
|
||||
installClient.Wait = config.Wait
|
||||
installClient.Timeout = time.Duration(config.Timeout) * time.Second //nolint:gosec
|
||||
|
||||
values := map[string]interface{}{}
|
||||
|
||||
for _, val := range chartVals {
|
||||
if err = strvals.ParseInto(val, values); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = installClient.Run(helmChart, values); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func debugLogf(format string, v ...interface{}) {
|
||||
}
|
||||
|
||||
func confirmExist(cfg *helm.Configuration) (bool, error) {
|
||||
func confirmExist(cfg *helm.Configuration, releaseName string) (bool, error) {
|
||||
client := helm.NewGet(cfg)
|
||||
release, err := client.Run(daprReleaseName)
|
||||
release, err := client.Run(releaseName)
|
||||
|
||||
if release == nil {
|
||||
return false, nil
|
||||
|
@ -237,3 +374,164 @@ func confirmExist(cfg *helm.Configuration) (bool, error) {
|
|||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func checkAndOverWriteFile(filePath string, b []byte) error {
|
||||
_, err := os.Stat(filePath)
|
||||
if os.IsNotExist(err) {
|
||||
// #nosec G306
|
||||
if err = os.WriteFile(filePath, b, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isComponentPresent(client versioned.Interface, namespace string, componentName string) (bool, error) {
|
||||
c, err := getComponent(client, namespace, componentName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return c.Name == componentName, err
|
||||
}
|
||||
|
||||
func isConfigurationPresent(client versioned.Interface, namespace string, configurationName string) (bool, error) {
|
||||
c, err := getDaprConfiguration(client, namespace, configurationName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return c.Name == configurationName, nil
|
||||
}
|
||||
|
||||
func initDevConfigs() error {
|
||||
redisStatestore := `
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: statestore
|
||||
spec:
|
||||
type: state.redis
|
||||
version: v1
|
||||
metadata:
|
||||
# These settings will work out of the box if you use helm install
|
||||
# bitnami/redis. If you have your own setup, replace
|
||||
# redis-master:6379 with your own Redis master address, and the
|
||||
# Redis password with your own Secret's name. For more information,
|
||||
# see https://docs.dapr.io/operations/components/component-secrets .
|
||||
- name: redisHost
|
||||
value: dapr-dev-redis-master:6379
|
||||
- name: redisPassword
|
||||
secretKeyRef:
|
||||
name: dapr-dev-redis
|
||||
key: redis-password
|
||||
auth:
|
||||
secretStore: kubernetes
|
||||
`
|
||||
|
||||
redisPubsub := `
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: pubsub
|
||||
spec:
|
||||
type: pubsub.redis
|
||||
version: v1
|
||||
metadata:
|
||||
# These settings will work out of the box if you use helm install
|
||||
# bitnami/redis. If you have your own setup, replace
|
||||
# redis-master:6379 with your own Redis master address, and the
|
||||
# Redis password with your own Secret's name. For more information,
|
||||
# see https://docs.dapr.io/operations/components/component-secrets .
|
||||
- name: redisHost
|
||||
value: dapr-dev-redis-master:6379
|
||||
- name: redisPassword
|
||||
secretKeyRef:
|
||||
name: dapr-dev-redis
|
||||
key: redis-password
|
||||
auth:
|
||||
secretStore: kubernetes
|
||||
`
|
||||
|
||||
// This config needs to be named as appconfig, as it is used in later steps in `dapr run -f . -k`. See `pkg/kubernetes/run.go`.
|
||||
zipkinConfig := `
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: appconfig
|
||||
spec:
|
||||
tracing:
|
||||
samplingRate: "1"
|
||||
zipkin:
|
||||
endpointAddress: "http://dapr-dev-zipkin.default.svc.cluster.local:9411/api/v2/spans"
|
||||
`
|
||||
tempDirPath, err := createTempDir()
|
||||
defer os.RemoveAll(tempDirPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := DaprClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
present, err := isComponentPresent(client, thirdPartyDevNamespace, stateStoreComponentName)
|
||||
if present || err != nil {
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stderr, "Error listing components, skipping default dev component creation.")
|
||||
} else {
|
||||
print.WarningStatusEvent(os.Stderr, "Component with name %q already present in namespace %q. Skipping component creation.", stateStoreComponentName, thirdPartyDevNamespace)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
redisPath := filepath.Join(tempDirPath, "redis-statestore.yaml")
|
||||
err = checkAndOverWriteFile(redisPath, []byte(redisStatestore))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, "Applying %q component to Kubernetes %q namespace.", stateStoreComponentName, thirdPartyDevNamespace)
|
||||
_, err = utils.RunCmdAndWait("kubectl", "apply", "-f", redisPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
present, err = isComponentPresent(client, thirdPartyDevNamespace, pubsubComponentName)
|
||||
if present || err != nil {
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stderr, "Error listing components, skipping default dev component creation.")
|
||||
} else {
|
||||
print.WarningStatusEvent(os.Stderr, "Component with name %q already present in namespace %q. Skipping component creation.", pubsubComponentName, thirdPartyDevNamespace)
|
||||
}
|
||||
return err
|
||||
}
|
||||
redisPath = filepath.Join(tempDirPath, "redis-pubsub.yaml")
|
||||
err = checkAndOverWriteFile(redisPath, []byte(redisPubsub))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, "Applying %q component to Kubernetes %q namespace.", pubsubComponentName, thirdPartyDevNamespace)
|
||||
_, err = utils.RunCmdAndWait("kubectl", "apply", "-f", redisPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
present, err = isConfigurationPresent(client, thirdPartyDevNamespace, zipkingConfigurationName)
|
||||
if present || err != nil {
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stderr, "Error listing configurations, skipping default dev configuration creation.")
|
||||
} else {
|
||||
print.WarningStatusEvent(os.Stderr, "Configuration with name %q already present in namespace %q. Skipping configuration creation.", zipkingConfigurationName, thirdPartyDevNamespace)
|
||||
}
|
||||
return err
|
||||
}
|
||||
zipkinPath := filepath.Join(tempDirPath, "zipkin-config.yaml")
|
||||
err = checkAndOverWriteFile(zipkinPath, []byte(zipkinConfig))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, "Applying %q zipkin configuration to Kubernetes %q namespace.", zipkingConfigurationName, thirdPartyDevNamespace)
|
||||
_, err = utils.RunCmdAndWait("kubectl", "apply", "-f", zipkinPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -14,17 +14,32 @@ limitations under the License.
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
)
|
||||
|
||||
const (
|
||||
daprdContainerName = "daprd"
|
||||
appIDContainerArgName = "--app-id"
|
||||
|
||||
// number of retries when trying to list pods for getting logs.
|
||||
maxListingRetry = 10
|
||||
// delay between retries of pod listing.
|
||||
listingDelay = 200 * time.Microsecond
|
||||
// delay before retrying for getting logs.
|
||||
streamingDelay = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
// Logs fetches Dapr sidecar logs from Kubernetes.
|
||||
|
@ -84,3 +99,98 @@ func Logs(appID, podName, namespace string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// streamContainerLogsToDisk streams all containers logs for the given selector to a given disk directory.
|
||||
func streamContainerLogsToDisk(ctx context.Context, appID string, appLogWriter, daprdLogWriter io.Writer, podClient v1.PodInterface) error {
|
||||
var err error
|
||||
var podList *corev1.PodList
|
||||
counter := 0
|
||||
for {
|
||||
podList, err = getPods(ctx, appID, podClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing the pod with label %s=%s: %w", daprAppIDKey, appID, err)
|
||||
}
|
||||
if len(podList.Items) != 0 {
|
||||
break
|
||||
}
|
||||
counter++
|
||||
if counter == maxListingRetry {
|
||||
return fmt.Errorf("error getting logs: error listing the pod with label %s=%s after %d retires", daprAppIDKey, appID, maxListingRetry)
|
||||
}
|
||||
// Retry after a delay.
|
||||
time.Sleep(listingDelay)
|
||||
}
|
||||
|
||||
for _, pod := range podList.Items {
|
||||
print.InfoStatusEvent(os.Stdout, "Streaming logs for containers in pod %q", pod.GetName())
|
||||
for _, container := range pod.Spec.Containers {
|
||||
fileWriter := daprdLogWriter
|
||||
if container.Name != daprdContainerName {
|
||||
fileWriter = appLogWriter
|
||||
}
|
||||
|
||||
// create a go routine for each container to stream logs into file/console.
|
||||
go func(pod, containerName, appID string, fileWriter io.Writer) {
|
||||
loop:
|
||||
for {
|
||||
req := podClient.GetLogs(pod, &corev1.PodLogOptions{
|
||||
Container: containerName,
|
||||
Follow: true,
|
||||
})
|
||||
stream, err := req.Stream(ctx)
|
||||
if err != nil {
|
||||
switch {
|
||||
case strings.Contains(err.Error(), "Pending"):
|
||||
// Retry after a delay.
|
||||
time.Sleep(streamingDelay)
|
||||
continue loop
|
||||
case strings.Contains(err.Error(), "ContainerCreating"):
|
||||
// Retry after a delay.
|
||||
time.Sleep(streamingDelay)
|
||||
continue loop
|
||||
case errors.Is(err, context.Canceled):
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
if containerName != daprdContainerName {
|
||||
streamScanner := bufio.NewScanner(stream)
|
||||
for streamScanner.Scan() {
|
||||
fmt.Fprintln(fileWriter, print.Blue(fmt.Sprintf("== APP - %s == %s", appID, streamScanner.Text())))
|
||||
}
|
||||
} else {
|
||||
_, err = io.Copy(fileWriter, stream)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, context.Canceled):
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}(pod.GetName(), container.Name, appID, fileWriter)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPods(ctx context.Context, appID string, podClient v1.PodInterface) (*corev1.PodList, error) {
|
||||
listCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
labelSelector := fmt.Sprintf("%s=%s", daprAppIDKey, appID)
|
||||
podList, err := podClient.List(listCtx, metav1.ListOptions{
|
||||
LabelSelector: labelSelector,
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return podList, nil
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func IsMTLSEnabled() (bool, error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return c.Spec.MTLSSpec.Enabled, nil
|
||||
return *c.Spec.MTLSSpec.Enabled, nil
|
||||
}
|
||||
|
||||
func getSystemConfig() (*v1alpha1.Configuration, error) {
|
||||
|
|
|
@ -15,24 +15,31 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
k8s "k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
func ListPodsInterface(client k8s.Interface, labelSelector map[string]string) (*core_v1.PodList, error) {
|
||||
opts := v1.ListOptions{}
|
||||
const podWatchErrTemplate = "error creating pod watcher"
|
||||
|
||||
var errPodUnknown error = errors.New("pod in unknown/failed state")
|
||||
|
||||
func ListPodsInterface(client k8s.Interface, labelSelector map[string]string) (*corev1.PodList, error) {
|
||||
opts := metav1.ListOptions{}
|
||||
if labelSelector != nil {
|
||||
opts.LabelSelector = labels.FormatLabels(labelSelector)
|
||||
}
|
||||
return client.CoreV1().Pods(v1.NamespaceAll).List(context.TODO(), opts)
|
||||
return client.CoreV1().Pods(metav1.NamespaceAll).List(context.TODO(), opts)
|
||||
}
|
||||
|
||||
func ListPods(client *k8s.Clientset, namespace string, labelSelector map[string]string) (*core_v1.PodList, error) {
|
||||
opts := v1.ListOptions{}
|
||||
func ListPods(client *k8s.Clientset, namespace string, labelSelector map[string]string) (*corev1.PodList, error) {
|
||||
opts := metav1.ListOptions{}
|
||||
if labelSelector != nil {
|
||||
opts.LabelSelector = labels.FormatLabels(labelSelector)
|
||||
}
|
||||
|
@ -41,8 +48,8 @@ func ListPods(client *k8s.Clientset, namespace string, labelSelector map[string]
|
|||
|
||||
// CheckPodExists returns a boolean representing the pod's existence and the namespace that the given pod resides in,
|
||||
// or empty if not present in the given namespace.
|
||||
func CheckPodExists(client *k8s.Clientset, namespace string, labelSelector map[string]string, deployName string) (bool, string) {
|
||||
opts := v1.ListOptions{}
|
||||
func CheckPodExists(client k8s.Interface, namespace string, labelSelector map[string]string, deployName string) (bool, string) {
|
||||
opts := metav1.ListOptions{}
|
||||
if labelSelector != nil {
|
||||
opts.LabelSelector = labels.FormatLabels(labelSelector)
|
||||
}
|
||||
|
@ -53,7 +60,7 @@ func CheckPodExists(client *k8s.Clientset, namespace string, labelSelector map[s
|
|||
}
|
||||
|
||||
for _, pod := range podList.Items {
|
||||
if pod.Status.Phase == core_v1.PodRunning {
|
||||
if pod.Status.Phase == corev1.PodRunning {
|
||||
if strings.HasPrefix(pod.Name, deployName) {
|
||||
return true, pod.Namespace
|
||||
}
|
||||
|
@ -61,3 +68,61 @@ func CheckPodExists(client *k8s.Clientset, namespace string, labelSelector map[s
|
|||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func createPodWatcher(ctx context.Context, client k8s.Interface, namespace, appID string) (watch.Interface, error) {
|
||||
labelSelector := fmt.Sprintf("%s=%s", daprAppIDKey, appID)
|
||||
|
||||
opts := metav1.ListOptions{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
LabelSelector: labelSelector,
|
||||
}
|
||||
|
||||
return client.CoreV1().Pods(namespace).Watch(ctx, opts)
|
||||
}
|
||||
|
||||
func waitPodDeleted(ctx context.Context, client k8s.Interface, namespace, appID string) error {
|
||||
watcher, err := createPodWatcher(ctx, client, namespace, appID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s : %w", podWatchErrTemplate, err)
|
||||
}
|
||||
|
||||
defer watcher.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.ResultChan():
|
||||
|
||||
if event.Type == watch.Deleted {
|
||||
return nil
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("error context cancelled while waiting for pod deletion: %w", context.Canceled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitPodRunning(ctx context.Context, client k8s.Interface, namespace, appID string) error {
|
||||
watcher, err := createPodWatcher(ctx, client, namespace, appID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s : %w", podWatchErrTemplate, err)
|
||||
}
|
||||
|
||||
defer watcher.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.ResultChan():
|
||||
pod := event.Object.(*corev1.Pod)
|
||||
|
||||
if pod.Status.Phase == corev1.PodRunning {
|
||||
return nil
|
||||
} else if pod.Status.Phase == corev1.PodFailed || pod.Status.Phase == corev1.PodUnknown {
|
||||
return fmt.Errorf("error waiting for pod run: %w", errPodUnknown)
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("error context cancelled while waiting for pod run: %w", context.Canceled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ func TestListPodsInterface(t *testing.T) {
|
|||
output, err := ListPodsInterface(k8s, map[string]string{
|
||||
"test": "test",
|
||||
})
|
||||
assert.Nil(t, err, "unexpected error")
|
||||
assert.NoError(t, err, "unexpected error")
|
||||
assert.NotNil(t, output, "Expected empty list")
|
||||
assert.Equal(t, 0, len(output.Items), "Expected length 0")
|
||||
assert.Empty(t, output.Items, "Expected length 0")
|
||||
})
|
||||
t.Run("one matching pod", func(t *testing.T) {
|
||||
k8s := fake.NewSimpleClientset((&v1.Pod{
|
||||
|
@ -46,9 +46,9 @@ func TestListPodsInterface(t *testing.T) {
|
|||
output, err := ListPodsInterface(k8s, map[string]string{
|
||||
"test": "test",
|
||||
})
|
||||
assert.Nil(t, err, "unexpected error")
|
||||
assert.NoError(t, err, "unexpected error")
|
||||
assert.NotNil(t, output, "Expected non empty list")
|
||||
assert.Equal(t, 1, len(output.Items), "Expected length 0")
|
||||
assert.Len(t, output.Items, 1, "Expected length 0")
|
||||
assert.Equal(t, "test", output.Items[0].Name, "expected name to match")
|
||||
assert.Equal(t, "test", output.Items[0].Namespace, "expected namespace to match")
|
||||
})
|
||||
|
|
|
@ -14,6 +14,7 @@ limitations under the License.
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -133,7 +134,7 @@ func (pf *PortForward) Init() error {
|
|||
return fmt.Errorf("can not get the local and remote ports: %w", err)
|
||||
}
|
||||
if len(ports) == 0 {
|
||||
return fmt.Errorf("can not get the local and remote ports: error getting ports length")
|
||||
return errors.New("can not get the local and remote ports: error getting ports length")
|
||||
}
|
||||
|
||||
pf.LocalPort = int(ports[0].Local)
|
||||
|
|
|
@ -15,6 +15,8 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
|
@ -26,8 +28,8 @@ import (
|
|||
"k8s.io/helm/pkg/strvals"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/dapr/pkg/sentry/ca"
|
||||
"github.com/dapr/dapr/pkg/sentry/certs"
|
||||
"github.com/dapr/cli/utils"
|
||||
"github.com/dapr/dapr/pkg/sentry/server/ca"
|
||||
)
|
||||
|
||||
type RenewCertificateParams struct {
|
||||
|
@ -37,6 +39,7 @@ type RenewCertificateParams struct {
|
|||
RootPrivateKeyFilePath string
|
||||
ValidUntil time.Duration
|
||||
Timeout uint
|
||||
ImageVariant string
|
||||
}
|
||||
|
||||
func RenewCertificate(conf RenewCertificateParams) error {
|
||||
|
@ -49,7 +52,6 @@ func RenewCertificate(conf RenewCertificateParams) error {
|
|||
conf.RootCertificateFilePath,
|
||||
conf.IssuerCertificateFilePath,
|
||||
conf.IssuerPrivateKeyFilePath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -57,13 +59,12 @@ func RenewCertificate(conf RenewCertificateParams) error {
|
|||
rootCertBytes, issuerCertBytes, issuerKeyBytes, err = GenerateNewCertificates(
|
||||
conf.ValidUntil,
|
||||
conf.RootPrivateKeyFilePath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
print.InfoStatusEvent(os.Stdout, "Updating certifcates in your Kubernetes cluster")
|
||||
err = renewCertificate(rootCertBytes, issuerCertBytes, issuerKeyBytes, conf.Timeout)
|
||||
err = renewCertificate(rootCertBytes, issuerCertBytes, issuerKeyBytes, conf.Timeout, conf.ImageVariant)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -86,29 +87,44 @@ func parseCertificateFiles(rootCert, issuerCert, issuerKey string) ([]byte, []by
|
|||
return rootCertBytes, issuerCertBytes, issuerKeyBytes, nil
|
||||
}
|
||||
|
||||
func renewCertificate(rootCert, issuerCert, issuerKey []byte, timeout uint) error {
|
||||
func renewCertificate(rootCert, issuerCert, issuerKey []byte, timeout uint, imageVariant string) error {
|
||||
var daprVersion, daprImageVariant string
|
||||
status, err := GetDaprResourcesStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
daprVersion := GetDaprVersion(status)
|
||||
daprVersion = GetDaprVersion(status)
|
||||
print.InfoStatusEvent(os.Stdout, "Dapr control plane version %s detected in namespace %s", daprVersion, status[0].Namespace)
|
||||
|
||||
// Get the control plane version from daprversion(1.x.x-mariner), if image variant is provided.
|
||||
// Here, imageVariant is used only to extract the actual control plane version,
|
||||
// and do some validation on top of that.
|
||||
if imageVariant != "" {
|
||||
daprVersion, daprImageVariant = utils.GetVersionAndImageVariant(daprVersion)
|
||||
if daprImageVariant != imageVariant {
|
||||
return fmt.Errorf("error in parsing dapr version. found image variant %q is not same as provided value %q", daprImageVariant, imageVariant)
|
||||
}
|
||||
}
|
||||
|
||||
helmConf, err := helmConfig(status[0].Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
daprChart, err := daprChart(daprVersion, helmConf)
|
||||
helmRepo := utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo)
|
||||
daprChart, err := getHelmChart(daprVersion, "dapr", helmRepo, helmConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upgradeClient := helm.NewUpgrade(helmConf)
|
||||
|
||||
// Reuse the existing helm configuration values i.e. tags, registry, etc.
|
||||
upgradeClient.ReuseValues = true
|
||||
upgradeClient.Wait = true
|
||||
upgradeClient.Timeout = time.Duration(timeout) * time.Second
|
||||
upgradeClient.Timeout = time.Duration(timeout) * time.Second //nolint:gosec
|
||||
upgradeClient.Namespace = status[0].Namespace
|
||||
|
||||
// Override the helm configuration values with the new certificates.
|
||||
vals, err := createHelmParamsForNewCertificates(string(rootCert), string(issuerCert), string(issuerKey))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -130,12 +146,12 @@ func createHelmParamsForNewCertificates(ca, issuerCert, issuerKey string) (map[s
|
|||
args := []string{}
|
||||
|
||||
if ca != "" && issuerCert != "" && issuerKey != "" {
|
||||
args = append(args, fmt.Sprintf("dapr_sentry.tls.root.certPEM=%s", ca),
|
||||
fmt.Sprintf("dapr_sentry.tls.issuer.certPEM=%s", issuerCert),
|
||||
fmt.Sprintf("dapr_sentry.tls.issuer.keyPEM=%s", issuerKey),
|
||||
args = append(args, "dapr_sentry.tls.root.certPEM="+ca,
|
||||
"dapr_sentry.tls.issuer.certPEM="+issuerCert,
|
||||
"dapr_sentry.tls.issuer.keyPEM="+issuerKey,
|
||||
)
|
||||
} else {
|
||||
return nil, fmt.Errorf("parameters not found")
|
||||
return nil, errors.New("parameters not found")
|
||||
}
|
||||
|
||||
for _, v := range args {
|
||||
|
@ -163,7 +179,7 @@ func GenerateNewCertificates(validUntil time.Duration, privateKeyFile string) ([
|
|||
}
|
||||
} else {
|
||||
var err error
|
||||
rootKey, err = certs.GenerateECPrivateKey()
|
||||
rootKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
@ -172,13 +188,18 @@ func GenerateNewCertificates(validUntil time.Duration, privateKeyFile string) ([
|
|||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
allowedClockSkew, err := time.ParseDuration(systemConfig.Spec.MTLSSpec.AllowedClockSkew)
|
||||
var allowedClockSkew time.Duration
|
||||
if systemConfig.Spec.MTLSSpec.AllowedClockSkew != nil {
|
||||
allowedClockSkew, err = time.ParseDuration(*systemConfig.Spec.MTLSSpec.AllowedClockSkew)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
bundle, err := ca.GenerateBundle(rootKey, "cluster.local", allowedClockSkew, &validUntil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
_, rootCertPem, issuerCertPem, issuerKeyPem, err := ca.GetNewSelfSignedCertificates(rootKey, validUntil, allowedClockSkew)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return rootCertPem, issuerCertPem, issuerKeyPem, nil
|
||||
|
||||
return bundle.TrustAnchors, bundle.IssChainPEM, bundle.IssKeyPEM, nil
|
||||
}
|
||||
|
|
|
@ -13,24 +13,447 @@ limitations under the License.
|
|||
|
||||
package kubernetes
|
||||
|
||||
// RunConfig represents the application configuration parameters.
|
||||
type RunConfig struct {
|
||||
AppID string
|
||||
AppPort int
|
||||
HTTPPort int
|
||||
GRPCPort int
|
||||
CodeDirectory string
|
||||
Arguments []string
|
||||
Image string
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
appV1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
k8s "k8s.io/client-go/kubernetes"
|
||||
podsv1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
// Specifically use k8s sig yaml to marshal into json, then convert to yaml.
|
||||
k8sYaml "sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/runfileconfig"
|
||||
daprsyscall "github.com/dapr/cli/pkg/syscall"
|
||||
"github.com/dapr/cli/utils"
|
||||
"github.com/dapr/dapr/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
const (
|
||||
serviceKind = "Service"
|
||||
deploymentKind = "Deployment"
|
||||
serviceAPIVersion = "v1"
|
||||
deploymentAPIVersion = "apps/v1"
|
||||
loadBalanceType = "LoadBalancer"
|
||||
daprEnableAnnotationKey = "dapr.io/enabled"
|
||||
daprConfigAnnotationKey = "dapr.io/config"
|
||||
daprConfigAnnotationValue = "appconfig"
|
||||
serviceFileName = "service.yaml"
|
||||
deploymentFileName = "deployment.yaml"
|
||||
appLabelKey = "app"
|
||||
nameKey = "name"
|
||||
namespaceKey = "namespace"
|
||||
labelsKey = "labels"
|
||||
tcpProtocol = "TCP"
|
||||
|
||||
podCreationDeletionTimeout = 1 * time.Minute
|
||||
)
|
||||
|
||||
type deploymentConfig struct {
|
||||
Kind string `json:"kind"`
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
Spec appV1.DeploymentSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// RunOutput represents the run output.
|
||||
type RunOutput struct {
|
||||
Message string
|
||||
type serviceConfig struct {
|
||||
Kind string `json:"kind"`
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
Spec corev1.ServiceSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// Run executes the application based on the run configuration.
|
||||
func Run(config *RunConfig) (*RunOutput, error) {
|
||||
//nolint
|
||||
return nil, nil
|
||||
type runState struct {
|
||||
serviceFilePath string
|
||||
deploymentFilePath string
|
||||
app runfileconfig.App
|
||||
logCancel context.CancelFunc
|
||||
}
|
||||
|
||||
// Run executes the application based on the run file configuration.
|
||||
// Run creates a temporary `deploy` folder within the app/.dapr directory and then applies that to the context pointed to
|
||||
// kubectl client.
|
||||
func Run(runFilePath string, config runfileconfig.RunFileConfig) (bool, error) {
|
||||
// At this point, we expect the runfile to be parsed and the values within config
|
||||
// Validations and default setting will only be done after this point.
|
||||
var exitWithError bool
|
||||
|
||||
// get k8s client for PodsInterface.
|
||||
client, cErr := Client()
|
||||
if cErr != nil {
|
||||
// exit with error.
|
||||
return true, fmt.Errorf("error getting k8s client: %w", cErr)
|
||||
}
|
||||
|
||||
// get dapr k8s client.
|
||||
daprClient, cErr := DaprClient()
|
||||
if cErr != nil {
|
||||
// exit with error.
|
||||
return true, fmt.Errorf("error getting dapr k8s client: %w", cErr)
|
||||
}
|
||||
|
||||
namespace := corev1.NamespaceDefault
|
||||
podsInterface := client.CoreV1().Pods(namespace)
|
||||
|
||||
// setup a monitoring context for shutdown call from another cli process.
|
||||
monitoringContext, monitoringCancel := context.WithCancel(context.Background())
|
||||
defer monitoringCancel()
|
||||
|
||||
// setup shutdown notify channel.
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
daprsyscall.SetupShutdownNotify(sigCh)
|
||||
|
||||
runStates := []runState{}
|
||||
print.InfoStatusEvent(os.Stdout, "This is a preview feature and subject to change in future releases.")
|
||||
|
||||
for _, app := range config.Apps {
|
||||
print.StatusEvent(os.Stdout, print.LogInfo, "Validating config and starting app %q", app.RunConfig.AppID)
|
||||
// Set defaults if zero value provided in config yaml.
|
||||
app.RunConfig.SetDefaultFromSchema()
|
||||
|
||||
// Validate validates the configs for k8s and modifies appId etc.
|
||||
err := app.RunConfig.ValidateK8s()
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error validating run config for app %q present in %s: %s", app.RunConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
var svc serviceConfig
|
||||
// create default service config.
|
||||
if app.ContainerConfiguration.CreateService {
|
||||
svc = createServiceConfig(app)
|
||||
}
|
||||
|
||||
// create default deployment config.
|
||||
dep := createDeploymentConfig(daprClient, app)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error creating deployment file for app %q present in %s: %s", app.RunConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
// overwrite <app-id>/.dapr/deploy/service.yaml.
|
||||
// overwrite <app-id>/.dapr/deploy/deployment.yaml.
|
||||
|
||||
err = writeYamlFile(app, svc, dep)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error creating deployment/service yaml files: %s", err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
deployDir := app.GetDeployDir()
|
||||
print.InfoStatusEvent(os.Stdout, "Deploying app %q to Kubernetes", app.AppID)
|
||||
serviceFilePath := filepath.Join(deployDir, serviceFileName)
|
||||
deploymentFilePath := filepath.Join(deployDir, deploymentFileName)
|
||||
rState := runState{}
|
||||
if app.CreateService {
|
||||
print.InfoStatusEvent(os.Stdout, "Deploying service YAML %q to Kubernetes", serviceFilePath)
|
||||
err = deployYamlToK8s(serviceFilePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error deploying service yaml file %q : %s", serviceFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
rState.serviceFilePath = serviceFilePath
|
||||
}
|
||||
|
||||
print.InfoStatusEvent(os.Stdout, "Deploying deployment YAML %q to Kubernetes", deploymentFilePath)
|
||||
err = deployYamlToK8s(deploymentFilePath)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stderr, "Error deploying deployment yaml file %q : %s", deploymentFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
// create log files and save state.
|
||||
err = app.CreateDaprdLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting daprd log file for app %q present in %s: %s", app.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
err = app.CreateAppLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting app log file for app %q present in %s: %s", app.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
||||
daprdLogWriter := runfileconfig.GetLogWriter(app.DaprdLogWriteCloser, app.DaprdLogDestination)
|
||||
// appDaprdWriter := runExec.GetAppDaprdWriter(app, false).
|
||||
appLogWriter := runfileconfig.GetLogWriter(app.AppLogWriteCloser, app.AppLogDestination)
|
||||
customAppLogWriter := print.CustomLogWriter{W: appLogWriter}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), podCreationDeletionTimeout)
|
||||
err = waitPodRunning(ctx, client, namespace, app.AppID)
|
||||
cancel()
|
||||
if err != nil {
|
||||
print.WarningStatusEvent(os.Stderr, "Error deploying pod to Kubernetes. See logs directly from Kubernetes command line.")
|
||||
// Close the log files since there is deployment error, and the container might be in crash loop back off state.
|
||||
app.CloseAppLogFile()
|
||||
app.CloseDaprdLogFile()
|
||||
} else {
|
||||
logContext, cancel := context.WithCancel(context.Background())
|
||||
rState.logCancel = cancel
|
||||
err = setupLogs(logContext, app.AppID, daprdLogWriter, customAppLogWriter, podsInterface)
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogWarning, "Error setting up logs for app %q present in %q . See logs directly from Kubernetes command line.: %s ", app.AppID, runFilePath, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
rState.deploymentFilePath = deploymentFilePath
|
||||
rState.app = app
|
||||
|
||||
// append runSate only on successful k8s deploy.
|
||||
runStates = append(runStates, rState)
|
||||
|
||||
print.InfoStatusEvent(os.Stdout, "Writing log files to directory : %s", app.GetLogsDir())
|
||||
}
|
||||
|
||||
// If all apps have been started and there are no errors in starting the apps wait for signal from sigCh.
|
||||
if !exitWithError {
|
||||
print.InfoStatusEvent(os.Stdout, "Starting to monitor Kubernetes pods for deletion.")
|
||||
go monitorK8sPods(monitoringContext, client, namespace, runStates, sigCh)
|
||||
// After all apps started wait for sigCh.
|
||||
<-sigCh
|
||||
monitoringCancel()
|
||||
print.InfoStatusEvent(os.Stdout, "Stopping Kubernetes pods monitoring.")
|
||||
// To add a new line in Stdout.
|
||||
fmt.Println()
|
||||
print.InfoStatusEvent(os.Stdout, "Received signal to stop. Deleting K8s Dapr app deployments.")
|
||||
}
|
||||
|
||||
closeErr := gracefullyShutdownK8sDeployment(runStates, client, namespace)
|
||||
return exitWithError, closeErr
|
||||
}
|
||||
|
||||
func createServiceConfig(app runfileconfig.App) serviceConfig {
|
||||
return serviceConfig{
|
||||
Kind: serviceKind,
|
||||
APIVersion: serviceAPIVersion,
|
||||
Metadata: map[string]any{
|
||||
nameKey: app.RunConfig.AppID,
|
||||
labelsKey: map[string]string{
|
||||
appLabelKey: app.AppID,
|
||||
},
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Protocol: tcpProtocol,
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(app.AppPort),
|
||||
},
|
||||
},
|
||||
Selector: map[string]string{
|
||||
appLabelKey: app.AppID,
|
||||
},
|
||||
Type: loadBalanceType,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createDeploymentConfig(client versioned.Interface, app runfileconfig.App) deploymentConfig {
|
||||
replicas := int32(1)
|
||||
dep := deploymentConfig{
|
||||
Kind: deploymentKind,
|
||||
APIVersion: deploymentAPIVersion,
|
||||
Metadata: map[string]any{
|
||||
nameKey: app.AppID,
|
||||
namespaceKey: corev1.NamespaceDefault,
|
||||
},
|
||||
}
|
||||
|
||||
dep.Spec = appV1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
appLabelKey: app.AppID,
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
appLabelKey: app.AppID,
|
||||
},
|
||||
Annotations: app.RunConfig.GetAnnotations(),
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: app.AppID,
|
||||
Image: app.ContainerImage,
|
||||
Env: getEnv(app),
|
||||
ImagePullPolicy: corev1.PullPolicy(app.ContainerImagePullPolicy),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Set dapr.io/enable annotation.
|
||||
dep.Spec.Template.ObjectMeta.Annotations[daprEnableAnnotationKey] = "true"
|
||||
|
||||
if ok, _ := isConfigurationPresent(client, corev1.NamespaceDefault, daprConfigAnnotationValue); ok {
|
||||
// Set dapr.io/config annotation only if present.
|
||||
dep.Spec.Template.ObjectMeta.Annotations[daprConfigAnnotationKey] = daprConfigAnnotationValue
|
||||
} else {
|
||||
print.WarningStatusEvent(os.Stderr, "Dapr configuration %q not found in namespace %q. Skipping annotation %q", daprConfigAnnotationValue, corev1.NamespaceDefault, daprConfigAnnotationKey)
|
||||
}
|
||||
|
||||
// set containerPort only if app port is present.
|
||||
if app.AppPort != 0 {
|
||||
dep.Spec.Template.Spec.Containers[0].Ports = []corev1.ContainerPort{
|
||||
{
|
||||
ContainerPort: int32(app.AppPort), //nolint:gosec
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return dep
|
||||
}
|
||||
|
||||
func getEnv(app runfileconfig.App) []corev1.EnvVar {
|
||||
envs := app.GetEnv()
|
||||
envVars := make([]corev1.EnvVar, len(envs))
|
||||
i := 0
|
||||
for k, v := range app.GetEnv() {
|
||||
envVars[i] = corev1.EnvVar{
|
||||
Name: k,
|
||||
Value: v,
|
||||
}
|
||||
i++
|
||||
}
|
||||
return envVars
|
||||
}
|
||||
|
||||
func writeYamlFile(app runfileconfig.App, svc serviceConfig, dep deploymentConfig) error {
|
||||
var yamlBytes []byte
|
||||
var err error
|
||||
var writeFile io.WriteCloser
|
||||
deployDir := app.GetDeployDir()
|
||||
if app.CreateService {
|
||||
yamlBytes, err = k8sYaml.Marshal(svc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling service yaml: %w", err)
|
||||
}
|
||||
serviceFilePath := filepath.Join(deployDir, serviceFileName)
|
||||
writeFile, err = os.Create(serviceFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating file %s : %w", serviceFilePath, err)
|
||||
}
|
||||
_, err = writeFile.Write(yamlBytes)
|
||||
if err != nil {
|
||||
writeFile.Close()
|
||||
return fmt.Errorf("error writing to file %s : %w", serviceFilePath, err)
|
||||
}
|
||||
writeFile.Close()
|
||||
}
|
||||
yamlBytes, err = k8sYaml.Marshal(dep)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling deployment yaml: %w", err)
|
||||
}
|
||||
deploymentFilePath := filepath.Join(deployDir, deploymentFileName)
|
||||
writeFile, err = os.Create(deploymentFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating file %s : %w", deploymentFilePath, err)
|
||||
}
|
||||
_, err = writeFile.Write(yamlBytes)
|
||||
if err != nil {
|
||||
writeFile.Close()
|
||||
return fmt.Errorf("error writing to file %s : %w", deploymentFilePath, err)
|
||||
}
|
||||
writeFile.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func deployYamlToK8s(yamlToDeployPath string) error {
|
||||
_, err := os.Stat(yamlToDeployPath)
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("error given file %q does not exist", yamlToDeployPath)
|
||||
}
|
||||
_, err = utils.RunCmdAndWait("kubectl", "apply", "-f", yamlToDeployPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deploying the yaml %s to Kubernetes: %w", yamlToDeployPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteYamlK8s(yamlToDeletePath string) error {
|
||||
print.InfoStatusEvent(os.Stdout, "Deleting %q from Kubernetes", yamlToDeletePath)
|
||||
_, err := os.Stat(yamlToDeletePath)
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("error given file %q does not exist", yamlToDeletePath)
|
||||
}
|
||||
_, err = utils.RunCmdAndWait("kubectl", "delete", "-f", yamlToDeletePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting the yaml %s from Kubernetes: %w", yamlToDeletePath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupLogs(ctx context.Context, appID string, daprdLogWriter, appLogWriter io.Writer, podInterface podsv1.PodInterface) error {
|
||||
return streamContainerLogsToDisk(ctx, appID, appLogWriter, daprdLogWriter, podInterface)
|
||||
}
|
||||
|
||||
func gracefullyShutdownK8sDeployment(runStates []runState, client k8s.Interface, namespace string) error {
|
||||
errs := make([]error, 0, len(runStates)*4)
|
||||
for _, r := range runStates {
|
||||
if len(r.serviceFilePath) != 0 {
|
||||
errs = append(errs, deleteYamlK8s(r.serviceFilePath))
|
||||
}
|
||||
errs = append(errs, deleteYamlK8s(r.deploymentFilePath))
|
||||
labelSelector := map[string]string{
|
||||
daprAppIDKey: r.app.AppID,
|
||||
}
|
||||
if ok, _ := CheckPodExists(client, namespace, labelSelector, r.app.AppID); ok {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), podCreationDeletionTimeout)
|
||||
err := waitPodDeleted(ctx, client, namespace, r.app.AppID)
|
||||
cancel()
|
||||
if err != nil {
|
||||
// swallowing err here intentionally.
|
||||
print.WarningStatusEvent(os.Stderr, "Error waiting for pods to be deleted. Final logs might only be partially available.")
|
||||
}
|
||||
}
|
||||
|
||||
// shutdown logs.
|
||||
if r.logCancel != nil { // checking nil, in scenarios where deployments are not run correctly.
|
||||
r.logCancel()
|
||||
}
|
||||
|
||||
errs = append(errs, r.app.CloseAppLogFile(), r.app.CloseDaprdLogFile())
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func monitorK8sPods(ctx context.Context, client k8s.Interface, namespace string, runStates []runState, sigCh chan os.Signal) {
|
||||
// for each app wait for pod to be deleted, if all pods are deleted, then send shutdown signal to the cli process.
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for _, r := range runStates {
|
||||
wg.Add(1)
|
||||
go func(appID string, wg *sync.WaitGroup) {
|
||||
err := waitPodDeleted(ctx, client, namespace, appID)
|
||||
if err != nil && strings.Contains(err.Error(), podWatchErrTemplate) {
|
||||
print.WarningStatusEvent(os.Stderr, "Error monitoring Kubernetes pod(s) for app %q.", appID)
|
||||
}
|
||||
wg.Done()
|
||||
}(r.app.AppID, &wg)
|
||||
}
|
||||
wg.Wait()
|
||||
// Send signal to gracefully close log writers and shut down process.
|
||||
sigCh <- syscall.SIGINT
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ var controlPlaneLabels = []string{
|
|||
"dapr-placement-server",
|
||||
"dapr-sidecar-injector",
|
||||
"dapr-dashboard",
|
||||
"dapr-scheduler-server",
|
||||
}
|
||||
|
||||
type StatusClient struct {
|
||||
|
@ -64,7 +65,6 @@ func NewStatusClient() (*StatusClient, error) {
|
|||
|
||||
// List status for Dapr resources.
|
||||
func (s *StatusClient) Status() ([]StatusOutput, error) {
|
||||
//nolint
|
||||
client := s.client
|
||||
if client == nil {
|
||||
return nil, errors.New("kubernetes client not initialized")
|
||||
|
@ -96,7 +96,11 @@ func (s *StatusClient) Status() ([]StatusOutput, error) {
|
|||
namespace := pod.GetNamespace()
|
||||
age := age.GetAge(pod.CreationTimestamp.Time)
|
||||
created := pod.CreationTimestamp.Format("2006-01-02 15:04.05")
|
||||
version := image[strings.IndexAny(image, ":")+1:]
|
||||
|
||||
// Version is part of the docker image tag which is expected to be present at the end of image uri.
|
||||
// expected format: <image>:<tag>. For example: daprio/dapr:1.8.0.
|
||||
// tag can be either <version> or <version>-<image-variant>. For example: 1.8.0-mariner.
|
||||
version := image[strings.LastIndex(image, ":")+1:]
|
||||
status := ""
|
||||
|
||||
// loop through all replicas and update to Running/Healthy status only if all instances are Running and Healthy.
|
||||
|
|
|
@ -25,37 +25,51 @@ import (
|
|||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
const (
|
||||
daprImageTag = "daprio/dapr:0.0.1"
|
||||
daprDashboardImageTag = "daprio/dashboard:0.0.1"
|
||||
)
|
||||
|
||||
type podDetails struct {
|
||||
name string
|
||||
appName string
|
||||
createdAt time.Time
|
||||
state v1.ContainerState
|
||||
ready bool
|
||||
imageURI string
|
||||
}
|
||||
|
||||
func newTestSimpleK8s(objects ...runtime.Object) *StatusClient {
|
||||
client := StatusClient{}
|
||||
client.client = fake.NewSimpleClientset(objects...)
|
||||
return &client
|
||||
}
|
||||
|
||||
func newDaprControlPlanePod(name string, appName string, creationTime time.Time, state v1.ContainerState, ready bool) *v1.Pod {
|
||||
func newDaprControlPlanePod(pd podDetails) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Name: pd.name,
|
||||
Namespace: "dapr-system",
|
||||
Annotations: map[string]string{},
|
||||
Labels: map[string]string{
|
||||
"app": appName,
|
||||
"app": pd.appName,
|
||||
},
|
||||
CreationTimestamp: metav1.Time{
|
||||
Time: creationTime,
|
||||
Time: pd.createdAt,
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
State: state,
|
||||
Ready: ready,
|
||||
State: pd.state,
|
||||
Ready: pd.ready,
|
||||
},
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: name + ":0.0.1",
|
||||
Image: pd.imageURI,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -69,22 +83,27 @@ func TestStatus(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("%s status should not raise an error", err.Error())
|
||||
}
|
||||
assert.Equal(t, 0, len(status), "Expected status to be empty list")
|
||||
assert.Empty(t, status, "Expected status to be empty list")
|
||||
})
|
||||
|
||||
t.Run("one status waiting", func(t *testing.T) {
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(
|
||||
"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard",
|
||||
time.Now(),
|
||||
v1.ContainerState{
|
||||
pd := podDetails{
|
||||
name: "dapr-dashboard-58877dbc9d-n8qg2",
|
||||
appName: "dapr-dashboard",
|
||||
createdAt: time.Now(),
|
||||
state: v1.ContainerState{
|
||||
Waiting: &v1.ContainerStateWaiting{
|
||||
Reason: "test",
|
||||
Message: "test",
|
||||
},
|
||||
}, false))
|
||||
},
|
||||
ready: false,
|
||||
imageURI: "daprio/dapr-dashboard:0.0.1",
|
||||
}
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(pd))
|
||||
status, err := k8s.Status()
|
||||
assert.Nil(t, err, "status should not raise an error")
|
||||
assert.Equal(t, 1, len(status), "Expected status to be non-empty list")
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
assert.Len(t, status, 1, "Expected status to be non-empty list")
|
||||
stat := status[0]
|
||||
assert.Equal(t, "dapr-dashboard", stat.Name, "expected name to match")
|
||||
assert.Equal(t, "dapr-system", stat.Namespace, "expected namespace to match")
|
||||
|
@ -96,19 +115,24 @@ func TestStatus(t *testing.T) {
|
|||
|
||||
t.Run("one status running", func(t *testing.T) {
|
||||
testTime := time.Now()
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(
|
||||
"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard",
|
||||
testTime.Add(time.Duration(-20)*time.Minute),
|
||||
v1.ContainerState{
|
||||
pd := podDetails{
|
||||
name: "dapr-dashboard-58877dbc9d-n8qg2",
|
||||
appName: "dapr-dashboard",
|
||||
createdAt: testTime.Add(time.Duration(-20) * time.Minute),
|
||||
state: v1.ContainerState{
|
||||
Running: &v1.ContainerStateRunning{
|
||||
StartedAt: metav1.Time{
|
||||
Time: testTime.Add(time.Duration(-19) * time.Minute),
|
||||
},
|
||||
},
|
||||
}, true))
|
||||
},
|
||||
ready: true,
|
||||
imageURI: "daprio/dapr-dashboard:0.0.1",
|
||||
}
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(pd))
|
||||
status, err := k8s.Status()
|
||||
assert.Nil(t, err, "status should not raise an error")
|
||||
assert.Equal(t, 1, len(status), "Expected status to be non-empty list")
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
assert.Len(t, status, 1, "Expected status to be non-empty list")
|
||||
stat := status[0]
|
||||
assert.Equal(t, "dapr-dashboard", stat.Name, "expected name to match")
|
||||
assert.Equal(t, "dapr-system", stat.Namespace, "expected namespace to match")
|
||||
|
@ -116,24 +140,28 @@ func TestStatus(t *testing.T) {
|
|||
assert.Equal(t, "0.0.1", stat.Version, "expected version to match")
|
||||
assert.Equal(t, 1, stat.Replicas, "expected replicas to match")
|
||||
assert.Equal(t, "True", stat.Healthy, "expected health to match")
|
||||
assert.Equal(t, stat.Status, "Running", "expected running status")
|
||||
assert.Equal(t, "Running", stat.Status, "expected running status")
|
||||
})
|
||||
|
||||
t.Run("one status terminated", func(t *testing.T) {
|
||||
testTime := time.Now()
|
||||
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(
|
||||
"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard",
|
||||
testTime.Add(time.Duration(-20)*time.Minute),
|
||||
v1.ContainerState{
|
||||
pd := podDetails{
|
||||
name: "dapr-dashboard-58877dbc9d-n8qg2",
|
||||
appName: "dapr-dashboard",
|
||||
createdAt: testTime.Add(time.Duration(-20) * time.Minute),
|
||||
state: v1.ContainerState{
|
||||
Terminated: &v1.ContainerStateTerminated{
|
||||
ExitCode: 1,
|
||||
},
|
||||
}, false))
|
||||
},
|
||||
ready: false,
|
||||
imageURI: "daprio/dapr-dashboard:0.0.1",
|
||||
}
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(pd))
|
||||
|
||||
status, err := k8s.Status()
|
||||
assert.Nil(t, err, "status should not raise an error")
|
||||
assert.Equal(t, 1, len(status), "Expected status to be non-empty list")
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
assert.Len(t, status, 1, "Expected status to be non-empty list")
|
||||
stat := status[0]
|
||||
assert.Equal(t, "dapr-dashboard", stat.Name, "expected name to match")
|
||||
assert.Equal(t, "dapr-system", stat.Namespace, "expected namespace to match")
|
||||
|
@ -141,28 +169,32 @@ func TestStatus(t *testing.T) {
|
|||
assert.Equal(t, "0.0.1", stat.Version, "expected version to match")
|
||||
assert.Equal(t, 1, stat.Replicas, "expected replicas to match")
|
||||
assert.Equal(t, "False", stat.Healthy, "expected health to match")
|
||||
assert.Equal(t, stat.Status, "Terminated", "expected terminated status")
|
||||
assert.Equal(t, "Terminated", stat.Status, "expected terminated status")
|
||||
})
|
||||
|
||||
t.Run("one status pending", func(t *testing.T) {
|
||||
testTime := time.Now()
|
||||
|
||||
pod := newDaprControlPlanePod(
|
||||
"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard",
|
||||
testTime.Add(time.Duration(-20)*time.Minute),
|
||||
v1.ContainerState{
|
||||
pd := podDetails{
|
||||
name: "dapr-dashboard-58877dbc9d-n8qg2",
|
||||
appName: "dapr-dashboard",
|
||||
createdAt: testTime.Add(time.Duration(-20) * time.Minute),
|
||||
state: v1.ContainerState{
|
||||
Terminated: &v1.ContainerStateTerminated{
|
||||
ExitCode: 1,
|
||||
},
|
||||
}, false)
|
||||
},
|
||||
ready: false,
|
||||
imageURI: "daprio/dapr-dashboard:0.0.1",
|
||||
}
|
||||
pod := newDaprControlPlanePod(pd)
|
||||
// delete pod's podstatus.
|
||||
pod.Status.ContainerStatuses = nil
|
||||
pod.Status.Phase = v1.PodPending
|
||||
|
||||
k8s := newTestSimpleK8s(pod)
|
||||
status, err := k8s.Status()
|
||||
assert.Nil(t, err, "status should not raise an error")
|
||||
assert.Equal(t, 1, len(status), "Expected status to be non-empty list")
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
assert.Len(t, status, 1, "Expected status to be non-empty list")
|
||||
stat := status[0]
|
||||
assert.Equal(t, "dapr-dashboard", stat.Name, "expected name to match")
|
||||
assert.Equal(t, "dapr-system", stat.Namespace, "expected namespace to match")
|
||||
|
@ -170,13 +202,13 @@ func TestStatus(t *testing.T) {
|
|||
assert.Equal(t, "0.0.1", stat.Version, "expected version to match")
|
||||
assert.Equal(t, 1, stat.Replicas, "expected replicas to match")
|
||||
assert.Equal(t, "False", stat.Healthy, "expected health to match")
|
||||
assert.Equal(t, stat.Status, "Pending", "expected pending status")
|
||||
assert.Equal(t, "Pending", stat.Status, "expected pending status")
|
||||
})
|
||||
|
||||
t.Run("one status empty client", func(t *testing.T) {
|
||||
k8s := &StatusClient{}
|
||||
status, err := k8s.Status()
|
||||
assert.NotNil(t, err, "status should raise an error")
|
||||
assert.Error(t, err, "status should raise an error")
|
||||
assert.Equal(t, "kubernetes client not initialized", err.Error(), "expected errors to match")
|
||||
assert.Nil(t, status, "expected nil for status")
|
||||
})
|
||||
|
@ -184,22 +216,26 @@ func TestStatus(t *testing.T) {
|
|||
|
||||
func TestControlPlaneServices(t *testing.T) {
|
||||
controlPlaneServices := []struct {
|
||||
name string
|
||||
appName string
|
||||
name string
|
||||
appName string
|
||||
imageURI string
|
||||
}{
|
||||
{"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard"},
|
||||
{"dapr-operator-67d7d7bb6c-7h96c", "dapr-operator"},
|
||||
{"dapr-operator-67d7d7bb6c-2h96d", "dapr-operator"},
|
||||
{"dapr-operator-67d7d7bb6c-3h96c", "dapr-operator"},
|
||||
{"dapr-placement-server-0", "dapr-placement-server"},
|
||||
{"dapr-placement-server-1", "dapr-placement-server"},
|
||||
{"dapr-placement-server-2", "dapr-placement-server"},
|
||||
{"dapr-sentry-647759cd46-9ptks", "dapr-sentry"},
|
||||
{"dapr-sentry-647759cd46-aptks", "dapr-sentry"},
|
||||
{"dapr-sentry-647759cd46-bptks", "dapr-sentry"},
|
||||
{"dapr-sidecar-injector-74648c9dcb-5bsmn", "dapr-sidecar-injector"},
|
||||
{"dapr-sidecar-injector-74648c9dcb-6bsmn", "dapr-sidecar-injector"},
|
||||
{"dapr-sidecar-injector-74648c9dcb-7bsmn", "dapr-sidecar-injector"},
|
||||
{"dapr-dashboard-58877dbc9d-n8qg2", "dapr-dashboard", daprDashboardImageTag},
|
||||
{"dapr-operator-67d7d7bb6c-7h96c", "dapr-operator", daprImageTag},
|
||||
{"dapr-operator-67d7d7bb6c-2h96d", "dapr-operator", daprImageTag},
|
||||
{"dapr-operator-67d7d7bb6c-3h96c", "dapr-operator", daprImageTag},
|
||||
{"dapr-placement-server-0", "dapr-placement-server", daprImageTag},
|
||||
{"dapr-placement-server-1", "dapr-placement-server", daprImageTag},
|
||||
{"dapr-placement-server-2", "dapr-placement-server", daprImageTag},
|
||||
{"dapr-sentry-647759cd46-9ptks", "dapr-sentry", daprImageTag},
|
||||
{"dapr-sentry-647759cd46-aptks", "dapr-sentry", daprImageTag},
|
||||
{"dapr-sentry-647759cd46-bptks", "dapr-sentry", daprImageTag},
|
||||
{"dapr-sidecar-injector-74648c9dcb-5bsmn", "dapr-sidecar-injector", daprImageTag},
|
||||
{"dapr-sidecar-injector-74648c9dcb-6bsmn", "dapr-sidecar-injector", daprImageTag},
|
||||
{"dapr-sidecar-injector-74648c9dcb-7bsmn", "dapr-sidecar-injector", daprImageTag},
|
||||
{"dapr-scheduler-server-0", "dapr-scheduler-server", daprImageTag},
|
||||
{"dapr-scheduler-server-1", "dapr-scheduler-server", daprImageTag},
|
||||
{"dapr-scheduler-server-2", "dapr-scheduler-server", daprImageTag},
|
||||
}
|
||||
|
||||
expectedReplicas := map[string]int{}
|
||||
|
@ -207,22 +243,27 @@ func TestControlPlaneServices(t *testing.T) {
|
|||
runtimeObj := make([]runtime.Object, len(controlPlaneServices))
|
||||
for i, s := range controlPlaneServices {
|
||||
testTime := time.Now()
|
||||
runtimeObj[i] = newDaprControlPlanePod(
|
||||
s.name, s.appName,
|
||||
testTime.Add(time.Duration(-20)*time.Minute),
|
||||
v1.ContainerState{
|
||||
pd := podDetails{
|
||||
name: s.name,
|
||||
appName: s.appName,
|
||||
createdAt: testTime.Add(time.Duration(-20) * time.Minute),
|
||||
state: v1.ContainerState{
|
||||
Running: &v1.ContainerStateRunning{
|
||||
StartedAt: metav1.Time{
|
||||
Time: testTime.Add(time.Duration(-19) * time.Minute),
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
},
|
||||
ready: true,
|
||||
imageURI: s.imageURI,
|
||||
}
|
||||
runtimeObj[i] = newDaprControlPlanePod(pd)
|
||||
expectedReplicas[s.appName]++
|
||||
}
|
||||
|
||||
k8s := newTestSimpleK8s(runtimeObj...)
|
||||
status, err := k8s.Status()
|
||||
assert.Nil(t, err, "status should not raise an error")
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
|
||||
assert.Equal(t, len(expectedReplicas), len(status), "Expected status to be empty list")
|
||||
|
||||
|
@ -232,3 +273,41 @@ func TestControlPlaneServices(t *testing.T) {
|
|||
assert.Equal(t, replicas, stat.Replicas, "expected replicas to match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestControlPlaneVersion(t *testing.T) {
|
||||
pd := podDetails{
|
||||
name: "dapr-sentry-647759cd46-9ptks",
|
||||
appName: "dapr-sentry",
|
||||
createdAt: time.Now().Add(time.Duration(-20) * time.Minute),
|
||||
state: v1.ContainerState{
|
||||
Running: &v1.ContainerStateRunning{
|
||||
StartedAt: metav1.Time{
|
||||
Time: time.Now().Add(time.Duration(-19) * time.Minute),
|
||||
},
|
||||
},
|
||||
},
|
||||
ready: true,
|
||||
}
|
||||
testcases := []struct {
|
||||
imageURI string
|
||||
expectedVersion string
|
||||
}{
|
||||
{
|
||||
imageURI: "mockImgReg:0.0.1",
|
||||
expectedVersion: "0.0.1",
|
||||
},
|
||||
{
|
||||
imageURI: "mockImgRegHost:mockPort:0.0.2",
|
||||
expectedVersion: "0.0.2",
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
pd.imageURI = tc.imageURI
|
||||
k8s := newTestSimpleK8s(newDaprControlPlanePod(pd))
|
||||
status, err := k8s.Status()
|
||||
assert.NoError(t, err, "status should not raise an error")
|
||||
assert.Len(t, status, 1, "Expected status to be non-empty list")
|
||||
stat := status[0]
|
||||
assert.Equal(t, tc.expectedVersion, stat.Version, "expected version to match")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/runfileconfig"
|
||||
)
|
||||
|
||||
func Stop(runFilePath string, config runfileconfig.RunFileConfig) error {
|
||||
errs := []error{}
|
||||
// get k8s client.
|
||||
client, cErr := Client()
|
||||
if cErr != nil {
|
||||
return fmt.Errorf("error getting k8s client for monitoring pod deletion: %w", cErr)
|
||||
}
|
||||
|
||||
var err error
|
||||
namespace := corev1.NamespaceDefault
|
||||
for _, app := range config.Apps {
|
||||
appError := false
|
||||
deployDir := app.GetDeployDir()
|
||||
serviceFilePath := filepath.Join(deployDir, serviceFileName)
|
||||
deploymentFilePath := filepath.Join(deployDir, deploymentFileName)
|
||||
if app.CreateService {
|
||||
err = deleteYamlK8s(serviceFilePath)
|
||||
if err != nil {
|
||||
appError = true
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
err = deleteYamlK8s(deploymentFilePath)
|
||||
if err != nil {
|
||||
appError = true
|
||||
}
|
||||
errs = append(errs, err)
|
||||
if !appError {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), podCreationDeletionTimeout)
|
||||
|
||||
// Ignoring errors here as it will anyway be printed in the other dapr cli process.
|
||||
waitPodDeleted(ctx, client, namespace, app.AppID)
|
||||
cancel()
|
||||
} else {
|
||||
print.WarningStatusEvent(os.Stderr, "Error stopping deployment for app %q in file %q", app.AppID, runFilePath)
|
||||
}
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
|
@ -24,13 +24,13 @@ import (
|
|||
)
|
||||
|
||||
// Uninstall removes Dapr from a Kubernetes cluster.
|
||||
func Uninstall(namespace string, uninstallAll bool, timeout uint) error {
|
||||
func Uninstall(namespace string, uninstallAll bool, uninstallDev bool, timeout uint) error {
|
||||
config, err := helmConfig(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := confirmExist(config)
|
||||
exists, err := confirmExist(config, daprReleaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,9 +41,19 @@ func Uninstall(namespace string, uninstallAll bool, timeout uint) error {
|
|||
}
|
||||
|
||||
uninstallClient := helm.NewUninstall(config)
|
||||
uninstallClient.Timeout = time.Duration(timeout) * time.Second
|
||||
_, err = uninstallClient.Run(daprReleaseName)
|
||||
uninstallClient.Timeout = time.Duration(timeout) * time.Second //nolint:gosec
|
||||
|
||||
// Uninstall Dashboard as a best effort.
|
||||
// Chart versions < 1.11 for Dapr will delete dashboard as part of the main chart.
|
||||
// Deleting Dashboard here is for versions >= 1.11.
|
||||
uninstallClient.Run(dashboardReleaseName)
|
||||
|
||||
if uninstallDev {
|
||||
// uninstall dapr-dev-zipkin and dapr-dev-redis as best effort.
|
||||
uninstallThirdParty()
|
||||
}
|
||||
|
||||
_, err = uninstallClient.Run(daprReleaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -59,3 +69,14 @@ func Uninstall(namespace string, uninstallAll bool, timeout uint) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func uninstallThirdParty() {
|
||||
print.InfoStatusEvent(os.Stdout, "Removing dapr-dev-redis and dapr-dev-zipkin from the cluster...")
|
||||
// Uninstall dapr-dev-redis and dapr-dev-zipkin from k8s as best effort.
|
||||
config, _ := helmConfig(thirdPartyDevNamespace)
|
||||
|
||||
uninstallClient := helm.NewUninstall(config)
|
||||
|
||||
uninstallClient.Run(redisReleaseName)
|
||||
uninstallClient.Run(zipkinReleaseName)
|
||||
}
|
||||
|
|
|
@ -14,14 +14,22 @@ limitations under the License.
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
helm "helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/helm/pkg/strvals"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
|
@ -35,6 +43,7 @@ var crds = []string{
|
|||
"configuration",
|
||||
"subscription",
|
||||
"resiliency",
|
||||
"httpendpoints",
|
||||
}
|
||||
|
||||
var crdsFullResources = []string{
|
||||
|
@ -42,17 +51,32 @@ var crdsFullResources = []string{
|
|||
"configurations.dapr.io",
|
||||
"subscriptions.dapr.io",
|
||||
"resiliencies.dapr.io",
|
||||
"httpendpoints.dapr.io",
|
||||
}
|
||||
|
||||
var versionWithHAScheduler = semver.MustParse("1.15.0-rc.1")
|
||||
|
||||
type UpgradeConfig struct {
|
||||
RuntimeVersion string
|
||||
DashboardVersion string
|
||||
Args []string
|
||||
Timeout uint
|
||||
ImageRegistryURI string
|
||||
ImageVariant string
|
||||
}
|
||||
|
||||
// UpgradeOptions represents options for the upgrade function.
|
||||
type UpgradeOptions struct {
|
||||
WithRetry bool
|
||||
MaxRetries int
|
||||
RetryInterval time.Duration
|
||||
}
|
||||
|
||||
// UpgradeOption is a functional option type for configuring upgrade.
|
||||
type UpgradeOption func(*UpgradeOptions)
|
||||
|
||||
func Upgrade(conf UpgradeConfig) error {
|
||||
helmRepo := utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo)
|
||||
status, err := GetDaprResourcesStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -61,22 +85,55 @@ func Upgrade(conf UpgradeConfig) error {
|
|||
daprVersion := GetDaprVersion(status)
|
||||
print.InfoStatusEvent(os.Stdout, "Dapr control plane version %s detected in namespace %s", daprVersion, status[0].Namespace)
|
||||
|
||||
helmConf, err := helmConfig(status[0].Namespace)
|
||||
hasDashboardInDaprChart, err := IsDashboardIncluded(daprVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
daprChart, err := daprChart(conf.RuntimeVersion, helmConf)
|
||||
upgradeClient, helmConf, err := newUpgradeClient(status[0].Namespace, conf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create helm client: %w", err)
|
||||
}
|
||||
|
||||
controlPlaneChart, err := getHelmChart(conf.RuntimeVersion, "dapr", helmRepo, helmConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get helm chart: %w", err)
|
||||
}
|
||||
|
||||
willHaveDashboardInDaprChart, err := IsDashboardIncluded(conf.RuntimeVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
upgradeClient := helm.NewUpgrade(helmConf)
|
||||
upgradeClient.ResetValues = true
|
||||
upgradeClient.Namespace = status[0].Namespace
|
||||
upgradeClient.CleanupOnFail = true
|
||||
upgradeClient.Wait = true
|
||||
upgradeClient.Timeout = time.Duration(conf.Timeout) * time.Second
|
||||
// Before we do anything, checks if installing dashboard is allowed.
|
||||
if willHaveDashboardInDaprChart && conf.DashboardVersion != "" {
|
||||
// We cannot install Dashboard separately if Dapr's chart has it already.
|
||||
return fmt.Errorf("cannot install Dashboard because Dapr version %s already contains it - installation aborted", conf.RuntimeVersion)
|
||||
}
|
||||
|
||||
dashboardExists, err := confirmExist(helmConf, dashboardReleaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasDashboardInDaprChart && willHaveDashboardInDaprChart && dashboardExists {
|
||||
print.InfoStatusEvent(os.Stdout, "Dashboard being uninstalled prior to Dapr control plane upgrade...")
|
||||
uninstallClient := helm.NewUninstall(helmConf)
|
||||
uninstallClient.Timeout = time.Duration(conf.Timeout) * time.Second //nolint:gosec
|
||||
|
||||
_, err = uninstallClient.Run(dashboardReleaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var dashboardChart *chart.Chart
|
||||
if conf.DashboardVersion != "" {
|
||||
dashboardChart, err = getHelmChart(conf.DashboardVersion, dashboardReleaseName, helmRepo, helmConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
print.InfoStatusEvent(os.Stdout, "Starting upgrade...")
|
||||
|
||||
|
@ -107,13 +164,42 @@ func Upgrade(conf UpgradeConfig) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// used to signal the deletion of the scheduler pods only when downgrading from 1.15 to previous versions to handle incompatible changes
|
||||
// in other cases the channel should be nil
|
||||
var downgradeDeletionChan chan error
|
||||
|
||||
if !isDowngrade(conf.RuntimeVersion, daprVersion) {
|
||||
err = applyCRDs(fmt.Sprintf("v%s", conf.RuntimeVersion))
|
||||
err = applyCRDs("v" + conf.RuntimeVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to apply CRDs: %w", err)
|
||||
}
|
||||
} else {
|
||||
print.InfoStatusEvent(os.Stdout, "Downgrade detected, skipping CRDs.")
|
||||
|
||||
targetVersion, errVersion := semver.NewVersion(conf.RuntimeVersion)
|
||||
if errVersion != nil {
|
||||
return fmt.Errorf("unable to parse dapr target version: %w", errVersion)
|
||||
}
|
||||
|
||||
currentVersion, errVersion := semver.NewVersion(daprVersion)
|
||||
if errVersion != nil {
|
||||
return fmt.Errorf("unable to parse dapr current version: %w", errVersion)
|
||||
}
|
||||
|
||||
if currentVersion.GreaterThanEqual(versionWithHAScheduler) && targetVersion.LessThan(versionWithHAScheduler) {
|
||||
downgradeDeletionChan = make(chan error)
|
||||
// Must delete all scheduler pods from cluster due to incompatible changes in version 1.15 with older versions.
|
||||
go func() {
|
||||
// Add an artificial delay to allow helm upgrade to progress and delete the pods only when necessary.
|
||||
time.Sleep(15 * time.Second)
|
||||
errDeletion := deleteSchedulerPods(status[0].Namespace, currentVersion, targetVersion)
|
||||
if errDeletion != nil {
|
||||
downgradeDeletionChan <- fmt.Errorf("failed to delete scheduler pods: %w", errDeletion)
|
||||
print.FailureStatusEvent(os.Stderr, "Failed to delete scheduler pods: "+errDeletion.Error())
|
||||
}
|
||||
close(downgradeDeletionChan)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
chart, err := GetDaprHelmChartName(helmConf)
|
||||
|
@ -121,17 +207,172 @@ func Upgrade(conf UpgradeConfig) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if _, err = upgradeClient.Run(chart, daprChart, vals); err != nil {
|
||||
// Deal with known race condition when applying both CRD and CR close together. The Helm upgrade fails
|
||||
// when a CR is applied tries to be applied before the CRD is fully registered. On each retry we need a
|
||||
// fresh client since the kube client locally caches the last OpenAPI schema it received from the server.
|
||||
// See https://github.com/kubernetes/kubectl/issues/1179
|
||||
_, err = helmUpgrade(upgradeClient, chart, controlPlaneChart, vals, WithRetry(5, 100*time.Millisecond))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure while running upgrade: %w", err)
|
||||
}
|
||||
|
||||
// wait for the deletion of the scheduler pods to finish
|
||||
if downgradeDeletionChan != nil {
|
||||
select {
|
||||
case <-downgradeDeletionChan:
|
||||
case <-time.After(3 * time.Minute):
|
||||
return errors.New("timed out waiting for downgrade deletion")
|
||||
}
|
||||
}
|
||||
|
||||
if dashboardChart != nil {
|
||||
if dashboardExists {
|
||||
if _, err = upgradeClient.Run(dashboardReleaseName, dashboardChart, vals); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// We need to install Dashboard since it does not exist yet.
|
||||
err = install(dashboardReleaseName, conf.DashboardVersion, helmRepo, InitConfiguration{
|
||||
DashboardVersion: conf.DashboardVersion,
|
||||
Namespace: upgradeClient.Namespace,
|
||||
Wait: upgradeClient.Wait,
|
||||
Timeout: conf.Timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteSchedulerPods(namespace string, currentVersion *semver.Version, targetVersion *semver.Version) error {
|
||||
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||
defer cancel()
|
||||
|
||||
var pods *core_v1.PodList
|
||||
|
||||
// wait for at least one pod of the target version to be in the list before deleting the rest
|
||||
// check the label app.kubernetes.io/version to determine the version of the pod
|
||||
foundTargetVersion := false
|
||||
for {
|
||||
if foundTargetVersion {
|
||||
break
|
||||
}
|
||||
k8sClient, err := Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pods, err = k8sClient.CoreV1().Pods(namespace).List(ctxWithTimeout, meta_v1.ListOptions{
|
||||
LabelSelector: "app=dapr-scheduler-server",
|
||||
})
|
||||
if err != nil && !errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(pods.Items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, pod := range pods.Items {
|
||||
pv, ok := pod.Labels["app.kubernetes.io/version"]
|
||||
if ok {
|
||||
podVersion, err := semver.NewVersion(pv)
|
||||
if err == nil && podVersion.Equal(targetVersion) {
|
||||
foundTargetVersion = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
if pods == nil {
|
||||
return errors.New("no scheduler pods found")
|
||||
}
|
||||
|
||||
// get a fresh client to ensure we have the latest state of the cluster
|
||||
k8sClient, err := Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// delete scheduler pods of the current version, i.e. >1.15.0
|
||||
for _, pod := range pods.Items {
|
||||
if pv, ok := pod.Labels["app.kubernetes.io/version"]; ok {
|
||||
podVersion, err := semver.NewVersion(pv)
|
||||
if err == nil && podVersion.Equal(currentVersion) {
|
||||
err = k8sClient.CoreV1().Pods(namespace).Delete(ctxWithTimeout, pod.Name, meta_v1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete pod %s during downgrade: %w", pod.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithRetry enables retry with the specified max retries and retry interval.
|
||||
func WithRetry(maxRetries int, retryInterval time.Duration) UpgradeOption {
|
||||
return func(o *UpgradeOptions) {
|
||||
o.WithRetry = true
|
||||
o.MaxRetries = maxRetries
|
||||
o.RetryInterval = retryInterval
|
||||
}
|
||||
}
|
||||
|
||||
func helmUpgrade(client *helm.Upgrade, name string, chart *chart.Chart, vals map[string]interface{}, options ...UpgradeOption) (*release.Release, error) {
|
||||
upgradeOptions := &UpgradeOptions{
|
||||
WithRetry: false,
|
||||
MaxRetries: 0,
|
||||
RetryInterval: 0,
|
||||
}
|
||||
|
||||
// Apply functional options.
|
||||
for _, option := range options {
|
||||
option(upgradeOptions)
|
||||
}
|
||||
|
||||
var release *release.Release
|
||||
for attempt := 1; ; attempt++ {
|
||||
_, err := client.Run(name, chart, vals)
|
||||
if err == nil {
|
||||
// operation succeeded, no need to retry.
|
||||
break
|
||||
}
|
||||
|
||||
if !upgradeOptions.WithRetry || attempt >= upgradeOptions.MaxRetries {
|
||||
// If not retrying or reached max retries, return the error.
|
||||
return nil, fmt.Errorf("max retries reached, unable to run command: %w", err)
|
||||
}
|
||||
|
||||
print.PendingStatusEvent(os.Stdout, "Retrying after %s...", upgradeOptions.RetryInterval)
|
||||
time.Sleep(upgradeOptions.RetryInterval)
|
||||
|
||||
// create a totally new helm client, this ensures that we fetch a fresh openapi schema from the server on each attempt.
|
||||
client, _, err = newUpgradeClient(client.Namespace, UpgradeConfig{
|
||||
Timeout: uint(client.Timeout), //nolint:gosec
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create helm client: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return release, nil
|
||||
}
|
||||
|
||||
func highAvailabilityEnabled(status []StatusOutput) bool {
|
||||
for _, s := range status {
|
||||
if s.Name == "dapr-dashboard" {
|
||||
continue
|
||||
}
|
||||
// Skip the scheduler server because it's in HA mode by default since version 1.15.0
|
||||
// This will fall back to other dapr services to determine if HA mode is enabled.
|
||||
if strings.HasPrefix(s.Name, "dapr-scheduler-server") {
|
||||
continue
|
||||
}
|
||||
if s.Replicas > 1 {
|
||||
return true
|
||||
}
|
||||
|
@ -144,7 +385,7 @@ func applyCRDs(version string) error {
|
|||
url := fmt.Sprintf("https://raw.githubusercontent.com/dapr/dapr/%s/charts/dapr/crds/%s.yaml", version, crd)
|
||||
|
||||
resp, _ := http.Get(url) //nolint:gosec
|
||||
if resp != nil && resp.StatusCode == 200 {
|
||||
if resp != nil && resp.StatusCode == http.StatusOK {
|
||||
defer resp.Body.Close()
|
||||
|
||||
_, err := utils.RunCmdAndWait("kubectl", "apply", "-f", url)
|
||||
|
@ -163,18 +404,18 @@ func upgradeChartValues(ca, issuerCert, issuerKey string, haMode, mtls bool, con
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
globalVals = append(globalVals, fmt.Sprintf("global.tag=%s", utils.GetVariantVersion(conf.RuntimeVersion, conf.ImageVariant)))
|
||||
globalVals = append(globalVals, "global.tag="+utils.GetVariantVersion(conf.RuntimeVersion, conf.ImageVariant))
|
||||
|
||||
if mtls && ca != "" && issuerCert != "" && issuerKey != "" {
|
||||
globalVals = append(globalVals, fmt.Sprintf("dapr_sentry.tls.root.certPEM=%s", ca),
|
||||
fmt.Sprintf("dapr_sentry.tls.issuer.certPEM=%s", issuerCert),
|
||||
fmt.Sprintf("dapr_sentry.tls.issuer.keyPEM=%s", issuerKey),
|
||||
globalVals = append(globalVals, "dapr_sentry.tls.root.certPEM="+ca,
|
||||
"dapr_sentry.tls.issuer.certPEM="+issuerCert,
|
||||
"dapr_sentry.tls.issuer.keyPEM="+issuerKey,
|
||||
)
|
||||
} else {
|
||||
globalVals = append(globalVals, "global.mtls.enabled=false")
|
||||
}
|
||||
if len(conf.ImageRegistryURI) != 0 {
|
||||
globalVals = append(globalVals, fmt.Sprintf("global.registry=%s", conf.ImageRegistryURI))
|
||||
globalVals = append(globalVals, "global.registry="+conf.ImageRegistryURI)
|
||||
}
|
||||
if haMode {
|
||||
globalVals = append(globalVals, "global.ha.enabled=true")
|
||||
|
@ -199,3 +440,19 @@ func isDowngrade(targetVersion, existingVersion string) bool {
|
|||
}
|
||||
return target.LessThan(existing)
|
||||
}
|
||||
|
||||
func newUpgradeClient(namespace string, cfg UpgradeConfig) (*helm.Upgrade, *helm.Configuration, error) {
|
||||
helmCfg, err := helmConfig(namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
client := helm.NewUpgrade(helmCfg)
|
||||
client.ResetValues = true
|
||||
client.Namespace = namespace
|
||||
client.CleanupOnFail = true
|
||||
client.Wait = true
|
||||
client.Timeout = time.Duration(cfg.Timeout) * time.Second //nolint:gosec
|
||||
|
||||
return client, helmCfg, nil
|
||||
}
|
||||
|
|
|
@ -31,6 +31,38 @@ func TestHAMode(t *testing.T) {
|
|||
assert.True(t, r)
|
||||
})
|
||||
|
||||
t.Run("ha mode with scheduler and other services", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
Name: "dapr-scheduler-server",
|
||||
Replicas: 3,
|
||||
},
|
||||
{
|
||||
Name: "dapr-placement-server",
|
||||
Replicas: 3,
|
||||
},
|
||||
}
|
||||
|
||||
r := highAvailabilityEnabled(s)
|
||||
assert.True(t, r)
|
||||
})
|
||||
|
||||
t.Run("non-ha mode with only scheduler image variant", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
Name: "dapr-scheduler-server-mariner",
|
||||
Replicas: 3,
|
||||
},
|
||||
{
|
||||
Name: "dapr-placement-server-mariner",
|
||||
Replicas: 3,
|
||||
},
|
||||
}
|
||||
|
||||
r := highAvailabilityEnabled(s)
|
||||
assert.True(t, r)
|
||||
})
|
||||
|
||||
t.Run("non-ha mode", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
|
@ -41,6 +73,46 @@ func TestHAMode(t *testing.T) {
|
|||
r := highAvailabilityEnabled(s)
|
||||
assert.False(t, r)
|
||||
})
|
||||
|
||||
t.Run("non-ha mode with scheduler and other services", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
Name: "dapr-scheduler-server",
|
||||
Replicas: 3,
|
||||
},
|
||||
{
|
||||
Name: "dapr-placement-server",
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
|
||||
r := highAvailabilityEnabled(s)
|
||||
assert.False(t, r)
|
||||
})
|
||||
|
||||
t.Run("non-ha mode with only scheduler", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
Name: "dapr-scheduler-server",
|
||||
Replicas: 3,
|
||||
},
|
||||
}
|
||||
|
||||
r := highAvailabilityEnabled(s)
|
||||
assert.False(t, r)
|
||||
})
|
||||
|
||||
t.Run("non-ha mode with only scheduler image variant", func(t *testing.T) {
|
||||
s := []StatusOutput{
|
||||
{
|
||||
Name: "dapr-scheduler-server-mariner",
|
||||
Replicas: 3,
|
||||
},
|
||||
}
|
||||
|
||||
r := highAvailabilityEnabled(s)
|
||||
assert.False(t, r)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMTLSChartValues(t *testing.T) {
|
||||
|
|
|
@ -75,7 +75,7 @@ func Put(httpPort int, key, value, appID, socket string) error {
|
|||
|
||||
url := makeMetadataPutEndpoint(httpPort, key)
|
||||
|
||||
req, err := retryablehttp.NewRequest("PUT", url, strings.NewReader(value))
|
||||
req, err := retryablehttp.NewRequest(http.MethodPut, url, strings.NewReader(value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -29,6 +32,16 @@ const (
|
|||
windowsOS = "windows"
|
||||
)
|
||||
|
||||
type logStatus string
|
||||
|
||||
const (
|
||||
LogSuccess logStatus = "success"
|
||||
LogFailure logStatus = "failure"
|
||||
LogWarning logStatus = "warning"
|
||||
LogInfo logStatus = "info"
|
||||
LogPending logStatus = "pending"
|
||||
)
|
||||
|
||||
type Result bool
|
||||
|
||||
const (
|
||||
|
@ -56,10 +69,36 @@ func IsJSONLogEnabled() bool {
|
|||
return logAsJSON
|
||||
}
|
||||
|
||||
// StatusEvent reports a event log with given status.
|
||||
func StatusEvent(w io.Writer, status logStatus, fmtstr string, a ...any) {
|
||||
if logAsJSON {
|
||||
logJSON(w, string(status), fmt.Sprintf(fmtstr, a...))
|
||||
return
|
||||
}
|
||||
if (w != os.Stdout && w != os.Stderr) || runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
return
|
||||
}
|
||||
switch status {
|
||||
case LogSuccess:
|
||||
fmt.Fprintf(w, "✅ %s\n", fmt.Sprintf(fmtstr, a...))
|
||||
case LogFailure:
|
||||
fmt.Fprintf(w, "❌ %s\n", fmt.Sprintf(fmtstr, a...))
|
||||
case LogWarning:
|
||||
fmt.Fprintf(w, "⚠ %s\n", fmt.Sprintf(fmtstr, a...))
|
||||
case LogPending:
|
||||
fmt.Fprintf(w, "⌛ %s\n", fmt.Sprintf(fmtstr, a...))
|
||||
case LogInfo:
|
||||
fmt.Fprintf(w, "ℹ️ %s\n", fmt.Sprintf(fmtstr, a...))
|
||||
default:
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
}
|
||||
}
|
||||
|
||||
// SuccessStatusEvent reports on a success event.
|
||||
func SuccessStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
||||
if logAsJSON {
|
||||
logJSON(w, "success", fmt.Sprintf(fmtstr, a...))
|
||||
logJSON(w, string(LogSuccess), fmt.Sprintf(fmtstr, a...))
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
} else {
|
||||
|
@ -70,7 +109,7 @@ func SuccessStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
|||
// FailureStatusEvent reports on a failure event.
|
||||
func FailureStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
||||
if logAsJSON {
|
||||
logJSON(w, "failure", fmt.Sprintf(fmtstr, a...))
|
||||
logJSON(w, string(LogFailure), fmt.Sprintf(fmtstr, a...))
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
} else {
|
||||
|
@ -81,7 +120,7 @@ func FailureStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
|||
// WarningStatusEvent reports on a failure event.
|
||||
func WarningStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
||||
if logAsJSON {
|
||||
logJSON(w, "warning", fmt.Sprintf(fmtstr, a...))
|
||||
logJSON(w, string(LogWarning), fmt.Sprintf(fmtstr, a...))
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
} else {
|
||||
|
@ -92,7 +131,7 @@ func WarningStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
|||
// PendingStatusEvent reports on a pending event.
|
||||
func PendingStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
||||
if logAsJSON {
|
||||
logJSON(w, "pending", fmt.Sprintf(fmtstr, a...))
|
||||
logJSON(w, string(LogPending), fmt.Sprintf(fmtstr, a...))
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
} else {
|
||||
|
@ -103,7 +142,7 @@ func PendingStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
|||
// InfoStatusEvent reports status information on an event.
|
||||
func InfoStatusEvent(w io.Writer, fmtstr string, a ...interface{}) {
|
||||
if logAsJSON {
|
||||
logJSON(w, "info", fmt.Sprintf(fmtstr, a...))
|
||||
logJSON(w, string(LogInfo), fmt.Sprintf(fmtstr, a...))
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", fmt.Sprintf(fmtstr, a...))
|
||||
} else {
|
||||
|
@ -117,7 +156,7 @@ func Spinner(w io.Writer, fmtstr string, a ...interface{}) func(result Result) {
|
|||
var s *spinner.Spinner
|
||||
|
||||
if logAsJSON {
|
||||
logJSON(w, "pending", msg)
|
||||
logJSON(w, string(LogPending), msg)
|
||||
} else if runtime.GOOS == windowsOS {
|
||||
fmt.Fprintf(w, "%s\n", msg)
|
||||
|
||||
|
@ -167,3 +206,37 @@ func logJSON(w io.Writer, status, message string) {
|
|||
|
||||
fmt.Fprintf(w, "%s\n", string(jsonBytes))
|
||||
}
|
||||
|
||||
type CustomLogWriter struct {
|
||||
W io.Writer
|
||||
}
|
||||
|
||||
func (c CustomLogWriter) Write(p []byte) (int, error) {
|
||||
write := func(w io.Writer, isStdIO bool) (int, error) {
|
||||
b := p
|
||||
if !isStdIO {
|
||||
// below regex is used to replace the color codes from the logs collected in the log file.
|
||||
reg := regexp.MustCompile("\x1b\\[[\\d;]+m")
|
||||
b = reg.ReplaceAll(b, []byte(""))
|
||||
}
|
||||
n, err := w.Write(b)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if n != len(b) {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
wIface := reflect.ValueOf(c.W).Interface()
|
||||
switch wType := wIface.(type) {
|
||||
case *os.File:
|
||||
if wType == os.Stderr || wType == os.Stdout {
|
||||
return write(c.W, true)
|
||||
} else {
|
||||
return write(c.W, false)
|
||||
}
|
||||
default:
|
||||
return write(c.W, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func tryGetRunDataLock() (*lockfile.Lockfile, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
err = lockFile.TryLock()
|
||||
|
||||
// Error handling is essential, as we only try to get the lock.
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runexec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/dapr/cli/pkg/runfileconfig"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
type CmdProcess struct {
|
||||
Command *exec.Cmd
|
||||
CommandErr error
|
||||
OutputWriter io.Writer
|
||||
ErrorWriter io.Writer
|
||||
}
|
||||
|
||||
type RunExec struct {
|
||||
DaprCMD *CmdProcess
|
||||
AppCMD *CmdProcess
|
||||
AppID string
|
||||
DaprHTTPPort int
|
||||
DaprGRPCPort int
|
||||
DaprMetricPort int
|
||||
}
|
||||
|
||||
// RunOutput represents the run execution.
|
||||
type RunOutput struct {
|
||||
DaprCMD *exec.Cmd
|
||||
DaprErr error
|
||||
DaprHTTPPort int
|
||||
DaprGRPCPort int
|
||||
AppID string
|
||||
AppCMD *exec.Cmd
|
||||
AppErr error
|
||||
}
|
||||
|
||||
func New(config *standalone.RunConfig, daprCmdProcess *CmdProcess, appCmdProcess *CmdProcess) *RunExec {
|
||||
return &RunExec{
|
||||
DaprCMD: daprCmdProcess,
|
||||
AppCMD: appCmdProcess,
|
||||
AppID: config.AppID,
|
||||
DaprHTTPPort: config.HTTPPort,
|
||||
DaprGRPCPort: config.GRPCPort,
|
||||
DaprMetricPort: config.MetricsPort,
|
||||
}
|
||||
}
|
||||
|
||||
func GetDaprCmdProcess(config *standalone.RunConfig) (*CmdProcess, error) {
|
||||
daprCMD, err := standalone.GetDaprCommand(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CmdProcess{
|
||||
Command: daprCMD,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetAppCmdProcess(config *standalone.RunConfig) (*CmdProcess, error) {
|
||||
//nolint
|
||||
var appCMD *exec.Cmd = standalone.GetAppCommand(config)
|
||||
return &CmdProcess{
|
||||
Command: appCMD,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CmdProcess) WithOutputWriter(w io.Writer) {
|
||||
c.OutputWriter = w
|
||||
}
|
||||
|
||||
// SetStdout should be called after WithOutputWriter.
|
||||
func (c *CmdProcess) SetStdout() error {
|
||||
if c.Command == nil {
|
||||
return errors.New("command is nil")
|
||||
}
|
||||
c.Command.Stdout = c.OutputWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CmdProcess) WithErrorWriter(w io.Writer) {
|
||||
c.ErrorWriter = w
|
||||
}
|
||||
|
||||
// SetStdErr should be called after WithErrorWriter.
|
||||
func (c *CmdProcess) SetStderr() error {
|
||||
if c.Command == nil {
|
||||
return errors.New("command is nil")
|
||||
}
|
||||
c.Command.Stderr = c.ErrorWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewOutput(config *standalone.RunConfig) (*RunOutput, error) {
|
||||
// set default values from RunConfig struct's tag.
|
||||
config.SetDefaultFromSchema()
|
||||
|
||||
err := config.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
daprCMD, err := standalone.GetDaprCommand(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint
|
||||
var appCMD *exec.Cmd = standalone.GetAppCommand(config)
|
||||
return &RunOutput{
|
||||
DaprCMD: daprCMD,
|
||||
DaprErr: nil,
|
||||
AppCMD: appCMD,
|
||||
AppErr: nil,
|
||||
AppID: config.AppID,
|
||||
DaprHTTPPort: config.HTTPPort,
|
||||
DaprGRPCPort: config.GRPCPort,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetAppDaprdWriter returns the writer for writing logs common to both daprd, app and stdout.
|
||||
func GetAppDaprdWriter(app runfileconfig.App, isAppCommandEmpty bool) io.Writer {
|
||||
var appDaprdWriter io.Writer
|
||||
if isAppCommandEmpty {
|
||||
if app.DaprdLogDestination != standalone.Console {
|
||||
appDaprdWriter = io.MultiWriter(os.Stdout, app.DaprdLogWriteCloser)
|
||||
} else {
|
||||
appDaprdWriter = os.Stdout
|
||||
}
|
||||
} else {
|
||||
if app.AppLogDestination != standalone.Console && app.DaprdLogDestination != standalone.Console {
|
||||
appDaprdWriter = io.MultiWriter(app.AppLogWriteCloser, app.DaprdLogWriteCloser, os.Stdout)
|
||||
} else if app.AppLogDestination != standalone.Console {
|
||||
appDaprdWriter = io.MultiWriter(app.AppLogWriteCloser, os.Stdout)
|
||||
} else if app.DaprdLogDestination != standalone.Console {
|
||||
appDaprdWriter = io.MultiWriter(app.DaprdLogWriteCloser, os.Stdout)
|
||||
} else {
|
||||
appDaprdWriter = os.Stdout
|
||||
}
|
||||
}
|
||||
return appDaprdWriter
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runexec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
func assertArgumentEqual(t *testing.T, key string, expectedValue string, args []string) {
|
||||
var value string
|
||||
for index, arg := range args {
|
||||
if arg == "--"+key {
|
||||
nextIndex := index + 1
|
||||
if nextIndex < len(args) {
|
||||
if !strings.HasPrefix(args[nextIndex], "--") {
|
||||
value = args[nextIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedValue, value)
|
||||
}
|
||||
|
||||
func assertArgumentNotEqual(t *testing.T, key string, expectedValue string, args []string) {
|
||||
var value string
|
||||
for index, arg := range args {
|
||||
if arg == "--"+key {
|
||||
nextIndex := index + 1
|
||||
if nextIndex < len(args) {
|
||||
if !strings.HasPrefix(args[nextIndex], "--") {
|
||||
value = args[nextIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotEqual(t, expectedValue, value)
|
||||
}
|
||||
|
||||
func assertArgumentContains(t *testing.T, key string, expectedValue string, args []string) {
|
||||
var value string
|
||||
for index, arg := range args {
|
||||
if arg == "--"+key {
|
||||
nextIndex := index + 1
|
||||
if nextIndex < len(args) {
|
||||
if !strings.HasPrefix(args[nextIndex], "--") {
|
||||
value = args[nextIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.Contains(t, value, expectedValue)
|
||||
}
|
||||
|
||||
func setupRun(t *testing.T) {
|
||||
myDaprPath, err := standalone.GetDaprRuntimePath("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
|
||||
configFile := standalone.GetDaprConfigPath(myDaprPath)
|
||||
err = os.MkdirAll(componentsDir, 0o700)
|
||||
assert.NoError(t, err, "Unable to setup components dir before running test")
|
||||
file, err := os.Create(configFile)
|
||||
file.Close()
|
||||
assert.NoError(t, err, "Unable to create config file before running test")
|
||||
}
|
||||
|
||||
func tearDownRun(t *testing.T) {
|
||||
myDaprPath, err := standalone.GetDaprRuntimePath("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
|
||||
configFile := standalone.GetDaprConfigPath(myDaprPath)
|
||||
|
||||
err = os.RemoveAll(componentsDir)
|
||||
assert.NoError(t, err, "Unable to delete default components dir after running test")
|
||||
err = os.Remove(configFile)
|
||||
assert.NoError(t, err, "Unable to delete default config file after running test")
|
||||
}
|
||||
|
||||
func assertCommonArgs(t *testing.T, basicConfig *standalone.RunConfig, output *RunOutput) {
|
||||
assert.NotNil(t, output)
|
||||
|
||||
assert.Equal(t, "MyID", output.AppID)
|
||||
assert.Equal(t, 8000, output.DaprHTTPPort)
|
||||
assert.Equal(t, 50001, output.DaprGRPCPort)
|
||||
|
||||
daprPath, err := standalone.GetDaprRuntimePath("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, output.DaprCMD.Args[0], "daprd")
|
||||
assertArgumentEqual(t, "app-id", "MyID", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "dapr-http-port", "8000", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "dapr-grpc-port", "50001", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "log-level", basicConfig.LogLevel, output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "app-max-concurrency", "-1", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "app-protocol", "http", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "app-port", "3000", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "components-path", standalone.GetDaprComponentsPath(daprPath), output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "app-ssl", "", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "metrics-port", "9001", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "max-body-size", "-1", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "dapr-internal-grpc-port", "5050", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "read-buffer-size", "-1", output.DaprCMD.Args)
|
||||
assertArgumentEqual(t, "dapr-listen-addresses", "127.0.0.1", output.DaprCMD.Args)
|
||||
}
|
||||
|
||||
func assertAppEnv(t *testing.T, config *standalone.RunConfig, output *RunOutput) {
|
||||
envSet := make(map[string]bool)
|
||||
for _, env := range output.AppCMD.Env {
|
||||
envSet[env] = true
|
||||
}
|
||||
|
||||
expectedEnvSet := getEnvSet(config)
|
||||
for _, env := range expectedEnvSet {
|
||||
_, found := envSet[env]
|
||||
if !found {
|
||||
assert.Fail(t, "Missing environment variable. Expected to have "+env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvSet(config *standalone.RunConfig) []string {
|
||||
set := []string{
|
||||
getEnv("DAPR_GRPC_PORT", config.GRPCPort),
|
||||
getEnv("DAPR_HTTP_PORT", config.HTTPPort),
|
||||
getEnv("DAPR_METRICS_PORT", config.MetricsPort),
|
||||
getEnv("APP_ID", config.AppID),
|
||||
}
|
||||
if config.AppPort > 0 {
|
||||
set = append(set, getEnv("APP_PORT", config.AppPort))
|
||||
}
|
||||
if config.EnableProfiling {
|
||||
set = append(set, getEnv("DAPR_PROFILE_PORT", config.ProfilePort))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func getEnv(key string, value interface{}) string {
|
||||
return fmt.Sprintf("%s=%v", key, value)
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
// Setup the components directory which is done at init time.
|
||||
setupRun(t)
|
||||
|
||||
// Setup the tearDown routine to run in the end.
|
||||
defer tearDownRun(t)
|
||||
|
||||
myDaprPath, err := standalone.GetDaprRuntimePath("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
|
||||
configFile := standalone.GetDaprConfigPath(myDaprPath)
|
||||
|
||||
sharedRunConfig := &standalone.SharedRunConfig{
|
||||
LogLevel: "WARN",
|
||||
EnableProfiling: false,
|
||||
AppProtocol: "http",
|
||||
ComponentsPath: componentsDir,
|
||||
AppSSL: true,
|
||||
MaxRequestBodySize: "-1",
|
||||
HTTPReadBufferSize: "-1",
|
||||
EnableAPILogging: true,
|
||||
APIListenAddresses: "127.0.0.1",
|
||||
}
|
||||
basicConfig := &standalone.RunConfig{
|
||||
AppID: "MyID",
|
||||
AppPort: 3000,
|
||||
HTTPPort: 8000,
|
||||
GRPCPort: 50001,
|
||||
Command: []string{"MyCommand", "--my-arg"},
|
||||
ProfilePort: 9090,
|
||||
MetricsPort: 9001,
|
||||
InternalGRPCPort: 5050,
|
||||
AppChannelAddress: "localhost",
|
||||
SharedRunConfig: *sharedRunConfig,
|
||||
}
|
||||
|
||||
t.Run("run happy http", func(t *testing.T) {
|
||||
output, err := NewOutput(basicConfig)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assertCommonArgs(t, basicConfig, output)
|
||||
assert.Equal(t, "MyCommand", output.AppCMD.Args[0])
|
||||
assert.Equal(t, "--my-arg", output.AppCMD.Args[1])
|
||||
assertArgumentEqual(t, "app-channel-address", "localhost", output.DaprCMD.Args)
|
||||
assertAppEnv(t, basicConfig, output)
|
||||
})
|
||||
|
||||
t.Run("run without app command", func(t *testing.T) {
|
||||
basicConfig.Command = nil
|
||||
basicConfig.LogLevel = "INFO"
|
||||
basicConfig.EnableAPILogging = true
|
||||
basicConfig.ConfigFile = configFile
|
||||
output, err := NewOutput(basicConfig)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assertCommonArgs(t, basicConfig, output)
|
||||
assertArgumentContains(t, "config", standalone.DefaultConfigFileName, output.DaprCMD.Args)
|
||||
assert.Nil(t, output.AppCMD)
|
||||
})
|
||||
|
||||
t.Run("run without port", func(t *testing.T) {
|
||||
basicConfig.HTTPPort = -1
|
||||
basicConfig.GRPCPort = -1
|
||||
basicConfig.MetricsPort = -1
|
||||
output, err := NewOutput(basicConfig)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, output)
|
||||
|
||||
assertArgumentNotEqual(t, "http-port", "-1", output.DaprCMD.Args)
|
||||
assertArgumentNotEqual(t, "grpc-port", "-1", output.DaprCMD.Args)
|
||||
assertArgumentNotEqual(t, "metrics-port", "-1", output.DaprCMD.Args)
|
||||
})
|
||||
|
||||
t.Run("app health check flags missing if not set", func(t *testing.T) {
|
||||
output, err := NewOutput(basicConfig)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, output)
|
||||
|
||||
argsFlattened := strings.Join(output.DaprCMD.Args, " ")
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--enable-app-health-check( |$)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-check-path( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-probe-interval( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-probe-timeout( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-threshold( |=)`), argsFlattened)
|
||||
})
|
||||
|
||||
t.Run("enable app health checks with default flags", func(t *testing.T) {
|
||||
basicConfig.EnableAppHealth = true
|
||||
output, err := NewOutput(basicConfig)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, output)
|
||||
|
||||
argsFlattened := strings.Join(output.DaprCMD.Args, " ")
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--enable-app-health-check( |$)`), argsFlattened)
|
||||
|
||||
// Other flags are not included so daprd can use the default value.
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-check-path( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-probe-interval( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-probe-timeout( |=)`), argsFlattened)
|
||||
assert.NotRegexp(t, regexp.MustCompile(`( |^)--app-health-threshold( |=)`), argsFlattened)
|
||||
})
|
||||
|
||||
t.Run("enable app health checks with all flags set", func(t *testing.T) {
|
||||
basicConfig.EnableAppHealth = true
|
||||
basicConfig.AppHealthInterval = 2
|
||||
basicConfig.AppHealthTimeout = 200
|
||||
basicConfig.AppHealthThreshold = 1
|
||||
basicConfig.AppHealthPath = "/foo"
|
||||
output, err := NewOutput(basicConfig)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, output)
|
||||
|
||||
argsFlattened := strings.Join(output.DaprCMD.Args, " ")
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--enable-app-health-check( |$)`), argsFlattened)
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--app-health-check-path( |=)/foo`), argsFlattened)
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--app-health-probe-interval( |=)2`), argsFlattened)
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--app-health-probe-timeout( |=)200`), argsFlattened)
|
||||
assert.Regexp(t, regexp.MustCompile(`( |^)--app-health-threshold( |=)1`), argsFlattened)
|
||||
})
|
||||
|
||||
t.Run("test setting defaults from struct tag", func(t *testing.T) {
|
||||
basicConfig.AppPort = 0
|
||||
basicConfig.HTTPPort = 0
|
||||
basicConfig.GRPCPort = 0
|
||||
basicConfig.MetricsPort = 0
|
||||
basicConfig.ProfilePort = 0
|
||||
basicConfig.EnableProfiling = true
|
||||
basicConfig.MaxConcurrency = 0
|
||||
basicConfig.MaxRequestBodySize = ""
|
||||
basicConfig.HTTPReadBufferSize = ""
|
||||
basicConfig.AppProtocol = ""
|
||||
|
||||
basicConfig.SetDefaultFromSchema()
|
||||
|
||||
assert.Equal(t, -1, basicConfig.AppPort)
|
||||
assert.Equal(t, -1, basicConfig.HTTPPort)
|
||||
assert.Equal(t, -1, basicConfig.GRPCPort)
|
||||
assert.Equal(t, -1, basicConfig.MetricsPort)
|
||||
assert.Equal(t, -1, basicConfig.ProfilePort)
|
||||
assert.True(t, basicConfig.EnableProfiling)
|
||||
assert.Equal(t, -1, basicConfig.MaxConcurrency)
|
||||
assert.Equal(t, "4Mi", basicConfig.MaxRequestBodySize)
|
||||
assert.Equal(t, "4Ki", basicConfig.HTTPReadBufferSize)
|
||||
assert.Equal(t, "http", basicConfig.AppProtocol)
|
||||
|
||||
// Test after Validate gets called.
|
||||
err := basicConfig.Validate()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 0, basicConfig.AppPort)
|
||||
assert.Positive(t, basicConfig.HTTPPort)
|
||||
assert.Positive(t, basicConfig.GRPCPort)
|
||||
assert.Positive(t, basicConfig.MetricsPort)
|
||||
assert.Positive(t, basicConfig.ProfilePort)
|
||||
assert.True(t, basicConfig.EnableProfiling)
|
||||
assert.Equal(t, -1, basicConfig.MaxConcurrency)
|
||||
assert.Equal(t, "4Mi", basicConfig.MaxRequestBodySize)
|
||||
assert.Equal(t, "4Ki", basicConfig.HTTPReadBufferSize)
|
||||
assert.Equal(t, "http", basicConfig.AppProtocol)
|
||||
})
|
||||
|
||||
t.Run("run with max body size without units", func(t *testing.T) {
|
||||
basicConfig.MaxRequestBodySize = "4000000"
|
||||
|
||||
output, err := NewOutput(basicConfig)
|
||||
require.NoError(t, err)
|
||||
assertArgumentEqual(t, "max-body-size", "4M", output.DaprCMD.Args)
|
||||
})
|
||||
|
||||
t.Run("run with max body size with units", func(t *testing.T) {
|
||||
basicConfig.MaxRequestBodySize = "4Mi"
|
||||
|
||||
output, err := NewOutput(basicConfig)
|
||||
require.NoError(t, err)
|
||||
assertArgumentEqual(t, "max-body-size", "4Mi", output.DaprCMD.Args)
|
||||
|
||||
basicConfig.MaxRequestBodySize = "5M"
|
||||
|
||||
output, err = NewOutput(basicConfig)
|
||||
require.NoError(t, err)
|
||||
assertArgumentEqual(t, "max-body-size", "5M", output.DaprCMD.Args)
|
||||
})
|
||||
|
||||
t.Run("run with read buffer size set without units", func(t *testing.T) {
|
||||
basicConfig.HTTPReadBufferSize = "16001"
|
||||
|
||||
output, err := NewOutput(basicConfig)
|
||||
require.NoError(t, err)
|
||||
assertArgumentEqual(t, "read-buffer-size", "16001", output.DaprCMD.Args)
|
||||
})
|
||||
|
||||
t.Run("run with read buffer size set with units", func(t *testing.T) {
|
||||
basicConfig.HTTPReadBufferSize = "4Ki"
|
||||
|
||||
output, err := NewOutput(basicConfig)
|
||||
require.NoError(t, err)
|
||||
assertArgumentEqual(t, "read-buffer-size", "4Ki", output.DaprCMD.Args)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runfileconfig
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
const (
|
||||
appLogFileNamePrefix = "app"
|
||||
daprdLogFileNamePrefix = "daprd"
|
||||
logFileExtension = ".log"
|
||||
logsDir = "logs"
|
||||
deployDir = "deploy"
|
||||
)
|
||||
|
||||
// RunFileConfig represents the complete configuration options for the run file.
|
||||
// It is meant to be used with - "dapr run --run-file <path-to-run-file>" command.
|
||||
type RunFileConfig struct {
|
||||
Common Common `yaml:"common"`
|
||||
Apps []App `yaml:"apps"`
|
||||
Version int `yaml:"version"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerConfiguration represents the application container configuration parameters.
|
||||
type ContainerConfiguration struct {
|
||||
ContainerImage string `yaml:"containerImage"`
|
||||
ContainerImagePullPolicy string `yaml:"containerImagePullPolicy"`
|
||||
CreateService bool `yaml:"createService"`
|
||||
}
|
||||
|
||||
// App represents the configuration options for the apps in the run file.
|
||||
type App struct {
|
||||
standalone.RunConfig `yaml:",inline"`
|
||||
ContainerConfiguration `yaml:",inline"`
|
||||
AppDirPath string `yaml:"appDirPath"`
|
||||
AppLogFileName string
|
||||
DaprdLogFileName string
|
||||
AppLogWriteCloser io.WriteCloser
|
||||
DaprdLogWriteCloser io.WriteCloser
|
||||
}
|
||||
|
||||
// Common represents the configuration options for the common section in the run file.
|
||||
type Common struct {
|
||||
standalone.SharedRunConfig `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (a *App) GetLogsDir() string {
|
||||
logsPath := filepath.Join(a.AppDirPath, standalone.DefaultDaprDirName, logsDir)
|
||||
os.MkdirAll(logsPath, 0o755)
|
||||
return logsPath
|
||||
}
|
||||
|
||||
func (a *App) GetDeployDir() string {
|
||||
logsPath := filepath.Join(a.AppDirPath, standalone.DefaultDaprDirName, deployDir)
|
||||
os.MkdirAll(logsPath, 0o755)
|
||||
return logsPath
|
||||
}
|
||||
|
||||
// CreateAppLogFile creates the log file, sets internal file handle
|
||||
// and returns error if any.
|
||||
func (a *App) CreateAppLogFile() error {
|
||||
var err error
|
||||
var f *os.File
|
||||
if a.AppLogDestination == standalone.Console {
|
||||
f = os.Stdout
|
||||
} else {
|
||||
f, err = a.createLogFile(appLogFileNamePrefix)
|
||||
}
|
||||
if err == nil {
|
||||
a.AppLogWriteCloser = f
|
||||
a.AppLogFileName = f.Name()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateDaprdLogFile creates the log file, sets internal file handle
|
||||
// and returns error if any.
|
||||
func (a *App) CreateDaprdLogFile() error {
|
||||
var err error
|
||||
var f *os.File
|
||||
if a.DaprdLogDestination == standalone.Console {
|
||||
f = os.Stdout
|
||||
} else {
|
||||
f, err = a.createLogFile(daprdLogFileNamePrefix)
|
||||
}
|
||||
if err == nil {
|
||||
a.DaprdLogWriteCloser = f
|
||||
a.DaprdLogFileName = f.Name()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// createLogFile creates the log file and returns the file handle and error if any.
|
||||
// It also adds the app ID as a prefix and the current timestamp to the file name as a suffix.
|
||||
func (a *App) createLogFile(logType string) (*os.File, error) {
|
||||
logsPath := a.GetLogsDir()
|
||||
fpath := filepath.Join(logsPath, a.AppID+"_"+logType+"_"+time.Now().Format("20060102150405")+logFileExtension)
|
||||
f, err := os.Create(fpath)
|
||||
return f, err
|
||||
}
|
||||
|
||||
func (a *App) CloseAppLogFile() error {
|
||||
if a.AppLogWriteCloser != nil {
|
||||
err := a.AppLogWriteCloser.Close()
|
||||
a.AppLogWriteCloser = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) CloseDaprdLogFile() error {
|
||||
if a.DaprdLogWriteCloser != nil {
|
||||
err := a.DaprdLogWriteCloser.Close()
|
||||
a.DaprdLogWriteCloser = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLogWriter returns the log writer based on the log destination.
|
||||
func GetLogWriter(fileLogWriterCloser io.WriteCloser, logDestination standalone.LogDestType) io.Writer {
|
||||
var logWriter io.Writer
|
||||
switch logDestination {
|
||||
case standalone.Console:
|
||||
logWriter = os.Stdout
|
||||
case standalone.File:
|
||||
logWriter = fileLogWriterCloser
|
||||
case standalone.FileAndConsole:
|
||||
logWriter = io.MultiWriter(os.Stdout, fileLogWriterCloser)
|
||||
}
|
||||
return logWriter
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runfileconfig
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/dapr/cli/utils"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var imagePullPolicyValuesAllowed = []string{"Always", "Never", "IfNotPresent"}
|
||||
|
||||
// Parse the provided run file into a RunFileConfig struct.
|
||||
func (a *RunFileConfig) parseAppsConfig(runFilePath string) error {
|
||||
var err error
|
||||
bytes, err := utils.ReadFile(runFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = yaml.Unmarshal(bytes, &a)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in parsing the provided app config file: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateRunConfig validates the run file config for mandatory fields.
|
||||
// It also resolves relative paths to absolute paths and validates them.
|
||||
func (a *RunFileConfig) validateRunConfig(runFilePath string) error {
|
||||
baseDir, err := filepath.Abs(filepath.Dir(runFilePath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in getting the absolute path of the provided run template file: %w", err)
|
||||
}
|
||||
if a.Version == 0 {
|
||||
return errors.New("required field 'version' not found in the provided run template file")
|
||||
}
|
||||
|
||||
// resolve relative path to absolute and validate all paths in commons.
|
||||
err = a.resolvePathToAbsAndValidate(baseDir, &a.Common.ConfigFile, &a.Common.ResourcesPath, &a.Common.DaprdInstallPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolves common's section ResourcesPaths to absolute paths and validates them.
|
||||
for i := range a.Common.ResourcesPaths {
|
||||
err := a.resolvePathToAbsAndValidate(baseDir, &a.Common.ResourcesPaths[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Merge common's section ResourcesPaths and ResourcePath. ResourcesPaths will be single source of truth for resources to be loaded.
|
||||
if len(strings.TrimSpace(a.Common.ResourcesPath)) > 0 {
|
||||
a.Common.ResourcesPaths = append(a.Common.ResourcesPaths, a.Common.ResourcesPath)
|
||||
}
|
||||
|
||||
for i := range len(a.Apps) {
|
||||
if a.Apps[i].AppDirPath == "" {
|
||||
return errors.New("required field 'appDirPath' not found in the provided app config file")
|
||||
}
|
||||
// It resolves the relative AppDirPath to absolute path and validates it.
|
||||
err := a.resolvePathToAbsAndValidate(baseDir, &a.Apps[i].AppDirPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// All other relative paths present inside the specific app's in the YAML file, should be resolved relative to AppDirPath for that app.
|
||||
err = a.resolvePathToAbsAndValidate(a.Apps[i].AppDirPath, &a.Apps[i].ConfigFile, &a.Apps[i].ResourcesPath, &a.Apps[i].DaprdInstallPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolves ResourcesPaths to absolute paths and validates them.
|
||||
for j := range a.Apps[i].ResourcesPaths {
|
||||
err := a.resolvePathToAbsAndValidate(a.Apps[i].AppDirPath, &a.Apps[i].ResourcesPaths[j])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Merge app's section ResourcesPaths and ResourcePath. ResourcesPaths will be single source of truth for resources to be loaded.
|
||||
if len(strings.TrimSpace(a.Apps[i].ResourcesPath)) > 0 {
|
||||
a.Apps[i].ResourcesPaths = append(a.Apps[i].ResourcesPaths, a.Apps[i].ResourcesPath)
|
||||
}
|
||||
|
||||
// Check containerImagePullPolicy is valid.
|
||||
if a.Apps[i].ContainerImagePullPolicy != "" {
|
||||
if !utils.Contains(imagePullPolicyValuesAllowed, a.Apps[i].ContainerImagePullPolicy) {
|
||||
return fmt.Errorf("invalid containerImagePullPolicy: %s, allowed values: %s", a.Apps[i].ContainerImagePullPolicy, strings.Join(imagePullPolicyValuesAllowed, ", "))
|
||||
}
|
||||
} else {
|
||||
a.Apps[i].ContainerImagePullPolicy = "Always"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetApps orchestrates the parsing of supplied run file, validating fields and consolidating SharedRunConfig for the apps.
|
||||
// It returns a list of apps with the merged values for the SharedRunConfig from common section of the YAML file.
|
||||
func (a *RunFileConfig) GetApps(runFilePath string) ([]App, error) {
|
||||
err := a.parseAppsConfig(runFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = a.validateRunConfig(runFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = a.resolveResourcesAndConfigFilePaths()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.mergeCommonAndAppsSharedRunConfig()
|
||||
a.mergeCommonAndAppsEnv()
|
||||
|
||||
// Set and validates default fields in the run file.
|
||||
err = a.setDefaultFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a.Apps, nil
|
||||
}
|
||||
|
||||
// mergeCommonAndAppsSharedRunConfig merges the common section of the run file with the apps section.
|
||||
func (a *RunFileConfig) mergeCommonAndAppsSharedRunConfig() {
|
||||
sharedConfigType := reflect.TypeOf(a.Common.SharedRunConfig)
|
||||
fields := reflect.VisibleFields(sharedConfigType)
|
||||
// Iterate for each field in common(shared configurations).
|
||||
for _, field := range fields {
|
||||
val := reflect.ValueOf(a.Common.SharedRunConfig).FieldByName(field.Name)
|
||||
// Iterate for each app's configurations.
|
||||
for i := range a.Apps {
|
||||
appVal := reflect.ValueOf(a.Apps[i].RunConfig.SharedRunConfig).FieldByName(field.Name)
|
||||
// If apppVal is the default value for the type.
|
||||
if appVal.IsZero() {
|
||||
// Here FieldByName always returns a valid value, it can also be zero but the field always exists.
|
||||
reflect.ValueOf(&a.Apps[i].RunConfig.SharedRunConfig).
|
||||
Elem().
|
||||
FieldByName(field.Name).
|
||||
Set(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultFields sets the default values for the fields that are not provided in the run file.
|
||||
func (a *RunFileConfig) setDefaultFields() error {
|
||||
for i := range a.Apps {
|
||||
if err := a.setAppIDIfEmpty(&a.Apps[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.setAndValidateLogDestination(&a.Apps[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set AppID to the directory name of appDirPath.
|
||||
// appDirPath is a mandatory field in the run file and at this point it is already validated and resolved to its absolute path.
|
||||
func (a *RunFileConfig) setAppIDIfEmpty(app *App) error {
|
||||
if app.AppID == "" {
|
||||
basePath, err := a.getBasePathFromAbsPath(app.AppDirPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in setting the app id: %w", err)
|
||||
}
|
||||
app.AppID = basePath
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setAndValidateLogDestination sets the default log destination if not provided in the run file.
|
||||
// It also validates the log destination if provided.
|
||||
func (a *RunFileConfig) setAndValidateLogDestination(app *App) error {
|
||||
if app.DaprdLogDestination == "" {
|
||||
app.DaprdLogDestination = standalone.DefaultDaprdLogDest
|
||||
} else if err := app.DaprdLogDestination.IsValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
if app.AppLogDestination == "" {
|
||||
app.AppLogDestination = standalone.DefaultAppLogDest
|
||||
} else if err := app.AppLogDestination.IsValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gets the base path from the absolute path of the appDirPath.
|
||||
func (a *RunFileConfig) getBasePathFromAbsPath(appDirPath string) (string, error) {
|
||||
if filepath.IsAbs(appDirPath) {
|
||||
return filepath.Base(appDirPath), nil
|
||||
}
|
||||
return "", fmt.Errorf("error in getting the base path from the provided appDirPath %q: ", appDirPath)
|
||||
}
|
||||
|
||||
// resolvePathToAbsAndValidate resolves the relative paths in run file to absolute path and validates the file path.
|
||||
func (a *RunFileConfig) resolvePathToAbsAndValidate(baseDir string, paths ...*string) error {
|
||||
var err error
|
||||
for _, path := range paths {
|
||||
if *path == "" {
|
||||
continue
|
||||
}
|
||||
*path, err = utils.ResolveHomeDir(*path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absPath := utils.GetAbsPath(baseDir, *path)
|
||||
*path = absPath
|
||||
if err = utils.ValidateFilePath(*path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resolve resources and config file paths for each app.
|
||||
func (a *RunFileConfig) resolveResourcesAndConfigFilePaths() error {
|
||||
for i := range a.Apps {
|
||||
app := &a.Apps[i]
|
||||
// Make sure apps's "DaprPathCmdFlag" is updated here as it is used in deciding precedence for resources and config path.
|
||||
if app.DaprdInstallPath == "" {
|
||||
app.DaprdInstallPath = a.Common.DaprdInstallPath
|
||||
}
|
||||
|
||||
err := a.resolveResourcesFilePath(app)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in resolving resources path for app %q: %w", app.AppID, err)
|
||||
}
|
||||
|
||||
err = a.resolveConfigFilePath(app)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in resolving config file path for app %q: %w", app.AppID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mergeCommonAndAppsEnv merges env maps from common and individual apps.
|
||||
// Precedence order for envs -> apps[i].envs > common.envs.
|
||||
func (a *RunFileConfig) mergeCommonAndAppsEnv() {
|
||||
for i := range a.Apps {
|
||||
for k, v := range a.Common.Env {
|
||||
if _, ok := a.Apps[i].Env[k]; !ok {
|
||||
a.Apps[i].Env[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resolveResourcesFilePath resolves the resources path for the app.
|
||||
// Precedence order for resourcesPaths -> apps[i].resourcesPaths > apps[i].appDirPath/.dapr/resources > common.resourcesPaths > dapr default resources path.
|
||||
func (a *RunFileConfig) resolveResourcesFilePath(app *App) error {
|
||||
if len(app.ResourcesPaths) > 0 {
|
||||
return nil
|
||||
}
|
||||
localResourcesDir := filepath.Join(app.AppDirPath, standalone.DefaultDaprDirName, standalone.DefaultResourcesDirName)
|
||||
if err := utils.ValidateFilePath(localResourcesDir); err == nil {
|
||||
app.ResourcesPaths = []string{localResourcesDir}
|
||||
} else if len(a.Common.ResourcesPaths) > 0 {
|
||||
app.ResourcesPaths = append(app.ResourcesPaths, a.Common.ResourcesPaths...)
|
||||
} else {
|
||||
daprDirPath, err := standalone.GetDaprRuntimePath(app.DaprdInstallPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting dapr install path: %w", err)
|
||||
}
|
||||
app.ResourcesPaths = []string{standalone.GetDaprComponentsPath(daprDirPath)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveConfigFilePath resolves the config file path for the app.
|
||||
// Precedence order for configFile -> apps[i].configFile > apps[i].appDirPath/.dapr/config.yaml > common.configFile > dapr default config file.
|
||||
func (a *RunFileConfig) resolveConfigFilePath(app *App) error {
|
||||
if app.ConfigFile != "" {
|
||||
return nil
|
||||
}
|
||||
localConfigFile := filepath.Join(app.AppDirPath, standalone.DefaultDaprDirName, standalone.DefaultConfigFileName)
|
||||
if err := utils.ValidateFilePath(localConfigFile); err == nil {
|
||||
app.ConfigFile = localConfigFile
|
||||
} else if len(strings.TrimSpace(a.Common.ConfigFile)) > 0 {
|
||||
app.ConfigFile = a.Common.ConfigFile
|
||||
} else {
|
||||
daprDirPath, err := standalone.GetDaprRuntimePath(app.DaprdInstallPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting dapr install path: %w", err)
|
||||
}
|
||||
app.ConfigFile = standalone.GetDaprConfigPath(daprDirPath)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runfileconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
validRunFilePath = filepath.Join(".", "testdata", "test_run_config.yaml")
|
||||
invalidRunFilePath1 = filepath.Join(".", "testdata", "test_run_config_invalid_path.yaml")
|
||||
invalidRunFilePath2 = filepath.Join(".", "testdata", "test_run_config_empty_app_dir.yaml")
|
||||
runFileForPrecedenceRule = filepath.Join(".", "testdata", "test_run_config_precedence_rule.yaml")
|
||||
runFileForPrecedenceRuleDaprDir = filepath.Join(".", "testdata", "test_run_config_precedence_rule_dapr_dir.yaml")
|
||||
runFileForLogDestination = filepath.Join(".", "testdata", "test_run_config_log_destination.yaml")
|
||||
runFileForMultiResourcePaths = filepath.Join(".", "testdata", "test_run_config_multiple_resources_paths.yaml")
|
||||
|
||||
runFileForContainerImagePullPolicy = filepath.Join(".", "testdata", "test_run_config_container_image_pull_policy.yaml")
|
||||
runFileForContainerImagePullPolicyInvalid = filepath.Join(".", "testdata", "test_run_config_container_image_pull_policy_invalid.yaml")
|
||||
)
|
||||
|
||||
func TestRunConfigFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("test parse valid run template", func(t *testing.T) {
|
||||
appsRunConfig := RunFileConfig{}
|
||||
err := appsRunConfig.parseAppsConfig(validRunFilePath)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, appsRunConfig.Apps, 2)
|
||||
|
||||
assert.Equal(t, 1, appsRunConfig.Version)
|
||||
assert.NotEmpty(t, appsRunConfig.Common.ResourcesPath)
|
||||
assert.NotEmpty(t, appsRunConfig.Common.Env)
|
||||
|
||||
firstAppConfig := appsRunConfig.Apps[0]
|
||||
secondAppConfig := appsRunConfig.Apps[1]
|
||||
assert.Equal(t, "", firstAppConfig.AppID)
|
||||
assert.Equal(t, "GRPC", secondAppConfig.AppProtocol)
|
||||
assert.Equal(t, 8080, firstAppConfig.AppPort)
|
||||
assert.Equal(t, "", firstAppConfig.UnixDomainSocket)
|
||||
})
|
||||
|
||||
t.Run("test GetApps", func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
|
||||
apps, err := config.GetApps(validRunFilePath)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, apps, 2)
|
||||
assert.Equal(t, "webapp", apps[0].AppID)
|
||||
assert.Equal(t, "backend", apps[1].AppID)
|
||||
assert.Equal(t, "HTTP", apps[0].AppProtocol)
|
||||
assert.Equal(t, "GRPC", apps[1].AppProtocol)
|
||||
assert.Equal(t, 8080, apps[0].AppPort)
|
||||
assert.Equal(t, 3000, apps[1].AppPort)
|
||||
assert.Equal(t, 1, apps[0].AppHealthTimeout)
|
||||
assert.Equal(t, 10, apps[1].AppHealthTimeout)
|
||||
assert.Equal(t, "", apps[0].UnixDomainSocket)
|
||||
assert.Equal(t, "/tmp/test-socket", apps[1].UnixDomainSocket)
|
||||
|
||||
// test resourcesPath and configPath after precedence order logic.
|
||||
assert.Equal(t, filepath.Join(apps[0].AppDirPath, "resources"), apps[0].ResourcesPaths[0])
|
||||
assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPaths[0])
|
||||
|
||||
assert.Equal(t, filepath.Join(apps[0].AppDirPath, "config.yaml"), apps[0].ConfigFile)
|
||||
assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "config.yaml"), apps[1].ConfigFile)
|
||||
|
||||
// temporarily set apps[0].ResourcesPath to empty string to test it is getting picked from common section.
|
||||
apps[0].ResourcesPaths = []string{}
|
||||
config.resolveResourcesAndConfigFilePaths()
|
||||
assert.Equal(t, config.Common.ResourcesPaths[0], apps[0].ResourcesPaths[0])
|
||||
assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPaths[0])
|
||||
|
||||
// test merged envs from common and app sections.
|
||||
assert.Len(t, apps[0].Env, 2)
|
||||
assert.Len(t, apps[1].Env, 2)
|
||||
assert.Contains(t, apps[0].Env, "DEBUG")
|
||||
assert.Contains(t, apps[0].Env, "tty")
|
||||
assert.Contains(t, apps[1].Env, "DEBUG")
|
||||
assert.Contains(t, apps[1].Env, "tty")
|
||||
assert.Equal(t, "false", apps[0].Env["DEBUG"])
|
||||
assert.Equal(t, "sts", apps[0].Env["tty"])
|
||||
assert.Equal(t, "true", apps[1].Env["DEBUG"])
|
||||
assert.Equal(t, "sts", apps[1].Env["tty"])
|
||||
})
|
||||
|
||||
t.Run("test precedence logic for resources-path and dapr config file", func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
|
||||
err := config.parseAppsConfig(runFileForPrecedenceRule)
|
||||
assert.NoError(t, err)
|
||||
err = config.validateRunConfig(runFileForPrecedenceRule)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test precedence logic for resourcesPath and configPath.
|
||||
err = config.resolveResourcesAndConfigFilePaths()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
expectedResourcesPath string
|
||||
expectedConfigFilePath string
|
||||
appIndex int
|
||||
}{
|
||||
{
|
||||
name: "resourcesPaths and configPath are set in app section",
|
||||
expectedResourcesPath: filepath.Join(config.Apps[0].AppDirPath, "resources"),
|
||||
expectedConfigFilePath: filepath.Join(config.Apps[0].AppDirPath, "config.yaml"),
|
||||
appIndex: 0,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths and configPath present in .dapr directory under appDirPath",
|
||||
expectedResourcesPath: filepath.Join(config.Apps[1].AppDirPath, ".dapr", "resources"),
|
||||
expectedConfigFilePath: filepath.Join(config.Apps[1].AppDirPath, ".dapr", "config.yaml"),
|
||||
appIndex: 1,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths and configPath are resolved from common's section",
|
||||
expectedResourcesPath: config.Common.ResourcesPaths[0], // from common section.
|
||||
expectedConfigFilePath: config.Common.ConfigFile, // from common section.
|
||||
appIndex: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0])
|
||||
assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test precedence logic with daprInstallDir for resources-path and dapr config file", func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
|
||||
err := config.parseAppsConfig(runFileForPrecedenceRuleDaprDir)
|
||||
assert.NoError(t, err)
|
||||
err = config.validateRunConfig(runFileForPrecedenceRuleDaprDir)
|
||||
assert.NoError(t, err)
|
||||
|
||||
app1Data := getResourcesAndConfigFilePaths(t, config.Apps[0].DaprdInstallPath)
|
||||
app1ResourcesPath := app1Data[0]
|
||||
app1ConfigFilePath := app1Data[1]
|
||||
|
||||
app2Data := getResourcesAndConfigFilePaths(t, config.Apps[1].DaprdInstallPath)
|
||||
app2ResourcesPath := app2Data[0]
|
||||
app2ConfigFilePath := app2Data[1]
|
||||
|
||||
// test precedence logic for resourcesPath and configPath.
|
||||
err = config.resolveResourcesAndConfigFilePaths()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
expectedResourcesPath string
|
||||
expectedConfigFilePath string
|
||||
appIndex int
|
||||
}{
|
||||
{
|
||||
name: "resourcesPaths and configPath are resolved from dapr's default installation path.",
|
||||
expectedResourcesPath: app1ResourcesPath,
|
||||
expectedConfigFilePath: app1ConfigFilePath,
|
||||
appIndex: 0,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths and configPath are resolved from dapr's custom installation path.",
|
||||
expectedResourcesPath: app2ResourcesPath,
|
||||
expectedConfigFilePath: app2ConfigFilePath,
|
||||
appIndex: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0])
|
||||
assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test validate run config", func(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid run config",
|
||||
input: validRunFilePath,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid run config - empty app dir path",
|
||||
input: invalidRunFilePath2,
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid run config - invalid app dir path",
|
||||
input: invalidRunFilePath1,
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
config.parseAppsConfig(tc.input)
|
||||
actualErr := config.validateRunConfig(tc.input)
|
||||
assert.Equal(t, tc.expectedErr, actualErr != nil)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test log destination for daprd and apps", func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
apps, err := config.GetApps(runFileForLogDestination)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, apps, 6)
|
||||
|
||||
assert.Equal(t, "file", apps[0].DaprdLogDestination.String())
|
||||
assert.Equal(t, "fileAndConsole", apps[0].AppLogDestination.String())
|
||||
|
||||
assert.Equal(t, "fileAndConsole", apps[1].DaprdLogDestination.String())
|
||||
assert.Equal(t, "fileAndConsole", apps[1].AppLogDestination.String())
|
||||
|
||||
assert.Equal(t, "file", apps[2].DaprdLogDestination.String())
|
||||
assert.Equal(t, "file", apps[2].AppLogDestination.String())
|
||||
|
||||
assert.Equal(t, "console", apps[3].DaprdLogDestination.String())
|
||||
assert.Equal(t, "console", apps[3].AppLogDestination.String())
|
||||
|
||||
assert.Equal(t, "console", apps[4].DaprdLogDestination.String())
|
||||
assert.Equal(t, "file", apps[4].AppLogDestination.String())
|
||||
|
||||
assert.Equal(t, "file", apps[5].DaprdLogDestination.String())
|
||||
assert.Equal(t, "console", apps[5].AppLogDestination.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestContainerImagePullPolicy(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
runfFile string
|
||||
expectedPullPolicies []string
|
||||
expectedBadPolicyValue string
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "default value is Always",
|
||||
runfFile: validRunFilePath,
|
||||
expectedPullPolicies: []string{"Always", "Always"},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "custom value is respected",
|
||||
runfFile: runFileForContainerImagePullPolicy,
|
||||
expectedPullPolicies: []string{"IfNotPresent", "Always"},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid value is rejected",
|
||||
runfFile: runFileForContainerImagePullPolicyInvalid,
|
||||
expectedPullPolicies: []string{"Always", "Always"},
|
||||
expectedBadPolicyValue: "Invalid",
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
config.parseAppsConfig(tc.runfFile)
|
||||
err := config.validateRunConfig(tc.runfFile)
|
||||
if tc.expectedErr {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), fmt.Sprintf("invalid containerImagePullPolicy: %s, allowed values: Always, Never, IfNotPresent", tc.expectedBadPolicyValue))
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tc.expectedPullPolicies[0], config.Apps[0].ContainerImagePullPolicy)
|
||||
assert.Equal(t, tc.expectedPullPolicies[1], config.Apps[1].ContainerImagePullPolicy)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiResourcePathsResolution(t *testing.T) {
|
||||
config := RunFileConfig{}
|
||||
|
||||
err := config.parseAppsConfig(runFileForMultiResourcePaths)
|
||||
assert.NoError(t, err)
|
||||
err = config.validateRunConfig(runFileForMultiResourcePaths)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test precedence logic for multiple resources paths.
|
||||
err = config.resolveResourcesAndConfigFilePaths()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
expectedNoOfResources int
|
||||
expectedResourcesPathsContains string
|
||||
appIndex int
|
||||
}{
|
||||
{
|
||||
name: "resourcesPaths should have 2 paths",
|
||||
expectedNoOfResources: 2,
|
||||
expectedResourcesPathsContains: filepath.Join(config.Apps[0].AppDirPath, "resources"),
|
||||
appIndex: 0,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths should have 2 paths",
|
||||
expectedNoOfResources: 2,
|
||||
expectedResourcesPathsContains: filepath.Join("backend", ".dapr", "resources"),
|
||||
appIndex: 0,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths should have 2 path from common section",
|
||||
expectedNoOfResources: 2,
|
||||
expectedResourcesPathsContains: filepath.Join("app", "resources"),
|
||||
appIndex: 1,
|
||||
},
|
||||
{
|
||||
name: "resourcesPaths should have 1 path from .dapr's folder",
|
||||
expectedNoOfResources: 1,
|
||||
expectedResourcesPathsContains: filepath.Join("backend", ".dapr", "resources"),
|
||||
appIndex: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Len(t, config.Apps[tc.appIndex].ResourcesPaths, tc.expectedNoOfResources)
|
||||
var rsrcFound bool
|
||||
for _, resourcePath := range config.Apps[tc.appIndex].ResourcesPaths {
|
||||
if rsrcFound = strings.Contains(resourcePath, tc.expectedResourcesPathsContains); rsrcFound {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, rsrcFound)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBasePathFromAbsPath(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedErr bool
|
||||
expectedAppID string
|
||||
}{
|
||||
{
|
||||
name: "valid absolute path",
|
||||
input: filepath.Join(os.TempDir(), "test"),
|
||||
expectedErr: false,
|
||||
expectedAppID: "test",
|
||||
},
|
||||
{
|
||||
name: "invalid absolute path",
|
||||
input: filepath.Join("..", "test"),
|
||||
expectedErr: true,
|
||||
expectedAppID: "",
|
||||
},
|
||||
{
|
||||
name: "invalid absolute path",
|
||||
input: filepath.Join(".", "test"),
|
||||
expectedErr: true,
|
||||
expectedAppID: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runFileConfig := RunFileConfig{}
|
||||
appID, actualErr := runFileConfig.getBasePathFromAbsPath(tc.input)
|
||||
assert.Equal(t, tc.expectedErr, actualErr != nil)
|
||||
assert.Equal(t, tc.expectedAppID, appID)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getResoucresAndConfigFilePaths returns a list containing resources and config file paths in order.
|
||||
func getResourcesAndConfigFilePaths(t *testing.T, daprInstallPath string) []string {
|
||||
t.Helper()
|
||||
result := make([]string, 2)
|
||||
daprDirPath, err := standalone.GetDaprRuntimePath(daprInstallPath)
|
||||
assert.NoError(t, err)
|
||||
result[0] = standalone.GetDaprComponentsPath(daprDirPath)
|
||||
result[1] = standalone.GetDaprConfigPath(daprDirPath)
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
version: 1
|
||||
common:
|
||||
resourcesPath: ./app/resources
|
||||
appProtocol: HTTP
|
||||
appHealthProbeTimeout: 10
|
||||
env:
|
||||
DEBUG: false
|
||||
tty: sts
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
resourcesPath: ./resources
|
||||
configFilePath: ./config.yaml
|
||||
appPort: 8080
|
||||
appHealthProbeTimeout: 1
|
||||
command: ["python3", "app.py"]
|
||||
- appID: backend
|
||||
appDirPath: ./backend/
|
||||
appProtocol: GRPC
|
||||
appPort: 3000
|
||||
unixDomainSocket: /tmp/test-socket
|
||||
env:
|
||||
DEBUG: true
|
||||
command: ["./backend"]
|
|
@ -0,0 +1,24 @@
|
|||
version: 1
|
||||
common:
|
||||
resourcesPath: ./app/resources
|
||||
appProtocol: HTTP
|
||||
appHealthProbeTimeout: 10
|
||||
env:
|
||||
DEBUG: false
|
||||
tty: sts
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
resourcesPath: ./resources
|
||||
configFilePath: ./config.yaml
|
||||
appPort: 8080
|
||||
appHealthProbeTimeout: 1
|
||||
containerImagePullPolicy: IfNotPresent
|
||||
containerImage: ghcr.io/dapr/dapr-workflows-python-sdk:latest
|
||||
- appID: backend
|
||||
appDirPath: ./backend/
|
||||
appProtocol: GRPC
|
||||
appPort: 3000
|
||||
unixDomainSocket: /tmp/test-socket
|
||||
env:
|
||||
DEBUG: true
|
||||
containerImage: ghcr.io/dapr/dapr-workflows-csharp-sdk:latest
|
24
pkg/runfileconfig/testdata/test_run_config_container_image_pull_policy_invalid.yaml
vendored
Normal file
24
pkg/runfileconfig/testdata/test_run_config_container_image_pull_policy_invalid.yaml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
version: 1
|
||||
common:
|
||||
resourcesPath: ./app/resources
|
||||
appProtocol: HTTP
|
||||
appHealthProbeTimeout: 10
|
||||
env:
|
||||
DEBUG: false
|
||||
tty: sts
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
resourcesPath: ./resources
|
||||
configFilePath: ./config.yaml
|
||||
appPort: 8080
|
||||
appHealthProbeTimeout: 1
|
||||
containerImagePullPolicy: Invalid
|
||||
containerImage: ghcr.io/dapr/dapr-workflows-python-sdk:latest
|
||||
- appID: backend
|
||||
appDirPath: ./backend/
|
||||
appProtocol: GRPC
|
||||
appPort: 3000
|
||||
unixDomainSocket: /tmp/test-socket
|
||||
env:
|
||||
DEBUG: true
|
||||
containerImage: ghcr.io/dapr/dapr-workflows-csharp-sdk:latest
|
|
@ -0,0 +1,5 @@
|
|||
version: 1
|
||||
common:
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
- appID: backend
|
|
@ -0,0 +1,6 @@
|
|||
version: 1
|
||||
common:
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
- appID: backend
|
||||
appDirPath: ./invalid_backend/
|
|
@ -0,0 +1,25 @@
|
|||
version: 1
|
||||
common:
|
||||
apps:
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_1
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_2
|
||||
daprdLogDestination: fileAndConsole
|
||||
appLogDestination: fileAndConsole
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_3
|
||||
daprdLogDestination: file
|
||||
appLogDestination: file
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_4
|
||||
daprdLogDestination: console
|
||||
appLogDestination: console
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_5
|
||||
daprdLogDestination: console
|
||||
appLogDestination: file
|
||||
- appDirPath: ./webapp/
|
||||
appID: app_6
|
||||
daprdLogDestination: file
|
||||
appLogDestination: console
|
|
@ -0,0 +1,19 @@
|
|||
version: 1
|
||||
common:
|
||||
# resourcesPath and resourcesPaths should be combined into resourcesPaths and should contain 1 path to load resources from.
|
||||
resourcesPath: ./app/resources
|
||||
resourcesPaths:
|
||||
- ./app/resources
|
||||
configFilePath: ./app/config.yaml
|
||||
apps:
|
||||
# resourcesPaths should contain 2 paths to load resources from.
|
||||
- appDirPath: ./webapp/
|
||||
resourcesPath: ./resources
|
||||
resourcesPaths:
|
||||
- ../backend/.dapr/resources
|
||||
# resourcesPaths should be resolved from common's section and should contain 1 path to load resources from.
|
||||
- appDirPath: ./webapp/
|
||||
appID: webapp_1
|
||||
# resourcesPaths resolved from app/.dapr folder and should contain 1 path to load resources from.
|
||||
- appID: backend
|
||||
appDirPath: ./backend/
|
|
@ -0,0 +1,15 @@
|
|||
version: 1
|
||||
common:
|
||||
resourcesPath: ./app/resources
|
||||
configFilePath: ./app/config.yaml
|
||||
apps:
|
||||
# tests resourcesPath and config_file resolved from app's section.
|
||||
- appDirPath: ./webapp/
|
||||
resourcesPath: ./resources
|
||||
configFilePath: ./config.yaml
|
||||
# tests resourcesPath and config_file resolved from app/.dapr folder.
|
||||
- appID: backend
|
||||
appDirPath: ./backend/
|
||||
# tests resourcesPath and config_file resolved from common's section.
|
||||
- appID: app_common_section
|
||||
appDirPath: ./app_precedence_rule/
|
|
@ -0,0 +1,10 @@
|
|||
version: 1
|
||||
common:
|
||||
apps:
|
||||
# tests resourcesPath and config_file resolved from dapr's default installation directory.
|
||||
- appID: app_default_dapr_dir
|
||||
appDirPath: ./app_precedence_rule/
|
||||
# tests resourcesPath and config_file resolved from dapr's custom installation directory.
|
||||
- appID: app_custom_dapr_dir
|
||||
appDirPath: ./app_precedence_rule/
|
||||
runtimePath: ../custom_dapr_dir
|
|
@ -55,10 +55,10 @@ func isStringNilOrEmpty(val *string) bool {
|
|||
return val == nil || strings.TrimSpace(*val) == ""
|
||||
}
|
||||
|
||||
func (b *bundleDetails) getPlacementImageName() string {
|
||||
func (b *bundleDetails) getDaprImageName() string {
|
||||
return *b.DaprImageName
|
||||
}
|
||||
|
||||
func (b *bundleDetails) getPlacementImageFileName() string {
|
||||
func (b *bundleDetails) getDaprImageFileName() string {
|
||||
return *b.DaprImageFileName
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ func TestParseDetails(t *testing.T) {
|
|||
assert.Equal(t, "0.10.0", *bd.DashboardVersion, "expected versions to match")
|
||||
assert.Equal(t, "dist", *bd.BinarySubDir, "expected value to match")
|
||||
assert.Equal(t, "docker", *bd.ImageSubDir, "expected value to match")
|
||||
assert.Equal(t, "daprio/dapr:1.7.2", bd.getPlacementImageName(), "expected value to match")
|
||||
assert.Equal(t, "daprio-dapr-1.7.2.tar.gz", bd.getPlacementImageFileName(), "expected value to match")
|
||||
assert.Equal(t, "daprio/dapr:1.7.2", bd.getDaprImageName(), "expected value to match")
|
||||
assert.Equal(t, "daprio-dapr-1.7.2.tar.gz", bd.getDaprImageFileName(), "expected value to match")
|
||||
}
|
||||
|
||||
func TestParseDetailsMissingDetails(t *testing.T) {
|
||||
|
|
|
@ -17,25 +17,50 @@ import (
|
|||
"os"
|
||||
path_filepath "path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDaprDirName = ".dapr"
|
||||
defaultDaprBinDirName = "bin"
|
||||
defaultComponentsDirName = "components"
|
||||
defaultConfigFileName = "config.yaml"
|
||||
DefaultDaprDirName = ".dapr"
|
||||
DefaultConfigFileName = "config.yaml"
|
||||
DefaultResourcesDirName = "resources"
|
||||
|
||||
defaultDaprBinDirName = "bin"
|
||||
defaultComponentsDirName = "components"
|
||||
defaultSchedulerDirName = "scheduler"
|
||||
defaultSchedulerDataDirName = "data"
|
||||
)
|
||||
|
||||
func defaultDaprDirPath() string {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
return path_filepath.Join(homeDir, defaultDaprDirName)
|
||||
// GetDaprRuntimePath returns the dapr runtime installation path.
|
||||
// daprRuntimePath is based on the --runtime-path command line flag.
|
||||
// The order of precedence is:
|
||||
// 1. From --runtime-path command line flag appended with `.dapr`
|
||||
// 2. From DAPR_RUNTIME_PATH environment variable appended with `.dapr`
|
||||
// 3. default $HOME/.dapr
|
||||
func GetDaprRuntimePath(daprRuntimePath string) (string, error) {
|
||||
runtimePath := strings.TrimSpace(daprRuntimePath)
|
||||
if runtimePath != "" {
|
||||
return path_filepath.Join(runtimePath, DefaultDaprDirName), nil
|
||||
}
|
||||
|
||||
envRuntimePath := strings.TrimSpace(os.Getenv("DAPR_RUNTIME_PATH"))
|
||||
if envRuntimePath != "" {
|
||||
return path_filepath.Join(envRuntimePath, DefaultDaprDirName), nil
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path_filepath.Join(homeDir, DefaultDaprDirName), nil
|
||||
}
|
||||
|
||||
func defaultDaprBinPath() string {
|
||||
return path_filepath.Join(defaultDaprDirPath(), defaultDaprBinDirName)
|
||||
func getDaprBinPath(daprDir string) string {
|
||||
return path_filepath.Join(daprDir, defaultDaprBinDirName)
|
||||
}
|
||||
|
||||
func binaryFilePath(binaryDir string, binaryFilePrefix string) string {
|
||||
func binaryFilePathWithDir(binaryDir string, binaryFilePrefix string) string {
|
||||
binaryPath := path_filepath.Join(binaryDir, binaryFilePrefix)
|
||||
if runtime.GOOS == daprWindowsOS {
|
||||
binaryPath += ".exe"
|
||||
|
@ -43,10 +68,19 @@ func binaryFilePath(binaryDir string, binaryFilePrefix string) string {
|
|||
return binaryPath
|
||||
}
|
||||
|
||||
func DefaultComponentsDirPath() string {
|
||||
return path_filepath.Join(defaultDaprDirPath(), defaultComponentsDirName)
|
||||
func lookupBinaryFilePath(inputInstallPath string, binaryFilePrefix string) (string, error) {
|
||||
daprPath, err := GetDaprRuntimePath(inputInstallPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return binaryFilePathWithDir(getDaprBinPath(daprPath), binaryFilePrefix), nil
|
||||
}
|
||||
|
||||
func DefaultConfigFilePath() string {
|
||||
return path_filepath.Join(defaultDaprDirPath(), defaultConfigFileName)
|
||||
func GetDaprComponentsPath(daprDir string) string {
|
||||
return path_filepath.Join(daprDir, defaultComponentsDirName)
|
||||
}
|
||||
|
||||
func GetDaprConfigPath(daprDir string) string {
|
||||
return path_filepath.Join(daprDir, DefaultConfigFileName)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue