Merge branch 'master' into feat/interact-with-kubernetes-dapr-apps

This commit is contained in:
Yaron Schneider 2023-08-16 07:30:51 -07:00 committed by GitHub
commit 7bf3b40355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 3426 additions and 1314 deletions

View File

@ -12,16 +12,12 @@
// 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
@ -58,12 +54,27 @@
// Run the entrypoint defined in container image.
"--init"
],
"settings": {
"go.toolsManagement.checkForUpdates": "local",
"go.useLanguageServer": true,
"go.gopath": "/go",
"go.buildTags": "e2e,perf,conftests,unit,integration_test,certtests",
"git.alwaysSignOff": true
"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"

View File

@ -29,8 +29,7 @@ jobs:
name: Build ${{ matrix.target_os }}_${{ matrix.target_arch }} binaries
runs-on: ${{ matrix.os }}
env:
GOVER: 1.19.3
GOLANG_CI_LINT_VER: v1.49.0
GOLANG_CI_LINT_VER: v1.51.2
GOOS: ${{ matrix.target_os }}
GOARCH: ${{ matrix.target_arch }}
GOPROXY: https://proxy.golang.org
@ -57,12 +56,43 @@ jobs:
- os: macOS-latest
target_arch: arm
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
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
id: setup-go
with:
go-version-file: 'go.mod'
- name: Cache Go modules (Linux)
if: matrix.target_os == 'linux'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Cache Go modules (Windows)
if: matrix.target_os == 'windows'
uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Cache Go modules (macOS)
if: matrix.target_os == 'darwin'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Run golangci-lint
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
uses: golangci/golangci-lint-action@v3.2.0
@ -72,11 +102,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 +116,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 }}
@ -144,41 +169,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')
env:
WINGETCREATE_VERSION: 1.1.2.0
runs-on: windows-latest
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v3
- 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://github.com/microsoft/winget-create/releases/download/v${{ env.WINGETCREATE_VERSION }}/wingetcreate.exe -OutFile wingetcreate.exe
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 }}"
.\wingetcreate.exe update "$PackageIdentifier" --submit --urls "$url|x64" --version "${{ env.REL_VERSION }}" --token "${{ secrets.DAPR_BOT_TOKEN }}"

View File

@ -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@v3
- 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

View File

@ -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@v3
- 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@v3
- 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@v3
- 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

View File

@ -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@v3
- name: "Validate devcontainer-feature.json files"
uses: devcontainers/action@v1
with:
validate-only: "true"
base-path-to-features: "./dev-container-feature/src"

View File

@ -34,16 +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@v3
- 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 }}
# Disable fossa test due to a bug on fossa side.
# - name: "Run FOSSA Test"
# 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 }}
# run-tests: true

View File

@ -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@v3
# Install Dapr
- name: Install DAPR CLI

View File

@ -50,12 +50,11 @@ jobs:
name: E2E tests for K8s (KinD)
runs-on: ubuntu-latest
env:
GOVER: 1.19.3
DAPR_RUNTIME_PINNED_VERSION: 1.9.4
DAPR_DASHBOARD_PINNED_VERSION: 0.11.0
DAPR_RUNTIME_LATEST_VERSION:
DAPR_DASHBOARD_LATEST_VERSION:
DAPR_TGZ: dapr-1.9.4.tgz
DAPR_RUNTIME_PINNED_VERSION: 1.11.0
DAPR_DASHBOARD_PINNED_VERSION: 0.13.0
DAPR_RUNTIME_LATEST_STABLE_VERSION:
DAPR_DASHBOARD_LATEST_STABLE_VERSION:
DAPR_TGZ: dapr-1.11.0.tgz
strategy:
fail-fast: false # Keep running if one leg fails.
matrix:
@ -80,14 +79,24 @@ jobs:
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@v3
with:
path: ./src/github.com/dapr/cli
- name: Set up Go
uses: actions/setup-go@v3
id: setup-go
with:
go-version-file: './src/github.com/dapr/cli/go.mod'
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.k8s-version }}-${{ matrix.kind-version }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.k8s-version }}-${{ matrix.kind-version }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Configure KinD
# Generate a KinD configuration file that uses:
@ -115,7 +124,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
@ -131,37 +140,39 @@ jobs:
- name: Free up some diskspace
run: |
docker image prune -a -f
- name: Determine latest stable Dapr Runtime version
- name: Determine latest Dapr Runtime version including Pre-releases
if: github.base_ref == 'master'
run: |
export 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)
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 default version $DAPR_RUNTIME_PINNED_VERSION"
echo "DAPR_RUNTIME_LATEST_VERSION=$DAPR_RUNTIME_PINNED_VERSION" >> $GITHUB_ENV
echo "Could not fetch the latest Dapr Runtime version. Using pinned version $DAPR_RUNTIME_PINNED_VERSION"
else
echo "Found $RUNTIME_VERSION"
echo "DAPR_RUNTIME_LATEST_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
base_ref=${{ github.base_ref }}
echo "Branch $base_ref"
if [[ $base_ref = 'master' ]]; then
echo "DAPR_RUNTIME_PINNED_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
fi
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: |
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 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)
if [[ -z "$DASHBOARD_VERSION" ]]; then
echo "Could not fetch the latest Dapr Dashboard version. Using default version $DAPR_DASHBOARD_PINNED_VERSION"
echo "DAPR_DASHBOARD_LATEST_VERSION=$DAPR_DASHBOARD_PINNED_VERSION" >> $GITHUB_ENV
else
echo "Found $DASHBOARD_VERSION"
echo "DAPR_DASHBOARD_LATEST_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
base_ref=${{ github.base_ref }}
echo "Branch $base_ref"
if [[ $base_ref = 'master' ]]; then
echo "DAPR_DASHBOARD_PINNED_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
fi
fi
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

View 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,31 +18,31 @@ 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.3
GOOS: ${{ matrix.target_os }}
GOARCH: ${{ matrix.target_arch }}
GOPROXY: https://proxy.golang.org
ARCHIVE_OUTDIR: dist/archives
DAPR_RUNTIME_PINNED_VERSION: "1.9.4"
DAPR_DASHBOARD_PINNED_VERSION: 0.11.0
DAPR_RUNTIME_LATEST_VERSION:
DAPR_DASHBOARD_LATEST_VERSION:
DAPR_RUNTIME_PINNED_VERSION: "1.11.0"
DAPR_DASHBOARD_PINNED_VERSION: 0.13.0
DAPR_RUNTIME_LATEST_STABLE_VERSION:
DAPR_DASHBOARD_LATEST_STABLE_VERSION:
PODMAN_VERSION: 4.4.4
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
@ -60,59 +59,95 @@ 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
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
id: setup-go
with:
go-version-file: "go.mod"
- name: Cache Go modules (Linux)
if: matrix.target_os == 'linux'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Cache Go modules (Windows)
if: matrix.target_os == 'windows'
uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Cache Go modules (macOS)
if: matrix.target_os == 'darwin'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.target_os }}-${{ matrix.target_arch }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Install podman - MacOS
timeout-minutes: 15
if: matrix.os == 'macos-latest' && matrix.dapr_install_mode == 'complete'
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
# 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
podman machine start
podman machine start --log-level debug
echo "CONTAINER_RUNTIME=podman" >> $GITHUB_ENV
- name: Determine latest stable Dapr Runtime version
- name: Determine latest Dapr Runtime version including Pre-releases
if: github.base_ref == 'master'
run: |
export 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)
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 default version $DAPR_RUNTIME_PINNED_VERSION"
echo "DAPR_RUNTIME_LATEST_VERSION=$DAPR_RUNTIME_PINNED_VERSION" >> $GITHUB_ENV
echo "Could not fetch the latest Dapr Runtime version. Using pinned version $DAPR_RUNTIME_PINNED_VERSION"
else
echo "Found $RUNTIME_VERSION"
echo "DAPR_RUNTIME_LATEST_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
base_ref=${{ github.base_ref }}
echo "Branch $base_ref"
if [[ $base_ref = 'master' ]]; then
echo "DAPR_RUNTIME_PINNED_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
fi
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: |
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 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)
if [[ -z "$DASHBOARD_VERSION" ]]; then
echo "Could not fetch the latest Dapr Dashboard version. Using default version $DAPR_DASHBOARD_PINNED_VERSION"
echo "DAPR_DASHBOARD_LATEST_VERSION=$DAPR_DASHBOARD_PINNED_VERSION" >> $GITHUB_ENV
else
echo "Found $DASHBOARD_VERSION"
echo "DAPR_DASHBOARD_LATEST_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
base_ref=${{ github.base_ref }}
echo "Branch $base_ref"
if [[ $base_ref = 'master' ]]; then
echo "DAPR_DASHBOARD_PINNED_VERSION=$DASHBOARD_VERSION" >> $GITHUB_ENV
fi
fi
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'
run: echo "E2E_SH_TEST_TIMEOUT=20m" >> $GITHUB_ENV
run: echo "E2E_SH_TEST_TIMEOUT=30m" >> $GITHUB_ENV
- name: Run E2E tests with GHCR
# runs every 6hrs
if: github.event.schedule == '0 */6 * * *'

View File

@ -49,8 +49,6 @@ jobs:
kubernetes-e2e:
name: Upgrade path tests (KinD)
runs-on: ubuntu-latest
env:
GOVER: 1.19.3
strategy:
fail-fast: false # Keep running if one leg fails.
matrix:
@ -75,14 +73,25 @@ jobs:
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@v3
with:
path: ./src/github.com/dapr/cli
- name: Set up Go
uses: actions/setup-go@v3
id: setup-go
with:
go-version-file: './src/github.com/dapr/cli/go.mod'
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ matrix.k8s-version }}-${{ matrix.kind-version }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ matrix.k8s-version }}-${{ matrix.kind-version }}-go-${{ steps.setup-go.outputs.go-version }}-
- name: Configure KinD
# Generate a KinD configuration file that uses:
@ -112,7 +121,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

View File

@ -24,6 +24,7 @@ run:
skip-dirs:
- ^pkg.*client.*clientset.*versioned.*
- ^pkg.*client.*informers.*externalversions.*
- pkg.*mod.*k8s.io.*
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
@ -244,7 +245,7 @@ linters:
- goerr113
- nlreturn
- exhaustive
- gci
- gci
- noctx
- exhaustivestruct
- exhaustruct

View File

@ -200,7 +200,7 @@ e2e-build-run-sh: build test-e2e-sh
################################################################################
.PHONY: modtidy
modtidy:
go mod tidy -compat=1.19
go mod tidy -compat=1.20
################################################################################
# Target: check-diff #
@ -208,3 +208,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 ./...

View File

@ -212,6 +212,20 @@ $ 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).
@ -736,7 +750,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)

View File

@ -359,7 +359,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,6 +385,7 @@ 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().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().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().BoolVar(&annotateHTTPStreamRequestBody, "http-stream-request-body", false, "Enable streaming request body for HTTP")

View File

@ -31,7 +31,7 @@ var BuildInfoCmd = &cobra.Command{
dapr build-info
`,
Run: func(cmd *cobra.Command, args []string) {
out, err := standalone.GetBuildInfo(daprPath, 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)

View File

@ -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 {
@ -53,43 +60,44 @@ const (
)
var (
daprVer daprVersion
logAsJSON bool
daprPath string
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
// err intentionally ignored since daprd may not yet be installed.
runtimeVer, _ := standalone.GetRuntimeVersion(daprPath)
daprVer = daprVersion{
CliVersion: version,
RuntimeVersion: strings.ReplaceAll(runtimeVer, "\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("-", "_"))
@ -97,6 +105,7 @@ func initConfig() {
}
func init() {
RootCmd.PersistentFlags().StringVarP(&daprPath, "dapr-path", "", "", "The path to the dapr installation directory")
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")
}

View File

@ -62,14 +62,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
# 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
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
@ -82,7 +82,7 @@ dapr dashboard -k -p 0
`,
Run: func(cmd *cobra.Command, args []string) {
if dashboardVersionCmd {
dashboardVer, err := standalone.GetDashboardVersion(daprPath)
dashboardVer, err := standalone.GetDashboardVersion(daprRuntimePath)
if err != nil {
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
os.Exit(1)
@ -194,7 +194,7 @@ dapr dashboard -k -p 0
<-portForward.GetStop()
} else {
// Standalone mode.
dashboardCmd, err := standalone.NewDashboardCmd(daprPath, dashboardLocalPort)
dashboardCmd, err := standalone.NewDashboardCmd(daprRuntimePath, dashboardLocalPort)
if err != nil {
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
} else {

View File

@ -14,6 +14,7 @@ limitations under the License.
package cmd
import (
"errors"
"fmt"
"os"
"strings"
@ -51,13 +52,17 @@ 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
@ -81,8 +86,9 @@ dapr init --from-dir <path-to-directory>
# Initialize dapr with a particular image variant. Allowed values: "mariner"
dapr init --image-variant <variant>
# Initialize Dapr to non-default install directory (default is $HOME/.dapr)
dapr init --dapr-path <path-to-install-directory>
# 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/
`,
@ -95,8 +101,8 @@ dapr init --dapr-path <path-to-install-directory>
imageRegistryURI := ""
var err error
if len(strings.TrimSpace(daprPath)) != 0 {
print.FailureStatusEvent(os.Stderr, "--dapr-path is only valid for self-hosted mode")
if len(strings.TrimSpace(daprRuntimePath)) != 0 {
print.FailureStatusEvent(os.Stderr, "--runtime-path is only valid for self-hosted mode")
os.Exit(1)
}
@ -110,16 +116,25 @@ dapr init --dapr-path <path-to-install-directory>
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,
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 {
@ -150,7 +165,7 @@ dapr init --dapr-path <path-to-install-directory>
print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.")
os.Exit(1)
}
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprPath)
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath)
if err != nil {
print.FailureStatusEvent(os.Stderr, err.Error())
os.Exit(1)
@ -160,30 +175,38 @@ dapr init --dapr-path <path-to-install-directory>
},
}
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(&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().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")
@ -193,7 +216,23 @@ func init() {
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. Supported values are docker (default) and podman")
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)
}

View File

@ -49,7 +49,7 @@ var (
logLevel string
protocol string
componentsPath string
resourcesPath string
resourcesPaths []string
appSSL bool
metricsPort int
maxRequestBodySize int
@ -63,6 +63,7 @@ var (
enableAPILogging bool
apiListenAddresses string
runFilePath string
appChannelAddress string
)
const (
@ -92,8 +93,12 @@ 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 --dapr-path /usr/local/dapr
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
@ -123,7 +128,7 @@ dapr run --run-file /path/to/directory
fmt.Println(print.WhiteBold("WARNING: no application command found."))
}
daprDirPath, err := standalone.GetDaprPath(daprPath)
daprDirPath, err := standalone.GetDaprRuntimePath(daprRuntimePath)
if err != nil {
print.FailureStatusEvent(os.Stderr, "Failed to get Dapr install directory: %v", err)
os.Exit(1)
@ -160,7 +165,7 @@ dapr run --run-file /path/to/directory
AppProtocol: protocol,
PlacementHostAddr: viper.GetString("placement-host-address"),
ComponentsPath: componentsPath,
ResourcesPath: resourcesPath,
ResourcesPaths: resourcesPaths,
AppSSL: appSSL,
MaxRequestBodySize: maxRequestBodySize,
HTTPReadBufferSize: readBufferSize,
@ -171,19 +176,20 @@ dapr run --run-file /path/to/directory
AppHealthThreshold: appHealthThreshold,
EnableAPILogging: enableAPILogging,
APIListenAddresses: apiListenAddresses,
DaprdInstallPath: daprPath,
DaprdInstallPath: daprRuntimePath,
}
output, err := runExec.NewOutput(&standalone.RunConfig{
AppID: appID,
AppPort: appPort,
HTTPPort: port,
GRPCPort: grpcPort,
ProfilePort: profilePort,
Command: args,
MetricsPort: metricsPort,
UnixDomainSocket: unixDomainSocket,
InternalGRPCPort: internalGRPCPort,
SharedRunConfig: *sharedRunConfig,
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())
@ -354,15 +360,23 @@ dapr run --run-file /path/to/directory
}
// 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)
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 {
@ -426,14 +440,16 @@ 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", "", "The path for components directory")
RunCmd.Flags().StringVarP(&resourcesPath, "resources-path", "", "", "The path for resources 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")
// 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")
@ -447,10 +463,11 @@ func init() {
RunCmd.Flags().BoolVar(&enableAPILogging, "enable-api-logging", false, "Log API calls at INFO verbosity. Valid values are: true or false")
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(runFilePath string, apps []runfileconfig.App) (bool, error) {
func executeRun(runTemplateName, runFilePath string, apps []runfileconfig.App) (bool, error) {
var exitWithError bool
// setup shutdown notify channel.
@ -464,6 +481,8 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
// This is done to provide a better grouping, which can be used to control all the proceses started by "dapr run -f".
daprsyscall.CreateProcessGroupID()
print.WarningStatusEvent(os.Stdout, "This is a preview feature and subject to change in future releases.")
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.
@ -487,13 +506,17 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
}
// Combined multiwriter for logs.
var appDaprdWriter io.Writer
// appLogWriterCloser is used when app command is present.
var appLogWriterCloser io.WriteCloser
daprdLogWriterCloser := app.DaprdLogWriteCloser
// 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 := 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 = app.DaprdLogWriteCloser
appLogWriterCloser = app.DaprdLogWriteCloser
appDaprdWriter = getAppDaprdWriter(app, true)
appLogWriter = app.DaprdLogWriteCloser
} else {
err = app.CreateAppLogFile()
if err != nil {
@ -501,14 +524,13 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
exitWithError = true
break
}
appDaprdWriter = io.MultiWriter(app.AppLogWriteCloser, app.DaprdLogWriteCloser)
appLogWriterCloser = app.AppLogWriteCloser
appDaprdWriter = getAppDaprdWriter(app, false)
appLogWriter = getLogWriter(app.AppLogWriteCloser, app.AppLogDestination)
}
customAppLogWriter = print.CustomLogWriter{W: appLogWriter}
runState, err := startDaprdAndAppProcesses(&runConfig, app.AppDirPath, sigCh,
daprdLogWriterCloser, daprdLogWriterCloser, appLogWriterCloser, appLogWriterCloser)
daprdLogWriterCloser, daprdLogWriterCloser, customAppLogWriter, customAppLogWriter)
if err != nil {
print.StatusEvent(os.Stdout, print.LogFailure, "Error starting Dapr and app (%q): %s", app.AppID, err.Error())
print.StatusEvent(appDaprdWriter, print.LogFailure, "Error starting Dapr and app (%q): %s", app.AppID, err.Error())
exitWithError = true
break
@ -522,9 +544,27 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
// 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)
}
}
print.StatusEvent(runState.DaprCMD.OutputWriter, print.LogSuccess, "You're up and running! Dapr logs will appear here.\n")
logInformationalStatusToStdout(app)
}
@ -552,6 +592,43 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
return exitWithError, closeError
}
// 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
}
// 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
}
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)
@ -588,7 +665,7 @@ func executeRunWithAppsConfigFile(runFilePath string) {
print.StatusEvent(os.Stdout, print.LogFailure, "No apps to run")
os.Exit(1)
}
exitWithError, closeErr := executeRun(runFilePath, apps)
exitWithError, closeErr := executeRun(config.Name, runFilePath, apps)
if exitWithError {
if closeErr != nil {
print.StatusEvent(os.Stdout, print.LogFailure, "Error closing resources: %s", closeErr)
@ -742,25 +819,14 @@ func startAppProcess(runConfig *standalone.RunConfig, runE *runExec.RunExec,
outScanner := bufio.NewScanner(stdOutPipe)
go func() {
for errScanner.Scan() {
if runE.AppCMD.ErrorWriter == os.Stderr {
// Add color and prefix to log and output to Stderr.
fmt.Fprintln(runE.AppCMD.ErrorWriter, print.Blue(fmt.Sprintf("== APP == %s", errScanner.Text())))
} else {
// Directly output app logs to the error writer.
fmt.Fprintln(runE.AppCMD.ErrorWriter, errScanner.Text())
}
fmt.Fprintln(runE.AppCMD.ErrorWriter, print.Blue(fmt.Sprintf("== APP - %s == %s", runE.AppID,
errScanner.Text())))
}
}()
go func() {
for outScanner.Scan() {
if runE.AppCMD.OutputWriter == os.Stdout {
// Add color and prefix to log and output to Stdout.
fmt.Fprintln(runE.AppCMD.OutputWriter, print.Blue(fmt.Sprintf("== APP == %s", outScanner.Text())))
} else {
// Directly output app logs to the output writer.
fmt.Fprintln(runE.AppCMD.OutputWriter, outScanner.Text())
}
fmt.Fprintln(runE.AppCMD.OutputWriter, print.Blue(fmt.Sprintf("== APP - %s == %s", runE.AppID, outScanner.Text())))
}
}()
@ -813,10 +879,8 @@ func startDaprdProcess(runConfig *standalone.RunConfig, runE *runExec.RunExec,
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())
@ -905,6 +969,14 @@ func putCLIProcessIDInMeta(runE *runExec.RunExec, pid int) {
}
}
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, " ")
@ -914,7 +986,6 @@ func putAppCommandInMeta(runConfig standalone.RunConfig, runE *runExec.RunExec)
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogWarning, "Could not update sidecar metadata for appCommand: %s", err.Error())
return
}
print.StatusEvent(runE.DaprCMD.OutputWriter, print.LogSuccess, "You're up and running! Dapr logs will appear here.\n")
}
// 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.
@ -926,7 +997,31 @@ func putRunFilePathInMeta(runE *runExec.RunExec, runFilePath string) {
}
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 runFile: %s", err.Error())
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())
}
}

View File

@ -48,8 +48,9 @@ dapr uninstall --all
# Uninstall from Kubernetes
dapr uninstall -k
# Uninstall Dapr from non-default install directory (default is $HOME/.dapr)
dapr uninstall --dapr-path <path-to-install-directory>
# 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"))
@ -59,8 +60,8 @@ dapr uninstall --dapr-path <path-to-install-directory>
var err error
if uninstallKubernetes {
if len(strings.TrimSpace(daprPath)) != 0 {
print.FailureStatusEvent(os.Stderr, "--dapr-path is only valid for self-hosted mode")
if len(strings.TrimSpace(daprRuntimePath)) != 0 {
print.FailureStatusEvent(os.Stderr, "--runtime-path is only valid for self-hosted mode")
os.Exit(1)
}
@ -73,7 +74,7 @@ dapr uninstall --dapr-path <path-to-install-directory>
}
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...")
dockerNetwork := viper.GetString("network")
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime, daprPath)
err = standalone.Uninstall(uninstallAll, dockerNetwork, uninstallContainerRuntime, daprRuntimePath)
}
if err != nil {

View File

@ -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")

View File

@ -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/).

View File

@ -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`._

View File

@ -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\")"
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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.20` [(instructions)](https://golang.org/doc/install#tarball).
* Make sure that your GOPATH and PATH are configured correctly
```bash
export GOPATH=~/go

View File

@ -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.

245
go.mod
View File

@ -1,16 +1,16 @@
module github.com/dapr/cli
go 1.19
go 1.20
require (
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
github.com/Pallinder/sillyname-go v0.0.0-20130730142914-97aeae9e6ba1
github.com/briandowns/spinner v1.19.0
github.com/dapr/dapr v1.9.0
github.com/dapr/dapr v1.11.0
github.com/dapr/go-sdk v1.6.0
github.com/docker/docker v20.10.20+incompatible
github.com/fatih/color v1.13.0
github.com/docker/docker v20.10.21+incompatible
github.com/fatih/color v1.15.0
github.com/gocarina/gocsv v0.0.0-20220927221512-ad3251f9fa25
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hashicorp/go-version v1.6.0
@ -18,119 +18,136 @@ require (
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/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/spf13/cobra v1.6.0
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.8.0
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
github.com/stretchr/testify v1.8.3
golang.org/x/sys v0.8.0
gopkg.in/yaml.v2 v2.4.0
helm.sh/helm/v3 v3.10.3
k8s.io/api v0.25.2
k8s.io/apiextensions-apiserver v0.25.2
k8s.io/apimachinery v0.25.2
k8s.io/cli-runtime v0.25.2
k8s.io/client-go v0.25.2
helm.sh/helm/v3 v3.11.1
k8s.io/api v0.26.3
k8s.io/apiextensions-apiserver v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/cli-runtime v0.26.3
k8s.io/client-go v0.26.3
k8s.io/helm v2.16.10+incompatible
sigs.k8s.io/yaml v1.3.0
)
require github.com/evanphx/json-patch v5.6.0+incompatible
require (
github.com/Masterminds/semver/v3 v3.2.0
github.com/evanphx/json-patch v5.6.0+incompatible
)
require (
cloud.google.com/go/compute v1.6.1 // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.1 // indirect
cloud.google.com/go/compute v1.19.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // 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.1.0 // indirect
github.com/BurntSushi/toml v1.2.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/sprig/v3 v3.2.3 // 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/andybalholm/brotli v1.0.4 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.6 // indirect
github.com/PuerkitoBio/purell v1.2.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // 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/bufbuild/protocompile v0.4.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/containerd/containerd v1.6.6 // indirect
github.com/containerd/continuity v0.2.2 // indirect
github.com/chebyrash/promise v0.0.0-20220530143319-1123826567d6 // indirect
github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.13.0 // indirect
github.com/cloudevents/sdk-go/v2 v2.13.0 // indirect
github.com/containerd/containerd v1.6.18 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/dapr/components-contrib v1.9.0-rc.5 // indirect
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7 // indirect
github.com/dapr/components-contrib v1.11.0-rc.11 // indirect
github.com/dapr/kit v0.11.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/cli v20.10.17+incompatible // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/cli v20.10.21+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.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/emicklei/go-restful/v3 v3.10.2 // indirect
github.com/evanphx/json-patch/v5 v5.6.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/fasthttp/router v1.4.18 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // 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-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // 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-jwt/jwt/v4 v4.5.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.12.5 // 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.3 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/cel-go v0.13.0 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.9 // 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/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.15.2 // 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.2 // 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/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jhump/protoreflect v1.13.0 // indirect
github.com/jhump/protoreflect v1.15.1 // indirect
github.com/jmoiron/sqlx v1.3.5 // 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.16.3 // 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.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.0.9 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lib/pq v1.10.7 // 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/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.18 // 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/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/microsoft/durabletask-go v0.2.4 // 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
@ -138,84 +155,84 @@ require (
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/term v0.0.0-20221205130635-1aeaba878587 // 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/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/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // 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.2 // indirect
github.com/russross/blackfriday v2.0.0+incompatible // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/prometheus/statsd_exporter v0.22.7 // indirect
github.com/rubenv/sql-migrate v1.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // 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/sirupsen/logrus v1.9.2 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cast v1.5.1 // 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/stretchr/objx v0.5.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.40.0 // indirect
github.com/valyala/fasthttp v1.47.0 // 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 v1.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.etcd.io/etcd/api/v3 v3.5.4 // 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.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.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-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // 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
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // 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
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiserver v0.25.2 // indirect
k8s.io/component-base v0.25.2 // indirect
k8s.io/klog/v2 v2.70.1 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/kubectl v0.25.2 // indirect
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
oras.land/oras-go v1.2.0 // indirect
sigs.k8s.io/controller-runtime v0.11.0 // indirect
k8s.io/apiserver v0.26.3 // indirect
k8s.io/component-base v0.26.3 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/kubectl v0.26.0 // indirect
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
oras.land/oras-go v1.2.2 // indirect
sigs.k8s.io/controller-runtime v0.14.6 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
@ -224,9 +241,9 @@ require (
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/cli-runtime => k8s.io/cli-runtime v0.25.2
k8s.io/client => github.com/kubernetes-client/go v0.0.0-20190928040339-c757968c4c36
k8s.io/client-go => k8s.io/client-go v0.25.2
)

647
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -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 (
@ -341,8 +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{
patchOps := []patcher.PatchOperation{}
patchOps = append(patchOps, patcher.PatchOperation{
Op: "add",
Path: path,
Value: annotations,

View File

@ -57,7 +57,9 @@ func GetDaprHelmChartName(helmConf *helm.Configuration) (string, error) {
}
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
}

View File

@ -130,7 +130,7 @@ func TestConfigurations(t *testing.T) {
name: "Yaml one config",
configName: "",
outputFormat: "yaml",
expectedOutput: "- name: appConfig\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: appConfig\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 rules: []\n metricsspec:\n enabled: false\n rules: []\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 denied: []\n componentsspec: {}\n loggingspec:\n apiLogging:\n enabled: false\n obfuscateURLs: false\n omitHealthChecks: false\n",
errString: "",
errorExpected: false,
k8sConfig: []v1alpha1.Configuration{
@ -148,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:\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 rules: []\n metricsspec:\n enabled: false\n rules: []\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 denied: []\n componentsspec: {}\n loggingspec:\n apiLogging:\n enabled: false\n obfuscateURLs: false\n omitHealthChecks: false\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 rules: []\n metricsspec:\n enabled: false\n rules: []\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 denied: []\n componentsspec: {}\n loggingspec:\n apiLogging:\n enabled: false\n obfuscateURLs: false\n omitHealthChecks: false\n",
errString: "",
errorExpected: false,
k8sConfig: []v1alpha1.Configuration{
@ -174,7 +174,7 @@ func TestConfigurations(t *testing.T) {
name: "Json one config",
configName: "",
outputFormat: "json",
expectedOutput: "[\n {\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 }\n]",
expectedOutput: "[\n {\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 \"rules\": null\n },\n \"metrics\": {\n \"enabled\": false,\n \"rules\": null\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 \"logging\": {\n \"apiLogging\": {\n \"enabled\": false,\n \"obfuscateURLs\": false,\n \"omitHealthChecks\": false\n }\n }\n }\n }\n]",
errString: "",
errorExpected: false,
k8sConfig: []v1alpha1.Configuration{
@ -192,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 \"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 \"rules\": null\n },\n \"metrics\": {\n \"enabled\": false,\n \"rules\": null\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 \"logging\": {\n \"apiLogging\": {\n \"enabled\": false,\n \"obfuscateURLs\": false,\n \"omitHealthChecks\": false\n }\n }\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 \"rules\": null\n },\n \"metrics\": {\n \"enabled\": false,\n \"rules\": null\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 \"logging\": {\n \"apiLogging\": {\n \"enabled\": false,\n \"obfuscateURLs\": false,\n \"omitHealthChecks\": false\n }\n }\n }\n }\n]",
errString: "",
errorExpected: false,
k8sConfig: []v1alpha1.Configuration{

View File

@ -0,0 +1,33 @@
/*
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 "github.com/Masterminds/semver/v3"
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
}

View File

@ -0,0 +1,76 @@
/*
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: "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")
})
}
}

View File

@ -36,34 +36,62 @@ import (
)
const (
daprReleaseName = "dapr"
daprHelmRepo = "https://dapr.github.io/helm-charts"
latestVersion = "latest"
daprReleaseName = "dapr"
dashboardReleaseName = "dapr-dashboard"
daprHelmRepo = "https://dapr.github.io/helm-charts"
latestVersion = "latest"
)
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
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 {
err := installWithConsole(daprReleaseName, config.Version, "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, "Dapr dashboard", config)
if err != nil {
return err
}
return nil
}
func installWithConsole(releaseName string, releaseVersion 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, config)
if err != nil {
return err
}
installSpinning(print.Success)
return nil
}
@ -93,16 +121,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,7 +156,7 @@ 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 daprChart(version string, releaseName string, config *helm.Configuration) (*chart.Chart, error) {
pull := helm.NewPullWithOpts(helm.WithConfig(config))
pull.RepoURL = utils.GetEnv("DAPR_HELM_REPO_URL", daprHelmRepo)
pull.Username = utils.GetEnv("DAPR_HELM_REPO_USERNAME", "")
@ -129,7 +164,7 @@ func daprChart(version string, config *helm.Configuration) (*chart.Chart, error)
pull.Settings = &cli.EnvSettings{}
if version != latestVersion {
if version != latestVersion && (releaseName == daprReleaseName || releaseName == dashboardReleaseName) {
pull.Version = chartVersion(version)
}
@ -141,7 +176,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
}
@ -159,17 +194,32 @@ func chartValues(config InitConfiguration, version string) (map[string]interface
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(version, config.ImageVariant)),
}
if len(config.ImageRegistryURI) != 0 {
globalVals = append(globalVals, fmt.Sprintf("global.registry=%s", config.ImageRegistryURI))
helmVals = append(helmVals, fmt.Sprintf("global.registry=%s", 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, fmt.Sprintf("dapr_sentry.tls.root.certPEM=%s", string(rootCertBytes)),
fmt.Sprintf("dapr_sentry.tls.issuer.certPEM=%s", string(issuerCertBytes)),
fmt.Sprintf("dapr_sentry.tls.issuer.keyPEM=%s", string(issuerKeyBytes)),
)
}
for _, v := range helmVals {
if err := strvals.ParseInto(v, chartVals); err != nil {
return nil, err
}
@ -177,7 +227,7 @@ func chartValues(config InitConfiguration, version string) (map[string]interface
return chartVals, nil
}
func install(config InitConfiguration) error {
func install(releaseName string, releaseVersion string, config InitConfiguration) error {
err := createNamespace(config.Namespace)
if err != nil {
return err
@ -188,23 +238,25 @@ func install(config InitConfiguration) error {
return err
}
daprChart, err := daprChart(config.Version, helmConf)
daprChart, err := daprChart(releaseVersion, releaseName, 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(fmt.Sprintf("v%s", 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
@ -217,15 +269,16 @@ func install(config InitConfiguration) error {
if _, err = installClient.Run(daprChart, 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

View File

@ -112,7 +112,7 @@ func renewCertificate(rootCert, issuerCert, issuerKey []byte, timeout uint, imag
return err
}
daprChart, err := daprChart(daprVersion, helmConf)
daprChart, err := daprChart(daprVersion, "dapr", helmConf)
if err != nil {
return err
}

View File

@ -30,7 +30,7 @@ func Uninstall(namespace string, uninstallAll bool, timeout uint) error {
return err
}
exists, err := confirmExist(config)
exists, err := confirmExist(config, daprReleaseName)
if err != nil {
return err
}
@ -42,6 +42,12 @@ func Uninstall(namespace string, uninstallAll bool, timeout uint) error {
uninstallClient := helm.NewUninstall(config)
uninstallClient.Timeout = time.Duration(timeout) * time.Second
// 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)
_, err = uninstallClient.Run(daprReleaseName)
if err != nil {

View File

@ -20,6 +20,7 @@ import (
"time"
helm "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"k8s.io/helm/pkg/strvals"
"github.com/hashicorp/go-version"
@ -35,6 +36,7 @@ var crds = []string{
"configuration",
"subscription",
"resiliency",
"httpendpoints",
}
var crdsFullResources = []string{
@ -42,10 +44,12 @@ var crdsFullResources = []string{
"configurations.dapr.io",
"subscriptions.dapr.io",
"resiliencies.dapr.io",
"httpendpoints.dapr.io",
}
type UpgradeConfig struct {
RuntimeVersion string
DashboardVersion string
Args []string
Timeout uint
ImageRegistryURI string
@ -61,16 +65,56 @@ 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)
hasDashboardInDaprChart, err := IsDashboardIncluded(daprVersion)
if err != nil {
return err
}
helmConf, err := helmConfig(status[0].Namespace)
if err != nil {
return err
}
daprChart, err := daprChart(conf.RuntimeVersion, helmConf)
controlPlaneChart, err := daprChart(conf.RuntimeVersion, "dapr", helmConf)
if err != nil {
return err
}
willHaveDashboardInDaprChart, err := IsDashboardIncluded(conf.RuntimeVersion)
if err != nil {
return err
}
// 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
_, err = uninstallClient.Run(dashboardReleaseName)
if err != nil {
return err
}
}
var dashboardChart *chart.Chart
if conf.DashboardVersion != "" {
dashboardChart, err = daprChart(conf.DashboardVersion, dashboardReleaseName, helmConf)
if err != nil {
return err
}
}
upgradeClient := helm.NewUpgrade(helmConf)
upgradeClient.ResetValues = true
upgradeClient.Namespace = status[0].Namespace
@ -121,9 +165,29 @@ func Upgrade(conf UpgradeConfig) error {
return err
}
if _, err = upgradeClient.Run(chart, daprChart, vals); err != nil {
if _, err = upgradeClient.Run(chart, controlPlaneChart, vals); err != nil {
return err
}
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, InitConfiguration{
DashboardVersion: conf.DashboardVersion,
Namespace: upgradeClient.Namespace,
Wait: upgradeClient.Wait,
Timeout: conf.Timeout,
})
if err != nil {
return err
}
}
}
return nil
}

View File

@ -18,6 +18,8 @@ import (
"fmt"
"io"
"os"
"reflect"
"regexp"
"runtime"
"sync"
"time"
@ -204,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)
}
}

View File

@ -74,7 +74,7 @@ func assertArgumentContains(t *testing.T, key string, expectedValue string, args
}
func setupRun(t *testing.T) {
myDaprPath, err := standalone.GetDaprPath("")
myDaprPath, err := standalone.GetDaprRuntimePath("")
assert.NoError(t, err)
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
@ -87,7 +87,7 @@ func setupRun(t *testing.T) {
}
func tearDownRun(t *testing.T) {
myDaprPath, err := standalone.GetDaprPath("")
myDaprPath, err := standalone.GetDaprRuntimePath("")
assert.NoError(t, err)
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
@ -106,7 +106,7 @@ func assertCommonArgs(t *testing.T, basicConfig *standalone.RunConfig, output *R
assert.Equal(t, 8000, output.DaprHTTPPort)
assert.Equal(t, 50001, output.DaprGRPCPort)
daprPath, err := standalone.GetDaprPath("")
daprPath, err := standalone.GetDaprRuntimePath("")
assert.NoError(t, err)
assert.Contains(t, output.DaprCMD.Args[0], "daprd")
@ -168,7 +168,7 @@ func TestRun(t *testing.T) {
// Setup the tearDown routine to run in the end.
defer tearDownRun(t)
myDaprPath, err := standalone.GetDaprPath("")
myDaprPath, err := standalone.GetDaprRuntimePath("")
assert.NoError(t, err)
componentsDir := standalone.GetDaprComponentsPath(myDaprPath)
@ -186,15 +186,16 @@ func TestRun(t *testing.T) {
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,
SharedRunConfig: *sharedRunConfig,
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) {
@ -204,6 +205,7 @@ func TestRun(t *testing.T) {
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)
})

View File

@ -17,6 +17,7 @@ import (
"os"
path_filepath "path/filepath"
"runtime"
"strings"
)
const (
@ -28,19 +29,21 @@ const (
defaultComponentsDirName = "components"
)
// GetDaprPath returns the dapr installation path.
// GetDaprRuntimePath returns the dapr runtime installation path.
// daprRuntimePath is based on the --runtime-path command line flag.
// The order of precedence is:
// 1. From --dapr-path command line flag
// 2. From DAPR_PATH environment variable
// 3. $HOME/.dapr
func GetDaprPath(inputInstallPath string) (string, error) {
if inputInstallPath != "" {
return inputInstallPath, nil
// 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
}
envDaprDir := os.Getenv("DAPR_PATH")
if envDaprDir != "" {
return envDaprDir, nil
envRuntimePath := strings.TrimSpace(os.Getenv("DAPR_RUNTIME_PATH"))
if envRuntimePath != "" {
return path_filepath.Join(envRuntimePath, DefaultDaprDirName), nil
}
homeDir, err := os.UserHomeDir()
@ -64,7 +67,7 @@ func binaryFilePathWithDir(binaryDir string, binaryFilePrefix string) string {
}
func lookupBinaryFilePath(inputInstallPath string, binaryFilePrefix string) (string, error) {
daprPath, err := GetDaprPath(inputInstallPath)
daprPath, err := GetDaprRuntimePath(inputInstallPath)
if err != nil {
return "", err
}

View File

@ -0,0 +1,69 @@
/*
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 standalone
import (
"os"
path_filepath "path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetDaprPath(t *testing.T) {
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "error getting home dir")
t.Run("without flag value or env var", func(t *testing.T) {
p, err := GetDaprRuntimePath("")
require.NoError(t, err)
assert.Equal(t, p, path_filepath.Join(homeDir, DefaultDaprDirName), "path should be $HOME/.dapr")
})
t.Run("check trim spaces", func(t *testing.T) {
p, err := GetDaprRuntimePath(" ")
require.NoError(t, err)
assert.Equal(t, path_filepath.Join(homeDir, DefaultDaprDirName), p, "path should be $HOME/.dapr")
t.Setenv("DAPR_RUNTIME_PATH", " ")
p, err = GetDaprRuntimePath("")
require.NoError(t, err)
assert.Equal(t, path_filepath.Join(homeDir, DefaultDaprDirName), p, "path should be $HOME/.dapr")
})
t.Run("with flag value", func(t *testing.T) {
input := path_filepath.Join("path", "to", "dapr")
p, err := GetDaprRuntimePath(input)
require.NoError(t, err)
assert.Equal(t, path_filepath.Join(input, ".dapr"), p, "path should be /path/to/dapr/.dapr")
})
t.Run("with env var", func(t *testing.T) {
input := path_filepath.Join("path", "to", "dapr")
t.Setenv("DAPR_RUNTIME_PATH", input)
p, err := GetDaprRuntimePath("")
require.NoError(t, err)
assert.Equal(t, path_filepath.Join(input, ".dapr"), p, "path should be /path/to/dapr/.dapr")
})
t.Run("with flag value and env var", func(t *testing.T) {
input := path_filepath.Join("path", "to", "dapr")
input2 := path_filepath.Join("path", "to", "dapr2")
t.Setenv("DAPR_RUNTIME_PATH", input2)
p, err := GetDaprRuntimePath(input)
require.NoError(t, err)
assert.Equal(t, path_filepath.Join(input, ".dapr"), p, "path should be /path/to/dapr/.dapr")
})
}

View File

@ -20,6 +20,7 @@ import (
)
func TestDashboardRun(t *testing.T) {
t.Parallel()
t.Run("build Cmd", func(t *testing.T) {
cmd, err := NewDashboardCmd("", 9090)

View File

@ -21,10 +21,11 @@ import (
ps "github.com/mitchellh/go-ps"
process "github.com/shirou/gopsutil/process"
"github.com/dapr/dapr/pkg/runtime"
"github.com/dapr/cli/pkg/age"
"github.com/dapr/cli/pkg/metadata"
"github.com/dapr/cli/utils"
"github.com/dapr/dapr/pkg/runtime"
)
// ListOutput represents the application ID, application port and creation time.
@ -39,9 +40,13 @@ type ListOutput struct {
Created string `csv:"CREATED" json:"created" yaml:"created"`
DaprdPID int `csv:"DAPRD PID" json:"daprdPid" yaml:"daprdPid"`
CliPID int `csv:"CLI PID" json:"cliPid" yaml:"cliPid"`
AppPID int `csv:"APP PID" json:"appPid" yaml:"appPid"`
MaxRequestBodySize int `csv:"-" json:"maxRequestBodySize" yaml:"maxRequestBodySize"` // Additional field, not displayed in table.
HTTPReadBufferSize int `csv:"-" json:"httpReadBufferSize" yaml:"httpReadBufferSize"` // Additional field, not displayed in table.
RunTemplatePath string `csv:"RUN_TEMPLATE_PATH" json:"runTemplatePath" yaml:"runTemplatePath"`
AppLogPath string `csv:"APP_LOG_PATH" json:"appLogPath" yaml:"appLogPath"`
DaprDLogPath string `csv:"DAPRD_LOG_PATH" json:"daprdLogPath" yaml:"daprdLogPath"`
RunTemplateName string `json:"runTemplateName" yaml:"runTemplateName"` // specifically omitted in csv output.
}
func (d *daprProcess) List() ([]ListOutput, error) {
@ -76,9 +81,16 @@ func List() ([]ListOutput, error) {
continue
}
// Parse command line arguments, example format for cmdLine `daprd --flag1 value1 --enable-flag2 --flag3 value3`.
argumentsMap := make(map[string]string)
for i := 1; i < len(cmdLineItems)-1; i += 2 {
argumentsMap[cmdLineItems[i]] = cmdLineItems[i+1]
for i := 1; i < len(cmdLineItems)-1; {
if !strings.HasPrefix(cmdLineItems[i+1], "--") {
argumentsMap[cmdLineItems[i]] = cmdLineItems[i+1]
i += 2
} else {
argumentsMap[cmdLineItems[i]] = ""
i++
}
}
httpPort := getIntArg(argumentsMap, "--dapr-http-port", runtime.DefaultDaprHTTPPort)
@ -99,14 +111,27 @@ func List() ([]ListOutput, error) {
appID := argumentsMap["--app-id"]
appCmd := ""
appPIDString := ""
cliPIDString := ""
runTemplatePath := ""
appLogPath := ""
daprdLogPath := ""
runTemplateName := ""
socket := argumentsMap["--unix-domain-socket"]
appMetadata, err := metadata.Get(httpPort, appID, socket)
if err == nil {
appCmd = appMetadata.Extended["appCommand"]
appPIDString = appMetadata.Extended["appPID"]
cliPIDString = appMetadata.Extended["cliPID"]
runTemplatePath = appMetadata.Extended["runTemplatePath"]
runTemplateName = appMetadata.Extended["runTemplateName"]
appLogPath = appMetadata.Extended["appLogPath"]
daprdLogPath = appMetadata.Extended["daprdLogPath"]
}
appPID, err := strconv.Atoi(appPIDString)
if err != nil {
appPID = 0
}
// Parse functions return an error on bad input.
@ -130,6 +155,7 @@ func List() ([]ListOutput, error) {
DaprdPID: daprPID,
CliPID: cliPID,
AppID: appID,
AppPID: appPID,
HTTPPort: httpPort,
GRPCPort: grpcPort,
AppPort: appPort,
@ -138,6 +164,9 @@ func List() ([]ListOutput, error) {
MaxRequestBodySize: maxRequestBodySize,
HTTPReadBufferSize: httpReadBufferSize,
RunTemplatePath: runTemplatePath,
RunTemplateName: runTemplateName,
AppLogPath: appLogPath,
DaprDLogPath: daprdLogPath,
}
// filter only dashboard instance.

View File

@ -29,50 +29,61 @@ import (
"github.com/dapr/cli/pkg/print"
"github.com/dapr/dapr/pkg/components"
modes "github.com/dapr/dapr/pkg/config/modes"
)
type LogDestType string
const (
Console LogDestType = "console"
File LogDestType = "file"
FileAndConsole LogDestType = "fileAndConsole"
DefaultDaprdLogDest = File
DefaultAppLogDest = FileAndConsole
sentryDefaultAddress = "localhost:50001"
defaultStructTagKey = "default"
)
// RunConfig represents the application configuration parameters.
type RunConfig struct {
SharedRunConfig `yaml:",inline"`
AppID string `env:"APP_ID" arg:"app-id" yaml:"appID"`
AppPort int `env:"APP_PORT" arg:"app-port" yaml:"appPort" default:"-1"`
HTTPPort int `env:"DAPR_HTTP_PORT" arg:"dapr-http-port" yaml:"daprHTTPPort" default:"-1"`
GRPCPort int `env:"DAPR_GRPC_PORT" arg:"dapr-grpc-port" yaml:"daprGRPCPort" default:"-1"`
ProfilePort int `arg:"profile-port" yaml:"profilePort" default:"-1"`
Command []string `yaml:"command"`
MetricsPort int `env:"DAPR_METRICS_PORT" arg:"metrics-port" yaml:"metricsPort" default:"-1"`
UnixDomainSocket string `arg:"unix-domain-socket" yaml:"unixDomainSocket"`
InternalGRPCPort int `arg:"dapr-internal-grpc-port" yaml:"daprInternalGRPCPort" default:"-1"`
SharedRunConfig `yaml:",inline"`
AppID string `env:"APP_ID" arg:"app-id" yaml:"appID"`
AppChannelAddress string `env:"APP_CHANNEL_ADDRESS" arg:"app-channel-address" ifneq:"127.0.0.1" yaml:"appChannelAddress"`
AppPort int `env:"APP_PORT" arg:"app-port" yaml:"appPort" default:"-1"`
HTTPPort int `env:"DAPR_HTTP_PORT" arg:"dapr-http-port" yaml:"daprHTTPPort" default:"-1"`
GRPCPort int `env:"DAPR_GRPC_PORT" arg:"dapr-grpc-port" yaml:"daprGRPCPort" default:"-1"`
ProfilePort int `arg:"profile-port" yaml:"profilePort" default:"-1"`
Command []string `yaml:"command"`
MetricsPort int `env:"DAPR_METRICS_PORT" arg:"metrics-port" yaml:"metricsPort" default:"-1"`
UnixDomainSocket string `arg:"unix-domain-socket" yaml:"unixDomainSocket"`
InternalGRPCPort int `arg:"dapr-internal-grpc-port" yaml:"daprInternalGRPCPort" default:"-1"`
}
// SharedRunConfig represents the application configuration parameters, which can be shared across many apps.
type SharedRunConfig struct {
ConfigFile string `arg:"config" yaml:"configFilePath"`
AppProtocol string `arg:"app-protocol" yaml:"appProtocol" default:"http"`
APIListenAddresses string `arg:"dapr-listen-addresses" yaml:"apiListenAddresses"`
EnableProfiling bool `arg:"enable-profiling" yaml:"enableProfiling"`
LogLevel string `arg:"log-level" yaml:"logLevel"`
MaxConcurrency int `arg:"app-max-concurrency" yaml:"appMaxConcurrency" default:"-1"`
PlacementHostAddr string `arg:"placement-host-address" yaml:"placementHostAddress"`
ComponentsPath string `arg:"components-path"`
ResourcesPath string `arg:"resources-path" yaml:"resourcesPath"`
AppSSL bool `arg:"app-ssl" yaml:"appSSL"`
MaxRequestBodySize int `arg:"dapr-http-max-request-size" yaml:"daprHTTPMaxRequestSize" default:"-1"`
HTTPReadBufferSize int `arg:"dapr-http-read-buffer-size" yaml:"daprHTTPReadBufferSize" default:"-1"`
EnableAppHealth bool `arg:"enable-app-health-check" yaml:"enableAppHealthCheck"`
AppHealthPath string `arg:"app-health-check-path" yaml:"appHealthCheckPath"`
AppHealthInterval int `arg:"app-health-probe-interval" ifneq:"0" yaml:"appHealthProbeInterval"`
AppHealthTimeout int `arg:"app-health-probe-timeout" ifneq:"0" yaml:"appHealthProbeTimeout"`
AppHealthThreshold int `arg:"app-health-threshold" ifneq:"0" yaml:"appHealthThreshold"`
EnableAPILogging bool `arg:"enable-api-logging" yaml:"enableApiLogging"`
DaprdInstallPath string `yaml:"daprPath"`
Env map[string]string `yaml:"env"`
ConfigFile string `arg:"config" yaml:"configFilePath"`
AppProtocol string `arg:"app-protocol" yaml:"appProtocol" default:"http"`
APIListenAddresses string `arg:"dapr-listen-addresses" yaml:"apiListenAddresses"`
EnableProfiling bool `arg:"enable-profiling" yaml:"enableProfiling"`
LogLevel string `arg:"log-level" yaml:"logLevel"`
MaxConcurrency int `arg:"app-max-concurrency" yaml:"appMaxConcurrency" default:"-1"`
PlacementHostAddr string `arg:"placement-host-address" yaml:"placementHostAddress"`
ComponentsPath string `arg:"components-path"` // Deprecated in run template file: use ResourcesPaths instead.
ResourcesPath string `yaml:"resourcesPath"` // Deprecated in run template file: use ResourcesPaths instead.
ResourcesPaths []string `arg:"resources-path" yaml:"resourcesPaths"`
AppSSL bool `arg:"app-ssl" yaml:"appSSL"`
MaxRequestBodySize int `arg:"dapr-http-max-request-size" yaml:"daprHTTPMaxRequestSize" default:"-1"`
HTTPReadBufferSize int `arg:"dapr-http-read-buffer-size" yaml:"daprHTTPReadBufferSize" default:"-1"`
EnableAppHealth bool `arg:"enable-app-health-check" yaml:"enableAppHealthCheck"`
AppHealthPath string `arg:"app-health-check-path" yaml:"appHealthCheckPath"`
AppHealthInterval int `arg:"app-health-probe-interval" ifneq:"0" yaml:"appHealthProbeInterval"`
AppHealthTimeout int `arg:"app-health-probe-timeout" ifneq:"0" yaml:"appHealthProbeTimeout"`
AppHealthThreshold int `arg:"app-health-threshold" ifneq:"0" yaml:"appHealthThreshold"`
EnableAPILogging bool `arg:"enable-api-logging" yaml:"enableApiLogging"`
DaprdInstallPath string `yaml:"runtimePath"`
Env map[string]string `yaml:"env"`
DaprdLogDestination LogDestType `yaml:"daprdLogDestination"`
AppLogDestination LogDestType `yaml:"appLogDestination"`
}
func (meta *DaprMeta) newAppID() string {
@ -84,17 +95,18 @@ func (meta *DaprMeta) newAppID() string {
}
}
func (config *RunConfig) validateResourcesPath() error {
dirPath := config.ResourcesPath
if dirPath == "" {
dirPath = config.ComponentsPath
func (config *RunConfig) validateResourcesPaths() error {
dirPath := config.ResourcesPaths
if len(dirPath) == 0 {
dirPath = []string{config.ComponentsPath}
}
_, err := os.Stat(dirPath)
if err != nil {
return fmt.Errorf("error validating resources path %q : %w", dirPath, err)
for _, path := range dirPath {
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("error validating resources path %q : %w", dirPath, err)
}
}
componentsLoader := components.NewStandaloneComponents(modes.StandaloneConfig{ComponentsPath: dirPath})
_, err = componentsLoader.LoadComponents()
componentsLoader := components.NewLocalComponents(dirPath...)
_, err := componentsLoader.LoadComponents()
if err != nil {
return fmt.Errorf("error validating components in resources path %q : %w", dirPath, err)
}
@ -143,12 +155,12 @@ func (config *RunConfig) Validate() error {
config.AppID = meta.newAppID()
}
err = config.validateResourcesPath()
err = config.validateResourcesPaths()
if err != nil {
return err
}
if config.ResourcesPath != "" {
if len(config.ResourcesPaths) > 0 {
config.ComponentsPath = ""
}
@ -287,11 +299,17 @@ func getArgsFromSchema(schema reflect.Value, args []string) []string {
ifneq, hasIfneq := typeField.Tag.Lookup("ifneq")
switch valueField.(type) {
switch vType := valueField.(type) {
case bool:
if valueField == true {
args = append(args, key)
}
case []string:
if len(vType) > 0 {
for _, val := range vType {
args = append(args, key, val)
}
}
default:
value := fmt.Sprintf("%v", reflect.ValueOf(valueField))
if len(value) != 0 && (!hasIfneq || value != ifneq) {
@ -331,6 +349,8 @@ func (config *RunConfig) setDefaultFromSchemaRecursive(schema reflect.Value) {
func (config *RunConfig) getEnv() []string {
env := []string{}
// Handle values from config that have an "env" tag.
schema := reflect.ValueOf(*config)
for i := 0; i < schema.NumField(); i++ {
valueField := schema.Field(i).Interface()
@ -347,12 +367,48 @@ func (config *RunConfig) getEnv() []string {
value := fmt.Sprintf("%v", reflect.ValueOf(valueField))
env = append(env, fmt.Sprintf("%s=%v", key, value))
}
// Handle APP_PROTOCOL separately since that requires some additional processing.
appProtocol := config.getAppProtocol()
if appProtocol != "" {
env = append(env, "APP_PROTOCOL="+appProtocol)
}
// Add user-defined env vars.
for k, v := range config.Env {
env = append(env, fmt.Sprintf("%s=%v", k, v))
}
return env
}
func (config *RunConfig) getAppProtocol() string {
appProtocol := strings.ToLower(config.AppProtocol)
switch appProtocol {
case string("grpcs"), string("https"), string("h2c"):
return appProtocol
case string("http"):
// For backwards compatibility, when protocol is HTTP and --app-ssl is set, use "https".
if config.AppSSL {
return "https"
} else {
return "http"
}
case string("grpc"):
// For backwards compatibility, when protocol is GRPC and --app-ssl is set, use "grpcs".
if config.AppSSL {
return string("grpcs")
} else {
return string("grpc")
}
case "":
return string("http")
default:
return ""
}
}
func GetDaprCommand(config *RunConfig) (*exec.Cmd, error) {
daprCMD, err := lookupBinaryFilePath(config.DaprdInstallPath, "daprd")
if err != nil {
@ -405,3 +461,15 @@ func GetAppCommand(config *RunConfig) *exec.Cmd {
return cmd
}
func (l LogDestType) String() string {
return string(l)
}
func (l LogDestType) IsValid() error {
switch l {
case Console, File, FileAndConsole:
return nil
}
return fmt.Errorf("invalid log destination type: %s", l)
}

141
pkg/standalone/run_test.go Normal file
View File

@ -0,0 +1,141 @@
/*
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 standalone
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetEnv(t *testing.T) {
config := &RunConfig{
SharedRunConfig: SharedRunConfig{},
AppID: "testapp",
AppChannelAddress: "localhost",
AppPort: 1234,
HTTPPort: 2345,
GRPCPort: 3456,
ProfilePort: 4567, // This is not included in env.
MetricsPort: 5678,
}
t.Run("no explicit app-protocol", func(t *testing.T) {
expect := []string{
"APP_ID=testapp",
"APP_CHANNEL_ADDRESS=localhost",
"APP_PORT=1234",
"APP_PROTOCOL=http",
"DAPR_HTTP_PORT=2345",
"DAPR_GRPC_PORT=3456",
"DAPR_METRICS_PORT=5678",
}
got := config.getEnv()
sort.Strings(expect)
sort.Strings(got)
assert.Equal(t, expect, got)
})
t.Run("app-protocol grpcs", func(t *testing.T) {
config.AppProtocol = "grpcs"
config.AppSSL = false
expect := []string{
"APP_ID=testapp",
"APP_CHANNEL_ADDRESS=localhost",
"APP_PORT=1234",
"APP_PROTOCOL=grpcs",
"DAPR_HTTP_PORT=2345",
"DAPR_GRPC_PORT=3456",
"DAPR_METRICS_PORT=5678",
}
got := config.getEnv()
sort.Strings(expect)
sort.Strings(got)
assert.Equal(t, expect, got)
})
t.Run("app-protocol http", func(t *testing.T) {
config.AppProtocol = "http"
config.AppSSL = false
expect := []string{
"APP_ID=testapp",
"APP_CHANNEL_ADDRESS=localhost",
"APP_PORT=1234",
"APP_PROTOCOL=http",
"DAPR_HTTP_PORT=2345",
"DAPR_GRPC_PORT=3456",
"DAPR_METRICS_PORT=5678",
}
got := config.getEnv()
sort.Strings(expect)
sort.Strings(got)
assert.Equal(t, expect, got)
})
t.Run("app-protocol http with app-ssl", func(t *testing.T) {
config.AppProtocol = "http"
config.AppSSL = true
expect := []string{
"APP_ID=testapp",
"APP_CHANNEL_ADDRESS=localhost",
"APP_PORT=1234",
"APP_PROTOCOL=https",
"DAPR_HTTP_PORT=2345",
"DAPR_GRPC_PORT=3456",
"DAPR_METRICS_PORT=5678",
}
got := config.getEnv()
sort.Strings(expect)
sort.Strings(got)
assert.Equal(t, expect, got)
})
t.Run("app-protocol grpc with app-ssl", func(t *testing.T) {
config.AppProtocol = "grpc"
config.AppSSL = true
expect := []string{
"APP_ID=testapp",
"APP_CHANNEL_ADDRESS=localhost",
"APP_PORT=1234",
"APP_PROTOCOL=grpcs",
"DAPR_HTTP_PORT=2345",
"DAPR_GRPC_PORT=3456",
"DAPR_METRICS_PORT=5678",
}
got := config.getEnv()
sort.Strings(expect)
sort.Strings(got)
assert.Equal(t, expect, got)
})
}

View File

@ -17,6 +17,7 @@ import (
"io"
"os"
"path/filepath"
"time"
"github.com/dapr/cli/pkg/standalone"
)
@ -34,6 +35,7 @@ type RunFileConfig struct {
Common Common `yaml:"common"`
Apps []App `yaml:"apps"`
Version int `yaml:"version"`
Name string `yaml:"name,omitempty"`
}
// App represents the configuration options for the apps in the run file.
@ -60,8 +62,13 @@ func (a *App) GetLogsDir() string {
// CreateAppLogFile creates the log file, sets internal file handle
// and returns error if any.
func (a *App) CreateAppLogFile() error {
logsPath := a.GetLogsDir()
f, err := os.Create(filepath.Join(logsPath, getAppLogFileName()))
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()
@ -72,8 +79,13 @@ func (a *App) CreateAppLogFile() error {
// CreateDaprdLogFile creates the log file, sets internal file handle
// and returns error if any.
func (a *App) CreateDaprdLogFile() error {
logsPath := a.GetLogsDir()
f, err := os.Create(filepath.Join(logsPath, getDaprdLogFileName()))
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()
@ -81,12 +93,13 @@ func (a *App) CreateDaprdLogFile() error {
return err
}
func getAppLogFileName() string {
return appLogFileNamePrefix + logFileExtension
}
func getDaprdLogFileName() string {
return daprdLogFileNamePrefix + logFileExtension
// 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 {

View File

@ -56,6 +56,20 @@ func (a *RunFileConfig) validateRunConfig(runFilePath string) error {
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 := 0; i < len(a.Apps); i++ {
if a.Apps[i].AppDirPath == "" {
return errors.New("required field 'appDirPath' not found in the provided app config file")
@ -70,6 +84,19 @@ func (a *RunFileConfig) validateRunConfig(runFilePath string) error {
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)
}
}
return nil
}
@ -91,11 +118,13 @@ func (a *RunFileConfig) GetApps(runFilePath string) ([]App, error) {
}
a.mergeCommonAndAppsSharedRunConfig()
a.mergeCommonAndAppsEnv()
// Resolve app ids if not provided in the run file.
err = a.setAppIDIfEmpty()
// Set and validates default fields in the run file.
err = a.setDefaultFields()
if err != nil {
return nil, err
}
return a.Apps, nil
}
@ -121,17 +150,44 @@ func (a *RunFileConfig) mergeCommonAndAppsSharedRunConfig() {
}
}
// 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() error {
for i := range a.Apps {
if a.Apps[i].AppID == "" {
basePath, err := a.getBasePathFromAbsPath(a.Apps[i].AppDirPath)
if err != nil {
return err
}
a.Apps[i].AppID = basePath
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
}
@ -151,6 +207,10 @@ func (a *RunFileConfig) resolvePathToAbsAndValidate(baseDir string, paths ...*st
if *path == "" {
continue
}
*path, err = utils.ResolveHomeDir(*path)
if err != nil {
return err
}
absPath := utils.GetAbsPath(baseDir, *path)
if err != nil {
return err
@ -198,22 +258,22 @@ func (a *RunFileConfig) mergeCommonAndAppsEnv() {
}
// resolveResourcesFilePath resolves the resources path for the app.
// Precedence order for resourcesPath -> apps[i].resourcesPath > apps[i].appDirPath/.dapr/resources > common.resourcesPath > dapr default resources path.
// 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 app.ResourcesPath != "" {
if len(app.ResourcesPaths) > 0 {
return nil
}
localResourcesDir := filepath.Join(app.AppDirPath, standalone.DefaultDaprDirName, standalone.DefaultResourcesDirName)
if err := utils.ValidateFilePath(localResourcesDir); err == nil {
app.ResourcesPath = localResourcesDir
} else if len(strings.TrimSpace(a.Common.ResourcesPath)) > 0 {
app.ResourcesPath = a.Common.ResourcesPath
app.ResourcesPaths = []string{localResourcesDir}
} else if len(a.Common.ResourcesPaths) > 0 {
app.ResourcesPaths = append(app.ResourcesPaths, a.Common.ResourcesPaths...)
} else {
daprDirPath, err := standalone.GetDaprPath(app.DaprdInstallPath)
daprDirPath, err := standalone.GetDaprRuntimePath(app.DaprdInstallPath)
if err != nil {
return fmt.Errorf("error getting dapr install path: %w", err)
}
app.ResourcesPath = standalone.GetDaprComponentsPath(daprDirPath)
app.ResourcesPaths = []string{standalone.GetDaprComponentsPath(daprDirPath)}
}
return nil
}
@ -230,7 +290,7 @@ func (a *RunFileConfig) resolveConfigFilePath(app *App) error {
} else if len(strings.TrimSpace(a.Common.ConfigFile)) > 0 {
app.ConfigFile = a.Common.ConfigFile
} else {
daprDirPath, err := standalone.GetDaprPath(app.DaprdInstallPath)
daprDirPath, err := standalone.GetDaprRuntimePath(app.DaprdInstallPath)
if err != nil {
return fmt.Errorf("error getting dapr install path: %w", err)
}

View File

@ -16,6 +16,7 @@ package runfileconfig
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/dapr/cli/pkg/standalone"
@ -29,9 +30,12 @@ var (
invalidRunFilePath2 = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_empty_app_dir.yaml")
runFileForPrecedenceRule = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_precedence_rule.yaml")
runFileForPrecedenceRuleDaprDir = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_precedence_rule_dapr_dir.yaml")
runFileForLogDestination = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_log_destination.yaml")
runFileForMultiResourcePaths = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_multiple_resources_paths.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)
@ -69,17 +73,17 @@ func TestRunConfigFile(t *testing.T) {
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].ResourcesPath)
assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPath)
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].ResourcesPath = ""
apps[0].ResourcesPaths = []string{}
config.resolveResourcesAndConfigFilePaths()
assert.Equal(t, config.Common.ResourcesPath, apps[0].ResourcesPath)
assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPath)
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.Equal(t, 2, len(apps[0].Env))
@ -102,45 +106,39 @@ func TestRunConfigFile(t *testing.T) {
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
disableCommonSection bool
expectedResourcesPath string
expectedConfigFilePath string
appIndex int
}{
{
name: "resourcesPath and configPath are set in app section",
disableCommonSection: false,
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: "resourcesPath and configPath present in .dapr directory under appDirPath",
disableCommonSection: false,
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: "resourcesPath and configPath are resolved from common's section",
disableCommonSection: false,
expectedResourcesPath: config.Common.ResourcesPath, // from common section.
expectedConfigFilePath: config.Common.ConfigFile, // from common section.
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) {
if tc.disableCommonSection {
config.Common.ResourcesPath = ""
config.Common.ConfigFile = ""
}
// test precedence logic for resourcesPath and configPath.
config.resolveResourcesAndConfigFilePaths()
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPath)
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0])
assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile)
})
}
@ -161,6 +159,11 @@ func TestRunConfigFile(t *testing.T) {
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
@ -168,13 +171,13 @@ func TestRunConfigFile(t *testing.T) {
appIndex int
}{
{
name: "resourcesPath and configPath are resolved from dapr's default installation path.",
name: "resourcesPaths and configPath are resolved from dapr's default installation path.",
expectedResourcesPath: app1ResourcesPath,
expectedConfigFilePath: app1ConfigFilePath,
appIndex: 0,
},
{
name: "resourcesPath and configPath are resolved from dapr's custom installation path.",
name: "resourcesPaths and configPath are resolved from dapr's custom installation path.",
expectedResourcesPath: app2ResourcesPath,
expectedConfigFilePath: app2ConfigFilePath,
appIndex: 1,
@ -183,9 +186,7 @@ func TestRunConfigFile(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
// test precedence logic for resourcesPath and configPath.
config.resolveResourcesAndConfigFilePaths()
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPath)
assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0])
assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile)
})
}
@ -223,6 +224,89 @@ func TestRunConfigFile(t *testing.T) {
})
}
})
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.Equal(t, 6, len(apps))
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 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.Equal(t, tc.expectedNoOfResources, len(config.Apps[tc.appIndex].ResourcesPaths))
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) {
@ -266,7 +350,7 @@ func TestGetBasePathFromAbsPath(t *testing.T) {
func getResourcesAndConfigFilePaths(t *testing.T, daprInstallPath string) []string {
t.Helper()
result := make([]string, 2)
daprDirPath, err := standalone.GetDaprPath(daprInstallPath)
daprDirPath, err := standalone.GetDaprRuntimePath(daprInstallPath)
assert.NoError(t, err)
result[0] = standalone.GetDaprComponentsPath(daprDirPath)
result[1] = standalone.GetDaprConfigPath(daprDirPath)

View File

@ -78,6 +78,9 @@ const (
DaprZipkinContainerName = "dapr_zipkin"
errInstallTemplate = "please run `dapr uninstall` first before running `dapr init`"
healthPort = 58080
metricPort = 59090
)
var (
@ -162,9 +165,9 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
setAirGapInit(fromDir)
if !slimMode {
// If --slim installation is not requested, check if docker is installed.
conatinerRuntimeAvailable := utils.IsDockerInstalled() || utils.IsPodmanInstalled()
if !conatinerRuntimeAvailable {
return errors.New("could not connect to Docker. Docker may not be installed or running")
containerRuntimeAvailable := utils.IsContainerRuntimeInstalled(containerRuntime)
if !containerRuntimeAvailable {
return fmt.Errorf("could not connect to %s. %s may not be installed or running", containerRuntime, containerRuntime)
}
// Initialize default registry only if any of --slim or --image-registry or --from-dir are not given.
@ -215,7 +218,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
print.InfoStatusEvent(os.Stdout, "Installing runtime version %s", runtimeVersion)
installDir, err := GetDaprPath(daprInstallPath)
installDir, err := GetDaprRuntimePath(daprInstallPath)
if err != nil {
return err
}
@ -520,7 +523,10 @@ func runPlacementService(wg *sync.WaitGroup, errorChan chan<- error, info initIn
}
args = append(args,
"-p", fmt.Sprintf("%v:50005", osPort))
"-p", fmt.Sprintf("%v:50005", osPort),
"-p", fmt.Sprintf("%v:8080", healthPort),
"-p", fmt.Sprintf("%v:9090", metricPort),
)
}
args = append(args, image)
@ -905,6 +911,7 @@ func moveFileToPath(filepath string, installLocation string) (string, error) {
p := os.Getenv("PATH")
if !strings.Contains(strings.ToLower(p), strings.ToLower(destDir)) {
destDir = utils.SanitizeDir(destDir)
pathCmd := "[System.Environment]::SetEnvironmentVariable('Path',[System.Environment]::GetEnvironmentVariable('Path','user') + '" + fmt.Sprintf(";%s", destDir) + "', 'user')"
_, err := utils.RunCmdAndWait("powershell", pathCmd)
if err != nil {

View File

@ -18,6 +18,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/dapr/cli/utils"
)
func TestStandaloneConfig(t *testing.T) {
@ -96,7 +98,9 @@ func TestResolveImageWithGHCR(t *testing.T) {
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
got, err := resolveImageURI(test.args)
assert.Equal(t, test.expectErr, err != nil)
assert.Equal(t, test.expect, got)
@ -140,7 +144,9 @@ func TestResolveImageWithDockerHub(t *testing.T) {
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
got, err := resolveImageURI(test.args)
assert.Equal(t, test.expectErr, err != nil)
assert.Equal(t, test.expect, got)
@ -184,7 +190,9 @@ func TestResolveImageWithPrivateRegistry(t *testing.T) {
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
got, err := resolveImageURI(test.args)
assert.Equal(t, test.expectErr, err != nil)
assert.Equal(t, test.expect, got)
@ -304,3 +312,25 @@ func TestIsAirGapInit(t *testing.T) {
})
}
}
func TestInitLogActualContainerRuntimeName(t *testing.T) {
tests := []struct {
containerRuntime string
testName string
}{
{"podman", "Init should log podman as container runtime"},
{"docker", "Init should log docker as container runtime"},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
containerRuntimeAvailable := utils.IsContainerRuntimeInstalled(test.containerRuntime)
if containerRuntimeAvailable {
t.Skip("Skipping test as container runtime is available")
}
err := Init(latestVersion, latestVersion, "", false, "", "", test.containerRuntime, "", "")
assert.NotNil(t, err)
assert.Contains(t, err.Error(), test.containerRuntime)
})
}
}

View File

@ -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

View File

@ -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/

View File

@ -7,4 +7,4 @@ apps:
# tests resourcesPath and config_file resolved from dapr's custom installation directory.
- appID: app_custom_dapr_dir
appDirPath: ./app_precedence_rule/
daprPath: ../custom_dapr_dir
runtimePath: ../custom_dapr_dir

View File

@ -75,7 +75,7 @@ func removeDir(dirPath string) error {
func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string, inputInstallPath string) error {
var containerErrs []error
inputInstallPath = strings.TrimSpace(inputInstallPath)
installDir, err := GetDaprPath(inputInstallPath)
installDir, err := GetDaprRuntimePath(inputInstallPath)
if err != nil {
return err
}
@ -92,10 +92,12 @@ func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string,
containerRuntime = strings.TrimSpace(containerRuntime)
runtimeCmd := utils.GetContainerRuntimeCmd(containerRuntime)
conatinerRuntimeAvailable := false
conatinerRuntimeAvailable = utils.IsDockerInstalled() || utils.IsPodmanInstalled()
if conatinerRuntimeAvailable {
containerRuntimeAvailable := false
containerRuntimeAvailable = utils.IsContainerRuntimeInstalled(containerRuntime)
if containerRuntimeAvailable {
containerErrs = removeContainers(uninstallPlacementContainer, uninstallAll, dockerNetwork, runtimeCmd)
} else if uninstallPlacementContainer || uninstallAll {
print.WarningStatusEvent(os.Stdout, "WARNING: could not delete supporting containers as container runtime is not installed or running")
}
if uninstallAll {
@ -111,8 +113,9 @@ func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string,
return nil
}
// TODO move to use errors.Join once we move to go 1.20.
for _, e := range containerErrs {
err = fmt.Errorf("%w \n %s", err, e)
err = fmt.Errorf("%w \n %w", err, e)
}
return err
}

View File

@ -49,6 +49,9 @@ type helmChartItems struct {
Dapr []struct {
Version string `yaml:"appVersion"`
}
DaprDashboard []struct {
Version string `yaml:"appVersion"`
} `yaml:"dapr-dashboard"`
}
}
@ -150,6 +153,12 @@ func GetLatestReleaseHelmChart(helmChartURL string) (string, error) {
}
}
// Did not find a non-rc version, so we fallback to an RC.
// This is helpful to allow us to validate installation of new charts (Dashboard).
for _, release := range helmChartReleases.Entries.Dapr {
return release.Version, nil
}
return "", fmt.Errorf("no releases")
})
}

View File

@ -213,8 +213,8 @@ func TestGetVersionsHelm(t *testing.T) {
ExpectedVer string
}{
{
"RC releases are skipped",
"/rcs_are_skipped",
"Use RC releases if there isn't a full release yet",
"/fallback_to_rc",
`apiVersion: v1
entries:
dapr:
@ -268,8 +268,8 @@ entries:
urls:
- https://dapr.github.io/helm-charts/dapr-1.2.3-rc.1.tgz
version: 1.2.3-rc.1 `,
"no releases",
"",
"1.2.3-rc.1",
},
}
m := http.NewServeMux()

View File

@ -1,3 +1,3 @@
module emit-metrics
go 1.19
go 1.20

View File

@ -1,3 +1,3 @@
module processor
go 1.19
go 1.20

View File

@ -29,6 +29,7 @@ import (
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dapr/cli/pkg/kubernetes"
"github.com/dapr/cli/tests/e2e/spawn"
k8s "k8s.io/client-go/kubernetes"
@ -60,11 +61,13 @@ type VersionDetails struct {
}
type TestOptions struct {
HAEnabled bool
MTLSEnabled bool
ApplyComponentChanges bool
CheckResourceExists map[Resource]bool
UninstallAll bool
HAEnabled bool
MTLSEnabled bool
ApplyComponentChanges bool
ApplyHTTPEndpointChanges bool
CheckResourceExists map[Resource]bool
UninstallAll bool
InitWithCustomCert bool
}
type TestCase struct {
@ -80,8 +83,8 @@ func GetVersionsFromEnv(t *testing.T, latest bool) (string, string) {
runtimeEnvVar := "DAPR_RUNTIME_PINNED_VERSION"
dashboardEnvVar := "DAPR_DASHBOARD_PINNED_VERSION"
if latest {
runtimeEnvVar = "DAPR_RUNTIME_LATEST_VERSION"
dashboardEnvVar = "DAPR_DASHBOARD_LATEST_VERSION"
runtimeEnvVar = "DAPR_RUNTIME_LATEST_STABLE_VERSION"
dashboardEnvVar = "DAPR_DASHBOARD_LATEST_STABLE_VERSION"
}
if runtimeVersion, ok := os.LookupEnv(runtimeEnvVar); ok {
daprRuntimeVersion = runtimeVersion
@ -105,6 +108,13 @@ func UpgradeTest(details VersionDetails, opts TestOptions) func(t *testing.T) {
"--log-as-json",
}
hasDashboardInDaprChart, err := kubernetes.IsDashboardIncluded(details.RuntimeVersion)
require.NoError(t, err, "failed to check if dashboard is included in dapr chart")
if !hasDashboardInDaprChart {
args = append(args, "--dashboard-version", details.DashboardVersion)
}
if details.ImageVariant != "" {
args = append(args, "--image-variant", details.ImageVariant)
}
@ -171,6 +181,7 @@ func GetTestsOnInstall(details VersionDetails, opts TestOptions) []TestCase {
{"clusterroles exist " + details.RuntimeVersion, ClusterRolesTest(details, opts)},
{"clusterrolebindings exist " + details.RuntimeVersion, ClusterRoleBindingsTest(details, opts)},
{"apply and check components exist " + details.RuntimeVersion, ComponentsTestOnInstallUpgrade(opts)},
{"apply and check httpendpoints exist " + details.RuntimeVersion, HTTPEndpointsTestOnInstallUpgrade(opts)},
{"check mtls " + details.RuntimeVersion, MTLSTestOnInstallUpgrade(opts)},
{"status check " + details.RuntimeVersion, StatusTestOnInstallUpgrade(details, opts)},
}
@ -184,6 +195,7 @@ func GetTestsOnUninstall(details VersionDetails, opts TestOptions) []TestCase {
{"clusterroles not exist " + details.RuntimeVersion, ClusterRolesTest(details, opts)},
{"clusterrolebindings not exist " + details.RuntimeVersion, ClusterRoleBindingsTest(details, opts)},
{"check components exist on uninstall " + details.RuntimeVersion, componentsTestOnUninstall(opts.UninstallAll)},
{"check httpendpoints exist on uninstall " + details.RuntimeVersion, httpEndpointsTestOnUninstall(opts)},
{"check mtls error " + details.RuntimeVersion, uninstallMTLSTest()},
{"check status error " + details.RuntimeVersion, statusTestOnUninstall()},
}
@ -237,6 +249,9 @@ func MTLSTestOnInstallUpgrade(opts TestOptions) func(t *testing.T) {
require.NoError(t, err, "expected no error on querying for mtls expiry")
assert.Contains(t, output, "Root certificate expires in", "expected output to contain string")
assert.Contains(t, output, "Expiry date:", "expected output to contain string")
if opts.InitWithCustomCert {
t.Log("check mtls expiry with custom cert: ", output)
}
// export
// check that the dir does not exist now.
@ -288,6 +303,28 @@ func ComponentsTestOnInstallUpgrade(opts TestOptions) func(t *testing.T) {
}
}
func HTTPEndpointsTestOnInstallUpgrade(opts TestOptions) func(t *testing.T) {
return func(t *testing.T) {
// if dapr is installed with httpendpoints.
if opts.ApplyHTTPEndpointChanges {
// apply any changes to the httpendpoint.
t.Log("apply httpendpoint changes")
output, err := spawn.Command("kubectl", "apply", "-f", "../testdata/namespace.yaml")
t.Log(output)
require.NoError(t, err, "expected no error on kubectl apply")
output, err = spawn.Command("kubectl", "apply", "-f", "../testdata/httpendpoint.yaml")
t.Log(output)
require.NoError(t, err, "expected no error on kubectl apply")
require.Equal(t, "httpendpoints.dapr.io/httpendpoint created\nhttpendpoints.dapr.io/httpendpoint created\n", output, "expected output to match")
httpEndpointOutputCheck(t, output)
t.Log("check applied httpendpoint exists")
_, err = spawn.Command("kubectl", "get", "httpendpoint")
require.NoError(t, err, "expected no error on calling to retrieve httpendpoints")
}
}
}
func StatusTestOnInstallUpgrade(details VersionDetails, opts TestOptions) func(t *testing.T) {
return func(t *testing.T) {
daprPath := GetDaprPath()
@ -329,7 +366,10 @@ func StatusTestOnInstallUpgrade(details VersionDetails, opts TestOptions) func(t
require.Equal(t, "True", cols[2], "healthly field must be true")
require.Equal(t, "Running", cols[3], "pods must be Running")
require.Equal(t, toVerify[1], cols[4], "replicas must be equal")
require.Equal(t, toVerify[0], cols[5], "versions must match")
// TODO: Skip the dashboard version check for now until the helm chart is updated.
if cols[0] != "dapr-dashboard" {
require.Equal(t, toVerify[0], cols[5], "versions must match")
}
delete(notFound, cols[0])
}
}
@ -708,6 +748,7 @@ func installTest(details VersionDetails, opts TestOptions) func(t *testing.T) {
"--log-as-json",
}
if !details.UseDaprLatestVersion {
// TODO: Pass dashboard-version also when charts are released.
args = append(args, "--runtime-version", details.RuntimeVersion)
}
if opts.HAEnabled {
@ -722,6 +763,14 @@ func installTest(details VersionDetails, opts TestOptions) func(t *testing.T) {
if details.ImageVariant != "" {
args = append(args, "--image-variant", details.ImageVariant)
}
if opts.InitWithCustomCert {
certParam := []string{
"--ca-root-certificate", "../testdata/customcerts/root.pem",
"--issuer-private-key", "../testdata/customcerts/issuer.key",
"--issuer-public-certificate", "../testdata/customcerts/issuer.pem",
}
args = append(args, certParam...)
}
output, err := spawn.Command(daprPath, args...)
t.Log(output)
require.NoError(t, err, "init failed")
@ -778,7 +827,7 @@ func componentsTestOnUninstall(all bool) func(t *testing.T) {
return func(t *testing.T) {
daprPath := GetDaprPath()
// On Dapr uninstall CRDs are not removed, consequently the components will not be removed.
// TODO Related to https://github.com/dapr/cli/issues/656.
// TODO: Related to https://github.com/dapr/cli/issues/656.
// For now the components remain.
output, err := spawn.Command(daprPath, "components", "-k")
require.NoError(t, err, "expected no error on calling dapr components")
@ -808,6 +857,37 @@ func componentsTestOnUninstall(all bool) func(t *testing.T) {
}
}
func httpEndpointsTestOnUninstall(opts TestOptions) func(t *testing.T) {
return func(t *testing.T) {
// If --all, then the below does not need to run.
if opts.UninstallAll {
// Note: Namespace is deleted in the uninstall components function,
// so this should return as there is nothing to delete or do.
return
}
if opts.ApplyHTTPEndpointChanges {
// On Dapr uninstall CRDs are not removed, consequently the http endpoints will not be removed.
output, err := spawn.Command("kubectl", "get", "httpendpoints")
require.NoError(t, err, "expected no error on calling dapr httpendpoints")
assert.Contains(t, output, "No resources found")
// Manually remove httpendpoints and verify output.
output, err = spawn.Command("kubectl", "delete", "-f", "../testdata/httpendpoint.yaml")
require.NoError(t, err, "expected no error on kubectl delete")
require.Equal(t, "httpendpoints.dapr.io \"httpendpint\" deleted\nhttpendpoints.dapr.io \"httpendpoint\" deleted\n", output, "expected output to match")
output, err = spawn.Command("kubectl", "delete", "-f", "../testdata/namespace.yaml")
require.NoError(t, err, "expected no error on kubectl delete")
t.Log(output)
output, err = spawn.Command("kubectl", "get", "httpendpoints")
require.NoError(t, err, "expected no error on calling dapr httpendpoints")
lines := strings.Split(output, "\n")
// An extra empty line is there in output.
require.Equal(t, 2, len(lines), "expected kubernetes response message to remain")
}
}
}
func statusTestOnUninstall() func(t *testing.T) {
return func(t *testing.T) {
daprPath := GetDaprPath()
@ -832,7 +912,7 @@ func componentOutputCheck(t *testing.T, output string, all bool) {
lines = strings.Split(output, "\n")[2:] // remove header and warning message.
assert.Equal(t, 2, len(lines), "expected 2 componets") // default and test namespace components.
assert.Equal(t, 2, len(lines), "expected 2 components") // default and test namespace components.
// for fresh cluster only one component yaml has been applied.
testNsFields := strings.Fields(lines[0])
@ -852,6 +932,17 @@ func namespaceComponentOutputCheck(t *testing.T, fields []string, namespace stri
assert.Equal(t, "app1", fields[4], "expected scopes to match")
}
func httpEndpointOutputCheck(t *testing.T, output string) {
const (
headerName = "NAME"
headerAge = "AGE"
)
assert.Contains(t, output, headerName)
assert.Contains(t, output, headerAge)
// check for test httpendpoint named httpendpoint output to be present in output.
assert.Contains(t, output, "httpendpoint")
}
func validatePodsOnInstallUpgrade(t *testing.T, details VersionDetails) {
ctx := context.Background()
ctxt, cancel := context.WithTimeout(ctx, 10*time.Second)
@ -864,9 +955,9 @@ func validatePodsOnInstallUpgrade(t *testing.T, details VersionDetails) {
require.NoError(t, err)
notFound := map[string]string{
"sentry": details.RuntimeVersion,
"sidecar": details.RuntimeVersion,
"dashboard": details.DashboardVersion,
"sentry": details.RuntimeVersion,
"sidecar": details.RuntimeVersion,
// "dashboard": details.DashboardVersion, TODO: enable when helm charts are updated.
"placement": details.RuntimeVersion,
"operator": details.RuntimeVersion,
}
@ -879,9 +970,9 @@ func validatePodsOnInstallUpgrade(t *testing.T, details VersionDetails) {
}
prefixes := map[string]string{
"sentry": "dapr-sentry-",
"sidecar": "dapr-sidecar-injector-",
"dashboard": "dapr-dashboard-",
"sentry": "dapr-sentry-",
"sidecar": "dapr-sidecar-injector-",
// "dashboard": "dapr-dashboard-", TODO: enable when helm charts are updated.
"placement": "dapr-placement-server-",
"operator": "dapr-operator-",
}

View File

@ -17,15 +17,20 @@ limitations under the License.
package kubernetes_test
import (
"strings"
"testing"
"github.com/dapr/cli/tests/e2e/common"
)
var (
currentRuntimeVersion string
currentDashboardVersion string
currentVersionDetails common.VersionDetails
currentRuntimeVersion string
currentDashboardVersion string
currentVersionDetails common.VersionDetails
clusterRoles1_9_X = []string{"dapr-operator-admin", "dashboard-reader"}
clusterRoleBindings1_9_X = []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"}
clusterRoles1_10_X = []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"}
clusterRoleBindings1_10_X = []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"}
)
// ensureCleanEnv function needs to be called in every Test function.
@ -36,12 +41,17 @@ func ensureCleanEnv(t *testing.T, useDaprLatestVersion bool) {
currentVersionDetails = common.VersionDetails{
RuntimeVersion: currentRuntimeVersion,
DashboardVersion: currentDashboardVersion,
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io"},
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io", "httpendpoints.dapr.io"},
ImageVariant: "",
UseDaprLatestVersion: useDaprLatestVersion,
}
if strings.HasPrefix(currentRuntimeVersion, "1.9.") {
currentVersionDetails.ClusterRoles = clusterRoles1_9_X
currentVersionDetails.ClusterRoleBindings = clusterRoleBindings1_9_X
} else {
currentVersionDetails.ClusterRoles = clusterRoles1_10_X
currentVersionDetails.ClusterRoleBindings = clusterRoleBindings1_10_X
}
// Ensure a clean environment
common.EnsureUninstall(true) // does not wait for pod deletion
}
@ -171,6 +181,38 @@ func TestKubernetesHAModeMTLSEnabled(t *testing.T) {
}
}
func TestKubernetesInitWithCustomCert(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, false)
// setup tests
tests := []common.TestCase{}
tests = append(tests, common.GetTestsOnInstall(currentVersionDetails, common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
InitWithCustomCert: true,
ApplyComponentChanges: true,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
common.ClusterRoleBindings: true,
},
})...)
tests = append(tests, common.GetTestsOnUninstall(currentVersionDetails, common.TestOptions{
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: false,
common.ClusterRoleBindings: false,
},
})...)
// execute tests
for _, tc := range tests {
t.Run(tc.Name, tc.Callable)
}
}
// Test for certificate renewal
func TestRenewCertificateMTLSEnabled(t *testing.T) {
@ -423,3 +465,38 @@ func TestKubernetesInstallwithoutRuntimeVersionFlag(t *testing.T) {
t.Run(tc.Name, tc.Callable)
}
}
func TestK8sInstallwithoutRuntimeVersionwithMarinerImagesFlag(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, true)
// install with mariner images
currentVersionDetails.ImageVariant = "mariner"
tests := []common.TestCase{}
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
ApplyComponentChanges: true,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
common.ClusterRoleBindings: true,
},
}
tests = append(tests, common.GetTestsOnInstall(currentVersionDetails, installOpts)...)
// teardown everything
tests = append(tests, common.GetTestsOnUninstall(currentVersionDetails, common.TestOptions{
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: false,
common.ClusterRoleBindings: false,
},
})...)
for _, tc := range tests {
t.Run(tc.Name, tc.Callable)
}
}

View File

@ -33,6 +33,7 @@ func TestStandaloneInitNegatives(t *testing.T) {
require.NoError(t, err, "expected no error on querying for os home dir")
t.Run("run without install", func(t *testing.T) {
t.Parallel()
output, err := cmdRun("")
require.Error(t, err, "expected error status on run without install")
path := filepath.Join(homeDir, ".dapr", "components")
@ -44,18 +45,21 @@ func TestStandaloneInitNegatives(t *testing.T) {
})
t.Run("list without install", func(t *testing.T) {
t.Parallel()
output, err := cmdList("")
require.NoError(t, err, "expected no error status on list without install")
require.Equal(t, "No Dapr instances found.\n", output)
})
t.Run("stop without install", func(t *testing.T) {
t.Parallel()
output, err := cmdStopWithAppID("test")
require.NoError(t, err, "expected no error on stop without install")
require.Contains(t, output, "failed to stop app id test: couldn't find app id test", "expected output to match")
})
t.Run("uninstall without install", func(t *testing.T) {
t.Parallel()
output, err := cmdUninstall()
require.NoError(t, err, "expected no error on uninstall without install")
require.Contains(t, output, "Removing Dapr from your machine...", "expected output to contain message")

View File

@ -0,0 +1,217 @@
//go:build e2e && !template
// +build e2e,!template
/*
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 standalone_test
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/dapr/cli/tests/e2e/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestStandaloneInitRunUninstallNonDefaultDaprPath covers init, version, run and uninstall with --runtime-path flag.
func TestStandaloneInitRunUninstallNonDefaultDaprPath(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
t.Run("run with --runtime-path flag", func(t *testing.T) {
daprPath, err := os.MkdirTemp("", "dapr-e2e-run-with-flag-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
daprRuntimeVersion, daprDashboardVersion := common.GetVersionsFromEnv(t, false)
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--runtime-path", daprPath,
}
output, err := cmdInit(args...)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
// check version
output, err = cmdVersion("", "--runtime-path", daprPath)
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[0], "edge")
assert.Contains(t, lines[1], "Runtime version")
assert.Contains(t, lines[1], daprRuntimeVersion)
args = []string{
"--runtime-path", daprPath,
"--app-id", "run_with_dapr_runtime_path_flag",
"--", "bash", "-c", "echo 'test'",
}
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
// Uninstall Dapr at the end of the test since it's being installed in a non-default location.
must(t, cmdUninstall, "failed to uninstall Dapr from custom path flag", "--runtime-path", daprPath)
customDaprPath := filepath.Join(daprPath, ".dapr")
assert.NoDirExists(t, customDaprPath)
assert.DirExists(t, daprPath)
// Check the directory is empty.
f, err := os.ReadDir(daprPath)
assert.NoError(t, err)
assert.Len(t, f, 0)
})
t.Run("run with custom runtime path env var", func(t *testing.T) {
daprPath, err := os.MkdirTemp("", "dapr-e2e-run-with-env-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
t.Setenv("DAPR_RUNTIME_PATH", daprPath)
daprRuntimeVersion, daprDashboardVersion := common.GetVersionsFromEnv(t, false)
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
}
output, err := cmdInit(args...)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
// check version
output, err = cmdVersion("", "--runtime-path", daprPath)
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[0], "edge")
assert.Contains(t, lines[1], "Runtime version")
assert.Contains(t, lines[1], daprRuntimeVersion)
args = []string{
"--app-id", "run_with_dapr_runtime_path_flag",
"--", "bash", "-c", "echo 'test'",
}
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
// Uninstall Dapr at the end of the test since it's being installed in a non-default location.
must(t, cmdUninstall, "failed to uninstall Dapr from custom env var path")
customDaprPath := filepath.Join(daprPath, ".dapr")
assert.NoDirExists(t, customDaprPath)
assert.DirExists(t, daprPath)
// Check the directory is empty.
f, err := os.ReadDir(daprPath)
assert.NoError(t, err)
assert.Len(t, f, 0)
})
t.Run("run with both runtime path flag and env var", func(t *testing.T) {
daprPathEnv, err := os.MkdirTemp("", "dapr-e2e-run-with-envflag-1-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPathEnv) // clean up
daprPathFlag, err := os.MkdirTemp("", "dapr-e2e-run-with-envflag-2-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPathFlag) // clean up
t.Setenv("DAPR_RUNTIME_PATH", daprPathEnv)
daprRuntimeVersion, daprDashboardVersion := common.GetVersionsFromEnv(t, false)
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--runtime-path", daprPathFlag,
}
output, err := cmdInit(args...)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
// check version
output, err = cmdVersion("", "--runtime-path", daprPathFlag)
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[0], "edge")
assert.Contains(t, lines[1], "Runtime version")
assert.Contains(t, lines[1], daprRuntimeVersion)
args = []string{
"--runtime-path", daprPathFlag,
"--app-id", "run_with_dapr_runtime_path_flag",
"--", "bash", "-c", "echo 'test'",
}
flagDaprdBinPath := filepath.Join(daprPathFlag, ".dapr", "bin", "daprd")
if runtime.GOOS == "windows" {
flagDaprdBinPath += ".exe"
}
assert.FileExists(t, flagDaprdBinPath)
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoDirExists(t, defaultDaprPath)
envDaprBinPath := filepath.Join(daprPathEnv, ".dapr", "bin")
assert.NoDirExists(t, envDaprBinPath)
// Uninstall Dapr at the end of the test since it's being installed in a non-default location.
must(t, cmdUninstall, "failed to uninstall Dapr from custom path flag", "--runtime-path", daprPathFlag)
customDaprPath := filepath.Join(daprPathFlag, ".dapr")
assert.NoDirExists(t, customDaprPath)
assert.DirExists(t, daprPathFlag)
// Check the directory is empty.
f, err := os.ReadDir(daprPathFlag)
assert.NoError(t, err)
assert.Len(t, f, 0)
})
}

View File

@ -36,6 +36,11 @@ import (
func TestStandaloneInit(t *testing.T) {
daprRuntimeVersion, daprDashboardVersion := common.GetVersionsFromEnv(t, false)
t.Cleanup(func() {
// remove dapr installation after all tests in this function.
must(t, cmdUninstall, "failed to uninstall Dapr")
})
t.Run("init with invalid private registry", func(t *testing.T) {
if isSlimMode() {
t.Skip("Skipping init with private registry test because of slim installation")
@ -45,6 +50,7 @@ func TestStandaloneInit(t *testing.T) {
must(t, cmdUninstall, "failed to uninstall Dapr")
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--image-registry", "smplregistry.io/owner",
}
output, err := cmdInit(args...)
@ -61,6 +67,7 @@ func TestStandaloneInit(t *testing.T) {
must(t, cmdUninstall, "failed to uninstall Dapr")
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--image-registry", "localhost:5000",
"--from-dir", "./local-dir",
}
@ -74,6 +81,7 @@ func TestStandaloneInit(t *testing.T) {
must(t, cmdUninstall, "failed to uninstall Dapr")
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--container-runtime", "invalid",
}
output, err := cmdInit(args...)
@ -87,6 +95,7 @@ func TestStandaloneInit(t *testing.T) {
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
}
output, err := cmdInit(args...)
t.Log(output)
@ -110,6 +119,7 @@ func TestStandaloneInit(t *testing.T) {
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
"--image-variant", "mariner",
}
output, err := cmdInit(args...)
@ -128,67 +138,6 @@ func TestStandaloneInit(t *testing.T) {
verifyConfigs(t, daprPath)
})
t.Run("init with --dapr-path flag", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-init-with-flag-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPath)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
verifyContainers(t, daprRuntimeVersion)
verifyBinaries(t, daprPath, daprRuntimeVersion, daprDashboardVersion)
verifyConfigs(t, daprPath)
})
t.Run("init with DAPR_PATH env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-init-with-env-var-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
t.Setenv("DAPR_PATH", daprPath)
output, err := cmdInit("--runtime-version", daprRuntimeVersion)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
verifyContainers(t, daprRuntimeVersion)
verifyBinaries(t, daprPath, daprRuntimeVersion, daprDashboardVersion)
verifyConfigs(t, daprPath)
})
t.Run("init with --dapr-path flag and DAPR_PATH env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath1, err := os.MkdirTemp("", "dapr-e2e-init-with-flag-and-env-1-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath1) // clean up
daprPath2, err := os.MkdirTemp("", "dapr-e2e-init-with-flag-and-env-2-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath2) // clean up
t.Setenv("DAPR_PATH", daprPath1)
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPath2)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
verifyContainers(t, daprRuntimeVersion)
verifyBinaries(t, daprPath2, daprRuntimeVersion, daprDashboardVersion)
verifyConfigs(t, daprPath2)
})
t.Run("init without runtime-version flag", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
@ -209,6 +158,29 @@ func TestStandaloneInit(t *testing.T) {
verifyBinaries(t, daprPath, latestDaprRuntimeVersion, latestDaprDashboardVersion)
verifyConfigs(t, daprPath)
})
t.Run("init without runtime-version flag with mariner images", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
args := []string{
"--image-variant", "mariner",
}
output, err := cmdInit(args...)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
daprPath := filepath.Join(homeDir, ".dapr")
require.DirExists(t, daprPath, "Directory %s does not exist", daprPath)
latestDaprRuntimeVersion, latestDaprDashboardVersion := common.GetVersionsFromEnv(t, true)
verifyContainers(t, latestDaprRuntimeVersion+"-mariner")
verifyBinaries(t, daprPath, latestDaprRuntimeVersion, latestDaprDashboardVersion)
verifyConfigs(t, daprPath)
})
}
// verifyContainers ensures that the correct containers are up and running.

View File

@ -20,6 +20,7 @@ import (
"context"
"fmt"
"net/http"
"strconv"
"testing"
"github.com/dapr/go-sdk/service/common"
@ -28,10 +29,8 @@ import (
"github.com/stretchr/testify/require"
)
func TestStandaloneInvoke(t *testing.T) {
ensureDaprInstallation(t)
s := daprHttp.NewService(":9987")
func StartTestService(t *testing.T, port int) common.Service {
s := daprHttp.NewService(":" + strconv.Itoa(port))
err := s.AddServiceInvocationHandler("/test", func(ctx context.Context, e *common.InvocationEvent) (*common.Content, error) {
val := &common.Content{
@ -44,7 +43,6 @@ func TestStandaloneInvoke(t *testing.T) {
assert.NoError(t, err, "unable to AddTopicEventHandler")
defer s.Stop()
go func() {
err = s.Start()
@ -53,8 +51,16 @@ func TestStandaloneInvoke(t *testing.T) {
err = nil
}
assert.NoError(t, err, "unable to listen on :9987")
assert.NoError(t, err, "unable to listen on :%d", port)
}()
return s
}
func TestStandaloneInvoke(t *testing.T) {
port := 9987
ensureDaprInstallation(t)
s := StartTestService(t, port)
defer s.Stop()
for _, path := range getSocketCases() {
executeAgainstRunningDapr(t, func() {
@ -106,6 +112,29 @@ func TestStandaloneInvoke(t *testing.T) {
t.Log(output)
require.NoError(t, err, "dapr stop failed")
assert.Contains(t, output, "app stopped successfully: invoke_e2e")
}, "run", "--app-id", "invoke_e2e", "--app-port", "9987", "--unix-domain-socket", path)
}, "run", "--app-id", "invoke_e2e", "--app-port", strconv.Itoa(port), "--unix-domain-socket", path)
}
}
func TestStandaloneInvokeWithAppChannel(t *testing.T) {
port := 9988
ensureDaprInstallation(t)
s := StartTestService(t, port)
defer s.Stop()
executeAgainstRunningDapr(t, func() {
t.Run(fmt.Sprintf("data from file with app channel address set to localhost"), func(t *testing.T) {
// empty unix domain socket path
output, err := cmdInvoke("invoke_e2e_app_channel", "test", "", "--data-file", "../testdata/message.json")
t.Log(output)
assert.NoError(t, err, "unable to invoke with --data-file")
assert.Contains(t, output, "App invoked successfully")
assert.Contains(t, output, "{\"dapr\": \"is_great\"}")
})
output, err := cmdStopWithAppID("invoke_e2e_app_channel")
t.Log(output)
require.NoError(t, err, "dapr stop failed")
assert.Contains(t, output, "app stopped successfully: invoke_e2e_app_channel")
}, "run", "--app-id", "invoke_e2e_app_channel", "--app-port", strconv.Itoa(port), "--app-channel-address", "localhost")
}

View File

@ -25,6 +25,7 @@ import (
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -33,7 +34,6 @@ import (
func TestStandaloneList(t *testing.T) {
ensureDaprInstallation(t)
executeAgainstRunningDapr(t, func() {
output, err := cmdList("")
t.Log(output)
@ -98,6 +98,27 @@ func TestStandaloneList(t *testing.T) {
cmd.Process.Kill()
})
t.Run("daprd instance started by run in list", func(t *testing.T) {
go func() {
// starts dapr run in a goroutine
runoutput, err := cmdRun("", "--app-id", "dapr_e2e_list", "--dapr-http-port", "3555", "--dapr-grpc-port", "4555", "--app-port", "0", "--enable-app-health-check", "--", "bash", "-c", "sleep 15; exit 0")
t.Log(runoutput)
require.NoError(t, err, "run failed")
// daprd starts and sleep for 50s, this ensures daprd started by `dapr run ...` is stopped
time.Sleep(15 * time.Second)
assert.Contains(t, runoutput, "Exited Dapr successfully")
}()
// wait for daprd to start
time.Sleep(time.Second)
output, err := cmdList("")
t.Log(output)
require.NoError(t, err, "dapr list failed with dapr run instance")
listOutputCheck(t, output, true)
// sleep to wait dapr run exit, in case have effect on other tests
time.Sleep(15 * time.Second)
})
t.Run("dashboard instance should not be listed", func(t *testing.T) {
// TODO: remove this after figuring out the fix.
// The issue is that the dashboard instance does not gets killed when the app is stopped.
@ -124,7 +145,7 @@ func listOutputCheck(t *testing.T, output string, isCli bool) {
// only one app is runnning at this time
fields := strings.Fields(lines[0])
// Fields splits on space, so Created time field might be split again
assert.GreaterOrEqual(t, len(fields), 4, "expected at least 4 fields in components output")
assert.GreaterOrEqual(t, len(fields), 10, "expected at least 10 fields in components output")
if isCli {
assert.Equal(t, "dapr_e2e_list", fields[0], "expected name to match")
} else {
@ -133,6 +154,7 @@ func listOutputCheck(t *testing.T, output string, isCli bool) {
assert.Equal(t, "3555", fields[1], "expected http port to match")
assert.Equal(t, "4555", fields[2], "expected grpc port to match")
assert.Equal(t, "0", fields[3], "expected app port to match")
assert.NotEmpty(t, fields[9], "expected an app PID (a real value or zero)")
}
func listJsonOutputCheck(t *testing.T, output string) {
@ -147,6 +169,9 @@ func listJsonOutputCheck(t *testing.T, output string) {
assert.Equal(t, 3555, int(result[0]["httpPort"].(float64)), "expected http port to match")
assert.Equal(t, 4555, int(result[0]["grpcPort"].(float64)), "expected grpc port to match")
assert.Equal(t, 0, int(result[0]["appPort"].(float64)), "expected app port to match")
assert.GreaterOrEqual(t, int(result[0]["appPid"].(float64)), 0, "expected an app PID (a real value or zero)")
assert.Equal(t, "", result[0]["appLogPath"], "expected app log path to be empty")
assert.Equal(t, "", result[0]["daprdLogPath"], "expected daprd log path to be empty")
}
func listYamlOutputCheck(t *testing.T, output string) {
@ -161,4 +186,7 @@ func listYamlOutputCheck(t *testing.T, output string) {
assert.Equal(t, 3555, result[0]["httpPort"], "expected http port to match")
assert.Equal(t, 4555, result[0]["grpcPort"], "expected grpc port to match")
assert.Equal(t, 0, result[0]["appPort"], "expected app port to match")
assert.GreaterOrEqual(t, result[0]["appPid"], 0, "expected an app PID (a real value or zero)")
assert.Equal(t, "", result[0]["appLogPath"], "expected app log path to be empty")
assert.Equal(t, "", result[0]["daprdLogPath"], "expected daprd log path to be empty")
}

View File

@ -30,7 +30,6 @@ import (
func TestStandalonePublish(t *testing.T) {
ensureDaprInstallation(t)
sub := &common.Subscription{
PubsubName: "pubsub",
Topic: "sample",

View File

@ -34,11 +34,12 @@ import (
)
type AppTestOutput struct {
appID string
appLogContents []string
daprdLogContent []string
baseLogDirPath string
appLogDoesNotExist bool
appID string
appLogContents []string
daprdLogContent []string
baseLogDirPath string
appLogDoesNotExist bool
daprdLogFileDoesNotExist bool
}
func TestRunWithTemplateFile(t *testing.T) {
@ -70,13 +71,13 @@ func TestRunWithTemplateFile(t *testing.T) {
require.NoError(t, err, "run failed")
// Deterministic output for template file, so we can assert line by line
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 4, "expected at least 4 lines in output of starting two apps")
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[2], "Writing log files to directory")
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[5], "Writing log files to directory")
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
assert.GreaterOrEqual(t, len(lines), 5, "expected at least 5 lines in output of starting two apps")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[6], "Writing log files to directory")
assert.Contains(t, lines[6], "tests/apps/emit-metrics/.dapr/logs")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
appTestOutput := AppTestOutput{
appID: "processor",
@ -120,21 +121,22 @@ func TestRunWithTemplateFile(t *testing.T) {
require.NoError(t, err, "run failed")
// Deterministic output for template file, so we can assert line by line
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 6, "expected at least 6 lines in output of starting two apps")
assert.Contains(t, lines[0], "Validating config and starting app \"processor\"")
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[2], "Writing log files to directory")
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[3], "Validating config and starting app \"emit-metrics\"")
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[5], "Writing log files to directory")
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
assert.GreaterOrEqual(t, len(lines), 7, "expected at least 7 lines in output of starting two apps")
assert.Contains(t, lines[0], "This is a preview feature and subject to change in future releases.")
assert.Contains(t, lines[1], "Validating config and starting app \"processor\"")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[4], "Validating config and starting app \"emit-metrics\"")
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[6], "Writing log files to directory")
assert.Contains(t, lines[6], "tests/apps/emit-metrics/.dapr/logs")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
appTestOutput := AppTestOutput{
appID: "processor",
baseLogDirPath: "../../apps/processor/.dapr/logs",
appLogContents: []string{
"Received metrics: {3}",
"Received metrics: {1}",
},
daprdLogContent: []string{
"http server is running on port 3510",
@ -148,7 +150,7 @@ func TestRunWithTemplateFile(t *testing.T) {
appLogContents: []string{
"DAPR_HTTP_PORT set to 3511",
"DAPR_HOST_ADD set to localhost",
"Metrics with ID 3 sent",
"Metrics with ID 1 sent",
},
daprdLogContent: []string{
"termination signal received: shutting down",
@ -177,13 +179,13 @@ func TestRunWithTemplateFile(t *testing.T) {
require.NoError(t, err, "run failed")
// Deterministic output for template file, so we can assert line by line
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 6, "expected at least 6 lines in output of starting two apps")
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[2], "Writing log files to directory")
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[5], "Writing log files to directory")
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
assert.GreaterOrEqual(t, len(lines), 7, "expected at least 7 lines in output of starting two apps")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[6], "Writing log files to directory")
assert.Contains(t, lines[6], "tests/apps/emit-metrics/.dapr/logs")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
appTestOutput := AppTestOutput{
appID: "processor",
@ -228,14 +230,14 @@ func TestRunWithTemplateFile(t *testing.T) {
require.NoError(t, err, "run failed")
// Deterministic output for template file, so we can assert line by line
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 7, "expected at least 7 lines in output of starting two apps with one app not having a command")
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[2], "Writing log files to directory")
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[4], "No application command found for app \"emit-metrics\" present in")
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[6], "Writing log files to directory")
assert.Contains(t, lines[6], "tests/apps/emit-metrics/.dapr/logs")
assert.GreaterOrEqual(t, len(lines), 8, "expected at least 8 lines in output of starting two apps with one app not having a command")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[5], "No application command found for app \"emit-metrics\" present in")
assert.Contains(t, lines[6], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
assert.Contains(t, lines[7], "Writing log files to directory")
assert.Contains(t, lines[7], "tests/apps/emit-metrics/.dapr/logs")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
appTestOutput := AppTestOutput{
appID: "processor",
@ -280,11 +282,11 @@ func TestRunWithTemplateFile(t *testing.T) {
require.Error(t, err, "run must fail")
// Deterministic output for template file, so we can assert line by line
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 5, "expected at least 5 lines in output of starting two apps with last app having an empty command")
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[2], "Writing log files to directory")
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[4], "Error starting Dapr and app (\"emit-metrics\"): exec: no command")
assert.GreaterOrEqual(t, len(lines), 6, "expected at least 6 lines in output of starting two apps with last app having an empty command")
assert.Contains(t, lines[2], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
assert.Contains(t, lines[3], "Writing log files to directory")
assert.Contains(t, lines[3], "tests/apps/processor/.dapr/logs")
assert.Contains(t, lines[5], "Error starting Dapr and app (\"emit-metrics\"): exec: no command")
appTestOutput := AppTestOutput{
appID: "processor",
baseLogDirPath: "../../apps/processor/.dapr/logs",
@ -310,6 +312,64 @@ func TestRunWithTemplateFile(t *testing.T) {
}
assertLogOutputForRunTemplateExec(t, appTestOutput)
})
t.Run("valid template file with app/daprd log destinations", func(t *testing.T) {
runFilePath := "../testdata/run-template-files/app_output_to_file_and_console.yaml"
t.Cleanup(func() {
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
os.RemoveAll("../../apps/processor/.dapr/logs")
stopAllApps(t, runFilePath)
})
args := []string{
"-f", runFilePath,
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
output, err := cmdRunWithContext(ctx, "", args...)
t.Logf(output)
require.NoError(t, err, "run failed")
// App logs for processor app should not be printed to console and only written to file.
assert.NotContains(t, output, "== APP - processor")
// Daprd logs for processor app should only be printed to console and not written to file.
assert.Contains(t, output, "msg=\"All outstanding components processed\" app_id=processor")
// App logs for emit-metrics app should be printed to console and written to file.
assert.Contains(t, output, "== APP - emit-metrics")
// Daprd logs for emit-metrics app should only be written to file.
assert.NotContains(t, output, "msg=\"All outstanding components processed\" app_id=emit-metrics")
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
appTestOutput := AppTestOutput{
appID: "processor",
baseLogDirPath: "../../apps/processor/.dapr/logs",
appLogContents: []string{
"Received metrics: {1}",
},
daprdLogContent: []string{},
daprdLogFileDoesNotExist: true,
}
assertLogOutputForRunTemplateExec(t, appTestOutput)
appTestOutput = AppTestOutput{
appID: "emit-metrics",
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
appLogContents: []string{
"DAPR_HTTP_PORT set to 3511",
"DAPR_HOST_ADD set to localhost",
"Metrics with ID 1 sent",
},
daprdLogContent: []string{
"termination signal received: shutting down",
"Exited Dapr successfully",
"Exited App successfully",
},
}
assertLogOutputForRunTemplateExec(t, appTestOutput)
})
}
func TestRunTemplateFileWithoutDaprInit(t *testing.T) {
@ -327,7 +387,7 @@ func TestRunTemplateFileWithoutDaprInit(t *testing.T) {
output, err := cmdRunWithContext(ctx, "", args...)
t.Logf(output)
require.Error(t, err, "run must fail")
assert.Contains(t, output, " Error starting Dapr and app (\"processor\"): fork/exec")
assert.Contains(t, output, "Error starting Dapr and app (\"processor\"): fork/exec")
assert.Contains(t, output, "daprd: no such file or directory")
})
}
@ -335,11 +395,12 @@ func TestRunTemplateFileWithoutDaprInit(t *testing.T) {
func assertLogOutputForRunTemplateExec(t *testing.T, appTestOutput AppTestOutput) {
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
// This is true for the tests in this file.
daprdLogFileName, err := lookUpFileFullName(appTestOutput.baseLogDirPath, "daprd")
require.NoError(t, err, "failed to find daprd log file")
daprdLogPath := filepath.Join(appTestOutput.baseLogDirPath, daprdLogFileName)
readAndAssertLogFileContents(t, daprdLogPath, appTestOutput.daprdLogContent)
if !appTestOutput.daprdLogFileDoesNotExist {
daprdLogFileName, err := lookUpFileFullName(appTestOutput.baseLogDirPath, "daprd")
require.NoError(t, err, "failed to find daprd log file")
daprdLogPath := filepath.Join(appTestOutput.baseLogDirPath, daprdLogFileName)
readAndAssertLogFileContents(t, daprdLogPath, appTestOutput.daprdLogContent)
}
if appTestOutput.appLogDoesNotExist {
return
}
@ -377,4 +438,5 @@ func lookUpFileFullName(dirPath, partialFilename string) (string, error) {
func stopAllApps(t *testing.T, runfile string) {
_, err := cmdStopWithRunTemplate(runfile)
require.NoError(t, err, "failed to stop apps")
time.Sleep(5 * time.Second)
}

View File

@ -18,20 +18,19 @@ package standalone_test
import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/dapr/cli/tests/e2e/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStandaloneRun(t *testing.T) {
ensureDaprInstallation(t)
t.Cleanup(func() {
// remove dapr installation after all tests in this function.
must(t, cmdUninstall, "failed to uninstall Dapr")
})
for _, path := range getSocketCases() {
t.Run(fmt.Sprintf("normal exit, socket: %s", path), func(t *testing.T) {
output, err := cmdRun(path, "--", "bash", "-c", "echo test")
@ -39,6 +38,7 @@ func TestStandaloneRun(t *testing.T) {
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "Could not update sidecar metadata for cliPID")
})
t.Run(fmt.Sprintf("error exit, socket: %s", path), func(t *testing.T) {
@ -47,6 +47,7 @@ func TestStandaloneRun(t *testing.T) {
require.Error(t, err, "run failed")
assert.Contains(t, output, "The App process exited with error code: exit status 1")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "Could not update sidecar metadata for cliPID")
})
t.Run("Use internal gRPC port if specified", func(t *testing.T) {
@ -56,6 +57,7 @@ func TestStandaloneRun(t *testing.T) {
assert.Contains(t, output, "internal gRPC server is running on port 9999")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "Could not update sidecar metadata for cliPID")
})
}
@ -66,6 +68,7 @@ func TestStandaloneRun(t *testing.T) {
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully", "App should be shutdown before it has a chance to return non-zero")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "Could not update sidecar metadata for cliPID")
})
t.Run("API shutdown with socket", func(t *testing.T) {
@ -78,6 +81,7 @@ func TestStandaloneRun(t *testing.T) {
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "Could not update sidecar metadata for cliPID")
})
t.Run(fmt.Sprintf("check enableAPILogging flag in enabled mode"), func(t *testing.T) {
@ -91,7 +95,10 @@ func TestStandaloneRun(t *testing.T) {
output, err := cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "level=info msg=\"HTTP API Called: PUT /v1.0/metadata/appCommand")
assert.Contains(t, output, "level=info msg=\"HTTP API Called\" app_id=enableApiLogging_info")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/appCommand\"")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/cliPID\"")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/appPID\"")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
})
@ -107,7 +114,28 @@ func TestStandaloneRun(t *testing.T) {
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
assert.NotContains(t, output, "level=info msg=\"HTTP API Called: PUT /v1.0/metadata/appCommand\"")
assert.NotContains(t, output, "level=info msg=\"HTTP API Called\" app_id=enableApiLogging_info")
assert.NotContains(t, output, "method=\"PUT /v1.0/metadata/appCommand\"")
assert.NotContains(t, output, "method=\"PUT /v1.0/metadata/cliPID\"")
assert.NotContains(t, output, "method=\"PUT /v1.0/metadata/appPID\"")
})
t.Run(fmt.Sprintf("check enableAPILogging with obfuscation through dapr config file"), func(t *testing.T) {
args := []string{
"--app-id", "enableApiLogging_info",
"--config", "../testdata/config.yaml",
"--", "bash", "-c", "echo 'test'",
}
output, err := cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
assert.Contains(t, output, "level=info msg=\"HTTP API Called\" app_id=enableApiLogging_info")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/{key}\"")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/{key}\"")
assert.Contains(t, output, "method=\"PUT /v1.0/metadata/{key}\"")
})
t.Run(fmt.Sprintf("check run with log JSON enabled"), func(t *testing.T) {
@ -145,7 +173,23 @@ func TestStandaloneRun(t *testing.T) {
output, err := cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "component loaded. name: test-statestore, type: state.in-memory/v1")
assert.Contains(t, output, "Component loaded: test-statestore (state.in-memory/v1)")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
})
t.Run("check run with multiple resources-path", func(t *testing.T) {
args := []string{
"--app-id", "testapp",
"--resources-path", "../testdata/resources",
"--resources-path", "../testdata/additional_resources",
"--", "bash", "-c", "echo 'test'",
}
output, err := cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Component loaded: test-statestore (state.in-memory/v1)")
assert.Contains(t, output, "Component loaded: test-statestore-additional-resource (state.in-memory/v1)")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
})
@ -158,127 +202,3 @@ func TestStandaloneRun(t *testing.T) {
require.Contains(t, output, "The id for your application, used for service discovery", "expected usage to be printed")
})
}
func TestStandaloneRunNonDefaultDaprPath(t *testing.T) {
// Uninstall Dapr at the end of the test since it's being installed in a non-default location.
t.Cleanup(func() {
must(t, cmdUninstall, "failed to uninstall Dapr")
})
t.Run("run with flag", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-run-with-flag-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPath)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
args := []string{
"--dapr-path", daprPath,
"--app-id", "run_with_dapr_path_flag",
"--", "bash", "-c", "echo 'test'",
}
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
})
t.Run("run with env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-run-with-env-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
t.Setenv("DAPR_PATH", daprPath)
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
args := []string{
"--app-id", "run_with_dapr_path_flag",
"--", "bash", "-c", "echo 'test'",
}
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
})
t.Run("run with both flag and env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPathForEnv, err := os.MkdirTemp("", "dapr-e2e-run-with-envflag-1-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPathForEnv) // clean up
daprPathForFlag, err := os.MkdirTemp("", "dapr-e2e-run-with-envflag-2-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPathForFlag) // clean up
t.Setenv("DAPR_PATH", daprPathForEnv)
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPathForFlag)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
args := []string{
"--dapr-path", daprPathForFlag,
"--app-id", "run_with_dapr_path_flag",
"--", "bash", "-c", "echo 'test'",
}
flagDaprdBinPath := filepath.Join(daprPathForFlag, "bin", "daprd")
if runtime.GOOS == "windows" {
flagDaprdBinPath += ".exe"
}
assert.FileExists(t, flagDaprdBinPath)
output, err = cmdRun("", args...)
t.Log(output)
require.NoError(t, err, "run failed")
assert.Contains(t, output, "Exited App successfully")
assert.Contains(t, output, "Exited Dapr successfully")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
envDaprBinPath := filepath.Join(daprPathForEnv, "bin")
assert.NoFileExists(t, envDaprBinPath)
})
}

View File

@ -25,7 +25,6 @@ import (
func TestStandaloneStop(t *testing.T) {
ensureDaprInstallation(t)
executeAgainstRunningDapr(t, func() {
t.Run("stop", func(t *testing.T) {
output, err := cmdStopWithAppID("dapr_e2e_stop")

View File

@ -44,6 +44,8 @@ func TestStopAppsStartedWithRunTemplate(t *testing.T) {
go ensureAllAppsStartedWithRunTemplate(t)
time.Sleep(10 * time.Second)
cliPID := getCLIPID(t)
// Assert dapr list contains template name
assertTemplateListOutput(t, "test_dapr_template")
output, err := cmdStopWithRunTemplate("../testdata/run-template-files/dapr.yaml")
assert.NoError(t, err, "failed to stop apps started with run template")
assert.Contains(t, output, "Dapr and app processes stopped successfully")
@ -110,7 +112,24 @@ func getCLIPID(t *testing.T) string {
}
func verifyCLIPIDNotExist(t *testing.T, pid string) {
time.Sleep(5 * time.Second)
output, err := cmdList("")
require.NoError(t, err, "failed to list apps")
assert.NotContains(t, output, pid)
}
func assertTemplateListOutput(t *testing.T, name string) {
output, err := cmdList("json")
t.Log(output)
require.NoError(t, err, "dapr list failed")
var result []map[string]interface{}
err = json.Unmarshal([]byte(output), &result)
assert.NoError(t, err, "output was not valid JSON")
assert.Len(t, result, 2, "expected two apps to be running")
assert.Equal(t, name, result[0]["runTemplateName"], "expected run template name to be %s", name)
assert.NotEmpty(t, result[0]["appLogPath"], "expected appLogPath to be non-empty")
assert.NotEmpty(t, result[0]["daprdLogPath"], "expected daprdLogPath to be non-empty")
}

View File

@ -125,7 +125,7 @@ func executeAgainstRunningDapr(t *testing.T, f func(), daprArgs ...string) {
// ensureDaprInstallation ensures that Dapr is installed.
// If Dapr is not installed, a new installation is attempted.
func ensureDaprInstallation(t *testing.T) {
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
daprRuntimeVersion, daprDashboardVersion := common.GetVersionsFromEnv(t, false)
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
@ -134,6 +134,7 @@ func ensureDaprInstallation(t *testing.T) {
if os.IsNotExist(err) {
args := []string{
"--runtime-version", daprRuntimeVersion,
"--dashboard-version", daprDashboardVersion,
}
output, err := cmdInit(args...)
require.NoError(t, err, "failed to install dapr:%v", output)

View File

@ -18,20 +18,16 @@ package standalone_test
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"github.com/dapr/cli/tests/e2e/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStandaloneVersion(t *testing.T) {
ensureDaprInstallation(t)
t.Run("version", func(t *testing.T) {
output, err := cmdVersion("")
t.Log(output)
@ -39,7 +35,10 @@ func TestStandaloneVersion(t *testing.T) {
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[0], "edge")
assert.Contains(t, lines[1], "Runtime version")
runtimeVer, _ := common.GetVersionsFromEnv(t, false)
assert.Contains(t, lines[1], runtimeVer)
})
t.Run("version json", func(t *testing.T) {
@ -49,105 +48,8 @@ func TestStandaloneVersion(t *testing.T) {
var result map[string]interface{}
err = json.Unmarshal([]byte(output), &result)
assert.NoError(t, err, "output was not valid JSON")
})
}
func TestStandaloneVersionNonDefaultDaprPath(t *testing.T) {
t.Run("version with flag", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-ver-with-flag-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPath)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
output, err = cmdVersion("", "--dapr-path", daprPath)
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[1], "Runtime version")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
})
t.Run("version with env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath, err := os.MkdirTemp("", "dapr-e2e-ver-with-env-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath) // clean up
t.Setenv("DAPR_PATH", daprPath)
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
output, err = cmdVersion("")
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[1], "Runtime version")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
})
t.Run("version with both flag and env var", func(t *testing.T) {
// Ensure a clean environment
must(t, cmdUninstall, "failed to uninstall Dapr")
daprPath1, err := os.MkdirTemp("", "dapr-e2e-ver-with-both-flag-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath1) // clean up
daprPath2, err := os.MkdirTemp("", "dapr-e2e-ver-with-both-env-*")
assert.NoError(t, err)
defer os.RemoveAll(daprPath2) // clean up
t.Setenv("DAPR_PATH", daprPath2)
daprRuntimeVersion, _ := common.GetVersionsFromEnv(t, false)
output, err := cmdInit("--runtime-version", daprRuntimeVersion, "--dapr-path", daprPath1)
t.Log(output)
require.NoError(t, err, "init failed")
assert.Contains(t, output, "Success! Dapr is up and running.")
output, err = cmdVersion("", "--dapr-path", daprPath1)
t.Log(output)
require.NoError(t, err, "dapr version failed")
lines := strings.Split(output, "\n")
assert.GreaterOrEqual(t, len(lines), 2, "expected at least 2 fields in components outptu")
assert.Contains(t, lines[0], "CLI version")
assert.Contains(t, lines[1], "Runtime version")
homeDir, err := os.UserHomeDir()
require.NoError(t, err, "failed to get user home directory")
defaultDaprPath := filepath.Join(homeDir, ".dapr")
assert.NoFileExists(t, defaultDaprPath)
envDaprBinPath := filepath.Join(daprPath2, "bin")
assert.NoFileExists(t, envDaprBinPath)
assert.Contains(t, result["Cli version"], "edge")
runtimeVer, _ := common.GetVersionsFromEnv(t, false)
assert.Contains(t, result["Runtime version"], runtimeVer)
})
}

View File

@ -0,0 +1,8 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: test-statestore-additional-resource
spec:
type: state.in-memory
version: v1
metadata:

9
tests/e2e/testdata/config.yaml vendored Normal file
View File

@ -0,0 +1,9 @@
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
logging:
apiLogging:
enabled: true
obfuscateURLs: true

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINqlhfOSK2ivIM6PZEQLLMKzN2XYoj+rsnuUiFPFNgh3oAoGCCqGSM49
AwEHoUQDQgAE32a9w5gISgHyxKSKDaQcJGKPVzPoil9VzbIx01bPg+xjzIEyw+Ab
ubZ7i9o0uaSlpyenBhUhyR6I6sT8UA92QQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICkzCCAjmgAwIBAgIUYTVByaDUJwdVWOtFyoqMoU+XvgAwCgYIKoZIzj0EAwIw
eDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMRIwEAYDVQQHDAlEYXBydmlsbGUx
FzAVBgNVBAoMDmRhcHIuaW8vc2VudHJ5MRcwFQYDVQQLDA5kYXByLmlvL3NlbnRy
eTEWMBQGA1UEAwwNY2x1c3Rlci5sb2NhbDAeFw0yMzAyMjcxNDE0MTVaFw0zMzAy
MjQxNDE0MTVaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTESMBAGA1UEBwwJ
RGFwcnZpbGxlMRcwFQYDVQQKDA5kYXByLmlvL3NlbnRyeTEXMBUGA1UECwwOZGFw
ci5pby9zZW50cnkxFjAUBgNVBAMMDWNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAATfZr3DmAhKAfLEpIoNpBwkYo9XM+iKX1XNsjHTVs+D7GPM
gTLD4Bu5tnuL2jS5pKWnJ6cGFSHJHojqxPxQD3ZBo4GgMIGdMBIGA1UdEwEB/wQI
MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAYBgNVHREEETAPgg1jbHVzdGVyLmxvY2FsMB0GA1UdDgQWBBRt6RVG
Y/Tu0iu/2n8Lw8LWYTAhLDAfBgNVHSMEGDAWgBSuUlkVIBFlcn6lB4XOeKRJeNLy
cTAKBggqhkjOPQQDAgNIADBFAiEAve7rRSuFt4zpeui5vnPvWvDhxzt1TaCe54iN
Y4SkoM8CIDQaa0EVxK+vSfew2t9b6KZ3/7rkLbUb3bjFhYqBCDCB
-----END CERTIFICATE-----

16
tests/e2e/testdata/customcerts/root.pem vendored Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICbTCCAhOgAwIBAgIUcDykAW2uO32/kmitYwg4vqntygQwCgYIKoZIzj0EAwIw
eDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMRIwEAYDVQQHDAlEYXBydmlsbGUx
FzAVBgNVBAoMDmRhcHIuaW8vc2VudHJ5MRcwFQYDVQQLDA5kYXByLmlvL3NlbnRy
eTEWMBQGA1UEAwwNY2x1c3Rlci5sb2NhbDAeFw0yMzAyMjcxNDEzNTBaFw0zMzAy
MjQxNDEzNTBaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTESMBAGA1UEBwwJ
RGFwcnZpbGxlMRcwFQYDVQQKDA5kYXByLmlvL3NlbnRyeTEXMBUGA1UECwwOZGFw
ci5pby9zZW50cnkxFjAUBgNVBAMMDWNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAAS492cvbcRQj2xhI7SVRWMidesLgEdcts7qwtXl0p/2AXB8
j/iYHJQh5ANugZW12WJnpM9/AVQ5fmp4B6GBcmI2o3sweTAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
AwIwGAYDVR0RBBEwD4INY2x1c3Rlci5sb2NhbDAdBgNVHQ4EFgQUrlJZFSARZXJ+
pQeFznikSXjS8nEwCgYIKoZIzj0EAwIDSAAwRQIgHCDe5YBRz0BHPJDUnHEzgYAt
FJo72wjN6BU5Sp0UbyUCIQCZAaEaLe7oUPIdLyaIiWj+FHTAi141uOOulP26AGwn
wQ==
-----END CERTIFICATE-----

12
tests/e2e/testdata/httpendpoint.yaml vendored Normal file
View File

@ -0,0 +1,12 @@
apiVersion: dapr.io/v1alpha1
kind: HTTPEndpoint
metadata:
name: "httpendpoint"
namespace: default
spec:
baseUrl: "https://test.com"
headers:
- name: "Accept-Language"
value: "en-US"
scopes:
- app1

View File

@ -0,0 +1,14 @@
version: 1
apps:
- appDirPath: ../../../apps/processor/
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: file
daprdLogDestination: console
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
env:
DAPR_HOST_ADD: localhost
command: ["go","run", "app.go"]

View File

@ -1,12 +1,15 @@
version: 1
name: test_dapr_template
apps:
- appDirPath: ../../../apps/processor/
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: file
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
env:
DAPR_HOST_ADD: localhost
command: ["go","run", "app.go"]
appLogDestination: file

View File

@ -4,9 +4,11 @@ apps:
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: file
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
appLogDestination: file
env:
DAPR_HOST_ADD: localhost
command: [""]

View File

@ -3,8 +3,10 @@ apps:
- appDirPath: ../../../apps/processor/
appPort: 9081
daprHTTPPort: 3510
appLogDestination: file
command: ["go","run", "app.go"]
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511 # required env var DAPR_HOST_ADD not set in the yaml file
appLogDestination: file
command: ["go","run", "app.go"]

View File

@ -9,9 +9,11 @@ apps:
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: file
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
appLogDestination: file
env:
DAPR_HOST_ADD: localhost

View File

@ -4,6 +4,7 @@ apps:
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
appLogDestination: file
- appID: emit-metrics
appDirPath: ../../../apps/emit-metrics/
daprHTTPPort: 3511
@ -11,3 +12,4 @@ apps:
DAPR_HOST_ADD: localhost
# Set wrong app name
command: ["go","run", "wrongappname.go"]
appLogDestination: file

View File

@ -15,6 +15,7 @@ package upgrade
import (
"fmt"
"strings"
"testing"
"github.com/dapr/cli/tests/e2e/common"
@ -37,7 +38,7 @@ var supportedUpgradePaths = []upgradePath{
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
next: common.VersionDetails{
RuntimeVersion: "1.8.4",
RuntimeVersion: "1.8.7",
DashboardVersion: "0.10.0",
ImageVariant: "mariner",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
@ -47,66 +48,50 @@ var supportedUpgradePaths = []upgradePath{
},
{
previous: common.VersionDetails{
RuntimeVersion: "1.7.4",
DashboardVersion: "0.10.0",
RuntimeVersion: "1.9.5",
DashboardVersion: "0.11.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
next: common.VersionDetails{
RuntimeVersion: "1.8.0",
DashboardVersion: "0.10.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
RuntimeVersion: "1.10.7",
DashboardVersion: "0.12.0",
ClusterRoles: []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"},
ClusterRoleBindings: []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
},
{
previous: common.VersionDetails{
RuntimeVersion: "1.6.0",
DashboardVersion: "0.9.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io"},
RuntimeVersion: "1.10.7",
DashboardVersion: "0.12.0",
ClusterRoles: []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"},
ClusterRoleBindings: []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
next: common.VersionDetails{
RuntimeVersion: "1.7.0",
DashboardVersion: "0.10.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
RuntimeVersion: "1.11.0",
DashboardVersion: "0.13.0",
ClusterRoles: []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"},
ClusterRoleBindings: []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io", "httpendpoints.dapr.io"},
},
},
// test downgrade.
{
previous: common.VersionDetails{
RuntimeVersion: "1.9.0",
DashboardVersion: "0.11.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
RuntimeVersion: "1.11.0",
DashboardVersion: "0.13.0",
ClusterRoles: []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"},
ClusterRoleBindings: []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io", "httpendpoints.dapr.io"},
},
next: common.VersionDetails{
RuntimeVersion: "1.8.4",
DashboardVersion: "0.10.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
},
{
previous: common.VersionDetails{
RuntimeVersion: "1.8.4",
DashboardVersion: "0.10.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
next: common.VersionDetails{
RuntimeVersion: "1.9.0",
DashboardVersion: "0.11.0",
ClusterRoles: []string{"dapr-operator-admin", "dashboard-reader"},
ClusterRoleBindings: []string{"dapr-operator", "dapr-role-tokenreview-binding", "dashboard-reader-global"},
RuntimeVersion: "1.10.7",
DashboardVersion: "0.12.0",
ClusterRoles: []string{"dapr-dashboard", "dapr-injector", "dapr-operator-admin", "dapr-placement", "dapr-sentry"},
ClusterRoleBindings: []string{"dapr-operator-admin", "dapr-dashboard", "dapr-injector", "dapr-placement", "dapr-sentry"},
CustomResourceDefs: []string{"components.dapr.io", "configurations.dapr.io", "subscriptions.dapr.io", "resiliencies.dapr.io"},
},
},
@ -126,6 +111,7 @@ func getTestsOnUpgrade(p upgradePath, installOpts, upgradeOpts common.TestOption
{Name: "clusterroles exist " + details.RuntimeVersion, Callable: common.ClusterRolesTest(details, upgradeOpts)},
{Name: "clusterrolebindings exist " + details.RuntimeVersion, Callable: common.ClusterRoleBindingsTest(details, upgradeOpts)},
{Name: "previously applied components exist " + details.RuntimeVersion, Callable: common.ComponentsTestOnInstallUpgrade(upgradeOpts)},
{Name: "previously applied http endpoints exist " + details.RuntimeVersion, Callable: common.HTTPEndpointsTestOnInstallUpgrade(upgradeOpts)},
{Name: "check mtls " + details.RuntimeVersion, Callable: common.MTLSTestOnInstallUpgrade(upgradeOpts)},
{Name: "status check " + details.RuntimeVersion, Callable: common.StatusTestOnInstallUpgrade(details, upgradeOpts)},
}...)
@ -163,9 +149,10 @@ func TestUpgradePathNonHAModeMTLSDisabled(t *testing.T) {
for _, p := range supportedUpgradePaths {
t.Run(fmt.Sprintf("v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: false,
ApplyComponentChanges: true,
HAEnabled: false,
MTLSEnabled: false,
ApplyComponentChanges: true,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -176,8 +163,9 @@ func TestUpgradePathNonHAModeMTLSDisabled(t *testing.T) {
upgradeOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: false,
// do not apply changes on upgrade, verify existing components.
ApplyComponentChanges: false,
// do not apply changes on upgrade, verify existing components and httpendpoints.
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -206,9 +194,10 @@ func TestUpgradePathNonHAModeMTLSEnabled(t *testing.T) {
for _, p := range supportedUpgradePaths {
t.Run(fmt.Sprintf("v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
ApplyComponentChanges: true,
HAEnabled: false,
MTLSEnabled: true,
ApplyComponentChanges: true,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -219,8 +208,9 @@ func TestUpgradePathNonHAModeMTLSEnabled(t *testing.T) {
upgradeOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
// do not apply changes on upgrade, verify existing components.
ApplyComponentChanges: false,
// do not apply changes on upgrade, verify existing components and httpendpoints.
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -249,9 +239,10 @@ func TestUpgradePathHAModeMTLSDisabled(t *testing.T) {
for _, p := range supportedUpgradePaths {
t.Run(fmt.Sprintf("v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
installOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: false,
ApplyComponentChanges: true,
HAEnabled: true,
MTLSEnabled: false,
ApplyComponentChanges: true,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -262,8 +253,9 @@ func TestUpgradePathHAModeMTLSDisabled(t *testing.T) {
upgradeOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: false,
// do not apply changes on upgrade, verify existing components.
ApplyComponentChanges: false,
// do not apply changes on upgrade, verify existing components and httpendpoints.
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -292,9 +284,10 @@ func TestUpgradePathHAModeMTLSEnabled(t *testing.T) {
for _, p := range supportedUpgradePaths {
t.Run(fmt.Sprintf("v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
installOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: true,
ApplyComponentChanges: true,
HAEnabled: true,
MTLSEnabled: true,
ApplyComponentChanges: true,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
@ -305,8 +298,60 @@ func TestUpgradePathHAModeMTLSEnabled(t *testing.T) {
upgradeOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: true,
// do not apply changes on upgrade, verify existing components.
ApplyComponentChanges: false,
// do not apply changes on upgrade, verify existing components and httpendpoints.
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: false,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
common.ClusterRoleBindings: true,
},
}
tests := getTestsOnUpgrade(p, installOpts, upgradeOpts)
for _, tc := range tests {
t.Run(tc.Name, tc.Callable)
}
})
}
}
// HTTPEndpoint Dapr resource is a new type as of v1.11.
// This test verifies install/upgrade functionality with this additional resource.
func TestUpgradeWithHTTPEndpoint(t *testing.T) {
// Ensure a clean environment.
common.EnsureUninstall(false) // does not wait for pod deletion.
for _, p := range supportedUpgradePaths {
t.Run(fmt.Sprintf("setup v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
t.Run("delete CRDs "+p.previous.RuntimeVersion, common.DeleteCRD(p.previous.CustomResourceDefs))
t.Run("delete CRDs "+p.next.RuntimeVersion, common.DeleteCRD(p.next.CustomResourceDefs))
})
}
for _, p := range supportedUpgradePaths {
// only check runtime versions that support HTTPEndpoint resource.
if !strings.Contains(p.next.RuntimeVersion, "1.11") {
return
}
t.Run(fmt.Sprintf("v%s to v%s", p.previous.RuntimeVersion, p.next.RuntimeVersion), func(t *testing.T) {
installOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: true,
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: true,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,
common.ClusterRoleBindings: true,
},
}
upgradeOpts := common.TestOptions{
HAEnabled: true,
MTLSEnabled: true,
// do not apply changes on upgrade, verify existing components and httpendpoints.
ApplyComponentChanges: false,
ApplyHTTPEndpointChanges: true,
CheckResourceExists: map[common.Resource]bool{
common.CustomResourceDefs: true,
common.ClusterRoles: true,

View File

@ -24,6 +24,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
@ -44,6 +45,12 @@ const (
marinerImageVariantName = "mariner"
socketFormat = "%s/dapr-%s-%s.socket"
windowsOsType = "windows"
homeDirPrefix = "~/"
// DefaultAppChannelAddress is the default local network address that user application listen on.
DefaultAppChannelAddress = "127.0.0.1"
)
// IsValidContainerRuntime checks if the input is a valid container runtime.
@ -169,10 +176,21 @@ func CreateDirectory(dir string) error {
return os.Mkdir(dir, 0o777)
}
// IsDockerInstalled checks whether docker is installed/running.
func IsDockerInstalled() bool {
//nolint:staticcheck
cli, err := client.NewEnvClient()
// IsContainerRuntimeInstalled checks whether the given container runtime is installed.
// If the container runtime is unsupported, false is returned.
func IsContainerRuntimeInstalled(containerRuntime string) bool {
if containerRuntime == string(PODMAN) {
return isPodmanInstalled()
} else if containerRuntime == string(DOCKER) {
return isDockerInstalled()
}
// This should never happen.
return false
}
// isDockerInstalled checks whether docker is installed.
func isDockerInstalled() bool {
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return false
}
@ -180,7 +198,8 @@ func IsDockerInstalled() bool {
return err == nil
}
func IsPodmanInstalled() bool {
// isPodmanInstalled checks whether podman is installed.
func isPodmanInstalled() bool {
cmd := exec.Command("podman", "version")
if err := cmd.Run(); err != nil {
return false
@ -350,6 +369,24 @@ func GetAbsPath(baseDir, path string) string {
return absPath
}
// ResolveHomeDir resolves prefix of the given path, if present, to the user's home directory and returns it.
func ResolveHomeDir(filePath string) (string, error) {
if filePath == "" {
return "", nil
}
// Resolve the home directory prefix, if present. This is only supported on non-Windows platforms.
if runtime.GOOS != windowsOsType && strings.HasPrefix(filePath, homeDirPrefix) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("error in getting the home directory for %s: %w", filePath, err)
}
filePath = filepath.Join(homeDir, filePath[len(homeDirPrefix):])
}
return filePath, nil
}
func ReadFile(filePath string) ([]byte, error) {
bytes, err := os.ReadFile(filePath)
if err != nil {
@ -366,3 +403,8 @@ func FindFileInDir(dirPath, fileName string) (string, error) {
}
return filePath, nil
}
// SanitizeDir sanitizes the input string to make it a valid directory.
func SanitizeDir(destDir string) string {
return strings.ReplaceAll(destDir, "'", "''")
}

View File

@ -18,6 +18,7 @@ import (
"math"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
@ -75,7 +76,9 @@ func TestContainerRuntimeUtils(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actualValid := IsValidContainerRuntime(tc.input)
if actualValid != tc.valid {
t.Errorf("expected %v, got %v", tc.valid, actualValid)
@ -117,7 +120,9 @@ func TestContains(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actualValid := Contains(tc.input, tc.expected)
if actualValid != tc.valid {
t.Errorf("expected %v, got %v", tc.valid, actualValid)
@ -160,7 +165,9 @@ func TestGetVersionAndImageVariant(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
version, imageVariant := GetVersionAndImageVariant(tc.input)
assert.Equal(t, tc.expectedVersion, version)
assert.Equal(t, tc.expectedImageVariant, imageVariant)
@ -195,7 +202,9 @@ func TestValidateFilePaths(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actual := ValidateFilePath(tc.input)
assert.Equal(t, tc.expectedErr, actual != nil)
})
@ -235,13 +244,77 @@ func TestGetAbsPath(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actual := GetAbsPath(baseDir, tc.input)
assert.Equal(t, tc.expected, actual)
})
}
}
func TestResolveHomeDir(t *testing.T) {
homeDir, err := os.UserHomeDir()
assert.NoError(t, err)
testcases := []struct {
name string
input string
expected string
skipWindows bool
}{
{
name: "empty path",
input: "",
expected: "",
skipWindows: false,
},
{
name: "home directory prefix with ~/",
input: "~/home/path",
expected: filepath.Join(homeDir, "home", "path"),
skipWindows: true,
},
{
name: "home directory prefix with ~/.",
input: "~/./home/path",
expected: filepath.Join(homeDir, ".", "home", "path"),
skipWindows: true,
},
{
name: "home directory prefix with ~/..",
input: "~/../home/path",
expected: filepath.Join(homeDir, "..", "home", "path"),
skipWindows: true,
},
{
name: "no home directory prefix",
input: "../home/path",
expected: "../home/path",
skipWindows: false,
},
{
name: "absolute path",
input: "/absolute/path",
expected: "/absolute/path",
skipWindows: false,
},
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if tc.skipWindows && runtime.GOOS == "windows" {
t.Skip("Skipping test on Windows")
}
t.Parallel()
actual, err := ResolveHomeDir(tc.input)
assert.NoError(t, err)
assert.Equal(t, tc.expected, actual)
})
}
}
func TestReadFile(t *testing.T) {
fileName := createTempFile(t, "", "test_read_file")
defer cleanupTempDir(t, fileName)
@ -262,7 +335,9 @@ func TestReadFile(t *testing.T) {
},
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
_, actual := ReadFile(tc.input)
assert.Equal(t, tc.expectedErr, actual != nil)
})
@ -323,7 +398,9 @@ func TestFindFileInDir(t *testing.T) {
},
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
filePath, err := FindFileInDir(tc.input, "dapr.yaml")
assert.Equal(t, tc.expectedErr, err != nil)
assert.Equal(t, tc.expectedFilePath, filePath)
@ -403,7 +480,9 @@ func TestPrintDetail(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
err := PrintDetail(&buf, tc.format, tc.list)
if tc.shouldError {
@ -433,3 +512,51 @@ func cleanupTempDir(t *testing.T, fileName string) {
err := os.RemoveAll(fileName)
assert.NoError(t, err)
}
func TestSanitizeDir(t *testing.T) {
testcases := []struct {
name string
input string
expected string
}{
{
name: "directory with single quote in three places",
input: "C:\\Use'rs\\sta'rk\\Docum'ents",
expected: "C:\\Use''rs\\sta''rk\\Docum''ents",
},
{
name: "directory with single quote in two places",
input: "C:\\Use'rs\\sta'rk",
expected: "C:\\Use''rs\\sta''rk",
},
{
name: "directory with single quote in username",
input: "C:\\Users\\Debash'ish",
expected: "C:\\Users\\Debash''ish",
},
{
name: "directory with no single quote",
input: "C:\\Users\\Shubham",
expected: "C:\\Users\\Shubham",
},
{
name: "directory with single quote in one place",
input: "C:\\Use'rs\\Shubham",
expected: "C:\\Use''rs\\Shubham",
},
{
name: "directory with single quote in many places in username",
input: "C:\\Users\\Shu'bh'am",
expected: "C:\\Users\\Shu''bh''am",
},
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actual := SanitizeDir(tc.input)
assert.Equal(t, tc.expected, actual)
})
}
}