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

send preflight results event when preflights fail #1553

Merged
merged 11 commits into from
Dec 5, 2024
26 changes: 15 additions & 11 deletions cmd/installer/cli/install_runpreflights.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/dryrun"
"github.com/replicatedhq/embedded-cluster/pkg/goods"
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/preflights"
"github.com/replicatedhq/embedded-cluster/pkg/prompts"
"github.com/replicatedhq/embedded-cluster/pkg/release"
Expand Down Expand Up @@ -48,8 +49,6 @@ func InstallRunPreflightsCmd(ctx context.Context, name string) *cobra.Command {
overrides string
privateCAs []string
configValues string
skipHostPreflights bool
ignoreHostPreflights bool

proxy *ecv1beta1.ProxySpec
)
Expand Down Expand Up @@ -155,9 +154,10 @@ func InstallRunPreflightsCmd(ctx context.Context, name string) *cobra.Command {
cmd.Flags().StringSliceVar(&privateCAs, "private-ca", []string{}, "Path to a trusted private CA certificate file")
cmd.Flags().StringVar(&configValues, "config-values", "", "path to a manifest containing config values (must be apiVersion: kots.io/v1beta1, kind: ConfigValues)")

cmd.Flags().BoolVar(&skipHostPreflights, "skip-host-preflights", false, "Skip host preflight checks. This is not recommended and has been deprecated.")
cmd.Flags().Bool("skip-host-preflights", false, "Skip host preflight checks. This is not recommended and has been deprecated.")
cmd.Flags().MarkHidden("skip-host-preflights")
cmd.Flags().BoolVar(&ignoreHostPreflights, "ignore-host-preflights", false, "Run host preflight checks, but prompt the user to continue if they fail instead of exiting.")
cmd.Flags().Bool("ignore-host-preflights", false, "Run host preflight checks, but prompt the user to continue if they fail instead of exiting.")
cmd.Flags().MarkHidden("ignore-host-preflights")

addProxyFlags(cmd)
addCIDRFlags(cmd)
Expand Down Expand Up @@ -378,10 +378,10 @@ func RunHostPreflights(cmd *cobra.Command, applier *addons.Applier, replicatedAP
return nil
}

return runHostPreflights(cmd, hpf, proxy, assumeYes)
return runHostPreflights(cmd, hpf, proxy, assumeYes, replicatedAPIURL)
}

func runHostPreflights(cmd *cobra.Command, hpf *v1beta2.HostPreflightSpec, proxy *ecv1beta1.ProxySpec, assumeYes bool) error {
func runHostPreflights(cmd *cobra.Command, hpf *v1beta2.HostPreflightSpec, proxy *ecv1beta1.ProxySpec, assumeYes bool, replicatedAPIURL string) error {
Copy link
Member

@emosbaugh emosbaugh Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this function is called from many different commands, wouldn't it be helpful to report which command was run? also, is it your intention to report for the run-preflights commands? and not related to this change, but why prompt at all for those commands?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the reporting to include the command that was called (install, run-preflights, join etc)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and not related to this change, but why prompt at all for those commands?

Because it's the same codepath, but we hide the 'skip-host-preflights' and 'ignore-host-preflight' flags on those commands, so there shouldn't be prompts (the code we're using expects the flags to exist, which is why they're there at all)

if len(hpf.Collectors) == 0 && len(hpf.Analyzers) == 0 {
return nil
}
Expand Down Expand Up @@ -437,9 +437,11 @@ func runHostPreflights(cmd *cobra.Command, hpf *v1beta2.HostPreflightSpec, proxy
}
if ignoreHostPreflightsFlag {
if assumeYes {
metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, true, cmd.CalledAs())
return nil
}
if prompts.New().Confirm("Are you sure you want to ignore these failures and continue installing?", false) {
metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, true, cmd.CalledAs())
return nil // user continued after host preflights failed
}
}
Expand All @@ -449,7 +451,7 @@ func runHostPreflights(cmd *cobra.Command, hpf *v1beta2.HostPreflightSpec, proxy
} else {
logrus.Info("Please address this issue and try again.")
}

metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, false, cmd.CalledAs())
return ErrPreflightsHaveFail
}

Expand All @@ -465,15 +467,17 @@ func runHostPreflights(cmd *cobra.Command, hpf *v1beta2.HostPreflightSpec, proxy
// so we just print the warnings and continue
pb.Close()
output.PrintTableWithoutInfo()
metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, true, cmd.CalledAs())
return nil
}
pb.Close()
output.PrintTableWithoutInfo()
if !prompts.New().Confirm("Do you want to continue?", false) {
pb.Close()
return fmt.Errorf("user aborted")
if prompts.New().Confirm("Do you want to continue?", false) {
metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, true, cmd.CalledAs())
return nil
}
return nil
metrics.ReportPreflightsFailed(cmd.Context(), replicatedAPIURL, *output, false, cmd.CalledAs())
return fmt.Errorf("user aborted")
}

// No failures or warnings
Expand Down
14 changes: 7 additions & 7 deletions cmd/installer/cli/join_runpreflights.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ import (

func JoinRunPreflightsCmd(ctx context.Context, name string) *cobra.Command {
var (
airgapBundle string
networkInterface string
assumeYes bool
skipHostPreflights bool
ignoreHostPreflights bool
airgapBundle string
networkInterface string
assumeYes bool
)
cmd := &cobra.Command{
Use: "run-preflights",
Expand Down Expand Up @@ -135,9 +133,11 @@ func JoinRunPreflightsCmd(ctx context.Context, name string) *cobra.Command {
cmd.Flags().StringVar(&airgapBundle, "airgap-bundle", "", "Path to the air gap bundle. If set, the installation will complete without internet access.")
cmd.Flags().MarkHidden("airgap-bundle")
cmd.Flags().StringVar(&networkInterface, "network-interface", "", "The network interface to use for the cluster")
cmd.Flags().BoolVar(&skipHostPreflights, "skip-host-preflights", false, "Skip host preflight checks. This is not recommended and has been deprecated.")

cmd.Flags().Bool("skip-host-preflights", false, "Skip host preflight checks. This is not recommended and has been deprecated.")
cmd.Flags().MarkHidden("skip-host-preflights")
cmd.Flags().BoolVar(&ignoreHostPreflights, "ignore-host-preflights", false, "Run host preflight checks, but prompt the user to continue if they fail instead of exiting.")
cmd.Flags().Bool("ignore-host-preflights", false, "Run host preflight checks, but prompt the user to continue if they fail instead of exiting.")
cmd.Flags().MarkHidden("ignore-host-preflights")

cmd.Flags().BoolVar(&assumeYes, "yes", false, "Assume yes to all prompts.")
cmd.Flags().SetNormalizeFunc(normalizeNoPromptToYes)
Expand Down
2 changes: 1 addition & 1 deletion cmd/installer/cli/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ func RunHostPreflightsForRestore(cmd *cobra.Command, applier *addons.Applier, pr
return fmt.Errorf("unable to read host preflights: %w", err)
}

return runHostPreflights(cmd, hpf, proxy, assumeYes)
return runHostPreflights(cmd, hpf, proxy, assumeYes, "")
}

// ensureK0sConfigForRestore creates a new k0s.yaml configuration file for restore operations.
Expand Down
36 changes: 36 additions & 0 deletions pkg/metrics/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package metrics

import (
"context"
"encoding/json"
"os"
"strings"
"sync"
Expand All @@ -12,6 +13,7 @@ import (

"github.com/replicatedhq/embedded-cluster/pkg/helpers"
"github.com/replicatedhq/embedded-cluster/pkg/metrics/types"
"github.com/replicatedhq/embedded-cluster/pkg/preflights"
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
"github.com/replicatedhq/embedded-cluster/pkg/versions"
Expand Down Expand Up @@ -163,3 +165,37 @@ func ReportApplyFinished(ctx context.Context, licenseFlag string, license *kotsv
}
ReportInstallationSucceeded(ctx, license)
}

// ReportPreflightsFailed reports that the preflights failed but were bypassed.
func ReportPreflightsFailed(ctx context.Context, url string, output preflights.Output, bypassed bool, entryCommand string) {
if url == "" {
url = BaseURL(nil)
}

hostname, err := os.Hostname()
if err != nil {
logrus.Warnf("unable to get hostname: %s", err)
hostname = "unknown"
}

eventType := "PreflightsFailed"
if bypassed {
eventType = "PreflightsBypassed"
}

outputJSON, err := json.Marshal(output)
if err != nil {
logrus.Warnf("unable to marshal preflight output: %s", err)
return
}

ev := types.PreflightsFailed{
ClusterID: ClusterID(),
Version: versions.Version,
NodeName: hostname,
PreflightOutput: string(outputJSON),
EventType: eventType,
EntryCommand: entryCommand,
}
go Send(ctx, url, ev)
}
16 changes: 16 additions & 0 deletions pkg/metrics/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,19 @@ type JoinFailed struct {
func (e JoinFailed) Title() string {
return "JoinFailed"
}

// PreflightsFailed event is send back home when the preflights failed but were bypassed.
type PreflightsFailed struct {
ClusterID uuid.UUID `json:"clusterID"`
Version string `json:"version"`
NodeName string `json:"nodeName"`
PreflightOutput string `json:"preflightOutput"`
EventType string `json:"eventType"`
EntryCommand string `json:"entryCommand"`
}

// Title returns the name of the event.
func (e PreflightsFailed) Title() string {
// GenericEvents are added to the events table, but do not update the cluster status
return "GenericEvent"
}
Loading