@@ -62,6 +62,7 @@ type installFlags struct {
6262 assumeYes bool
6363 overrides string
6464 configValues string
65+ headless bool
6566
6667 // linux flags
6768 dataDir string
@@ -97,6 +98,7 @@ type installConfig struct {
9798 tlsCert tls.Certificate
9899 tlsCertBytes []byte
99100 tlsKeyBytes []byte
101+ configValues * kotsv1beta1.ConfigValues
100102}
101103
102104// webAssetsFS is the filesystem to be used by the web component. Defaults to nil allowing the web server to use the default assets embedded in the binary. Useful for testing.
@@ -129,6 +131,7 @@ func InstallCmd(ctx context.Context, appSlug, appTitle string) *cobra.Command {
129131 if err != nil {
130132 return err
131133 }
134+
132135 if err := verifyAndPrompt (ctx , cmd , appSlug , & flags , installCfg , prompts .New ()); err != nil {
133136 return err
134137 }
@@ -346,13 +349,17 @@ func addTLSFlags(cmd *cobra.Command, flags *installFlags) error {
346349
347350func addManagementConsoleFlags (cmd * cobra.Command , flags * installFlags ) error {
348351 cmd .Flags ().IntVar (& flags .managerPort , "manager-port" , ecv1beta1 .DefaultManagerPort , "Port on which the Manager will be served" )
352+ cmd .Flags ().BoolVar (& flags .headless , "headless" , false , "Run installation in headless mode without UI interaction." )
349353
350354 // If the ENABLE_V3 environment variable is set, default to the new manager experience and do
351355 // not hide the manager-port flag.
352356 if ! isV3Enabled () {
353357 if err := cmd .Flags ().MarkHidden ("manager-port" ); err != nil {
354358 return err
355359 }
360+ if err := cmd .Flags ().MarkHidden ("headless" ); err != nil {
361+ return err
362+ }
356363 }
357364
358365 return nil
@@ -493,12 +500,8 @@ func runManagerExperienceInstall(
493500 }
494501
495502 var configValues apitypes.AppConfigValues
496- if flags .configValues != "" {
497- kotsConfigValues , err := helpers .ParseConfigValues (flags .configValues )
498- if err != nil {
499- return fmt .Errorf ("parse config values file: %w" , err )
500- }
501- configValues = apitypes .ConvertToAppConfigValues (kotsConfigValues )
503+ if installCfg .configValues != nil {
504+ configValues = apitypes .ConvertToAppConfigValues (installCfg .configValues )
502505 }
503506
504507 apiConfig := apiOptions {
@@ -532,6 +535,7 @@ func runManagerExperienceInstall(
532535 },
533536
534537 ManagerPort : flags .managerPort ,
538+ Headless : flags .headless ,
535539 WebMode : web .ModeInstall ,
536540 MetricsReporter : metricsReporter ,
537541 }
@@ -543,6 +547,11 @@ func runManagerExperienceInstall(
543547 return fmt .Errorf ("failed to start api: %w" , err )
544548 }
545549
550+ if flags .headless {
551+ // TODO(PR2): Implement headless installation orchestration
552+ return fmt .Errorf ("headless installation is not yet fully implemented - coming in a future release" )
553+ }
554+
546555 logrus .Infof ("\n Visit the %s manager to continue: %s\n " ,
547556 appTitle ,
548557 getManagerURL (flags .hostname , flags .managerPort ))
@@ -718,10 +727,11 @@ func verifyAndPrompt(ctx context.Context, cmd *cobra.Command, appSlug string, fl
718727 }
719728
720729 logrus .Debugf ("checking license matches" )
721- license , err : = verifyLicense (installCfg .license )
730+ err = verifyLicense (installCfg .license )
722731 if err != nil {
723732 return err
724733 }
734+
725735 if installCfg .airgapMetadata != nil && installCfg .airgapMetadata .AirgapInfo != nil {
726736 logrus .Debugf ("checking airgap bundle matches binary" )
727737 if err := checkAirgapMatches (installCfg .airgapMetadata .AirgapInfo ); err != nil {
@@ -730,7 +740,7 @@ func verifyAndPrompt(ctx context.Context, cmd *cobra.Command, appSlug string, fl
730740 }
731741
732742 if ! installCfg .isAirgap {
733- if err := maybePromptForAppUpdate (ctx , prompt , license , flags .assumeYes ); err != nil {
743+ if err := maybePromptForAppUpdate (ctx , prompt , installCfg . license , flags .assumeYes ); err != nil {
734744 if errors .As (err , & ErrorNothingElseToAdd {}) {
735745 return err
736746 }
@@ -796,7 +806,7 @@ func ensureAdminConsolePassword(flags *installFlags) error {
796806 return nil
797807}
798808
799- func verifyLicense (license * kotsv1beta1.License ) ( * kotsv1beta1. License , error ) {
809+ func verifyLicense (license * kotsv1beta1.License ) error {
800810 rel := release .GetChannelRelease ()
801811
802812 // handle the three cases that do not require parsing the license file
@@ -805,42 +815,42 @@ func verifyLicense(license *kotsv1beta1.License) (*kotsv1beta1.License, error) {
805815 // 3. a license and no release, which is not OK
806816 if rel == nil && license == nil {
807817 // no license and no release, this is OK
808- return nil , nil
818+ return nil
809819 } else if rel == nil && license != nil {
810820 // license is present but no release, this means we would install without vendor charts and k0s overrides
811- return nil , fmt .Errorf ("a license was provided but no release was found in binary, please rerun without the license flag" )
821+ return fmt .Errorf ("a license was provided but no release was found in binary, please rerun without the license flag" )
812822 } else if rel != nil && license == nil {
813823 // release is present but no license, this is not OK
814- return nil , fmt .Errorf ("no license was provided for %s and one is required, please rerun with '--license <path to license file>'" , rel .AppSlug )
824+ return fmt .Errorf ("no license was provided for %s and one is required, please rerun with '--license <path to license file>'" , rel .AppSlug )
815825 }
816826
817827 // Check if the license matches the application version data
818828 if rel .AppSlug != license .Spec .AppSlug {
819829 // if the app is different, we will not be able to provide the correct vendor supplied charts and k0s overrides
820- return nil , fmt .Errorf ("license app %s does not match binary app %s, please provide the correct license" , license .Spec .AppSlug , rel .AppSlug )
830+ return fmt .Errorf ("license app %s does not match binary app %s, please provide the correct license" , license .Spec .AppSlug , rel .AppSlug )
821831 }
822832
823833 // Ensure the binary channel actually is present in the supplied license
824834 if err := checkChannelExistence (license , rel ); err != nil {
825- return nil , err
835+ return err
826836 }
827837
828838 if license .Spec .Entitlements ["expires_at" ].Value .StrVal != "" {
829839 // read the expiration date, and check it against the current date
830840 expiration , err := time .Parse (time .RFC3339 , license .Spec .Entitlements ["expires_at" ].Value .StrVal )
831841 if err != nil {
832- return nil , fmt .Errorf ("parse expiration date: %w" , err )
842+ return fmt .Errorf ("parse expiration date: %w" , err )
833843 }
834844 if time .Now ().After (expiration ) {
835- return nil , fmt .Errorf ("license expired on %s, please provide a valid license" , expiration )
845+ return fmt .Errorf ("license expired on %s, please provide a valid license" , expiration )
836846 }
837847 }
838848
839849 if ! license .Spec .IsEmbeddedClusterDownloadEnabled {
840- return nil , fmt .Errorf ("license does not have embedded cluster enabled, please provide a valid license" )
850+ return fmt .Errorf ("license does not have embedded cluster enabled, please provide a valid license" )
841851 }
842852
843- return license , nil
853+ return nil
844854}
845855
846856// checkChannelExistence verifies that a channel exists in a supplied license, returning a user-friendly
0 commit comments