github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/validator/distro_validator.go (about)

     1  package validator
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/evergreen-ci/evergreen"
     7  	"github.com/evergreen-ci/evergreen/cloud/providers"
     8  	"github.com/evergreen-ci/evergreen/cloud/providers/static"
     9  	"github.com/evergreen-ci/evergreen/model/distro"
    10  	"github.com/evergreen-ci/evergreen/util"
    11  	"github.com/mitchellh/mapstructure"
    12  )
    13  
    14  type distroValidator func(*distro.Distro, *evergreen.Settings) []ValidationError
    15  
    16  // Functions used to validate the syntax of a distro object.
    17  var distroSyntaxValidators = []distroValidator{
    18  	ensureHasRequiredFields,
    19  	ensureValidSSHOptions,
    20  	ensureValidExpansions,
    21  	ensureStaticHostsAreNotSpawnable,
    22  }
    23  
    24  // CheckDistro checks if the distro configuration syntax is valid. Returns
    25  // a slice of any validation errors found.
    26  func CheckDistro(d *distro.Distro, s *evergreen.Settings, newDistro bool) ([]ValidationError, error) {
    27  	validationErrs := []ValidationError{}
    28  	distroIds := []string{}
    29  	var err error
    30  	if newDistro {
    31  		// check ensureUniqueId separately and pass in distroIds list
    32  		distroIds, err = getDistroIds()
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  	}
    37  	validationErrs = append(validationErrs, ensureUniqueId(d, distroIds)...)
    38  
    39  	for _, v := range distroSyntaxValidators {
    40  		validationErrs = append(validationErrs, v(d, s)...)
    41  	}
    42  	return validationErrs, nil
    43  }
    44  
    45  // ensureStaticHostsAreNotSpawnable makes sure that any static distro cannot also be spawnable.
    46  func ensureStaticHostsAreNotSpawnable(d *distro.Distro, s *evergreen.Settings) []ValidationError {
    47  	if d.SpawnAllowed && d.Provider == static.ProviderName {
    48  		return []ValidationError{
    49  			{
    50  				Message: fmt.Sprintf("static distro %s cannot be spawnable", d.Id),
    51  				Level:   Error,
    52  			},
    53  		}
    54  	}
    55  
    56  	return nil
    57  }
    58  
    59  // ensureHasRequiredFields check that the distro configuration has all the required fields
    60  func ensureHasRequiredFields(d *distro.Distro, s *evergreen.Settings) []ValidationError {
    61  	errs := []ValidationError{}
    62  
    63  	if d.Id == "" {
    64  		errs = append(errs, ValidationError{
    65  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.IdKey),
    66  			Level:   Error,
    67  		})
    68  	}
    69  
    70  	if d.Arch == "" {
    71  		errs = append(errs, ValidationError{
    72  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.ArchKey),
    73  			Level:   Error,
    74  		})
    75  	}
    76  
    77  	if d.User == "" {
    78  		errs = append(errs, ValidationError{
    79  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.UserKey),
    80  			Level:   Error,
    81  		})
    82  	}
    83  
    84  	if d.WorkDir == "" {
    85  		errs = append(errs, ValidationError{
    86  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.WorkDirKey),
    87  			Level:   Error,
    88  		})
    89  	}
    90  
    91  	if d.SSHKey == "" && d.Provider != static.ProviderName {
    92  		errs = append(errs, ValidationError{
    93  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.SSHKeyKey),
    94  			Level:   Error,
    95  		})
    96  	}
    97  
    98  	if d.Provider == "" {
    99  		errs = append(errs, ValidationError{
   100  			Message: fmt.Sprintf("distro '%v' cannot be blank", distro.ProviderKey),
   101  			Level:   Error,
   102  		})
   103  		return errs
   104  	}
   105  
   106  	mgr, err := providers.GetCloudManager(d.Provider, s)
   107  	if err != nil {
   108  		errs = append(errs, ValidationError{
   109  			Message: err.Error(),
   110  			Level:   Error,
   111  		})
   112  		return errs
   113  	}
   114  
   115  	settings := mgr.GetSettings()
   116  
   117  	if err = mapstructure.Decode(d.ProviderSettings, settings); err != nil {
   118  		errs = append(errs, ValidationError{
   119  			Message: fmt.Sprintf("distro '%v' decode error: %v", distro.ProviderSettingsKey, err),
   120  			Level:   Error,
   121  		})
   122  		return errs
   123  	}
   124  
   125  	if err := settings.Validate(); err != nil {
   126  		errs = append(errs, ValidationError{Error, err.Error()})
   127  	}
   128  
   129  	return errs
   130  }
   131  
   132  // ensureUniqueId checks that the distro's id does not collide with an existing id.
   133  func ensureUniqueId(d *distro.Distro, distroIds []string) []ValidationError {
   134  	if util.SliceContains(distroIds, d.Id) {
   135  		return []ValidationError{{Error, fmt.Sprintf("distro '%v' uses an existing identifier", d.Id)}}
   136  	}
   137  	return nil
   138  }
   139  
   140  // ensureValidExpansions checks that no expansion option key is blank.
   141  func ensureValidExpansions(d *distro.Distro, s *evergreen.Settings) []ValidationError {
   142  	for _, e := range d.Expansions {
   143  		if e.Key == "" {
   144  			return []ValidationError{{Error, fmt.Sprintf("distro cannot be blank expansion key")}}
   145  		}
   146  	}
   147  	return nil
   148  }
   149  
   150  // ensureValidSSHOptions checks that no SSH option key is blank.
   151  func ensureValidSSHOptions(d *distro.Distro, s *evergreen.Settings) []ValidationError {
   152  	for _, o := range d.SSHOptions {
   153  		if o == "" {
   154  			return []ValidationError{{Error, fmt.Sprintf("distro cannot be blank SSH option")}}
   155  		}
   156  	}
   157  	return nil
   158  }