Skip to content

Commit

Permalink
feat: Display unsupported errors for targeted recipes (#1621)
Browse files Browse the repository at this point in the history
  • Loading branch information
noahmmcgivern authored Jun 21, 2024
1 parent 2315167 commit 2471eac
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 16 deletions.
1 change: 1 addition & 0 deletions internal/install/recipe_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ func (i *RecipeInstall) install(ctx context.Context) error {
return nil
}

// TODO: remove?
func (i *RecipeInstall) printStartInstallingMessage(repo *recipes.RecipeRepository) {
message := "\n\nInstalling New Relic"
if i.RecipeNamesProvided() && len(i.RecipeNames) > 0 {
Expand Down
2 changes: 1 addition & 1 deletion internal/install/recipes/mock_process_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (pe *MockProcessEvaluator) GetOrLoadProcesses(ctx context.Context) []types.
return pe.processes
}

func (pe *MockProcessEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe) execution.RecipeStatusType {
func (pe *MockProcessEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe, recipeNames []string) execution.RecipeStatusType {
return execution.RecipeStatusTypes.AVAILABLE
}

Expand Down
2 changes: 1 addition & 1 deletion internal/install/recipes/mock_recipe_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (mre *MockRecipeEvaluator) WithRecipeStatus(recipe *types.OpenInstallationR
mre.recipeStatus[recipe.Name] = status
}

func (mre *MockRecipeEvaluator) DetectionStatus(ctx context.Context, recipe *types.OpenInstallationRecipe) execution.RecipeStatusType {
func (mre *MockRecipeEvaluator) DetectionStatus(ctx context.Context, recipe *types.OpenInstallationRecipe, recipeNames []string) execution.RecipeStatusType {
if status, ok := mre.recipeStatus[recipe.Name]; ok {
return status
}
Expand Down
13 changes: 11 additions & 2 deletions internal/install/recipes/process_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package recipes

import (
"context"
"fmt"

"github.com/newrelic/newrelic-cli/internal/install/execution"
"golang.org/x/exp/slices"

"github.com/shirou/gopsutil/v3/process"
log "github.com/sirupsen/logrus"
Expand All @@ -12,7 +15,7 @@ import (

type ProcessEvaluatorInterface interface {
GetOrLoadProcesses(ctx context.Context) []types.GenericProcess
DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe) execution.RecipeStatusType
DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe, recipeNames []string) execution.RecipeStatusType
FindProcess(process string) bool
}

Expand Down Expand Up @@ -73,14 +76,20 @@ func (pe *ProcessEvaluator) GetOrLoadProcesses(ctx context.Context) []types.Gene
return pe.processFetcher(ctx)
}

func (pe *ProcessEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe) execution.RecipeStatusType {
func (pe *ProcessEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe, recipeNames []string) execution.RecipeStatusType {
if len(r.ProcessMatch) == 0 {
return execution.RecipeStatusTypes.AVAILABLE
}

processes := pe.GetOrLoadProcesses(ctx)
matches := pe.processMatchFinder.FindMatches(ctx, processes, *r)
if len(matches) == 0 {
if slices.Contains(recipeNames, r.Name) {
log.Errorf("Unsupported (%s): Unable to match any of the following processes:\n", r.DisplayName)
for _, v := range r.ProcessMatch {
fmt.Println("-", v)
}
}
log.Tracef("recipe %s is not matching any process", r.Name)
return execution.RecipeStatusTypes.NULL
}
Expand Down
6 changes: 3 additions & 3 deletions internal/install/recipes/process_evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
func TestProcessEvaluatorShouldGetAvailable(t *testing.T) {
recipe := NewRecipeBuilder().Build()

status := GivenProcessEvaluator().DetectionStatus(context.Background(), recipe)
status := GivenProcessEvaluator().DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.AVAILABLE, status)
}
Expand All @@ -25,7 +25,7 @@ func TestProcessEvaluatorShouldGetAvailable_Matching(t *testing.T) {
recipe := NewRecipeBuilder().ProcessMatch("abc").Build()
processEvaluator := GivenProcessEvaluatorMatchedProcess()

status := processEvaluator.DetectionStatus(context.Background(), recipe)
status := processEvaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.AVAILABLE, status)
}
Expand All @@ -34,7 +34,7 @@ func TestProcessEvaluatorShouldNotDetect_NoMatch(t *testing.T) {
recipe := NewRecipeBuilder().ProcessMatch("abc").Build()
processEvaluator := GivenProcessEvaluator()

status := processEvaluator.DetectionStatus(context.Background(), recipe)
status := processEvaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.NULL, status)
}
Expand Down
8 changes: 5 additions & 3 deletions internal/install/recipes/recipe_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

type DetectionStatusProvider interface {
DetectionStatus(context.Context, *types.OpenInstallationRecipe) execution.RecipeStatusType
DetectionStatus(context.Context, *types.OpenInstallationRecipe, []string) execution.RecipeStatusType
}

type RecipeDetectionResult struct {
Expand Down Expand Up @@ -106,11 +106,13 @@ func (dt *RecipeDetector) detectRecipe(recipe *types.OpenInstallationRecipe) *Re
}
}

status := dt.processEvaluator.DetectionStatus(dt.context, recipe)
recipeNames := dt.installerContext.RecipeNames

status := dt.processEvaluator.DetectionStatus(dt.context, recipe, recipeNames)
durationMs := time.Since(start).Milliseconds()

if status == execution.RecipeStatusTypes.AVAILABLE && recipe.PreInstall.RequireAtDiscovery != "" {
status = dt.scriptEvaluator.DetectionStatus(dt.context, recipe)
status = dt.scriptEvaluator.DetectionStatus(dt.context, recipe, recipeNames)
durationMs = time.Since(start).Milliseconds()
log.Debugf("ScriptEvaluation for recipe:%s completed in %dms with status:%s", recipe.Name, durationMs, status)
}
Expand Down
7 changes: 6 additions & 1 deletion internal/install/recipes/script_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"

"github.com/newrelic/newrelic-cli/internal/install/execution"
"github.com/newrelic/newrelic-cli/internal/install/types"
Expand All @@ -24,7 +25,7 @@ func newScriptEvaluator(executor execution.RecipeExecutor) *ScriptEvaluator {
}
}

func (se *ScriptEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe) (statusResult execution.RecipeStatusType) {
func (se *ScriptEvaluator) DetectionStatus(ctx context.Context, r *types.OpenInstallationRecipe, recipeNames []string) (statusResult execution.RecipeStatusType) {

defer func() {
if err := recover(); err != nil {
Expand All @@ -36,6 +37,10 @@ func (se *ScriptEvaluator) DetectionStatus(ctx context.Context, r *types.OpenIns
if err := se.executor.ExecutePreInstall(ctx, *r, types.RecipeVars{}); err != nil {
log.Debugf("recipe %s failed script evaluation %s", r.Name, err)

if slices.Contains(recipeNames, r.Name) {
log.Errorf("Unsupported (%s): Requirements not satisfied:\n- %s", r.DisplayName, err)
}

if utils.IsExitStatusCode(132, err) {
statusResult = execution.RecipeStatusTypes.DETECTED
} else if utils.IsExitStatusCode(131, err) {
Expand Down
10 changes: 5 additions & 5 deletions internal/install/recipes/script_evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
func TestScriptEvaluatorShouldGetAvailable(t *testing.T) {
recipe := NewRecipeBuilder().Build()

status := GivenScriptEvaluator().DetectionStatus(context.Background(), recipe)
status := GivenScriptEvaluator().DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.AVAILABLE, status)
}
Expand All @@ -22,7 +22,7 @@ func TestScriptEvaluatorShouldDetect(t *testing.T) {
recipe := NewRecipeBuilder().Build()

evaluator := GivenScriptEvaluatorError("This is the specific message with exit status 132 special case")
status := evaluator.DetectionStatus(context.Background(), recipe)
status := evaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.DETECTED, status)
}
Expand All @@ -31,7 +31,7 @@ func TestScriptEvaluatorShouldNotDetect(t *testing.T) {
recipe := NewRecipeBuilder().Build()

evaluator := GivenScriptEvaluatorError("something went wrong")
status := evaluator.DetectionStatus(context.Background(), recipe)
status := evaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.NULL, status)
}
Expand All @@ -42,7 +42,7 @@ func TestScriptEvaluatorShouldReturnWhenPanic(t *testing.T) {
recipeExecutor.ShouldPanic = true

evaluator := newScriptEvaluator(recipeExecutor)
status := evaluator.DetectionStatus(context.Background(), recipe)
status := evaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.NULL, status)
}
Expand All @@ -62,7 +62,7 @@ func TestScriptEvaluatorShouldBeUnSupported(t *testing.T) {
recipe := NewRecipeBuilder().Build()

evaluator := GivenScriptEvaluatorError("This is the specific message with exit status 131 un-support case")
status := evaluator.DetectionStatus(context.Background(), recipe)
status := evaluator.DetectionStatus(context.Background(), recipe, []string{})

require.Equal(t, execution.RecipeStatusTypes.UNSUPPORTED, status)
}

0 comments on commit 2471eac

Please sign in to comment.