Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure working JVM before enabling Jib actions to avoid hangs #5725

Merged
merged 10 commits into from
May 3, 2021
4 changes: 4 additions & 0 deletions integration/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/sirupsen/logrus"

"github.com/GoogleContainerTools/skaffold/integration/skaffold"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/jib"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
Expand Down Expand Up @@ -112,6 +113,9 @@ func TestBuild(t *testing.T) {
// TestExpectedBuildFailures verifies that `skaffold build` fails in expected ways
func TestExpectedBuildFailures(t *testing.T) {
MarkIntegrationTest(t, CanRunWithoutGcp)
if !jib.JVMFound() {
t.Fatal("test requires Java VM")
}

tests := []struct {
description string
Expand Down
7 changes: 7 additions & 0 deletions pkg/skaffold/build/gcb/jib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package gcb

import (
"os"
"path/filepath"
"testing"

Expand All @@ -27,6 +28,12 @@ import (
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestMain(m *testing.M) {
// these tests don't actually require a JVM
jib.JVMFound = func() bool { return true }
os.Exit(m.Run())
}

func TestJibMavenBuildSpec(t *testing.T) {
tests := []struct {
description string
Expand Down
4 changes: 4 additions & 0 deletions pkg/skaffold/build/jib/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ type jibJSON struct {

// validate checks if a file is a valid Jib configuration. Returns the list of Config objects corresponding to each Jib project built by the file, or nil if Jib is not configured.
func validate(path string, enableGradleAnalysis bool) []ArtifactConfig {
if !JVMFound() {
logrus.Debugf("Skipping Jib for init for %q: no functioning Java VM", path)
return nil
}
// Determine whether maven or gradle
var builderType PluginType
var executable, wrapper, taskName, searchString, consoleFlag string
Expand Down
4 changes: 4 additions & 0 deletions pkg/skaffold/build/jib/jib.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ func GetDependencies(ctx context.Context, workspace string, artifact *latest_v1.

// DeterminePluginType tries to determine the Jib plugin type for the given artifact.
func DeterminePluginType(workspace string, artifact *latest_v1.JibArtifact) (PluginType, error) {
if !JVMFound() {
return "", errors.New("no working JVM available")
}

// check if explicitly specified
if artifact != nil {
if t := PluginType(artifact.Type); t.IsKnown() {
Expand Down
60 changes: 60 additions & 0 deletions pkg/skaffold/build/jib/jvm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
Copyright 2021 The Skaffold 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 jib

import (
"os/exec"
"sync"

"github.com/sirupsen/logrus"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
)

var (
// JVMFound is replaceable for testing
JVMFound = jvmFound

// JVMFound() returns true if a Java VM was found and works.
resolveJVMOnce sync.Once
jvmPresent bool
)

// jvmFound returns true if a Java VM was found and works.
func jvmFound() bool {
// Check on demand: performing the check in an init() causes the
// check to be run even when no jib functionality was used.
resolveJVMOnce.Do(func() {
jvmPresent = resolveJVM()
})
return jvmPresent
}

// resolveJVM returns true if a Java VM was found and works. It is intended for
// `skaffold init` on macOS where calling out to the Maven Wrapper script (mvnw) can
// hang if there is no installed Java VM found.
func resolveJVM() bool {
// Note that just checking for the existence of `java` is insufficient
// as macOS ships with /usr/bin/java that tries to hand off to a JVM
// installed in /Library/Java/JavaVirtualMachines
cmd := exec.Command("java", "-version")
err := util.RunCmd(cmd)
if err != nil {
logrus.Warnf("Skipping Jib: no JVM: %v failed: %v", cmd.Args, err)
}
return err == nil
}
51 changes: 51 additions & 0 deletions pkg/skaffold/build/jib/jvm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
Copyright 2021 The Skaffold 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 jib

import (
"errors"
"os"
"testing"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestMain(m *testing.M) {
// these tests don't actually require a JVM
JVMFound = func() bool { return true }
os.Exit(m.Run())
}

func TestResolveJVM(t *testing.T) {
tests := []struct {
name string
cmd *testutil.FakeCmd
expected bool
}{
{name: "found", cmd: testutil.CmdRun("java -version"), expected: true},
{name: "not found", cmd: testutil.CmdRunErr("java -version", errors.New("not found")), expected: false},
}
for _, test := range tests {
testutil.Run(t, test.name, func(t *testutil.T) {
t.Override(&util.DefaultExecCommand, test.cmd)

result := resolveJVM()
t.CheckDeepEqual(test.expected, result)
})
}
}