|
|
|
@ -7,7 +7,6 @@ import (
|
|
|
|
|
"path"
|
|
|
|
|
|
|
|
|
|
"coopcloud.tech/abra/pkg/config"
|
|
|
|
|
"coopcloud.tech/abra/pkg/recipe"
|
|
|
|
|
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
|
|
|
|
"coopcloud.tech/tagcmp"
|
|
|
|
|
"github.com/docker/distribution/reference"
|
|
|
|
@ -19,13 +18,13 @@ import (
|
|
|
|
|
var Warn = "warn"
|
|
|
|
|
var Critical = "critical"
|
|
|
|
|
|
|
|
|
|
type LintFunction func(recipe.Recipe) (bool, error)
|
|
|
|
|
type LintFunction func(recipePkg.Recipe) (bool, error)
|
|
|
|
|
|
|
|
|
|
// SkipFunction determines whether the LintFunction is run or not. It should
|
|
|
|
|
// not take the lint rule level into account because some rules are always an
|
|
|
|
|
// error but may depend on some additional context of the recipe configuration.
|
|
|
|
|
// This function aims to cover those additional cases.
|
|
|
|
|
type SkipFunction func(recipe.Recipe) (bool, error)
|
|
|
|
|
type SkipFunction func(recipePkg.Recipe) (bool, error)
|
|
|
|
|
|
|
|
|
|
// LintRule is a linting rule which helps a recipe maintainer avoid common
|
|
|
|
|
// problems in their recipe configurations. We aim to highlight things that
|
|
|
|
@ -42,7 +41,7 @@ type LintRule struct {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip implements the SkipFunction for the lint rule.
|
|
|
|
|
func (l LintRule) Skip(recipe recipe.Recipe) bool {
|
|
|
|
|
func (l LintRule) Skip(recipe recipePkg.Recipe) bool {
|
|
|
|
|
if l.SkipCondition != nil {
|
|
|
|
|
ok, err := l.SkipCondition(recipe)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -166,7 +165,7 @@ var LintRules = map[string][]LintRule{
|
|
|
|
|
// LintForErrors lints specifically for errors and not other levels. This is
|
|
|
|
|
// used in code paths such as "app deploy" to avoid nasty surprises but not for
|
|
|
|
|
// the typical linting commands, which do handle other levels.
|
|
|
|
|
func LintForErrors(recipe recipe.Recipe) error {
|
|
|
|
|
func LintForErrors(recipe recipePkg.Recipe) error {
|
|
|
|
|
logrus.Debugf("linting for critical errors in %s configs", recipe.Name)
|
|
|
|
|
|
|
|
|
|
for level := range LintRules {
|
|
|
|
@ -194,7 +193,7 @@ func LintForErrors(recipe recipe.Recipe) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintComposeVersion(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintComposeVersion(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
if recipe.Config.Version == "3.8" {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
@ -202,7 +201,7 @@ func LintComposeVersion(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintEnvConfigPresent(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintEnvConfigPresent(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
envSample := fmt.Sprintf("%s/%s/.env.sample", config.RECIPES_DIR, recipe.Name)
|
|
|
|
|
if _, err := os.Stat(envSample); !os.IsNotExist(err) {
|
|
|
|
|
return true, nil
|
|
|
|
@ -211,7 +210,7 @@ func LintEnvConfigPresent(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintAppService(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintAppService(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
if service.Name == "app" {
|
|
|
|
|
return true, nil
|
|
|
|
@ -225,7 +224,7 @@ func LintAppService(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
// confirms that there is no "DOMAIN=..." in the .env.sample configuration of
|
|
|
|
|
// the recipe. This typically means that no domain is required to deploy and
|
|
|
|
|
// therefore no matching traefik deploy label will be present.
|
|
|
|
|
func LintTraefikEnabledSkipCondition(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintTraefikEnabledSkipCondition(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
envSamplePath := path.Join(config.RECIPES_DIR, recipe.Name, ".env.sample")
|
|
|
|
|
sampleEnv, err := config.ReadEnv(envSamplePath)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -239,7 +238,7 @@ func LintTraefikEnabledSkipCondition(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintTraefikEnabled(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
for label := range service.Deploy.Labels {
|
|
|
|
|
if label == "traefik.enable" {
|
|
|
|
@ -253,7 +252,7 @@ func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintHealthchecks(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintHealthchecks(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
if service.HealthCheck == nil {
|
|
|
|
|
return false, nil
|
|
|
|
@ -263,7 +262,7 @@ func LintHealthchecks(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintAllImagesTagged(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
img, err := reference.ParseNormalizedNamed(service.Image)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -277,7 +276,7 @@ func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintNoUnstableTags(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
img, err := reference.ParseNormalizedNamed(service.Image)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -300,7 +299,7 @@ func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintSemverLikeTags(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
img, err := reference.ParseNormalizedNamed(service.Image)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -323,7 +322,7 @@ func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintImagePresent(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintImagePresent(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
if service.Image == "" {
|
|
|
|
|
return false, nil
|
|
|
|
@ -332,7 +331,7 @@ func LintImagePresent(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintHasPublishedVersion(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
catl, err := recipePkg.ReadRecipeCatalogue(false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logrus.Fatal(err)
|
|
|
|
@ -350,8 +349,8 @@ func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintMetadataFilledIn(r recipe.Recipe) (bool, error) {
|
|
|
|
|
features, category, err := recipe.GetRecipeFeaturesAndCategory(r.Name)
|
|
|
|
|
func LintMetadataFilledIn(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
features, category, err := recipePkg.GetRecipeFeaturesAndCategory(recipe.Name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
@ -371,7 +370,7 @@ func LintMetadataFilledIn(r recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintAbraShVendors(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintAbraShVendors(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
for _, service := range recipe.Config.Services {
|
|
|
|
|
if len(service.Configs) > 0 {
|
|
|
|
|
abraSh := path.Join(config.RECIPES_DIR, recipe.Name, "abra.sh")
|
|
|
|
@ -386,7 +385,7 @@ func LintAbraShVendors(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintHasRecipeRepo(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintHasRecipeRepo(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, recipe.Name)
|
|
|
|
|
|
|
|
|
|
res, err := http.Get(url)
|
|
|
|
@ -401,7 +400,7 @@ func LintHasRecipeRepo(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LintValidTags(recipe recipe.Recipe) (bool, error) {
|
|
|
|
|
func LintValidTags(recipe recipePkg.Recipe) (bool, error) {
|
|
|
|
|
recipeDir := path.Join(config.RECIPES_DIR, recipe.Name)
|
|
|
|
|
|
|
|
|
|
repo, err := git.PlainOpen(recipeDir)
|
|
|
|
|