diff --git a/e2e/playwright/tests/@change-license/test.spec.ts b/e2e/playwright/tests/@change-license/test.spec.ts index 7fdd4e72eb..58255d6ecb 100644 --- a/e2e/playwright/tests/@change-license/test.spec.ts +++ b/e2e/playwright/tests/@change-license/test.spec.ts @@ -6,8 +6,8 @@ test('change license', async ({ page }) => { await login(page); await uploadLicense(page, expect, "community-license.yaml"); await expect(page.locator('#app')).toContainText('Change License', { timeout: 10000 }); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); - await expect(page.locator('#app')).toContainText('Currently deployed version'); await page.getByRole('link', { name: 'License', exact: true }).click(); await expect(page.locator('#app')).toContainText('change-license-community', { timeout: 10000 }); await expect(page.locator('#app')).toContainText('Community license'); diff --git a/e2e/playwright/tests/@multi-app-backup-and-restore/test.spec.ts b/e2e/playwright/tests/@multi-app-backup-and-restore/test.spec.ts index 2a3ec5805c..5526a71899 100644 --- a/e2e/playwright/tests/@multi-app-backup-and-restore/test.spec.ts +++ b/e2e/playwright/tests/@multi-app-backup-and-restore/test.spec.ts @@ -6,14 +6,14 @@ test('multi app backup and restore', async ({ page }) => { await login(page); await uploadLicense(page, expect, "app1-license.yaml"); await expect(page.locator('#app')).toContainText('Multi App Backup and Restore 1', { timeout: 10000 }); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); - await expect(page.locator('#app')).toContainText('Currently deployed version'); await page.locator('div').filter({ hasText: /^Change passwordAdd new applicationLog out$/ }).getByRole('img').click(); await page.getByText('Add new application').click(); await uploadLicense(page, expect, "app2-license.yaml"); await expect(page.locator('#app')).toContainText('Multi App Backup and Restore 2', { timeout: 10000 }); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); - await expect(page.locator('#app')).toContainText('Currently deployed version'); await page.locator('.NavItem').getByText('Snapshots', { exact: true }).click(); await page.getByRole('link', { name: 'Partial Snapshots' }).click({ timeout: 10000 }); await page.getByRole('button', { name: 'Start a snapshot' }).click({ timeout: 15000 }); diff --git a/e2e/playwright/tests/@multi-app-install/test.spec.ts b/e2e/playwright/tests/@multi-app-install/test.spec.ts index 5a83b2c2b4..82f628db7d 100644 --- a/e2e/playwright/tests/@multi-app-install/test.spec.ts +++ b/e2e/playwright/tests/@multi-app-install/test.spec.ts @@ -13,8 +13,8 @@ test('multi app install', async ({ page }) => { await expect(page.locator('#app')).toContainText('Your cluster meets the recommended and required versions of Kubernetes'); await page.getByRole('button', { name: 'Deploy' }).click(); await expect(page.locator('#app')).toContainText('Multi App Install 1'); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); - await expect(page.locator('#app')).toContainText('Currently deployed version'); await expect(page.locator('#app')).toContainText('0.1.3'); const app1Status = execSync(`kubectl kots get apps -n ${process.env.NAMESPACE} | grep mutli-app-install | awk '{print $2}'`).toString().trim(); expect(app1Status).toBe('ready'); @@ -27,8 +27,8 @@ test('multi app install', async ({ page }) => { await expect(page.locator('#app')).toContainText('Your cluster meets the recommended and required versions of Kubernetes'); await page.getByRole('button', { name: 'Deploy' }).click(); await expect(page.locator('#app')).toContainText('Multi App Install 2'); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); - await expect(page.locator('#app')).toContainText('Currently deployed version'); await expect(page.locator('#app')).toContainText('2.1.2'); const app2Status = execSync(`kubectl kots get apps -n ${process.env.NAMESPACE} | grep multi-app-install-2 | awk '{print $2}'`).toString().trim(); expect(app2Status).toBe('ready'); diff --git a/e2e/playwright/tests/@no-required-config/test.spec.ts b/e2e/playwright/tests/@no-required-config/test.spec.ts index 0d72e076b7..bf1abcca44 100644 --- a/e2e/playwright/tests/@no-required-config/test.spec.ts +++ b/e2e/playwright/tests/@no-required-config/test.spec.ts @@ -12,5 +12,5 @@ test('no required config', async ({ page }) => { await page.getByRole('button', { name: 'Continue' }).click(); await expect(page.locator('#app')).toContainText('Ready', { timeout: 30000 }); await page.getByRole('link', { name: 'Version history' }).click(); - await expect(page.locator('#app')).toContainText('Currently deployed version'); + await expect(page.locator('#app')).toContainText('Currently deployed version', { timeout: 15000 }); }); diff --git a/pkg/kotsutil/kots.go b/pkg/kotsutil/kots.go index 9e6d5e010a..f2df1c0bcd 100644 --- a/pkg/kotsutil/kots.go +++ b/pkg/kotsutil/kots.go @@ -32,6 +32,7 @@ import ( kotsscheme "github.com/replicatedhq/kotskinds/client/kotsclientset/scheme" kurlscheme "github.com/replicatedhq/kurlkinds/client/kurlclientset/scheme" kurlv1beta1 "github.com/replicatedhq/kurlkinds/pkg/apis/cluster/v1beta1" + troubleshootanalyze "github.com/replicatedhq/troubleshoot/pkg/analyze" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" troubleshootscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme" "github.com/replicatedhq/troubleshoot/pkg/collect" @@ -89,7 +90,8 @@ type KotsKinds struct { V1Beta2HelmCharts *kotsv1beta2.HelmChartList Collector *troubleshootv1beta2.Collector - Preflight *troubleshootv1beta2.Preflight + Preflight *troubleshootv1beta2.Preflight // TODO: consolidate this with Preflights + Preflights []troubleshootv1beta2.Preflight Analyzer *troubleshootv1beta2.Analyzer SupportBundle *troubleshootv1beta2.SupportBundle Redactor *troubleshootv1beta2.Redactor @@ -235,10 +237,28 @@ func (k *KotsKinds) IsConfigurable() bool { } func (k *KotsKinds) HasPreflights() bool { - if k == nil || k.Preflight == nil { + if k == nil { return false } - return len(k.Preflight.Spec.Analyzers) > 0 + numAnalyzers := 0 + for _, p := range k.AllPreflights() { + for _, a := range p.Spec.Analyzers { + exclude := troubleshootanalyze.GetExcludeFlag(a).BoolOrDefaultFalse() + if !exclude { + numAnalyzers += 1 + } + } + } + return numAnalyzers > 0 +} + +func (k *KotsKinds) AllPreflights() []troubleshootv1beta2.Preflight { + all := []troubleshootv1beta2.Preflight{} + if k.Preflight != nil { + all = append(all, *k.Preflight) + } + all = append(all, k.Preflights...) + return all } func (o KotsKinds) Marshal(g string, v string, k string) (string, error) { @@ -725,6 +745,12 @@ func LoadKotsKindsWithOpts(archive string, opts LoadKotsKindsOptions) (*KotsKind return nil, errors.Wrap(err, "failed to walk upstream dir") } + tsKinds, err := LoadTSKindsFromPath(fromDir) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("failed to load troubleshoot kinds from: %s", fromDir)) + } + kotsKinds.Preflights = append(kotsKinds.Preflights, tsKinds.PreflightsV1Beta2...) + return &kotsKinds, nil } diff --git a/pkg/kotsutil/kots_test.go b/pkg/kotsutil/kots_test.go index d6b200fbd0..ebffdad412 100644 --- a/pkg/kotsutil/kots_test.go +++ b/pkg/kotsutil/kots_test.go @@ -19,6 +19,7 @@ import ( kotsv1beta2 "github.com/replicatedhq/kotskinds/apis/kots/v1beta2" kurlv1beta1 "github.com/replicatedhq/kurlkinds/pkg/apis/cluster/v1beta1" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" + "github.com/replicatedhq/troubleshoot/pkg/multitype" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" @@ -567,7 +568,32 @@ var _ = Describe("Kots", func() { Expect(preflightResult).To(BeFalse()) }) - It("returns true when there are more than one analyzers defined in the preflight spec", func() { + It("returns false when the client-side object does not have analyzers", func() { + kotsKind := &kotsutil.KotsKinds{ + Preflight: &troubleshootv1beta2.Preflight{ + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{}, + }, + }, + Preflights: []troubleshootv1beta2.Preflight{ + { + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{}, + }, + }, + { + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{}, + }, + }, + }, + } + preflightResult := kotsKind.HasPreflights() + Expect(preflightResult).To(BeFalse()) + }) + + It("returns true when there are analyzers defined in the preflight spec", func() { + // single spec kotsKind := &kotsutil.KotsKinds{ Preflight: &troubleshootv1beta2.Preflight{ Spec: troubleshootv1beta2.PreflightSpec{ @@ -579,6 +605,101 @@ var _ = Describe("Kots", func() { } preflightResult := kotsKind.HasPreflights() Expect(preflightResult).To(BeTrue()) + + // multiple specs + kotsKind = &kotsutil.KotsKinds{ + Preflights: []troubleshootv1beta2.Preflight{ + { + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + {}, + }, + }, + }, + { + Spec: troubleshootv1beta2.PreflightSpec{}, + }, + }, + } + preflightResult = kotsKind.HasPreflights() + Expect(preflightResult).To(BeTrue()) + }) + + It("returns false when all analyzers are excluded", func() { + kotsKind := &kotsutil.KotsKinds{ + Preflight: &troubleshootv1beta2.Preflight{ + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{ + Exclude: multitype.FromBool(true), + }, + }, + }, + }, + }, + }, + Preflights: []troubleshootv1beta2.Preflight{ + { + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{ + Exclude: multitype.FromBool(true), + }, + }, + }, + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{ + Exclude: multitype.FromBool(true), + }, + }, + }, + }, + }, + }, + }, + } + preflightResult := kotsKind.HasPreflights() + Expect(preflightResult).To(BeFalse()) + }) + + It("returns true when a single analyzer is not excluded", func() { + kotsKind := &kotsutil.KotsKinds{ + Preflight: &troubleshootv1beta2.Preflight{ + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{ + Exclude: multitype.FromBool(true), + }, + }, + }, + }, + }, + }, + Preflights: []troubleshootv1beta2.Preflight{ + { + Spec: troubleshootv1beta2.PreflightSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{ + Exclude: multitype.FromBool(false), + }, + }, + }, + }, + }, + }, + }, + } + preflightResult := kotsKind.HasPreflights() + Expect(preflightResult).To(BeTrue()) }) }) diff --git a/pkg/preflight/preflight.go b/pkg/preflight/preflight.go index 8ec1b21b1e..5746e2cc0e 100644 --- a/pkg/preflight/preflight.go +++ b/pkg/preflight/preflight.go @@ -19,9 +19,7 @@ import ( "github.com/replicatedhq/kots/pkg/preflight/types" "github.com/replicatedhq/kots/pkg/registry" registrytypes "github.com/replicatedhq/kots/pkg/registry/types" - "github.com/replicatedhq/kots/pkg/render" "github.com/replicatedhq/kots/pkg/render/helper" - rendertypes "github.com/replicatedhq/kots/pkg/render/types" "github.com/replicatedhq/kots/pkg/reporting" "github.com/replicatedhq/kots/pkg/store" storetypes "github.com/replicatedhq/kots/pkg/store/types" @@ -47,11 +45,6 @@ const ( ) func Run(appID string, appSlug string, sequence int64, isAirgap bool, ignoreNonStrict bool, archiveDir string) error { - kotsKinds, err := kotsutil.LoadKotsKinds(archiveDir) - if err != nil { - return errors.Wrap(err, "failed to load rendered kots kinds") - } - status, err := store.GetStore().GetDownstreamVersionStatus(appID, sequence) if err != nil { return errors.Wrapf(err, "failed to check downstream version %d status", sequence) @@ -65,180 +58,110 @@ func Run(appID string, appSlug string, sequence int64, isAirgap bool, ignoreNonS return nil } - var ignoreRBAC bool - var registrySettings registrytypes.RegistrySettings + kotsKinds, err := kotsutil.LoadKotsKinds(archiveDir) + if err != nil { + return errors.Wrap(err, "failed to load rendered kots kinds") + } + if !kotsKinds.HasPreflights() { + return nil + } + var preflight *troubleshootv1beta2.Preflight + for _, p := range kotsKinds.AllPreflights() { + preflight = troubleshootpreflight.ConcatPreflightSpec(preflight, &p) + } - ignoreRBAC, err = store.GetStore().GetIgnoreRBACErrors(appID, sequence) + ignoreRBAC, err := store.GetStore().GetIgnoreRBACErrors(appID, sequence) if err != nil { return errors.Wrap(err, "failed to get ignore rbac flag") } - registrySettings, err = store.GetStore().GetRegistryDetailsForApp(appID) + registrySettings, err := store.GetStore().GetRegistryDetailsForApp(appID) if err != nil { return errors.Wrap(err, "failed to get registry settings for app") } - tsKinds, err := kotsutil.LoadTSKindsFromPath(filepath.Join(archiveDir, "rendered")) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to load troubleshoot kinds from path: %s", filepath.Join(archiveDir, "rendered"))) - } - - runPreflights := false - if tsKinds.PreflightsV1Beta2 != nil { + var preflightErr error + defer func() { + if preflightErr != nil { + preflightResults := &types.PreflightResults{ + Errors: []*types.PreflightError{ + { + Error: preflightErr.Error(), + IsRBAC: false, + }, + }, + } + if err := setPreflightResults(appID, sequence, preflightResults); err != nil { + logger.Error(errors.Wrap(err, "failed to set preflight results")) + return + } + } + }() - for _, v := range tsKinds.PreflightsV1Beta2 { - preflight = troubleshootpreflight.ConcatPreflightSpec(preflight, &v) + if status != storetypes.VersionDeployed && status != storetypes.VersionDeploying { + if err := store.GetStore().SetDownstreamVersionStatus(appID, sequence, storetypes.VersionPendingPreflight, ""); err != nil { + preflightErr = errors.Wrapf(err, "failed to set downstream version %d pending preflight", sequence) + return preflightErr } + } - InjectDefaultPreflights(preflight, kotsKinds, registrySettings) + collectors, err := registry.UpdateCollectorSpecsWithRegistryData(preflight.Spec.Collectors, registrySettings, kotsKinds.Installation, kotsKinds.License, &kotsKinds.KotsApplication) + if err != nil { + preflightErr = errors.Wrap(err, "failed to rewrite images in preflight") + return preflightErr + } + preflight.Spec.Collectors = collectors - numAnalyzers := 0 - for _, analyzer := range preflight.Spec.Analyzers { - exclude := troubleshootanalyze.GetExcludeFlag(analyzer).BoolOrDefaultFalse() - if !exclude { - numAnalyzers += 1 - } - } - runPreflights = numAnalyzers > 0 - } else if kotsKinds.Preflight != nil { - // render the preflight file - // we need to convert to bytes first, so that we can reuse the renderfile function - renderedMarshalledPreflights, err := kotsKinds.Marshal("troubleshoot.replicated.com", "v1beta1", "Preflight") - if err != nil { - return errors.Wrap(err, "failed to marshal rendered preflight") - } + go func() { + logger.Info("preflight checks beginning", + zap.String("appID", appID), + zap.Int64("sequence", sequence)) - renderedPreflight, err := render.RenderFile(rendertypes.RenderFileOptions{ - KotsKinds: kotsKinds, - RegistrySettings: registrySettings, - AppSlug: appSlug, - Sequence: sequence, - IsAirgap: isAirgap, - Namespace: util.PodNamespace, - InputContent: []byte(renderedMarshalledPreflights), - }) - if err != nil { - return errors.Wrap(err, "failed to render preflights") + setProgress := func(progress map[string]interface{}) error { + return setPreflightProgress(appID, sequence, progress) + } + setResults := func(results *types.PreflightResults) error { + return setPreflightResults(appID, sequence, results) } - preflight, err = kotsutil.LoadPreflightFromContents(renderedPreflight) + uploadPreflightResults, err := Execute(preflight, ignoreRBAC, setProgress, setResults) if err != nil { - return errors.Wrap(err, "failed to load rendered preflight") + logger.Error(errors.Wrap(err, "failed to run preflight checks")) + return } + logger.Info("preflight checks completed") - InjectDefaultPreflights(preflight, kotsKinds, registrySettings) - - numAnalyzers := 0 - for _, analyzer := range preflight.Spec.Analyzers { - exclude := troubleshootanalyze.GetExcludeFlag(analyzer).BoolOrDefaultFalse() - if !exclude { - numAnalyzers += 1 - } - } - runPreflights = numAnalyzers > 0 - } - - if runPreflights { - var preflightErr error - defer func() { - if preflightErr != nil { - preflightResults := &types.PreflightResults{ - Errors: []*types.PreflightError{ - { - Error: preflightErr.Error(), - IsRBAC: false, - }, - }, - } - if err := setPreflightResults(appID, sequence, preflightResults); err != nil { - logger.Error(errors.Wrap(err, "failed to set preflight results")) - return - } + go func() { + err := reporting.GetReporter().SubmitAppInfo(appID) // send app and preflight info when preflights finish + if err != nil { + logger.Debugf("failed to submit app info: %v", err) } }() + // status could've changed while preflights were running status, err := store.GetStore().GetDownstreamVersionStatus(appID, sequence) if err != nil { - preflightErr = errors.Wrap(err, "failed to get version status") - return preflightErr + logger.Error(errors.Wrapf(err, "failed to check downstream version %d status", sequence)) + return } - - if status != storetypes.VersionDeployed && status != storetypes.VersionDeploying { - if err := store.GetStore().SetDownstreamVersionStatus(appID, sequence, storetypes.VersionPendingPreflight, ""); err != nil { - preflightErr = errors.Wrapf(err, "failed to set downstream version %d pending preflight", sequence) - return preflightErr - } + if status == storetypes.VersionDeployed || status == storetypes.VersionDeploying || status == storetypes.VersionFailed { + return } - collectors, err := registry.UpdateCollectorSpecsWithRegistryData(preflight.Spec.Collectors, registrySettings, kotsKinds.Installation, kotsKinds.License, &kotsKinds.KotsApplication) + isDeployed, err := maybeDeployFirstVersion(appID, sequence, uploadPreflightResults, ignoreNonStrict) if err != nil { - preflightErr = errors.Wrap(err, "failed to rewrite images in preflight") - return preflightErr + logger.Error(errors.Wrap(err, "failed to deploy first version")) + return } - preflight.Spec.Collectors = collectors - - go func() { - logger.Info("preflight checks beginning", - zap.String("appID", appID), - zap.Int64("sequence", sequence)) - - setProgress := func(progress map[string]interface{}) error { - return setPreflightProgress(appID, sequence, progress) - } - setResults := func(results *types.PreflightResults) error { - return setPreflightResults(appID, sequence, results) - } - uploadPreflightResults, err := Execute(preflight, ignoreRBAC, setProgress, setResults) - if err != nil { - logger.Error(errors.Wrap(err, "failed to run preflight checks")) - return - } - logger.Info("preflight checks completed") - - go func() { - err := reporting.GetReporter().SubmitAppInfo(appID) // send app and preflight info when preflights finish - if err != nil { - logger.Debugf("failed to submit app info: %v", err) - } - }() - - // status could've changed while preflights were running - status, err := store.GetStore().GetDownstreamVersionStatus(appID, sequence) - if err != nil { - logger.Error(errors.Wrapf(err, "failed to check downstream version %d status", sequence)) - return - } - if status == storetypes.VersionDeployed || status == storetypes.VersionDeploying || status == storetypes.VersionFailed { - return - } - isDeployed, err := maybeDeployFirstVersion(appID, sequence, uploadPreflightResults, ignoreNonStrict) - if err != nil { - logger.Error(errors.Wrap(err, "failed to deploy first version")) + // preflight reporting + if isDeployed { + if err := reporting.WaitAndReportPreflightChecks(appID, sequence, false, false); err != nil { + logger.Debugf("failed to send preflights data to replicated app: %v", err) return } - - // preflight reporting - if isDeployed { - if err := reporting.WaitAndReportPreflightChecks(appID, sequence, false, false); err != nil { - logger.Debugf("failed to send preflights data to replicated app: %v", err) - return - } - } - }() - } else if status != storetypes.VersionDeployed && status != storetypes.VersionFailed { - if sequence == 0 { - _, err := maybeDeployFirstVersion(appID, sequence, &types.PreflightResults{}, ignoreNonStrict) - if err != nil { - return errors.Wrap(err, "failed to deploy first version") - } - } else { - err := store.GetStore().SetDownstreamVersionStatus(appID, sequence, storetypes.VersionPending, "") - if err != nil { - return errors.Wrap(err, "failed to set downstream version status to pending") - } } - } + }() return nil } diff --git a/pkg/store/kotsstore/version_store.go b/pkg/store/kotsstore/version_store.go index c475765d88..80ec7ab7e1 100644 --- a/pkg/store/kotsstore/version_store.go +++ b/pkg/store/kotsstore/version_store.go @@ -753,13 +753,15 @@ func (s *KOTSStore) determineDownstreamVersionStatus(a *apptypes.App, sequence i if !skipPreflights { return types.VersionPendingPreflight, nil } - hasStrictPreflights, err := troubleshootpreflight.HasStrictAnalyzers(kotsKinds.Preflight) - if err != nil { - return types.VersionUnknown, errors.Wrap(err, "failed to check strict preflights from spec") - } - if hasStrictPreflights { - logger.Warnf("preflights will not be skipped, strict preflights are set to true") - return types.VersionPendingPreflight, nil + for _, p := range kotsKinds.AllPreflights() { + hasStrictPreflights, err := troubleshootpreflight.HasStrictAnalyzers(&p) + if err != nil { + return types.VersionUnknown, errors.Wrap(err, "failed to check strict preflights from spec") + } + if hasStrictPreflights { + logger.Warnf("preflights will not be skipped, strict preflights are set to true") + return types.VersionPendingPreflight, nil + } } }