github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/step/step_validate.go (about)

     1  package step
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/olli-ai/jx/v2/pkg/cmd/opts/step"
     7  
     8  	"github.com/olli-ai/jx/v2/pkg/cmd/helper"
     9  
    10  	"github.com/olli-ai/jx/v2/pkg/helm"
    11  
    12  	"github.com/blang/semver"
    13  	"github.com/jenkins-x/jx-logging/pkg/log"
    14  	"github.com/olli-ai/jx/v2/pkg/cmd/opts"
    15  	"github.com/olli-ai/jx/v2/pkg/cmd/templates"
    16  	"github.com/olli-ai/jx/v2/pkg/config"
    17  	"github.com/olli-ai/jx/v2/pkg/kube"
    18  	"github.com/olli-ai/jx/v2/pkg/util"
    19  	"github.com/olli-ai/jx/v2/pkg/version"
    20  	"github.com/spf13/cobra"
    21  	"k8s.io/apimachinery/pkg/util/errors"
    22  )
    23  
    24  const (
    25  	optionMinJxVersion = "min-jx-version"
    26  )
    27  
    28  var (
    29  	stepValidateLong = templates.LongDesc(`
    30  		Validates the command line tools, container and platform to ensure a pipeline can run properly.
    31  
    32  		This helps ensure that your platform installation, 'addons, builder images and Jenkinsfile' are all on compatible versions.
    33  `)
    34  
    35  	stepValidateExample = templates.Examples(`
    36  		# Validates that the jx version is new enough
    37  		jx step validate --min-jx-version ` + version.StringDefault(version.ExampleVersion) + `
    38  			`)
    39  )
    40  
    41  // StepValidateOptions contains the command line flags
    42  type StepValidateOptions struct {
    43  	step.StepOptions
    44  
    45  	MinimumJxVersion string
    46  	Dir              string
    47  }
    48  
    49  // NewCmdStepValidate Creates a new Command object
    50  func NewCmdStepValidate(commonOpts *opts.CommonOptions) *cobra.Command {
    51  	options := &StepValidateOptions{
    52  		StepOptions: step.StepOptions{
    53  			CommonOptions: commonOpts,
    54  		},
    55  	}
    56  
    57  	cmd := &cobra.Command{
    58  		Use:     "validate",
    59  		Short:   "Validates the command line tools, container and platform to ensure a pipeline can run properly",
    60  		Long:    stepValidateLong,
    61  		Example: stepValidateExample,
    62  		Run: func(cmd *cobra.Command, args []string) {
    63  			options.Cmd = cmd
    64  			options.Args = args
    65  			err := options.Run()
    66  			helper.CheckErr(err)
    67  		},
    68  	}
    69  	cmd.Flags().StringVarP(&options.MinimumJxVersion, optionMinJxVersion, "v", "", "The minimum version of the 'jx' command line tool required")
    70  	cmd.Flags().StringVarP(&options.Dir, "dir", "d", "", "The project directory to look inside for the Project configuration for things like required addons")
    71  	return cmd
    72  }
    73  
    74  // Run implements this command
    75  func (o *StepValidateOptions) Run() error {
    76  	errs := []error{}
    77  	if o.MinimumJxVersion != "" {
    78  		err := o.verifyJxVersion(o.MinimumJxVersion)
    79  		if err != nil {
    80  			errs = append(errs, err)
    81  		}
    82  	}
    83  	errs = append(errs, o.verifyAddons()...)
    84  	return errors.NewAggregate(errs)
    85  }
    86  
    87  func (o *StepValidateOptions) verifyJxVersion(minJxVersion string) error {
    88  	require, err := semver.Parse(minJxVersion)
    89  	if err != nil {
    90  		return fmt.Errorf("Given jx version '%s' is not a valid semantic version: %s", minJxVersion, err)
    91  	}
    92  	current, err := version.GetSemverVersion()
    93  	if err != nil {
    94  		return fmt.Errorf("Could not find current jx version: %s", err)
    95  	}
    96  	if require.GT(current) {
    97  		info := util.ColorInfo
    98  		log.Logger().Infof("\nThe current installation of the %s CLI is too old: %s.\nWe require an installation of %s or later.\n", info("jx"), info(current.String()), info(require.String()))
    99  		log.Logger().Infof(`To upgrade try these commands:
   100  * to upgrade the CLI locally: %s
   101  `, info("jx upgrade cli"))
   102  
   103  		return fmt.Errorf("The current jx install is too old: %s. We require: %s or later", current.String(), require.String())
   104  	}
   105  	return nil
   106  }
   107  
   108  func (o *StepValidateOptions) verifyAddons() []error {
   109  	errs := []error{}
   110  	config, fileName, err := config.LoadProjectConfig(o.Dir)
   111  	if err != nil {
   112  		errs = append(errs, fmt.Errorf("Failed to load project config: %s", err))
   113  		return errs
   114  	}
   115  	if len(config.Addons) == 0 {
   116  		return errs
   117  	}
   118  	_, ns, err := o.KubeClientAndNamespace()
   119  	if err != nil {
   120  		errs = append(errs, err)
   121  		return errs
   122  	}
   123  	releases, _, err := o.Helm().ListReleases(ns)
   124  	if err != nil {
   125  		errs = append(errs, fmt.Errorf("Failed to load addons statuses: %s", err))
   126  		return errs
   127  	}
   128  
   129  	for _, addonConfig := range config.Addons {
   130  		if addonConfig != nil {
   131  			err := o.verifyAddon(addonConfig, fileName, releases)
   132  			if err != nil {
   133  				errs = append(errs, err)
   134  			}
   135  		}
   136  	}
   137  	return errs
   138  }
   139  
   140  func (o *StepValidateOptions) verifyAddon(addonConfig *config.AddonConfig, fileName string,
   141  	releases map[string]helm.ReleaseSummary) error {
   142  	name := addonConfig.Name
   143  	if name == "" {
   144  		log.Logger().Warnf("Ignoring addon with no name inside the projects configuration file %s", fileName)
   145  		return nil
   146  	}
   147  	ch := kube.AddonCharts[name]
   148  	if ch == "" {
   149  		return fmt.Errorf("No such addon name %s in %s: %s", name, fileName, util.InvalidArg(name, util.SortedMapKeys(kube.AddonCharts)))
   150  	}
   151  	status := releases[name].Status
   152  	if status == "DEPLOYED" {
   153  		return nil
   154  	}
   155  	info := util.ColorInfo
   156  
   157  	log.Logger().Infof(`
   158  The Project Configuration %s requires the %s addon to be installed. To fix this please type:
   159  
   160      %s
   161  
   162  `, fileName, info(name), info(fmt.Sprintf("jx create addon %s", name)))
   163  
   164  	return fmt.Errorf("The addon %s is required. Please install with: jx create addon %s", name, name)
   165  }