Change `--from-dir` init flow (#945)

* fix --from-dir flag init

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* fix env var not set for k8s tests also

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* fix k8s test

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* address review comments

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* fix typo

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* addressed comments

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

* Update tests/e2e/common/common.go

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

Co-authored-by: Shubham Sharma <shubhash@microsoft.com>

* fix typo

Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>

Co-authored-by: Shubham Sharma <shubhash@microsoft.com>
This commit is contained in:
Mukundan Sundararajan 2022-04-05 05:05:51 +05:30 committed by GitHub
parent 1331e29eca
commit 5879d915bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 371 additions and 119 deletions

View File

@ -16,6 +16,7 @@ package cmd
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -52,7 +53,8 @@ var InitCmd = &cobra.Command{
# 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>
# 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.
dapr init --image-registry <registry-url>
# Initialize Dapr in Kubernetes
@ -103,10 +105,15 @@ dapr init --from-dir <path-to-directory>
dockerNetwork = viper.GetString("network")
imageRegistryURL = viper.GetString("image-registry")
}
if fromDir != "" {
print.WarningStatusEvent(os.Stdout, "Local bundle installation using from-dir flag is currently a preview feature.")
// If both --image-registry and --from-dir flags are given, error out saying only one can be given.
if len(strings.TrimSpace(imageRegistryURL)) != 0 && len(strings.TrimSpace(fromDir)) != 0 {
print.FailureStatusEvent(os.Stderr, "both --image-registry and --from-dir flags cannot be given at the same time")
os.Exit(1)
}
if imageRegistryURL != "" {
if len(strings.TrimSpace(fromDir)) != 0 {
print.WarningStatusEvent(os.Stdout, "Local bundle installation using --from-dir flag is currently a preview feature and is subject to change. It is only available from CLI version 1.7 onwards.")
}
if len(strings.TrimSpace(imageRegistryURL)) != 0 {
print.WarningStatusEvent(os.Stdout, "Flag --image-registry is a preview feature and is subject to change. It is only available from CLI version 1.7 onwards.")
}
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURL, fromDir)
@ -142,9 +149,9 @@ func init() {
InitCmd.Flags().BoolVarP(&enableMTLS, "enable-mtls", "", true, "Enable mTLS in your cluster")
InitCmd.Flags().BoolVarP(&enableHA, "enable-ha", "", false, "Enable high availability (HA) mode")
InitCmd.Flags().String("network", "", "The Docker network on which to deploy the Dapr runtime")
InitCmd.Flags().StringVarP(&fromDir, "from-dir", "", "", "Use Dapr artifacts from local directory instead of from network to init")
InitCmd.Flags().StringVarP(&fromDir, "from-dir", "", "", "Use Dapr artifacts from local directory for self-hosted installation")
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().String("image-registry", "", "Custom/Private docker image repository URL")
RootCmd.AddCommand(InitCmd)
}

64
pkg/standalone/bundle.go Normal file
View File

@ -0,0 +1,64 @@
/*
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 (
"encoding/json"
"fmt"
"io/ioutil"
"strings"
)
const bundleDetailsFileName = "details.json"
type bundleDetails struct {
RuntimeVersion *string `json:"daprd"`
DashboardVersion *string `json:"dashboard"`
CLIVersion *string `json:"cli"`
BinarySubDir *string `json:"daprBinarySubDir"`
ImageSubDir *string `json:"dockerImageSubDir"`
DaprImageName *string `json:"daprImageName"`
DaprImageFileName *string `json:"daprImageFileName"`
}
// readAndParseDetails reads the file in detailsFilePath and tries to parse it into the bundleDetails struct.
func (b *bundleDetails) readAndParseDetails(detailsFilePath string) error {
bytes, err := ioutil.ReadFile(detailsFilePath)
if err != nil {
return err
}
err = json.Unmarshal(bytes, &b)
if err != nil {
return err
}
if isStringNilOrEmpty(b.RuntimeVersion) || isStringNilOrEmpty(b.DashboardVersion) ||
isStringNilOrEmpty(b.DaprImageName) || isStringNilOrEmpty(b.DaprImageFileName) ||
isStringNilOrEmpty(b.BinarySubDir) || isStringNilOrEmpty(b.ImageSubDir) {
return fmt.Errorf("required fields are missing in %s", detailsFilePath)
}
return nil
}
func isStringNilOrEmpty(val *string) bool {
return val == nil || strings.TrimSpace(*val) == ""
}
func (b *bundleDetails) getPlacementImageName() string {
return *b.DaprImageName
}
func (b *bundleDetails) getPlacementImageFileName() string {
return *b.DaprImageFileName
}

View File

@ -0,0 +1,103 @@
/*
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 (
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseDetails(t *testing.T) {
correctDetails := `{
"daprd" : "1.7.0-rc.2",
"dashboard": "0.10.0-rc.2",
"cli": "1.7.0-rc.2",
"daprBinarySubDir": "dist",
"dockerImageSubDir": "docker",
"daprImageName": "daprio/dapr:1.7.2-rc.2",
"daprImageFileName": "daprio-dapr-1.7.2-rc.2.tar.gz"
}`
f, err := os.CreateTemp("", "*-details.json")
if err != nil {
t.Fatalf("error creating temp directory for testing: %s", err)
}
defer os.Remove(f.Name())
f.WriteString(correctDetails)
f.Close()
bd := bundleDetails{}
err = bd.readAndParseDetails(f.Name())
assert.NoError(t, err, "expected no error on parsing correct details in file")
assert.Equal(t, "1.7.0-rc.2", *bd.RuntimeVersion, "expected versions to match")
assert.Equal(t, "0.10.0-rc.2", *bd.DashboardVersion, "expected versions to match")
assert.Equal(t, "dist", *bd.BinarySubDir, "expected value to match")
assert.Equal(t, "docker", *bd.ImageSubDir, "expected value to match")
assert.Equal(t, "daprio/dapr:1.7.2-rc.2", bd.getPlacementImageName(), "expected value to match")
assert.Equal(t, "daprio-dapr-1.7.2-rc.2.tar.gz", bd.getPlacementImageFileName(), "expected value to match")
}
func TestParseDetailsMissingDetails(t *testing.T) {
missingDetails := `{
"daprd" : "1.7.0-rc.2",
"dashboard": "0.10.0-rc.2",
"cli": "1.7.0-rc.2",
"daprImageName": "daprio/dapr:1.7.2-rc.2"
"daprImageFileName": "daprio-dapr-1.7.2-rc.2.tar.gz"
}`
f, err := os.CreateTemp("", "*-details.json")
if err != nil {
t.Fatalf("error creating temp directory for testing: %s", err)
}
defer os.Remove(f.Name())
f.WriteString(missingDetails)
f.Close()
bd := bundleDetails{}
err = bd.readAndParseDetails(f.Name())
assert.Error(t, err, "expected error on parsing missing details in file")
}
func TestParseDetailsEmptyDetails(t *testing.T) {
missingDetails := `{
"daprd" : "",
"dashboard": "",
"cli": "1.7.0-rc.2",
"daprBinarySubDir": "dist",
"dockerImageSubDir": "docker",
"daprImageName": "daprio/dapr:1.7.2-rc.2",
"daprImageFileName": "daprio-dapr-1.7.2-rc.2.tar.gz"
}`
f, err := os.CreateTemp("", "*-details.json")
if err != nil {
t.Fatalf("error creating temp directory for testing: %s", err)
}
defer os.Remove(f.Name())
f.WriteString(missingDetails)
f.Close()
bd := bundleDetails{}
err = bd.readAndParseDetails(f.Name())
assert.Error(t, err, "expected error on parsing missing details in file")
}
func TestParseDetailsMissingFile(t *testing.T) {
f, err := os.CreateTemp("", "*-details.json")
if err != nil {
t.Fatalf("error creating temp directory for testing: %s", err)
}
f.Close()
os.Remove(f.Name())
bd := bundleDetails{}
err = bd.readAndParseDetails(f.Name())
assert.Error(t, err, "expected error on parsing missing details file")
}

View File

@ -53,16 +53,16 @@ func runDockerLoad(in io.Reader) error {
return nil
}
func loadDocker(dir string, dockerImage string) error {
func loadDocker(dir string, dockerImageFileName string) error {
var imageFile io.Reader
var err error
imageFile, err = os.Open(path_filepath.Join(dir, imageFileName(dockerImage)))
imageFile, err = os.Open(path_filepath.Join(dir, dockerImageFileName))
if err != nil {
return fmt.Errorf("fail to read docker image file %s: %w", dockerImage, err)
return fmt.Errorf("fail to read docker image file %s: %w", dockerImageFileName, err)
}
err = runDockerLoad(imageFile)
if err != nil {
return fmt.Errorf("fail to load docker image %s: %w", dockerImage, err)
return fmt.Errorf("fail to load docker image from file %s: %w", dockerImageFileName, err)
}
return nil
@ -121,14 +121,7 @@ func parseDockerError(component string, err error) error {
return err
}
func imageFileName(image string) string {
filename := image + ".tar.gz"
filename = strings.ReplaceAll(filename, "/", "-")
filename = strings.ReplaceAll(filename, ":", "-")
return filename
}
func TryPullImage(imageName string) bool {
func tryPullImage(imageName string) bool {
args := []string{
"pull",
imageName,

View File

@ -17,7 +17,6 @@ import (
"archive/tar"
"archive/zip"
"compress/gzip"
"encoding/json"
"errors"
"fmt"
"io"
@ -39,22 +38,28 @@ import (
)
const (
daprDockerImageName = "daprio/dapr"
daprRuntimeFilePrefix = "daprd"
dashboardFilePrefix = "dashboard"
placementServiceFilePrefix = "placement"
daprWindowsOS = "windows"
latestVersion = "latest"
daprDefaultHost = "localhost"
pubSubYamlFileName = "pubsub.yaml"
stateStoreYamlFileName = "statestore.yaml"
// used when DAPR_DEFAULT_IMAGE_REGISTRY is not set.
dockerContainerRegistryName = "dockerhub"
daprDockerImageName = "daprio/dapr"
redisDockerImageName = "redis"
zipkinDockerImageName = "openzipkin/zipkin"
// used when DAPR_DEFAULT_IMAGE_REGISTRY is set as GHCR.
githubContainerRegistryName = "ghcr"
ghcrURI = "ghcr.io/dapr"
daprGhcrImageName = "dapr"
dockerContainerRegistryName = "dockerhub"
redisGhcrImageName = "3rdparty/redis"
zipkinGhcrImageName = "3rdparty/zipkin"
@ -66,14 +71,12 @@ const (
DaprZipkinContainerName = "dapr_zipkin"
errInstallTemplate = "please run `dapr uninstall` first before running `dapr init`"
daprBinarySubDir = "dist"
dockerImageSubDir = "docker"
)
var (
defaultImageRegistryName string
privateRegTemplateString = "%s/dapr/%s"
isAirGapInit bool
)
type configuration struct {
@ -112,6 +115,7 @@ type componentMetadataItem struct {
type initInfo struct {
fromDir string
bundleDet *bundleDetails
slimMode bool
runtimeVersion string
dashboardVersion string
@ -141,14 +145,19 @@ func isBinaryInstallationRequired(binaryFilePrefix, installDir string) (bool, er
// Init installs Dapr on a local machine using the supplied runtimeVersion.
func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMode bool, imageRegistryURL string, fromDir string) error {
var err error
var bundleDet bundleDetails
fromDir = strings.TrimSpace(fromDir)
// AirGap init flow is true when fromDir var is set i.e. --from-dir flag has value.
setAirGapInit(fromDir)
if !slimMode {
// If --slim installation is not requested, check if docker is installed.
dockerInstalled := utils.IsDockerInstalled()
if !dockerInstalled {
return errors.New("could not connect to Docker. Docker may not be installed or running")
}
// Initialize default registry only if it is not airgap mode or from private registries.
if len(strings.TrimSpace(imageRegistryURL)) == 0 && len(strings.TrimSpace(fromDir)) == 0 {
// Initialize default registry only if any of --slim or --image-registry or --from-dir are not given.
if len(strings.TrimSpace(imageRegistryURL)) == 0 && !isAirGapInit {
defaultImageRegistryName, err = utils.GetDefaultRegistry(githubContainerRegistryName, dockerContainerRegistryName)
if err != nil {
return err
@ -156,16 +165,16 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
}
}
if runtimeVersion == latestVersion && fromDir == "" {
// Set runtime version.
if runtimeVersion == latestVersion && !isAirGapInit {
runtimeVersion, err = cli_ver.GetDaprVersion()
if err != nil {
return fmt.Errorf("cannot get the latest release version: '%w'. Try specifying --runtime-version=<desired_version>", err)
}
}
print.InfoStatusEvent(os.Stdout, "Installing runtime version %s", runtimeVersion)
if dashboardVersion == latestVersion && fromDir == "" {
if dashboardVersion == latestVersion && !isAirGapInit {
dashboardVersion, err = cli_ver.GetDashboardVersion()
if err != nil {
print.WarningStatusEvent(os.Stdout, "cannot get the latest dashboard version: '%s'. Try specifying --dashboard-version=<desired_version>", err)
@ -173,15 +182,28 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
}
}
if fromDir != "" {
v1, v2 := parseVersionFile(fromDir)
if v1 != "" && v2 != "" {
runtimeVersion, dashboardVersion = v1, v2
} else {
return fmt.Errorf("runtime and dashboard versions cannot be parsed from version file in directory")
// If --from-dir flag is given try parsing the details from the expected details file in the specified directory.
if isAirGapInit {
bundleDet = bundleDetails{}
detailsFilePath := path_filepath.Join(fromDir, bundleDetailsFileName)
err = bundleDet.readAndParseDetails(detailsFilePath)
if err != nil {
return fmt.Errorf("error parsing details file from bundle location: %w", err)
}
// Set runtime and dashboard versions from the bundle details parsed.
runtimeVersion = *bundleDet.RuntimeVersion
dashboardVersion = *bundleDet.DashboardVersion
}
// At this point the runtimeVersion variable is parsed either from the details file if --fromDir is specified or
// got from running the command cli_ver.GetRuntimeVersion().
// After this point runtimeVersion will not be latest string but rather actual version.
print.InfoStatusEvent(os.Stdout, "Installing runtime version %s", runtimeVersion)
daprBinDir := defaultDaprBinPath()
err = prepareDaprInstallDir(daprBinDir)
if err != nil {
@ -210,7 +232,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
wg.Add(len(initSteps))
msg := "Downloading binaries and setting up components..."
if fromDir != "" {
if isAirGapInit {
msg = "Extracting binaries and setting up components..."
}
stopSpinning := print.Spinner(os.Stdout, msg)
@ -223,6 +245,8 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
}
info := initInfo{
// values in bundleDet can be nil if fromDir is empty, so must be used in conjunction with fromDir.
bundleDet: &bundleDet,
fromDir: fromDir,
slimMode: slimMode,
runtimeVersion: runtimeVersion,
@ -249,7 +273,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
stopSpinning(print.Success)
msg = "Downloaded binaries and completed components set up."
if fromDir != "" {
if isAirGapInit {
msg = "Extracted binaries and completed components set up."
}
print.SuccessStatusEvent(os.Stdout, msg)
@ -260,7 +284,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
} else {
dockerContainerNames := []string{DaprPlacementContainerName, DaprRedisContainerName, DaprZipkinContainerName}
// Skip redis and zipkin in local installation mode.
if fromDir != "" {
if isAirGapInit {
dockerContainerNames = []string{DaprPlacementContainerName}
}
for _, container := range dockerContainerNames {
@ -281,7 +305,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod
func runZipkin(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) {
defer wg.Done()
if info.slimMode || info.fromDir != "" {
if info.slimMode || isAirGapInit {
return
}
@ -348,7 +372,7 @@ func runZipkin(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) {
func runRedis(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) {
defer wg.Done()
if info.slimMode || info.fromDir != "" {
if info.slimMode || isAirGapInit {
return
}
@ -419,26 +443,6 @@ func runPlacementService(wg *sync.WaitGroup, errorChan chan<- error, info initIn
placementContainerName := utils.CreateContainerName(DaprPlacementContainerName, info.dockerNetwork)
imgInfo := daprImageInfo{
ghcrImageName: daprGhcrImageName,
dockerHubImageName: daprDockerImageName,
imageRegistryURL: info.imageRegistryURL,
imageRegistryName: defaultImageRegistryName,
}
image, err := resolveImageURI(imgInfo)
if err != nil {
errorChan <- err
return
}
image = getPlacementImageWithTag(image, info.runtimeVersion)
if checkFallbackImgForPlacement(imgInfo, info.fromDir) {
if !TryPullImage(image) {
print.InfoStatusEvent(os.Stdout, "Placement image not found in Github container registry, pulling it from Docker Hub")
image = getPlacementImageWithTag(daprDockerImageName, info.runtimeVersion)
}
}
exists, err := confirmContainerIsRunningOrExists(placementContainerName, false)
if err != nil {
@ -448,10 +452,27 @@ func runPlacementService(wg *sync.WaitGroup, errorChan chan<- error, info initIn
errorChan <- fmt.Errorf("%s container exists or is running. %s", placementContainerName, errInstallTemplate)
return
}
var image string
if info.fromDir != "" {
dir := path_filepath.Join(info.fromDir, dockerImageSubDir)
err = loadDocker(dir, image)
imgInfo := daprImageInfo{
ghcrImageName: daprGhcrImageName,
dockerHubImageName: daprDockerImageName,
imageRegistryURL: info.imageRegistryURL,
imageRegistryName: defaultImageRegistryName,
}
if isAirGapInit {
// if --from-dir flag is given load the image details from the installer-bundle.
dir := path_filepath.Join(info.fromDir, *info.bundleDet.ImageSubDir)
image = info.bundleDet.getPlacementImageName()
err = loadDocker(dir, info.bundleDet.getPlacementImageFileName())
if err != nil {
errorChan <- err
return
}
} else {
// otherwise load the image from the specified repository.
image, err = getPlacementImageName(imgInfo, info)
if err != nil {
errorChan <- err
return
@ -529,7 +550,7 @@ func moveDashboardFiles(extractedFilePath string, dir string) (string, error) {
func installDaprRuntime(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) {
defer wg.Done()
err := installBinary(info.runtimeVersion, daprRuntimeFilePrefix, cli_ver.DaprGitHubRepo, info.fromDir)
err := installBinary(info.runtimeVersion, daprRuntimeFilePrefix, cli_ver.DaprGitHubRepo, info)
if err != nil {
errorChan <- err
}
@ -541,7 +562,7 @@ func installDashboard(wg *sync.WaitGroup, errorChan chan<- error, info initInfo)
return
}
err := installBinary(info.dashboardVersion, dashboardFilePrefix, cli_ver.DashboardGitHubRepo, info.fromDir)
err := installBinary(info.dashboardVersion, dashboardFilePrefix, cli_ver.DashboardGitHubRepo, info)
if err != nil {
errorChan <- err
}
@ -554,26 +575,27 @@ func installPlacement(wg *sync.WaitGroup, errorChan chan<- error, info initInfo)
return
}
err := installBinary(info.runtimeVersion, placementServiceFilePrefix, cli_ver.DaprGitHubRepo, info.fromDir)
err := installBinary(info.runtimeVersion, placementServiceFilePrefix, cli_ver.DaprGitHubRepo, info)
if err != nil {
errorChan <- err
}
}
func installBinary(version, binaryFilePrefix string, githubRepo string, fromDir string) error {
// installBinary installs the daprd, placement or dashboard binaries and associated files inside the default dapr bin directory.
func installBinary(version, binaryFilePrefix, githubRepo string, info initInfo) error {
var (
err error
filepath string
)
dir := defaultDaprBinPath()
if fromDir == "" {
if isAirGapInit {
filepath = path_filepath.Join(info.fromDir, *info.bundleDet.BinarySubDir, binaryName(binaryFilePrefix))
} else {
filepath, err = downloadBinary(dir, version, binaryFilePrefix, githubRepo)
if err != nil {
return fmt.Errorf("error downloading %s binary: %w", binaryFilePrefix, err)
}
} else {
filepath = path_filepath.Join(fromDir, daprBinarySubDir, binaryName(binaryFilePrefix))
}
extractedFilePath, err := extractFile(filepath, dir, binaryFilePrefix)
@ -581,7 +603,8 @@ func installBinary(version, binaryFilePrefix string, githubRepo string, fromDir
return err
}
if fromDir == "" {
// remove downloaded archive from the default dapr bin path.
if !isAirGapInit {
err = os.Remove(filepath)
if err != nil {
return fmt.Errorf("failed to remove archive: %w", err)
@ -1050,19 +1073,24 @@ func downloadFile(dir string, url string) (string, error) {
return filepath, nil
}
func parseVersionFile(fromDir string) (string, string) {
bytes, err := ioutil.ReadFile(path_filepath.Join(fromDir, "version.json"))
// getPlacementImageName returns the resolved placement image name for online `dapr init`.
// It can either be resolved to the image-registry if given, otherwise GitHub container registry if
// selected or fallback to Docker Hub.
func getPlacementImageName(imageInfo daprImageInfo, info initInfo) (string, error) {
image, err := resolveImageURI(imageInfo)
if err != nil {
return "", ""
return "", err
}
var versions map[string]string
err = json.Unmarshal(bytes, &versions)
if err != nil {
return "", ""
}
image = getPlacementImageWithTag(image, info.runtimeVersion)
return versions[daprRuntimeFilePrefix], versions[dashboardFilePrefix]
// if default registry is GHCR and the image is not available in or cannot be pulled from GHCR
// fallback to using dockerhub.
if useGHCR(imageInfo, info.fromDir) && !tryPullImage(image) {
print.InfoStatusEvent(os.Stdout, "Placement image not found in Github container registry, pulling it from Docker Hub")
image = getPlacementImageWithTag(daprDockerImageName, info.runtimeVersion)
}
return image, nil
}
func getPlacementImageWithTag(name, version string) string {
@ -1072,9 +1100,9 @@ func getPlacementImageWithTag(name, version string) string {
return fmt.Sprintf("%s:%s", name, version)
}
// Try for fallback image from docker iff this init flow is using GHCR as default registry.
// useGHCR returns true iff default registry is set as GHCR and --image-registry and --from-dir flags are not set.
// TODO: We may want to remove this logic completely after next couple of releases.
func checkFallbackImgForPlacement(imageInfo daprImageInfo, fromDir string) bool {
func useGHCR(imageInfo daprImageInfo, fromDir string) bool {
if imageInfo.imageRegistryURL != "" || fromDir != "" {
return false
}
@ -1082,9 +1110,9 @@ func checkFallbackImgForPlacement(imageInfo daprImageInfo, fromDir string) bool
}
func resolveImageURI(imageInfo daprImageInfo) (string, error) {
if imageInfo.imageRegistryURL != "" {
if strings.TrimSpace(imageInfo.imageRegistryURL) != "" {
if imageInfo.imageRegistryURL == ghcrURI || imageInfo.imageRegistryURL == "docker.io" {
err := fmt.Errorf("flag %s not set correctly", "--image-registry")
err := fmt.Errorf("flag --image-registry not set correctly. It cannot be %q or \"docker.io\"", ghcrURI)
return "", err
}
return fmt.Sprintf(privateRegTemplateString, imageInfo.imageRegistryURL, imageInfo.ghcrImageName), nil
@ -1095,6 +1123,12 @@ func resolveImageURI(imageInfo daprImageInfo) (string, error) {
case githubContainerRegistryName:
return fmt.Sprintf("%s/%s", ghcrURI, imageInfo.ghcrImageName), nil
default:
return "", errors.New("imageRegistryName not set correctly")
return "", fmt.Errorf("imageRegistryName not set correctly %s", imageInfo.imageRegistryName)
}
}
// setAirGapInit is used to set the bool value.
func setAirGapInit(fromDir string) {
// mostly this is used for unit testing aprat from one use in Init() function.
isAirGapInit = (len(strings.TrimSpace(fromDir)) != 0)
}

View File

@ -282,8 +282,26 @@ func TestCheckFallbackImg(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := checkFallbackImgForPlacement(test.imageInfo, test.fromDir)
got := useGHCR(test.imageInfo, test.fromDir)
assert.Equal(t, test.expect, got)
})
}
}
func TestIsAirGapInit(t *testing.T) {
tests := []struct {
name string
fromDir string
expect bool
}{
{"empty string", "", false},
{"string with spaces", " ", false},
{"string with value", "./local-dir", true},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
setAirGapInit(test.fromDir)
assert.Equal(t, test.expect, isAirGapInit)
})
}
}

View File

@ -70,6 +70,22 @@ type TestCase struct {
Callable func(*testing.T)
}
// GetVersionsFromEnv will return values from required environment variables,
// if environment variables are not set it fails the test.
func GetVersionsFromEnv(t *testing.T) (daprRuntimeVersion string, daprDashboardVersion string) {
if runtimeVersion, ok := os.LookupEnv("DAPR_RUNTIME_VERSION"); ok {
daprRuntimeVersion = runtimeVersion
} else {
t.Fatalf("env var \"DAPR_RUNTIME_VERSION\" not set")
}
if dashboardVersion, ok := os.LookupEnv("DAPR_DASHBOARD_VERSION"); ok {
daprDashboardVersion = dashboardVersion
} else {
t.Fatalf("env var \"DAPR_DASHBOARD_VERSION\" not set")
}
return
}
func UpgradeTest(details VersionDetails, opts TestOptions) func(t *testing.T) {
return func(t *testing.T) {
daprPath := getDaprPath()

View File

@ -17,33 +17,36 @@ limitations under the License.
package kubernetes_test
import (
"os"
"testing"
"github.com/dapr/cli/tests/e2e/common"
)
var (
currentRuntimeVersion = os.Getenv("DAPR_RUNTIME_VERSION")
currentDashboardVersion = os.Getenv("DAPR_DASHBOARD_VERSION")
currentRuntimeVersion string
currentDashboardVersion string
currentVersionDetails common.VersionDetails
)
var currentVersionDetails = common.VersionDetails{
// ensureCleanEnv function needs to be called in every Test function.
// sets necessary variable values and uninstalls any previously installed `dapr`.
func ensureCleanEnv(t *testing.T) {
currentRuntimeVersion, currentDashboardVersion = common.GetVersionsFromEnv(t)
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"},
}
func ensureCleanEnv(t *testing.T, details common.VersionDetails) {
}
// Ensure a clean environment
common.EnsureUninstall(true) // does not wait for pod deletion
}
func TestKubernetesNonHAModeMTLSDisabled(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, currentVersionDetails)
ensureCleanEnv(t)
// setup tests
tests := []common.TestCase{}
@ -74,7 +77,7 @@ func TestKubernetesNonHAModeMTLSDisabled(t *testing.T) {
func TestKubernetesHAModeMTLSDisabled(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, currentVersionDetails)
ensureCleanEnv(t)
// setup tests
tests := []common.TestCase{}
@ -105,7 +108,7 @@ func TestKubernetesHAModeMTLSDisabled(t *testing.T) {
func TestKubernetesNonHAModeMTLSEnabled(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, currentVersionDetails)
ensureCleanEnv(t)
// setup tests
tests := []common.TestCase{}
@ -136,7 +139,7 @@ func TestKubernetesNonHAModeMTLSEnabled(t *testing.T) {
func TestKubernetesHAModeMTLSEnabled(t *testing.T) {
// ensure clean env for test
ensureCleanEnv(t, currentVersionDetails)
ensureCleanEnv(t)
// setup tests
tests := []common.TestCase{}
@ -169,10 +172,11 @@ func TestKubernetesHAModeMTLSEnabled(t *testing.T) {
// Test for certificate renewal
func TestRenewCertificateMTLSEnabled(t *testing.T) {
common.EnsureUninstall(true)
// ensure clean env for test
ensureCleanEnv(t)
tests := []common.TestCase{}
var installOpts = common.TestOptions{
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
ApplyComponentChanges: true,
@ -218,10 +222,11 @@ func TestRenewCertificateMTLSEnabled(t *testing.T) {
}
func TestRenewCertificateMTLSDisabled(t *testing.T) {
common.EnsureUninstall(true)
// ensure clean env for test
ensureCleanEnv(t)
tests := []common.TestCase{}
var installOpts = common.TestOptions{
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: false,
ApplyComponentChanges: true,
@ -267,10 +272,11 @@ func TestRenewCertificateMTLSDisabled(t *testing.T) {
}
func TestRenewCertWithPrivateKey(t *testing.T) {
common.EnsureUninstall(true)
// ensure clean env for test
ensureCleanEnv(t)
tests := []common.TestCase{}
var installOpts = common.TestOptions{
installOpts := common.TestOptions{
HAEnabled: false,
MTLSEnabled: true,
ApplyComponentChanges: true,

View File

@ -33,6 +33,7 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
testCommon "github.com/dapr/cli/tests/e2e/common"
"github.com/dapr/cli/tests/e2e/spawn"
"github.com/dapr/go-sdk/service/common"
daprHttp "github.com/dapr/go-sdk/service/http"
@ -41,8 +42,8 @@ import (
)
var (
daprRuntimeVersion = os.Getenv("DAPR_RUNTIME_VERSION")
daprDashboardVersion = os.Getenv("DAPR_DASHBOARD_VERSION")
daprRuntimeVersion string
daprDashboardVersion string
)
var socketCases = []string{"", "/tmp"}
@ -50,6 +51,7 @@ var socketCases = []string{"", "/tmp"}
func TestStandaloneInstall(t *testing.T) {
// Ensure a clean environment.
uninstall()
daprRuntimeVersion, daprDashboardVersion = testCommon.GetVersionsFromEnv(t)
tests := []struct {
name string
@ -73,6 +75,7 @@ func TestStandaloneInstall(t *testing.T) {
func TestEnableAPILogging(t *testing.T) {
// Ensure a clean environment.
uninstall()
daprRuntimeVersion, daprDashboardVersion = testCommon.GetVersionsFromEnv(t)
tests := []struct {
name string
@ -91,6 +94,7 @@ func TestEnableAPILogging(t *testing.T) {
func TestNegativeScenarios(t *testing.T) {
// Ensure a clean environment
uninstall()
daprRuntimeVersion, daprDashboardVersion = testCommon.GetVersionsFromEnv(t)
daprPath := getDaprPath()
homeDir, err := os.UserHomeDir()
@ -146,15 +150,22 @@ func TestNegativeScenarios(t *testing.T) {
t.Run("filter dashboard instance from list", func(t *testing.T) {
spawn.Command(daprPath, "dashboard", "-p", "5555")
cmd, err := spawn.Command(daprPath, "list")
output, err := spawn.Command(daprPath, "list")
require.NoError(t, err, "expected no error status on list without install")
require.Equal(t, "No Dapr instances found.\n", cmd)
require.Equal(t, "No Dapr instances found.\n", output)
})
t.Run("error if both --from-dir and --image-registry given", func(t *testing.T) {
output, err := spawn.Command(daprPath, "init", "--image-registry", "localhost:5000", "--from-dir", "./local-dir")
require.Error(t, err, "expected error if both flags are given")
require.Contains(t, output, "both --image-registry and --from-dir flags cannot be given at the same time")
})
}
func TestPrivateRegistry(t *testing.T) {
// Ensure a clean environment.
uninstall()
daprRuntimeVersion, daprDashboardVersion = testCommon.GetVersionsFromEnv(t)
tests := []struct {
name string