diff --git a/cmd/cluster/clusterCreate.go b/cmd/cluster/clusterCreate.go index b13ea8ef..94bef74d 100644 --- a/cmd/cluster/clusterCreate.go +++ b/cmd/cluster/clusterCreate.go @@ -28,6 +28,7 @@ import ( "os" "path/filepath" "runtime" + "strconv" "strings" "time" @@ -434,10 +435,15 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) { // Set to random port if port is empty string if len(exposeAPI.Binding.HostPort) == 0 { - exposeAPI, err = cliutil.ParsePortExposureSpec("random", k3d.DefaultAPIPort) - if err != nil { - return cfg, err + var freePort string + port, err := cliutil.GetFreePort() + freePort = strconv.Itoa(port) + if err != nil || port == 0 { + l.Log().Warnf("Failed to get random free port: %+v", err) + l.Log().Warnf("Falling back to internal port %s (may be blocked though)...", k3d.DefaultAPIPort) + freePort = k3d.DefaultAPIPort } + exposeAPI.Binding.HostPort = freePort } cfg.ExposeAPI = conf.SimpleExposureOpts{ diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index a34f4097..bc20c528 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -178,7 +178,11 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime, } -func findImages(ctx context.Context, runtime runtimes.Runtime, requestedImages []string) (imagesFromRuntime, imagesFromTar []string, err error) { +type runtimeImageGetter interface { + GetImages(context.Context) ([]string, error) +} + +func findImages(ctx context.Context, runtime runtimeImageGetter, requestedImages []string) (imagesFromRuntime, imagesFromTar []string, err error) { runtimeImages, err := runtime.GetImages(ctx) if err != nil { l.Log().Errorln("Failed to fetch list of existing images from runtime") @@ -189,14 +193,14 @@ func findImages(ctx context.Context, runtime runtimes.Runtime, requestedImages [ if isFile(requestedImage) { imagesFromTar = append(imagesFromTar, requestedImage) l.Log().Debugf("Selected image '%s' is a file", requestedImage) - break + continue } runtimeImage, found := findRuntimeImage(requestedImage, runtimeImages) if found { imagesFromRuntime = append(imagesFromRuntime, runtimeImage) l.Log().Debugf("Selected image '%s' (found as '%s') in runtime", requestedImage, runtimeImage) - break + continue } l.Log().Warnf("Image '%s' is not a file and couldn't be found in the container runtime", requestedImage) diff --git a/pkg/tools/tools_test.go b/pkg/tools/tools_test.go index 1e104c07..8fc5f8a7 100644 --- a/pkg/tools/tools_test.go +++ b/pkg/tools/tools_test.go @@ -23,7 +23,12 @@ THE SOFTWARE. package tools import ( + "context" + "io/ioutil" + "os" "testing" + + "github.com/go-test/deep" ) func Test_findRuntimeImage(T *testing.T) { @@ -170,3 +175,44 @@ func Test_findRuntimeImage(T *testing.T) { }) } } + +func Test_findImages(t *testing.T) { + // given + tarImage, err := ioutil.TempFile("", "images.tgz") + if err != nil { + t.Fatal("Failed to create temporary file") + } + defer os.Remove(tarImage.Name()) + + tarImages := []string{tarImage.Name()} + runtimeImages := []string{ + "alpine:version", + "busybox:latest", + } + runtime := &FakeRuntimeImageGetter{runtimeImages: runtimeImages} + + requestedImages := append(runtimeImages, tarImages...) + + // when + foundRuntimeImages, foundTarImages, err := findImages(context.Background(), runtime, requestedImages) + + // then + if err != nil { + t.Errorf("Got unexpected error %v", err) + } + + if diff := deep.Equal(foundRuntimeImages, runtimeImages); diff != nil { + t.Errorf("Found runtime images\n%+v\ndoes not match expected runtime images\n%+v\nDiff:\n%+v", foundRuntimeImages, runtimeImages, diff) + } + if diff := deep.Equal(foundTarImages, tarImages); diff != nil { + t.Errorf("Found tar images\n%+v\ndoes not match expected tar images\n%+v\nDiff:\n%+v", foundTarImages, runtimeImages, diff) + } +} + +type FakeRuntimeImageGetter struct { + runtimeImages []string +} + +func (f *FakeRuntimeImageGetter) GetImages(_ context.Context) ([]string, error) { + return f.runtimeImages, nil +}