From a5ef3344aa11194e50f7dc2d1d48272bca839f9b Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Thu, 25 Jul 2024 16:51:20 +1000 Subject: [PATCH 01/10] feat: add support to types for additional, consumes, provides volumes --- internal/servicetypes/basic.go | 7 +++++-- internal/servicetypes/cli.go | 7 +++++-- internal/servicetypes/elasticsearch.go | 1 + internal/servicetypes/mariadb.go | 1 + internal/servicetypes/mongodb.go | 1 + internal/servicetypes/nginx.go | 12 ++++++++---- internal/servicetypes/node.go | 7 +++++-- internal/servicetypes/opensearch.go | 1 + internal/servicetypes/postgres.go | 1 + internal/servicetypes/python.go | 7 +++++-- internal/servicetypes/rabbitmq.go | 1 + internal/servicetypes/redis.go | 5 +++-- internal/servicetypes/solr.go | 1 + internal/servicetypes/types.go | 21 ++++++++++++--------- internal/servicetypes/varnish.go | 5 +++-- internal/servicetypes/worker.go | 7 +++++-- 16 files changed, 58 insertions(+), 27 deletions(-) diff --git a/internal/servicetypes/basic.go b/internal/servicetypes/basic.go index f072ce6b..a2d2f6e7 100644 --- a/internal/servicetypes/basic.go +++ b/internal/servicetypes/basic.go @@ -25,6 +25,7 @@ var basic = ServiceType{ }, }, }, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "basic", Container: corev1.Container{ @@ -73,8 +74,10 @@ var basic = ServiceType{ // contains all the persistent type overrides that the basic service doesn't have var basicPersistent = ServiceType{ - Name: "basic-persistent", - Ports: basic.Ports, + Name: "basic-persistent", + Ports: basic.Ports, + ProvidesPersistentVolume: true, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: basic.PrimaryContainer.Name, Container: basic.PrimaryContainer.Container, diff --git a/internal/servicetypes/cli.go b/internal/servicetypes/cli.go index 00d2c871..8a9dd524 100644 --- a/internal/servicetypes/cli.go +++ b/internal/servicetypes/cli.go @@ -8,7 +8,8 @@ import ( // defines all the cli service type defaults var cli = ServiceType{ - Name: "cli", + Name: "cli", + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "cli", Volumes: []corev1.Volume{ @@ -58,7 +59,9 @@ var cli = ServiceType{ // contains all the persistent type overrides that the cli service doesn't have var cliPersistent = ServiceType{ - Name: "cli-persistent", + Name: "cli-persistent", + ConsumesPersistentVolume: true, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: cli.PrimaryContainer.Name, Container: cli.PrimaryContainer.Container, diff --git a/internal/servicetypes/elasticsearch.go b/internal/servicetypes/elasticsearch.go index 5707b466..e1ed4a72 100644 --- a/internal/servicetypes/elasticsearch.go +++ b/internal/servicetypes/elasticsearch.go @@ -27,6 +27,7 @@ var elasticsearch = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "elasticsearch", Container: corev1.Container{ diff --git a/internal/servicetypes/mariadb.go b/internal/servicetypes/mariadb.go index 23d5e5d0..d7034fb3 100644 --- a/internal/servicetypes/mariadb.go +++ b/internal/servicetypes/mariadb.go @@ -27,6 +27,7 @@ var mariadbSingle = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "mariadb-single", Container: corev1.Container{ diff --git a/internal/servicetypes/mongodb.go b/internal/servicetypes/mongodb.go index e9987fa6..2179903a 100644 --- a/internal/servicetypes/mongodb.go +++ b/internal/servicetypes/mongodb.go @@ -27,6 +27,7 @@ var mongodbSingle = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "mongodb-single", Container: corev1.Container{ diff --git a/internal/servicetypes/nginx.go b/internal/servicetypes/nginx.go index efdc82ef..1e42dbde 100644 --- a/internal/servicetypes/nginx.go +++ b/internal/servicetypes/nginx.go @@ -25,6 +25,7 @@ var nginx = ServiceType{ }, }, }, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "nginx", Container: corev1.Container{ @@ -75,8 +76,9 @@ var nginx = ServiceType{ } var nginxPHP = ServiceType{ - Name: "nginx-php", - Ports: nginx.Ports, + Name: "nginx-php", + Ports: nginx.Ports, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "nginx", Container: corev1.Container{ @@ -183,8 +185,10 @@ var nginxPHP = ServiceType{ } var nginxPHPPersistent = ServiceType{ - Name: "nginx-php-persistent", - Ports: nginx.Ports, + Name: "nginx-php-persistent", + Ports: nginx.Ports, + ProvidesPersistentVolume: true, + AllowAdditionalVolumes: true, Volumes: ServiceVolume{ PersistentVolumeSize: "5Gi", PersistentVolumeType: corev1.ReadWriteMany, diff --git a/internal/servicetypes/node.go b/internal/servicetypes/node.go index 5547afe8..c66a9c15 100644 --- a/internal/servicetypes/node.go +++ b/internal/servicetypes/node.go @@ -23,6 +23,7 @@ var node = ServiceType{ }, }, }, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "node", Container: corev1.Container{ @@ -70,8 +71,10 @@ var node = ServiceType{ } var nodePersistent = ServiceType{ - Name: "node-persistent", - Ports: node.Ports, + Name: "node-persistent", + Ports: node.Ports, + ProvidesPersistentVolume: true, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: node.PrimaryContainer.Name, Container: node.PrimaryContainer.Container, diff --git a/internal/servicetypes/opensearch.go b/internal/servicetypes/opensearch.go index eda243ea..b9871192 100644 --- a/internal/servicetypes/opensearch.go +++ b/internal/servicetypes/opensearch.go @@ -27,6 +27,7 @@ var opensearch = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "opensearch", Container: corev1.Container{ diff --git a/internal/servicetypes/postgres.go b/internal/servicetypes/postgres.go index 7972ce47..21a7265a 100644 --- a/internal/servicetypes/postgres.go +++ b/internal/servicetypes/postgres.go @@ -27,6 +27,7 @@ var postgresSingle = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "postgres-single", Container: corev1.Container{ diff --git a/internal/servicetypes/python.go b/internal/servicetypes/python.go index dbe57248..2eb1c847 100644 --- a/internal/servicetypes/python.go +++ b/internal/servicetypes/python.go @@ -23,6 +23,7 @@ var python = ServiceType{ }, }, }, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "python", Container: corev1.Container{ @@ -70,8 +71,10 @@ var python = ServiceType{ } var pythonPersistent = ServiceType{ - Name: "python-persistent", - Ports: python.Ports, + Name: "python-persistent", + Ports: python.Ports, + ProvidesPersistentVolume: true, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: python.PrimaryContainer.Name, Container: python.PrimaryContainer.Container, diff --git a/internal/servicetypes/rabbitmq.go b/internal/servicetypes/rabbitmq.go index e3820c65..0fd44cd7 100644 --- a/internal/servicetypes/rabbitmq.go +++ b/internal/servicetypes/rabbitmq.go @@ -36,6 +36,7 @@ var rabbitmq = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "rabbitmq", Container: corev1.Container{ diff --git a/internal/servicetypes/redis.go b/internal/servicetypes/redis.go index 31acbf4d..9bb01953 100644 --- a/internal/servicetypes/redis.go +++ b/internal/servicetypes/redis.go @@ -73,8 +73,9 @@ var redis = ServiceType{ } var redisPersistent = ServiceType{ - Name: "redis-persistent", - Ports: redis.Ports, + Name: "redis-persistent", + Ports: redis.Ports, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: redis.PrimaryContainer.Name, Container: redis.PrimaryContainer.Container, diff --git a/internal/servicetypes/solr.go b/internal/servicetypes/solr.go index 0857bc1a..7008f41f 100644 --- a/internal/servicetypes/solr.go +++ b/internal/servicetypes/solr.go @@ -26,6 +26,7 @@ var solr = ServiceType{ }, }, }, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: "solr", Container: corev1.Container{ diff --git a/internal/servicetypes/types.go b/internal/servicetypes/types.go index 27c43d84..fca42486 100644 --- a/internal/servicetypes/types.go +++ b/internal/servicetypes/types.go @@ -6,15 +6,18 @@ import ( ) type ServiceType struct { - Name string - Ports ServicePorts - Volumes ServiceVolume - Strategy appsv1.DeploymentStrategy - PrimaryContainer ServiceContainer - InitContainer ServiceContainer - SecondaryContainer ServiceContainer - PodSecurityContext ServicePodSecurityContext - EnableServiceLinks bool + Name string + Ports ServicePorts + Volumes ServiceVolume + Strategy appsv1.DeploymentStrategy + PrimaryContainer ServiceContainer + InitContainer ServiceContainer + SecondaryContainer ServiceContainer + PodSecurityContext ServicePodSecurityContext + EnableServiceLinks bool + ProvidesPersistentVolume bool + ConsumesPersistentVolume bool + AllowAdditionalVolumes bool } type ServicePodSecurityContext struct { diff --git a/internal/servicetypes/varnish.go b/internal/servicetypes/varnish.go index 78376cd2..ef77d2b5 100644 --- a/internal/servicetypes/varnish.go +++ b/internal/servicetypes/varnish.go @@ -86,8 +86,9 @@ var varnish = ServiceType{ } var varnishPersistent = ServiceType{ - Name: "varnish-persistent", - Ports: varnish.Ports, + Name: "varnish-persistent", + Ports: varnish.Ports, + ProvidesPersistentVolume: true, PrimaryContainer: ServiceContainer{ Name: varnish.PrimaryContainer.Name, Container: varnish.PrimaryContainer.Container, diff --git a/internal/servicetypes/worker.go b/internal/servicetypes/worker.go index 58bfb705..5e4fd768 100644 --- a/internal/servicetypes/worker.go +++ b/internal/servicetypes/worker.go @@ -7,7 +7,8 @@ import ( ) var worker = ServiceType{ - Name: "worker", + Name: "worker", + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: "worker", Volumes: []corev1.Volume{ @@ -56,7 +57,9 @@ var worker = ServiceType{ } var workerPersistent = ServiceType{ - Name: "worker-persistent", + Name: "worker-persistent", + ConsumesPersistentVolume: true, + AllowAdditionalVolumes: true, PrimaryContainer: ServiceContainer{ Name: worker.PrimaryContainer.Name, Container: worker.PrimaryContainer.Container, From 4acd2f181e2bb8fb8e5cf82a21586dd5cbee93f7 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 Jul 2024 09:23:18 +1000 Subject: [PATCH 02/10] feat: add initial support for additional volumes --- internal/generator/buildvalues.go | 12 + internal/generator/helpers_generator.go | 78 +++++ internal/generator/helpers_generator_test.go | 83 +++++ internal/generator/images.go | 135 ++++++++ internal/generator/services.go | 295 +++++------------ internal/generator/services_test.go | 163 ++++------ internal/generator/volumes.go | 117 +++++++ internal/lagoon/compose.go | 66 +++- internal/lagoon/compose_test.go | 188 +++++++++-- .../services/templates_deployment.go | 33 +- internal/templating/services/templates_pvc.go | 297 ++++++++++++------ 11 files changed, 1019 insertions(+), 448 deletions(-) create mode 100644 internal/generator/helpers_generator_test.go create mode 100644 internal/generator/images.go create mode 100644 internal/generator/volumes.go diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index f1494aef..12a48fab 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -81,6 +81,7 @@ type BuildValues struct { IgnoreImageCache bool `json:"ignoreImageCache"` SSHPrivateKey string `json:"sshPrivateKey"` ForcePullImages []string `json:"forcePullImages"` + Volumes []ComposeVolume `json:"volumes,omitempty" description:"stores any additional persistent volume definitions"` } type Resources struct { @@ -148,6 +149,16 @@ type ImageCacheBuildArguments struct { Name string `json:"name"` } +type ComposeVolume struct { + Name string `json:"name" description:"name is the name the volume, when creating in kubernetes will have a prefix"` + Size string `json:"size" description:"the size of the volume to request if the system enforces it"` +} + +type ServiceVolume struct { + ComposeVolume + Path string `json:"path" description:"path is where the volume will be mounted in a specific service"` +} + // ServiceValues is the values for a specific service used by a lagoon build type ServiceValues struct { Name string `json:"name"` // the actual compose service name @@ -185,6 +196,7 @@ type ServiceValues struct { BackupsEnabled bool `json:"backupsEnabled"` IsDBaaS bool `json:"isDBaaS"` IsSingle bool `json:"isSingle"` + AdditionalVolumes []ServiceVolume `json:"additonalVolumes,omitempty"` } type ImageBuild struct { diff --git a/internal/generator/helpers_generator.go b/internal/generator/helpers_generator.go index 5a71de65..0b42e892 100644 --- a/internal/generator/helpers_generator.go +++ b/internal/generator/helpers_generator.go @@ -1,9 +1,11 @@ package generator import ( + "encoding/json" "errors" "fmt" "os" + "regexp" "strings" "github.com/spf13/cobra" @@ -198,3 +200,79 @@ func ValidateResourceQuantity(s string) (err error) { resource.MustParse(s) return nil } + +func ValidateResourceSize(size string) (int64, error) { + volQ, err := resource.ParseQuantity(size) + if err != nil { + return 0, err + } + volS, _ := volQ.AsInt64() + return volS, nil +} + +// ContainsRegistry checks if a string slice contains a specific string regex match. +func ContainsRegistry(regex []ContainerRegistry, match string) bool { + for _, v := range regex { + m, _ := regexp.MatchString(v.URL, match) + if m { + return true + } + } + return false +} + +func checkDuplicateCronjobs(cronjobs []lagoon.Cronjob) error { + var unique []lagoon.Cronjob + var duplicates []lagoon.Cronjob + for _, v := range cronjobs { + skip := false + for _, u := range unique { + if v.Name == u.Name { + skip = true + duplicates = append(duplicates, v) + break + } + } + if !skip { + unique = append(unique, v) + } + } + var uniqueDuplicates []lagoon.Cronjob + for _, d := range duplicates { + for _, u := range unique { + if d.Name == u.Name { + uniqueDuplicates = append(uniqueDuplicates, u) + } + } + } + // join the two together + result := append(duplicates, uniqueDuplicates...) + if result != nil { + b, _ := json.Marshal(result) + return fmt.Errorf("duplicate named cronjobs detected: %v", string(b)) + } + return nil +} + +// getDBaasEnvironment will check the dbaas provider to see if an environment exists or not +func getDBaasEnvironment( + buildValues *BuildValues, + dbaasEnvironment *string, + lagoonOverrideName, + lagoonType string, +) (bool, error) { + if buildValues.DBaaSEnvironmentTypeOverrides != nil { + dbaasEnvironmentTypeSplit := strings.Split(buildValues.DBaaSEnvironmentTypeOverrides.Value, ",") + for _, sType := range dbaasEnvironmentTypeSplit { + sTypeSplit := strings.Split(sType, ":") + if sTypeSplit[0] == lagoonOverrideName { + *dbaasEnvironment = sTypeSplit[1] + } + } + } + exists, err := buildValues.DBaaSClient.CheckProvider(buildValues.DBaaSOperatorEndpoint, lagoonType, *dbaasEnvironment) + if err != nil { + return exists, fmt.Errorf("there was an error checking DBaaS endpoint %s: %v", buildValues.DBaaSOperatorEndpoint, err) + } + return exists, nil +} diff --git a/internal/generator/helpers_generator_test.go b/internal/generator/helpers_generator_test.go new file mode 100644 index 00000000..831eee67 --- /dev/null +++ b/internal/generator/helpers_generator_test.go @@ -0,0 +1,83 @@ +package generator + +import ( + "testing" + + "github.com/uselagoon/build-deploy-tool/internal/lagoon" +) + +func Test_checkDuplicateCronjobs(t *testing.T) { + type args struct { + cronjobs []lagoon.Cronjob + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1 - no duplicate cronjob names", + args: args{ + cronjobs: []lagoon.Cronjob{ + { + Name: "drush uli", + Command: "drush uli", + Service: "cli", + Schedule: "5 * * * *", + }, + { + Name: "drush cron", + Command: "drush cron", + Service: "cli", + Schedule: "5 * * * *", + }, + { + Name: "drush cr", + Command: "drush cr", + Service: "cli", + Schedule: "5 * * * *", + }, + }, + }, + }, + { + name: "test2 - duplicate cronjob names", + args: args{ + cronjobs: []lagoon.Cronjob{ + { + Name: "drush uli", + Command: "drush uli", + Service: "cli", + Schedule: "5 * * * *", + }, + { + Name: "drush cr", + Command: "drush cr", + Service: "cli", + Schedule: "5,25,2 4 * * *", + }, + { + Name: "drush cron", + Command: "drush cron", + Service: "cli", + Schedule: "5 * * * *", + }, + { + Name: "drush cr", + Command: "drush cr", + Service: "cli", + Schedule: "5 * * * *", + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := checkDuplicateCronjobs(tt.args.cronjobs); (err != nil) != tt.wantErr { + t.Errorf("checkDuplicateCronjobs() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/generator/images.go b/internal/generator/images.go new file mode 100644 index 00000000..b74b0ce2 --- /dev/null +++ b/internal/generator/images.go @@ -0,0 +1,135 @@ +package generator + +import ( + "errors" + "fmt" + "os" + "strings" + + composetypes "github.com/compose-spec/compose-go/types" + "github.com/drone/envsubst" + "github.com/uselagoon/build-deploy-tool/internal/lagoon" +) + +// generateImageBuild will work out all the build arguments and build options required for a specific service from docker compose +func generateImageBuild(buildValues BuildValues, composeServiceValues composetypes.ServiceConfig, composeService string) (ImageBuild, error) { + // create a holder for all the docker related information, if this is a pull through image or a build image + imageBuild := ImageBuild{} + // if this is not a promote environment, then attempt to work out the image build information that is required for the builder + if buildValues.BuildType != "promote" { + // handle extracting the built image name from the provided image references + if composeServiceValues.Build != nil { + // if a build spec is defined, consume it + // set the dockerfile + imageBuild.DockerFile = composeServiceValues.Build.Dockerfile + // set the context if found, otherwise set '.' + imageBuild.Context = func(s string) string { + if s == "" { + return "." + } + return s + }(composeServiceValues.Build.Context) + // if there is a build target defined, set that here too + imageBuild.Target = composeServiceValues.Build.Target + } + // if there is a dockerfile defined in the + if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Dockerfile != "" { + imageBuild.DockerFile = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Dockerfile + if imageBuild.Context == "" { + // if we get here, it means that a dockerfile override was defined in the .lagoon.yml file + // but there was no `build` spec defined in the docker-compose file, so this just sets the context to the default `.` + // in the same way the legacy script used to do it + imageBuild.Context = "." + } + } + if imageBuild.DockerFile == "" { + // no dockerfile determined, this must be a pull through image + if composeServiceValues.Image == "" { + return imageBuild, fmt.Errorf( + "defined Dockerfile or Image for service %s defined", composeService, + ) + } + // check docker-compose override image + pullImage := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.image") + // check lagoon.yml override image + if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Image != "" { + pullImage = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Image + } + if pullImage != "" { + // if an override image is provided, envsubst it + // not really sure why we do this, but legacy bash says `expand environment variables from ${OVERRIDE_IMAGE}` + // so there may be some undocumented functionality that allows people to use envvars in their image overrides? + evalImage, err := envsubst.EvalEnv(pullImage) + if err != nil { + return imageBuild, fmt.Errorf( + "error evaluating override image %s with envsubst", pullImage, + ) + } + // set the evalled image now + pullImage = evalImage + } else { + // else set the pullimage to whatever is defined in the docker-compose file otherwise + pullImage = composeServiceValues.Image + } + // if the image just is an image name (like "alpine") we prefix it with `libary/` as the imagecache does not understand + // the magic `alpine` image + if !strings.Contains(pullImage, "/") { + imageBuild.PullImage = fmt.Sprintf("library/%s", pullImage) + } else { + imageBuild.PullImage = pullImage + } + if !ContainsRegistry(buildValues.ContainerRegistry, pullImage) { + // if the image isn't in dockerhub, then the imagecache can't be used + if buildValues.ImageCache != "" && strings.Count(pullImage, "/") == 1 && !buildValues.IgnoreImageCache { + imageBuild.PullImage = fmt.Sprintf("%s%s", buildValues.ImageCache, imageBuild.PullImage) + } + } + } else { + // otherwise this must be an image build + // set temporary image to prevent clashes?? not sure this is even required, the temporary name is just as unique as the final image name eventually is + // so clashing would occur in both situations + imageBuild.TemporaryImage = fmt.Sprintf("%s-%s", buildValues.Namespace, composeService) //@TODO maybe get rid of this + if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Context != "" { + imageBuild.Context = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Context + } + // check the dockerfile exists + if _, err := os.Stat(fmt.Sprintf("%s/%s", imageBuild.Context, imageBuild.DockerFile)); errors.Is(err, os.ErrNotExist) { + return imageBuild, fmt.Errorf( + "defined Dockerfile %s for service %s not found", + fmt.Sprintf("%s/%s", imageBuild.Context, imageBuild.DockerFile), composeService, + ) + } + } + } + // since we know what the final build image will be, we can set it here, this is what all images will be built as during the build + // for `pullimages` they will get retagged as this imagename and pushed to the registry + imageBuild.BuildImage = fmt.Sprintf("%s/%s/%s/%s:%s", buildValues.ImageRegistry, buildValues.Project, buildValues.Environment, composeService, "latest") + if buildValues.BuildType == "promote" { + imageBuild.PromoteImage = fmt.Sprintf("%s/%s/%s/%s:%s", buildValues.ImageRegistry, buildValues.Project, buildValues.PromotionSourceEnvironment, composeService, "latest") + } + // populate the docker derived information here, this information will be used by the build and pushing scripts + return imageBuild, nil + // cService.ImageBuild = &imageBuild + + // // // cService.ImageName = buildValues.ImageReferences[composeService] + // unfortunately, this uses a specific hash which is computed "AFTER" the image builds take place, so this + // `ImageName` is an unreliable field in respect to consuming data from generator during phases of a build + // it would be great if there was a way to precalculate this, but there are other issues that could pop up + // using the buildname as the tag could be one way, but this could result in container restarts even if the image hash does not change :( + // for now `ImageName` is disabled, and ImageReferences must be provided whenever templating occurs that needs an image reference + // luckily the templating engine will reproduce identical data when it is run as to when the image build data is populated as above + // so when the templating is done in a later step, at least it can be informed of the resulting image references by way of the + // images flag that is passed to it + /* + // example in code + ImageReferences: map[string]string{ + "myservice": "harbor.example.com/example-project/environment-name/myservice@sha256:abcdefg", + }, + + // in bash, the images are provided from yaml as base64 encoded data to retain formatting + // the command `lagoon-services` decodes and unmarshals it + build-deploy-tool template lagoon-services \ + --saved-templates-path ${LAGOON_SERVICES_YAML_FOLDER} \ + --images $(yq3 r -j /kubectl-build-deploy/images.yaml | jq -M -c | base64 -w0) + */ +} diff --git a/internal/generator/services.go b/internal/generator/services.go index 33d0ef0f..58a3964c 100644 --- a/internal/generator/services.go +++ b/internal/generator/services.go @@ -1,18 +1,15 @@ package generator import ( - "encoding/json" - "errors" "fmt" - "github.com/distribution/reference" - "os" "reflect" "regexp" "strconv" "strings" + "github.com/distribution/reference" + composetypes "github.com/compose-spec/compose-go/types" - "github.com/drone/envsubst" "github.com/uselagoon/build-deploy-tool/internal/helpers" "github.com/uselagoon/build-deploy-tool/internal/lagoon" "github.com/uselagoon/build-deploy-tool/internal/servicetypes" @@ -80,6 +77,11 @@ var typesWithBackups = []string{ "mongodb-single", } +// this is commented out as this is not enforced currently, but some enforcement should be implemented +// var ( +// maxServices int = 10 +// ) + // generateServicesFromDockerCompose unmarshals the docker-compose file and processes the services using composeToServiceValues func generateServicesFromDockerCompose( buildValues *BuildValues, @@ -95,7 +97,18 @@ func generateServicesFromDockerCompose( buildValues.Services = []ServiceValues{} // unmarshal the docker-compose.yml file - lCompose, lComposeOrder, err := lagoon.UnmarshaDockerComposeYAML(buildValues.LagoonYAML.DockerComposeYAML, ignoreNonStringKeyErrors, ignoreMissingEnvFiles, composeVars) + lCompose, lComposeOrder, lComposeVolumes, err := lagoon.UnmarshaDockerComposeYAML( + buildValues.LagoonYAML.DockerComposeYAML, + ignoreNonStringKeyErrors, + ignoreMissingEnvFiles, + composeVars, + ) + if err != nil { + return err + } + + // convert docker-compose volumes to buildvolumes, + err = convertVolumes(buildValues, lCompose, lComposeVolumes, debug) if err != nil { return err } @@ -109,10 +122,17 @@ func generateServicesFromDockerCompose( if err != nil { return err } - if cService.BackupsEnabled { - buildValues.BackupsEnabled = true + if cService != nil { + if cService.BackupsEnabled { + buildValues.BackupsEnabled = true + } + buildValues.Services = append(buildValues.Services, *cService) } - buildValues.Services = append(buildValues.Services, cService) + // to prevent too many services from being provisioned, some sort of limit should probably be imposed + // this is commented out as this is not enforced currently, but some enforcement should be implemented + // if len(buildValues.Services) > maxServices { + // return fmt.Errorf("unable to provision more than %d services for this environment, if you need more please contact your lagoon administrator", maxServices) + // } } } } @@ -127,15 +147,18 @@ func composeToServiceValues( composeService string, composeServiceValues composetypes.ServiceConfig, debug bool, -) (ServiceValues, error) { +) (*ServiceValues, error) { lagoonType := "" // if there are no labels, then this is probably not going to end up in Lagoon // the lagoonType check will skip to the end and return an empty service definition if composeServiceValues.Labels != nil { - lagoonType = lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.type") + lagoonType = lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.type") } if lagoonType == "" { - return ServiceValues{}, fmt.Errorf("no lagoon.type has been set for service %s. If a Lagoon service is not required, please set the lagoon.type to 'none' for this service in docker-compose.yaml. See the Lagoon documentation for supported service types", composeService) + return nil, fmt.Errorf( + "no lagoon.type has been set for service %s. If a Lagoon service is not required, please set the lagoon.type to 'none' for this service in docker-compose.yaml. See the Lagoon documentation for supported service types", + composeService, + ) } else { // if the lagoontype is populated, even none is valid as there may be a servicetype override in an environment variable autogenEnabled := true @@ -182,7 +205,7 @@ func composeToServiceValues( lagoonType = value } // check if the service has a specific override - serviceAutogenerated := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.autogeneratedroute") + serviceAutogenerated := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.autogeneratedroute") if serviceAutogenerated != "" { if reflect.TypeOf(serviceAutogenerated).Kind() == reflect.String { vBool, err := strconv.ParseBool(serviceAutogenerated) @@ -192,7 +215,7 @@ func composeToServiceValues( } } // check if the service has a tls-acme specific override - serviceAutogeneratedTLSAcme := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.autogeneratedroute.tls-acme") + serviceAutogeneratedTLSAcme := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.autogeneratedroute.tls-acme") if serviceAutogeneratedTLSAcme != "" { if reflect.TypeOf(serviceAutogeneratedTLSAcme).Kind() == reflect.String { vBool, err := strconv.ParseBool(serviceAutogeneratedTLSAcme) @@ -202,13 +225,16 @@ func composeToServiceValues( } } // check if the service has a deployment servicetype override - serviceDeploymentServiceType := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.deployment.servicetype") + // @TODO: this was previously used to detect which image to use for a linked service, but the logic for that has changed now + // this isn't required anymore. leaving the check here for now but `serviceDeploymentServiceType` is currently unused + // REF: https://github.com/uselagoon/build-deploy-tool/blob/997483b59ac7c055a07f04f579b91ccd7e4fb4a2/legacy/build-deploy-docker-compose.sh#L439-L444 + serviceDeploymentServiceType := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.deployment.servicetype") if serviceDeploymentServiceType == "" { serviceDeploymentServiceType = composeService } // if there is a `lagoon.name` label on this service, this should be used as an override name - lagoonOverrideName := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.name") + lagoonOverrideName := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.name") if lagoonOverrideName != "" { // if there is an override name, check all other services already existing for _, service := range buildValues.Services { @@ -224,24 +250,39 @@ func composeToServiceValues( } // check if the service has any persistent labels, this is the path that the volume will be mounted to - servicePersistentPath := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.persistent") + servicePersistentPath := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.persistent") if servicePersistentPath == "" { // if there is no persistent path, check if the service type has a default path if val, ok := servicetypes.ServiceTypes[lagoonType]; ok { servicePersistentPath = val.Volumes.PersistentVolumePath + // check if the service type provides or consumes a default persistent volume + if (val.ProvidesPersistentVolume || val.ConsumesPersistentVolume) && servicePersistentPath == "" { + return nil, fmt.Errorf("label lagoon.persistent not defined for service %s, no valid mount path was found", composeService) + } } } - servicePersistentName := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.persistent.name") + servicePersistentName := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.persistent.name") if servicePersistentName == "" && servicePersistentPath != "" { // if there is a persistent path defined, then set the persistent name to be the compose service if no persistent name is provided // persistent name is used by joined services like nginx/php or cli or worker pods to mount another service volume servicePersistentName = lagoonOverrideName } - servicePersistentSize := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.persistent.size") + servicePersistentSize := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.persistent.size") if servicePersistentSize == "" { // if there is no persistent size, check if the service type has a default size allocated if val, ok := servicetypes.ServiceTypes[lagoonType]; ok { servicePersistentSize = val.Volumes.PersistentVolumeSize + // check if the service type provides persistent volume, and that a size was detected + if val.ProvidesPersistentVolume && servicePersistentSize == "" { + return nil, fmt.Errorf("label lagoon.persistent.size not defined for service %s, no valid size was found", composeService) + } + } + } + if servicePersistentSize != "" { + // check the provided size is a valid resource size for kubernetes + _, err := ValidateResourceSize(servicePersistentSize) + if err != nil { + return nil, fmt.Errorf("provided persistent volume size for %s is not valid: %v", servicePersistentName, err) } } @@ -274,7 +315,7 @@ func composeToServiceValues( // if there are no overrides, and the type is none, then abort here, no need to proceed calculating the type if lagoonType == "none" { - return ServiceValues{}, nil + return nil, nil } // anything after this point is where heavy processing is done as the service type has now been determined by this stage @@ -289,7 +330,7 @@ func composeToServiceValues( if err != nil { // @TODO eventually this error should be handled and fail a build, with a flag to override https://github.com/uselagoon/build-deploy-tool/issues/56 // if !buildValues.DBaaSFallbackSingle { - // return ServiceValues{}, fmt.Errorf("unable to check the DBaaS endpoint %s: %v", buildValues.DBaaSOperatorEndpoint, err) + // return nil, fmt.Errorf("unable to check the DBaaS endpoint %s: %v", buildValues.DBaaSOperatorEndpoint, err) // } if debug { fmt.Printf("Unable to check the DBaaS endpoint %s, falling back to %s-single: %v\n", buildValues.DBaaSOperatorEndpoint, lagoonType, err) @@ -301,7 +342,7 @@ func composeToServiceValues( lagoonType = fmt.Sprintf("%s-single", lagoonType) } else { // if there is a `lagoon.%s-dbaas.environment` label on this service, this should be used as an the environment type for the dbaas - dbaasLabelOverride := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, fmt.Sprintf("lagoon.%s-dbaas.environment", lagoonType)) + dbaasLabelOverride := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, fmt.Sprintf("lagoon.%s-dbaas.environment", lagoonType)) if dbaasLabelOverride != "" { dbaasEnvironment = dbaasLabelOverride } @@ -318,7 +359,7 @@ func composeToServiceValues( if err != nil { // @TODO eventually this error should be handled and fail a build, with a flag to override https://github.com/uselagoon/build-deploy-tool/issues/56 // if !buildValues.DBaaSFallbackSingle { - // return ServiceValues{}, err + // return nil, err // } if debug { fmt.Printf( @@ -340,6 +381,13 @@ func composeToServiceValues( } } + // calculate if this service needs any additional volumes attached from the calculated build volumes + // additional volumes can only be attached to certain + serviceVolumes, err := calculateServiceVolumes(buildValues.Volumes, lagoonType, servicePersistentName, composeServiceValues.Labels) + if err != nil { + return nil, err + } + // start spot instance handling useSpot := false forceSpot := false @@ -405,7 +453,7 @@ func composeToServiceValues( nativecronjobs := []lagoon.Cronjob{} // check if there are any duplicate named cronjobs if err := checkDuplicateCronjobs(buildValues.LagoonYAML.Environments[buildValues.Branch].Cronjobs); err != nil { - return ServiceValues{}, err + return nil, err } if !buildValues.CronjobsDisabled { for _, cronjob := range buildValues.LagoonYAML.Environments[buildValues.Branch].Cronjobs { @@ -414,11 +462,11 @@ func composeToServiceValues( var err error inpod, err := helpers.IsInPodCronjob(cronjob.Schedule) if err != nil { - return ServiceValues{}, fmt.Errorf("unable to validate crontab for cronjob %s: %v", cronjob.Name, err) + return nil, fmt.Errorf("unable to validate crontab for cronjob %s: %v", cronjob.Name, err) } cronjob.Schedule, err = helpers.ConvertCrontab(buildValues.Namespace, cronjob.Schedule) if err != nil { - return ServiceValues{}, fmt.Errorf("unable to convert crontab for cronjob %s: %v", cronjob.Name, err) + return nil, fmt.Errorf("unable to convert crontab for cronjob %s: %v", cronjob.Name, err) } // if the cronjob is inpod, or the cronjob has an inpod flag override if inpod || (cronjob.InPod != nil && *cronjob.InPod) { @@ -451,7 +499,7 @@ func composeToServiceValues( } // create the service values - cService := ServiceValues{ + cService := &ServiceValues{ Name: composeService, OverrideName: lagoonOverrideName, Type: lagoonType, @@ -473,144 +521,32 @@ func composeToServiceValues( IsDBaaS: svcIsDBaaS, IsSingle: svcIsSingle, BackupsEnabled: backupsEnabled, + AdditionalVolumes: serviceVolumes, } // work out the images here and the associated dockerfile and contexts // if the type is in the ignored image types, then there is no image to build or pull for this service (eg, its a dbaas service) if !helpers.Contains(ignoredImageTypes, lagoonType) { - // create a holder for all the docker related information, if this is a pull through image or a build image - imageBuild := ImageBuild{} - // if this is not a promote environment, then attempt to work out the image build information that is required for the builder - if buildValues.BuildType != "promote" { - // handle extracting the built image name from the provided image references - if composeServiceValues.Build != nil { - // if a build spec is defined, consume it - // set the dockerfile - imageBuild.DockerFile = composeServiceValues.Build.Dockerfile - // set the context if found, otherwise set '.' - imageBuild.Context = func(s string) string { - if s == "" { - return "." - } - return s - }(composeServiceValues.Build.Context) - // if there is a build target defined, set that here too - imageBuild.Target = composeServiceValues.Build.Target - } - // if there is a dockerfile defined in the - if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Dockerfile != "" { - imageBuild.DockerFile = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Dockerfile - if imageBuild.Context == "" { - // if we get here, it means that a dockerfile override was defined in the .lagoon.yml file - // but there was no `build` spec defined in the docker-compose file, so this just sets the context to the default `.` - // in the same way the legacy script used to do it - imageBuild.Context = "." - } - } - if imageBuild.DockerFile == "" { - // no dockerfile determined, this must be a pull through image - if composeServiceValues.Image == "" { - return ServiceValues{}, fmt.Errorf( - "defined Dockerfile or Image for service %s defined", composeService, - ) - } - // check docker-compose override image - pullImage := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.image") - // check lagoon.yml override image - if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Image != "" { - pullImage = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Image - } - if pullImage != "" { - // if an override image is provided, envsubst it - // not really sure why we do this, but legacy bash says `expand environment variables from ${OVERRIDE_IMAGE}` - // so there may be some undocumented functionality that allows people to use envvars in their image overrides? - evalImage, err := envsubst.EvalEnv(pullImage) - if err != nil { - return ServiceValues{}, fmt.Errorf( - "error evaluating override image %s with envsubst", pullImage, - ) - } - // set the evalled image now - pullImage = evalImage - } else { - // else set the pullimage to whatever is defined in the docker-compose file otherwise - pullImage = composeServiceValues.Image - } - // if the image just is an image name (like "alpine") we prefix it with `libary/` as the imagecache does not understand - // the magic `alpine` image - if !strings.Contains(pullImage, "/") { - imageBuild.PullImage = fmt.Sprintf("library/%s", pullImage) - } else { - imageBuild.PullImage = pullImage - } - if !ContainsRegistry(buildValues.ContainerRegistry, pullImage) { - // if the image isn't in dockerhub, then the imagecache can't be used - if buildValues.ImageCache != "" && strings.Count(pullImage, "/") == 1 && !buildValues.IgnoreImageCache { - imageBuild.PullImage = fmt.Sprintf("%s%s", buildValues.ImageCache, imageBuild.PullImage) - } - } - } else { - // otherwise this must be an image build - // set temporary image to prevent clashes?? not sure this is even required, the temporary name is just as unique as the final image name eventually is - // so clashing would occur in both situations - imageBuild.TemporaryImage = fmt.Sprintf("%s-%s", buildValues.Namespace, composeService) //@TODO maybe get rid of this - if buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Context != "" { - imageBuild.Context = buildValues.LagoonYAML.Environments[buildValues.Environment].Overrides[composeService].Build.Context - } - // check the dockerfile exists - if _, err := os.Stat(fmt.Sprintf("%s/%s", imageBuild.Context, imageBuild.DockerFile)); errors.Is(err, os.ErrNotExist) { - return ServiceValues{}, fmt.Errorf( - "defined Dockerfile %s for service %s not found", - fmt.Sprintf("%s/%s", imageBuild.Context, imageBuild.DockerFile), composeService, - ) - } - } - } - // since we know what the final build image will be, we can set it here, this is what all images will be built as during the build - // for `pullimages` they will get retagged as this imagename and pushed to the registry - imageBuild.BuildImage = fmt.Sprintf("%s/%s/%s/%s:%s", buildValues.ImageRegistry, buildValues.Project, buildValues.Environment, composeService, "latest") - if buildValues.BuildType == "promote" { - imageBuild.PromoteImage = fmt.Sprintf("%s/%s/%s/%s:%s", buildValues.ImageRegistry, buildValues.Project, buildValues.PromotionSourceEnvironment, composeService, "latest") + imageBuild, err := generateImageBuild(*buildValues, composeServiceValues, composeService) + if err != nil { + return nil, err } - // populate the docker derived information here, this information will be used by the build and pushing scripts cService.ImageBuild = &imageBuild - - // // // cService.ImageName = buildValues.ImageReferences[composeService] - // unfortunately, this uses a specific hash which is computed "AFTER" the image builds take place, so this - // `ImageName` is an unreliable field in respect to consuming data from generator during phases of a build - // it would be great if there was a way to precalculate this, but there are other issues that could pop up - // using the buildname as the tag could be one way, but this could result in container restarts even if the image hash does not change :( - // for now `ImageName` is disabled, and ImageReferences must be provided whenever templating occurs that needs an image reference - // luckily the templating engine will reproduce identical data when it is run as to when the image build data is populated as above - // so when the templating is done in a later step, at least it can be informed of the resulting image references by way of the - // images flag that is passed to it - /* - // example in code - ImageReferences: map[string]string{ - "myservice": "harbor.example.com/example-project/environment-name/myservice@sha256:abcdefg", - }, - - // in bash, the images are provided from yaml as base64 encoded data to retain formatting - // the command `lagoon-services` decodes and unmarshals it - build-deploy-tool template lagoon-services \ - --saved-templates-path ${LAGOON_SERVICES_YAML_FOLDER} \ - --images $(yq3 r -j /kubectl-build-deploy/images.yaml | jq -M -c | base64 -w0) - */ } // check if the service has a service port override (this only applies to basic(-persistent)) - servicePortOverride := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.service.port") + servicePortOverride := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.service.port") if servicePortOverride != "" { sPort, err := strconv.Atoi(servicePortOverride) if err != nil { - return ServiceValues{}, fmt.Errorf( + return nil, fmt.Errorf( "the provided service port %s for service %s is not a valid integer: %v", servicePortOverride, composeService, err, ) } cService.ServicePort = int32(sPort) } - useComposeServices := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.service.usecomposeports") + useComposeServices := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.service.usecomposeports") if useComposeServices == "true" { for _, compPort := range composeServiceValues.Ports { newService := AdditionalServicePort{ @@ -623,70 +559,3 @@ func composeToServiceValues( return cService, nil } } - -// getDBaasEnvironment will check the dbaas provider to see if an environment exists or not -func getDBaasEnvironment( - buildValues *BuildValues, - dbaasEnvironment *string, - lagoonOverrideName, - lagoonType string, -) (bool, error) { - if buildValues.DBaaSEnvironmentTypeOverrides != nil { - dbaasEnvironmentTypeSplit := strings.Split(buildValues.DBaaSEnvironmentTypeOverrides.Value, ",") - for _, sType := range dbaasEnvironmentTypeSplit { - sTypeSplit := strings.Split(sType, ":") - if sTypeSplit[0] == lagoonOverrideName { - *dbaasEnvironment = sTypeSplit[1] - } - } - } - exists, err := buildValues.DBaaSClient.CheckProvider(buildValues.DBaaSOperatorEndpoint, lagoonType, *dbaasEnvironment) - if err != nil { - return exists, fmt.Errorf("there was an error checking DBaaS endpoint %s: %v", buildValues.DBaaSOperatorEndpoint, err) - } - return exists, nil -} - -func checkDuplicateCronjobs(cronjobs []lagoon.Cronjob) error { - var unique []lagoon.Cronjob - var duplicates []lagoon.Cronjob - for _, v := range cronjobs { - skip := false - for _, u := range unique { - if v.Name == u.Name { - skip = true - duplicates = append(duplicates, v) - break - } - } - if !skip { - unique = append(unique, v) - } - } - var uniqueDuplicates []lagoon.Cronjob - for _, d := range duplicates { - for _, u := range unique { - if d.Name == u.Name { - uniqueDuplicates = append(uniqueDuplicates, u) - } - } - } - // join the two together - result := append(duplicates, uniqueDuplicates...) - if result != nil { - b, _ := json.Marshal(result) - return fmt.Errorf("duplicate named cronjobs detected: %v", string(b)) - } - return nil -} - -// ContainsR checks if a string slice contains a specific string regex match. -func ContainsRegistry(regex []ContainerRegistry, match string) bool { - for _, v := range regex { - m, _ := regexp.MatchString(v.URL, match) - if m { - return true - } - } - return false -} diff --git a/internal/generator/services_test.go b/internal/generator/services_test.go index 048c557c..19c03796 100644 --- a/internal/generator/services_test.go +++ b/internal/generator/services_test.go @@ -20,7 +20,7 @@ func Test_composeToServiceValues(t *testing.T) { tests := []struct { name string args args - want ServiceValues + want *ServiceValues wantErr bool }{ { @@ -51,7 +51,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx", @@ -96,7 +96,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx-php", Type: "nginx", @@ -113,7 +113,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, { - name: "test3 - lagoon.yml type override", + name: "test3a - lagoon.yml type override", args: args{ buildValues: &BuildValues{ Namespace: "example-project-main", @@ -136,7 +136,8 @@ func Test_composeToServiceValues(t *testing.T) { composeService: "nginx", composeServiceValues: composetypes.ServiceConfig{ Labels: composetypes.Labels{ - "lagoon.type": "nginx-php", + "lagoon.type": "nginx-php", + "lagoon.persistent": "/app/docroot/sites/default/files/", }, Build: &composetypes.BuildConfig{ Context: ".", @@ -144,7 +145,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx-php-persistent", @@ -159,8 +160,44 @@ func Test_composeToServiceValues(t *testing.T) { DockerFile: "../testdata/basic/docker/basic.dockerfile", BuildImage: "harbor.example/example-project/main/nginx:latest", }, - BackupsEnabled: true, + PersistentVolumeName: "nginx", + PersistentVolumePath: "/app/docroot/sites/default/files/", + BackupsEnabled: true, + }, + }, + { + name: "test3b - lagoon.yml type override with missing labels should get error", + args: args{ + buildValues: &BuildValues{ + Namespace: "example-project-main", + Project: "example-project", + ImageRegistry: "harbor.example", + Environment: "main", + Branch: "main", + BuildType: "branch", + ServiceTypeOverrides: &lagoon.EnvironmentVariable{}, + LagoonYAML: lagoon.YAML{ + Environments: lagoon.Environments{ + "main": lagoon.Environment{ + Types: map[string]string{ + "nginx": "nginx-php-persistent", + }, + }, + }, + }, + }, + composeService: "nginx", + composeServiceValues: composetypes.ServiceConfig{ + Labels: composetypes.Labels{ + "lagoon.type": "nginx-php", + }, + Build: &composetypes.BuildConfig{ + Context: ".", + Dockerfile: "../testdata/basic/docker/basic.dockerfile", + }, + }, }, + wantErr: true, }, { name: "test4 - variable servicetypes type override", @@ -193,7 +230,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx-php-persistent", @@ -240,7 +277,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx", @@ -291,7 +328,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx-php", @@ -343,7 +380,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx-php", @@ -387,7 +424,7 @@ func Test_composeToServiceValues(t *testing.T) { composeService: "nginx", composeServiceValues: composetypes.ServiceConfig{}, }, - want: ServiceValues{}, + want: nil, wantErr: true, }, { @@ -426,7 +463,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{}, + want: nil, }, { name: "test10 - mariadb to mariadb-dbaas", @@ -462,7 +499,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-mariadb:latest", }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "mariadb", OverrideName: "mariadb", Type: "mariadb-dbaas", @@ -514,7 +551,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-mariadb:latest", }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "mariadb", OverrideName: "mariadb", Type: "mariadb-single", @@ -565,7 +602,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-postgres:latest", }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "postgres", OverrideName: "postgres", Type: "postgres-dbaas", @@ -606,7 +643,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "python-ckan", OverrideName: "python-ckan", Type: "python", @@ -659,7 +696,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx", @@ -776,7 +813,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "service-a", OverrideName: "service-a", Type: "basic", @@ -851,7 +888,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "cli", OverrideName: "cli", Type: "cli", @@ -931,7 +968,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "cli", OverrideName: "cli", Type: "cli", @@ -976,7 +1013,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{}, + want: nil, wantErr: true, }, { @@ -1055,7 +1092,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-redis:latest", }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "redis", OverrideName: "redis", Type: "redis", @@ -1103,7 +1140,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx", @@ -1150,7 +1187,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-redis:latest", //intentionally wrong, override by lagoon.yml }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "redis", OverrideName: "redis", Type: "redis", @@ -1221,79 +1258,3 @@ func Test_composeToServiceValues(t *testing.T) { }) } } - -func Test_checkDuplicateCronjobs(t *testing.T) { - type args struct { - cronjobs []lagoon.Cronjob - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "test1 - no duplicate cronjob names", - args: args{ - cronjobs: []lagoon.Cronjob{ - { - Name: "drush uli", - Command: "drush uli", - Service: "cli", - Schedule: "5 * * * *", - }, - { - Name: "drush cron", - Command: "drush cron", - Service: "cli", - Schedule: "5 * * * *", - }, - { - Name: "drush cr", - Command: "drush cr", - Service: "cli", - Schedule: "5 * * * *", - }, - }, - }, - }, - { - name: "test2 - duplicate cronjob names", - args: args{ - cronjobs: []lagoon.Cronjob{ - { - Name: "drush uli", - Command: "drush uli", - Service: "cli", - Schedule: "5 * * * *", - }, - { - Name: "drush cr", - Command: "drush cr", - Service: "cli", - Schedule: "5,25,2 4 * * *", - }, - { - Name: "drush cron", - Command: "drush cron", - Service: "cli", - Schedule: "5 * * * *", - }, - { - Name: "drush cr", - Command: "drush cr", - Service: "cli", - Schedule: "5 * * * *", - }, - }, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := checkDuplicateCronjobs(tt.args.cronjobs); (err != nil) != tt.wantErr { - t.Errorf("checkDuplicateCronjobs() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/internal/generator/volumes.go b/internal/generator/volumes.go new file mode 100644 index 00000000..43f9dd5d --- /dev/null +++ b/internal/generator/volumes.go @@ -0,0 +1,117 @@ +package generator + +import ( + "fmt" + + composetypes "github.com/compose-spec/compose-go/types" + "github.com/uselagoon/build-deploy-tool/internal/lagoon" + "github.com/uselagoon/build-deploy-tool/internal/servicetypes" +) + +var ( + maxAdditionalVolumes int = 6 + defaultAdditionalVolumeSize string = "5Gi" + maxAdditionalVolumeSize string = "4Ti" +) + +// convertVolumes handles converting docker compose volumes into lagoon volumes and adds them to build values +func convertVolumes(buildValues *BuildValues, lCompose *composetypes.Project, lComposeVolumes []lagoon.OriginalVolumeOrder, debug bool) error { + // convert docker-compose volumes to buildvolumes, + // range over the volumes and add them to build values + for _, vol := range lComposeVolumes { + for _, composeVolumeValues := range lCompose.Volumes { + // check that the volumename from the ordered volumes matches (with the composestack name prefix) + if lagoon.GetComposeVolumeName(lCompose.Name, vol.Name) == composeVolumeValues.Name { + // if so, check that the volume returns values correctly + cVolume, err := composeToVolumeValues(lCompose.Name, composeVolumeValues, debug) + if err != nil { + return err + } + if cVolume != nil { + buildValues.Volumes = append(buildValues.Volumes, *cVolume) + } + // to prevent too many volumes from being provisioned, some sort of limit should probably be imposed + // harcdoded now to maxAdditionalVolumes, but could be configurable + if len(buildValues.Volumes) > maxAdditionalVolumes { + return fmt.Errorf("unable to provision more than %d volumes for this environment, if you need more please contact your lagoon administrator", maxAdditionalVolumes) + } + } + } + } + return nil +} + +// composeToVolumeValues handles converting a docker compose volume and the labels into a lagoon volume +func composeToVolumeValues( + composeName string, + composeVolumeValues composetypes.VolumeConfig, + debug bool, +) (*ComposeVolume, error) { + // if there are no labels, then this is probably not going to end up in Lagoon + // the lagoonType check will skip to the end and return an empty service definition + if composeVolumeValues.Labels != nil { + volumeType := lagoon.CheckDockerComposeLagoonLabel(composeVolumeValues.Labels, "lagoon.type") + if volumeType == "" || volumeType == "none" { + return nil, nil + } else if volumeType == "persistent" { + originalVolumeName := lagoon.GetVolumeNameFromComposeName(composeName, composeVolumeValues.Name) + lagoonVolumeName := lagoon.GetLagoonVolumeName(originalVolumeName) + volumeSize := lagoon.CheckDockerComposeLagoonLabel(composeVolumeValues.Labels, "lagoon.persistent.size") + if volumeSize == "" { + volumeSize = defaultAdditionalVolumeSize + } + // check the provided size is a valid resource size for kubernetes + volS, err := ValidateResourceSize(volumeSize) + if err != nil { + return nil, fmt.Errorf("provided volume size for %s is not valid: %v", originalVolumeName, err) + } + // reject volumes over maxAdditionalVolumeSize for now + maxSize, _ := ValidateResourceSize(maxAdditionalVolumeSize) + if volS > maxSize { + return nil, fmt.Errorf( + "provided volume %s with size %s exceeds limit, if you need larger volumes please contact your Lagoon administrator", + originalVolumeName, + volumeSize, + ) + } + // create the volume values + cVolume := &ComposeVolume{ + // use the lagoonVolumename which contains the `custom-` prefix + Name: lagoonVolumeName, + Size: volumeSize, + } + return cVolume, nil + } + } + return nil, nil +} + +// calculateServiceVolumes checks if a service type is allowed to have additional volumes attached, and if any volumes from docker compose +// are to be attached to this service or not +func calculateServiceVolumes(buildVolumes []ComposeVolume, lagoonType, servicePersistentName string, serviceLabels composetypes.Labels) ([]ServiceVolume, error) { + serviceVolumes := []ServiceVolume{} + if val, ok := servicetypes.ServiceTypes[lagoonType]; ok { + for _, vol := range buildVolumes { + volName := lagoon.GetVolumeNameFromLagoonVolume(vol.Name) + // if there is a `lagoon.volumes..path` for a custom volume that matches the default persistent volume + // don't add it again as a service volume + if servicePersistentName != volName { + volumePath := lagoon.CheckDockerComposeLagoonLabel(serviceLabels, fmt.Sprintf("lagoon.volumes.%s.path", volName)) + if volumePath != "" { + if val.AllowAdditionalVolumes { + sVol := ServiceVolume{ + ComposeVolume: vol, + Path: volumePath, + } + serviceVolumes = append(serviceVolumes, sVol) + } else { + // if the service type is not allowed additional volumes, return an error + return nil, fmt.Errorf("the service type %s is not permitted to have additional volumes attached", lagoonType) + } + } + } + } + } + + return serviceVolumes, nil +} diff --git a/internal/lagoon/compose.go b/internal/lagoon/compose.go index 072f5252..13b90372 100644 --- a/internal/lagoon/compose.go +++ b/internal/lagoon/compose.go @@ -1,9 +1,9 @@ package lagoon import ( - "errors" "fmt" "os" + "strings" "github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/loader" @@ -18,8 +18,14 @@ type OriginalServiceOrder struct { Index int } +var ( + customVolumePrefix string = "custom-" +) + +type OriginalVolumeOrder OriginalServiceOrder + // UnmarshaDockerComposeYAML unmarshal the lagoon.yml file into a YAML and map for consumption. -func UnmarshaDockerComposeYAML(file string, ignoreErrors, ignoreMissingEnvFiles bool, envvars map[string]string) (*composetypes.Project, []OriginalServiceOrder, error) { +func UnmarshaDockerComposeYAML(file string, ignoreErrors, ignoreMissingEnvFiles bool, envvars map[string]string) (*composetypes.Project, []OriginalServiceOrder, []OriginalVolumeOrder, error) { options, err := cli.NewProjectOptions([]string{file}, cli.WithResolvedPaths(false), cli.WithLoadOptions( @@ -31,27 +37,31 @@ func UnmarshaDockerComposeYAML(file string, ignoreErrors, ignoreMissingEnvFiles }, ), ) + if err != nil { + return nil, nil, nil, err + } options.Environment = envvars l, err := cli.ProjectFromOptions(options) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - originalOrder, err := UnmarshalLagoonDockerComposeYAML(file) + originalOrder, originalVolume, err := UnmarshalLagoonDockerComposeYAML(file) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - return l, originalOrder, nil + return l, originalOrder, originalVolume, nil } // UnmarshalLagoonDockerComposeYAML unmarshal the docker-compose.yml file into a YAML and map for consumption. // this uses yaml mapslice to preserve the order of the services in the docker-compose file // as lagoon relies on this order for building images and determining the order of routes -func UnmarshalLagoonDockerComposeYAML(file string) ([]OriginalServiceOrder, error) { +func UnmarshalLagoonDockerComposeYAML(file string) ([]OriginalServiceOrder, []OriginalVolumeOrder, error) { rawYAML, err := os.ReadFile(file) - l := []OriginalServiceOrder{} if err != nil { - return nil, fmt.Errorf("couldn't read %v: %v", file, err) + return nil, nil, fmt.Errorf("couldn't read %v: %v", file, err) } + ls := []OriginalServiceOrder{} + lv := []OriginalVolumeOrder{} // unmarshal docker-compose.yml // use to gopkg yaml v2 for MapSlice m := goyaml.MapSlice{} @@ -61,13 +71,19 @@ func UnmarshalLagoonDockerComposeYAML(file string) ([]OriginalServiceOrder, erro if item.Key.(string) == "services" { for idx, v := range item.Value.(goyaml.MapSlice) { if err := CheckServiceNameValidity(v); err != nil { - return nil, err + return nil, nil, err } - l = append(l, OriginalServiceOrder{Index: idx, Name: v.Key.(string)}) + ls = append(ls, OriginalServiceOrder{Index: idx, Name: v.Key.(string)}) + } + } + // extract the volumes only + if item.Key.(string) == "volumes" { + for idx, v := range item.Value.(goyaml.MapSlice) { + lv = append(lv, OriginalVolumeOrder{Index: idx, Name: v.Key.(string)}) } } } - return l, nil + return ls, lv, nil } // use goyamlv3 that newer versions of compose-go uses to validate @@ -94,7 +110,7 @@ func CheckServiceNameValidity(v goyaml.MapItem) error { // check if the lagoon.type != none if label.Key == "lagoon.type" && label.Value != "none" { if err := utilvalidation.IsDNS1035Label(v.Key.(string)); err != nil { - return errors.New("Service name is invalid. Please refer to the documentation regarding service naming requirements") + return fmt.Errorf("service name is invalid. Please refer to the documentation regarding service naming requirements") } } } @@ -103,8 +119,8 @@ func CheckServiceNameValidity(v goyaml.MapItem) error { return nil } -// CheckServiceLagoonLabel checks the labels in a compose service to see if the requested label exists, and returns the value if so -func CheckServiceLagoonLabel(labels map[string]string, label string) string { +// CheckDockerComposeLagoonLabel checks the labels in a compose service to see if the requested label exists, and returns the value if so +func CheckDockerComposeLagoonLabel(labels map[string]string, label string) string { for k, v := range labels { if k == label { return v @@ -112,3 +128,23 @@ func CheckServiceLagoonLabel(labels map[string]string, label string) string { } return "" } + +// pad volume names from the docker compose file with the compose stack name +func GetComposeVolumeName(c, n string) string { + return fmt.Sprintf("%s_%s", c, n) +} + +// trim compose stack name from volume name +func GetVolumeNameFromComposeName(c, n string) string { + return strings.Replace(n, fmt.Sprintf("%s_", c), "", 1) +} + +// pad volume names from the docker compose file with the custom volume prefix +func GetLagoonVolumeName(n string) string { + return fmt.Sprintf("%s%s", customVolumePrefix, n) +} + +// trim the custom prefix from lagoon volume names returning them to the name defined in the docker compose file +func GetVolumeNameFromLagoonVolume(n string) string { + return strings.Replace(n, customVolumePrefix, "", 1) +} diff --git a/internal/lagoon/compose_test.go b/internal/lagoon/compose_test.go index 1179b910..bcd8264f 100644 --- a/internal/lagoon/compose_test.go +++ b/internal/lagoon/compose_test.go @@ -15,20 +15,22 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { ignoreMissingEnvFiles bool } tests := []struct { - name string - args args - wantErr bool - wantErrMsg string - want string - wantOrder []OriginalServiceOrder + name string + args args + wantErr bool + wantErrMsg string + want string + wantServiceOrder []OriginalServiceOrder + wantVolumeOrder []OriginalVolumeOrder }{ + // these tests are specific to docker-compose validations, but will pass yaml validations { name: "test1 docker-compose drupal example", args: args{ file: "../../internal/testdata/docker-compose/test1/docker-compose.yml", }, want: `{"name":"test1","services":{"cli":{"build":{"context":".","dockerfile":"lagoon/cli.dockerfile"},"environment":{"LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"image":"drupal9-example-advanced-cli","labels":{"lagoon.persistent":"/app/web/sites/default/files/","lagoon.persistent.name":"nginx","lagoon.type":"cli-persistent","lando.type":"php-cli-drupal"},"networks":{"default":null},"user":"root","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"volume","source":"files","target":"/app/web/sites/default/files","volume":{}}],"volumes_from":["container:amazeeio-ssh-agent"]},"mariadb":{"environment":{"LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"image":"uselagoon/mariadb-10.5-drupal:latest","labels":{"lagoon.type":"mariadb","lando.type":"mariadb-drupal"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}],"user":"1000"},"nginx":{"build":{"context":".","dockerfile":"lagoon/nginx.dockerfile","args":{"CLI_IMAGE":"drupal9-example-advanced-cli"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"LAGOON_LOCALDEV_URL":"http://drupal9-example-advanced.docker.amazee.io","LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"labels":{"lagoon.persistent":"/app/web/sites/default/files/","lagoon.type":"nginx-php-persistent","lando.type":"nginx-drupal"},"networks":{"amazeeio-network":null,"default":null},"user":"1000","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"volume","source":"files","target":"/app/web/sites/default/files","volume":{}}]},"php":{"build":{"context":".","dockerfile":"lagoon/php.dockerfile","args":{"CLI_IMAGE":"drupal9-example-advanced-cli"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"labels":{"lagoon.name":"nginx","lagoon.persistent":"/app/web/sites/default/files/","lagoon.type":"nginx-php-persistent","lando.type":"php-fpm"},"networks":{"default":null},"user":"1000","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"volume","source":"files","target":"/app/web/sites/default/files","volume":{}}]},"redis":{"environment":{"LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"image":"uselagoon/redis-5:latest","labels":{"lagoon.type":"redis","lando.type":"redis"},"networks":{"default":null},"ports":[{"mode":"ingress","target":6379,"protocol":"tcp"}],"user":"1000"},"solr":{"environment":{"LAGOON_ROUTE":"http://drupal9-example-advanced.docker.amazee.io"},"image":"uselagoon/solr-7.7-drupal:latest","labels":{"lagoon.type":"solr","lando.type":"solr-drupal"},"networks":{"default":null},"ports":[{"mode":"ingress","target":8983,"protocol":"tcp"}]}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test1_default","ipam":{},"external":false}},"volumes":{"files":{"name":"test1_files","external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, @@ -36,6 +38,9 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { {Index: 4, Name: "redis"}, {Index: 5, Name: "solr"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "files"}, + }, }, { name: "test2 docker-compose node example", @@ -43,9 +48,10 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test2/docker-compose.yml", }, want: `{"name":"test2","services":{"node":{"build":{"context":".","dockerfile":"node.dockerfile"},"environment":{"LAGOON_LOCALDEV_HTTP_PORT":"3000","LAGOON_ROUTE":"http://node.docker.amazee.io"},"labels":{"lagoon.type":"node"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test2_default","ipam":{},"external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "node"}, }, + wantVolumeOrder: []OriginalVolumeOrder{}, }, { name: "test3 docker-compose complex", @@ -53,12 +59,17 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test3/docker-compose.yml", }, want: `{"name":"test3","services":{"cli":{"build":{"context":".","dockerfile":".lagoon/cli.dockerfile","args":{"DOCKER_CLI_IMAGE_URI":"","ENVIRONMENT_TYPE_ID":""}},"container_name":"_cli","environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.name":"nginx","lagoon.type":"cli-persistent"},"networks":{"default":null},"user":"root","volumes":[{"type":"bind","source":"./.lagoon/scripts/bash_prompts.rc","target":"/home/.bashrc","bind":{"create_host_path":true}},{"type":"bind","source":"./.lagoon/scripts/color_grid.sh","target":"/home/color_grid.sh","bind":{"create_host_path":true}}],"volumes_from":["container:amazeeio-ssh-agent"]},"mariadb":{"container_name":"_db","environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"image":"amazeeio/mariadb-drupal","labels":{"lagoon.type":"mariadb"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}],"volumes":[{"type":"volume","source":"mysql","target":"/var/lib/mysql","volume":{}}]},"nginx":{"build":{"context":".","dockerfile":".lagoon/nginx.dockerfile","args":{"CLI_IMAGE":"","DOCKER_NGINX_IMAGE_URI":"","LAGOON_GIT_BRANCH":""}},"container_name":"_nginx","depends_on":{"cli":{"condition":"service_started"}},"environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_LOCALDEV_URL":"http://","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.name":"nginx","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"bind","source":"./.lagoon/nginx/nginx-http.conf","target":"/etc/nginx/conf.d/000-nginx-http.conf","bind":{"create_host_path":true}},{"type":"bind","source":"./.lagoon/nginx/app.conf","target":"/etc/nginx/conf.d/app.conf","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":".lagoon/php.dockerfile","args":{"CLI_IMAGE":"","DOCKER_PHP_IMAGE_URI":""}},"container_name":"_php","depends_on":{"cli":{"condition":"service_started"}},"environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.deployment.servicetype":"php","lagoon.name":"nginx","lagoon.persistent":"/app/docroot/sites/default/files","lagoon.type":"nginx-php-persistent"},"networks":{"default":null}}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test3_default","ipam":{},"external":false}},"volumes":{"app":{"name":"test3_app","external":false},"mysql":{"name":"test3_mysql","external":false},"solr7":{"name":"test3_solr7","external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, {Index: 3, Name: "mariadb"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "app"}, + {Index: 1, Name: "mysql"}, + {Index: 2, Name: "solr7"}, + }, }, { name: "test4 docker-compose complex", @@ -66,7 +77,7 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test4/docker-compose.yml", }, want: `{"name":"test4","services":{"chrome":{"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"image":"seleniarm/standalone-chromium:101.0","labels":{"lagoon.type":"none"},"networks":{"default":null},"shm_size":"1073741824","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"bind","source":"./docroot/sites/default/files","target":"/app/docroot/sites/default/files","bind":{"create_host_path":true}}]},"clamav":{"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"image":"clamav/example-clamav:4.x","labels":{"lagoon.type":"none"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3310,"protocol":"tcp"}]},"cli":{"build":{"context":".","dockerfile":".docker/Dockerfile.cli","args":{"COMPOSER":"composer.json","EXAMPLE_IMAGE_VERSION":"4.x"}},"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"image":"mysite","labels":{"lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.name":"nginx-php","lagoon.persistent.size":"50Gi","lagoon.type":"cli-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"bind","source":"./docroot/sites/default/files","target":"/app/docroot/sites/default/files","bind":{"create_host_path":true}}],"volumes_from":["container:amazeeio-ssh-agent"]},"elasticsearch":{"build":{"context":".","dockerfile":".docker/Dockerfile.elasticsearch","args":{"ES_TPL":"elasticsearch.yml"}},"labels":{"lagoon.type":"none"},"networks":{"default":null}},"mariadb":{"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"image":"uselagoon/mariadb-10.4-drupal:latest","labels":{"lagoon.type":"mariadb-shared"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}]},"nginx":{"build":{"context":".","dockerfile":".docker/Dockerfile.nginx-drupal","args":{"CLI_IMAGE":"mysite","EXAMPLE_IMAGE_VERSION":"4.x"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"expose":["8080"],"labels":{"lagoon.name":"nginx-php","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.size":"50Gi","lagoon.type":"nginx-php-persistent"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"bind","source":"./docroot/sites/default/files","target":"/app/docroot/sites/default/files","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":".docker/Dockerfile.php","args":{"CLI_IMAGE":"mysite","EXAMPLE_IMAGE_VERSION":"4.x"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CKEDITOR_SCAYT_CUSTOMERID":"","CKEDITOR_SCAYT_SLANG":"","DB_ALIAS":"example.prod-left","DRUPAL_HASH_SALT":"fakehashsaltfakehashsaltfakehashsalt","DRUPAL_REFRESH_SEARCHAPI":"","EXAMPLE_IMAGE_VERSION":"latest","EXAMPLE_INGRESS_ENABLED":"","EXAMPLE_INGRESS_HEADER":"","EXAMPLE_INGRESS_PSK":"","EXAMPLE_KEY":"","GITHUB_TOKEN":"","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"http://mysite.docker.amazee.io","LAGOON_PROJECT":"mysite","LAGOON_ROUTE":"http://mysite.docker.amazee.io","PHP_MEMORY_LIMIT":"1024M","REDIS_CACHE_PREFIX":"tide_"},"labels":{"lagoon.name":"nginx-php","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.size":"50Gi","lagoon.type":"nginx-php-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"bind","source":"./docroot/sites/default/files","target":"/app/docroot/sites/default/files","bind":{"create_host_path":true}}]},"redis":{"image":"uselagoon/redis-5:latest","labels":{"lagoon.type":"redis"},"networks":{"default":null}}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test4_default","ipam":{},"external":false}},"volumes":{"app":{"name":"test4_app","external":false},"files":{"name":"test4_files","external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, @@ -76,6 +87,10 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { {Index: 6, Name: "chrome"}, {Index: 7, Name: "clamav"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "app"}, + {Index: 1, Name: "files"}, + }, }, { name: "test5 docker-compose complex", @@ -83,7 +98,7 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test5/docker-compose.yml", }, want: `{"name":"test5","services":{"chrome":{"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"image":"selenium/standalone-chrome:3.141.59-oxygen","labels":{"lagoon.type":"none"},"networks":{"default":null},"shm_size":"1073741824","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]},"cli":{"build":{"context":".","dockerfile":".docker/Dockerfile.cli"},"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"image":"example-project","labels":{"lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.name":"nginx-php","lagoon.type":"cli-persistent"},"networks":{"default":null},"ports":[{"mode":"ingress","target":35729,"protocol":"tcp"}],"user":"root","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}],"volumes_from":["container:amazeeio-ssh-agent"]},"mariadb":{"build":{"context":".","dockerfile":".docker/Dockerfile.mariadb","args":{"IMAGE":"amazeeio/mariadb-drupal:21.7.0"}},"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"labels":{"lagoon.type":"mariadb"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}]},"nginx":{"build":{"context":".","dockerfile":".docker/Dockerfile.nginx-drupal","args":{"CLI_IMAGE":"example-project"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"labels":{"lagoon.name":"nginx-php","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.class":"slow","lagoon.type":"nginx-php-persistent"},"networks":{"amazeeio-network":null,"default":null},"user":"1000","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":".docker/Dockerfile.php","args":{"CLI_IMAGE":"example-project"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"labels":{"lagoon.name":"nginx-php","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.class":"slow","lagoon.type":"nginx-php-persistent"},"networks":{"default":null},"user":"1000","volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]},"redis":{"environment":{"CI":"","DOCKERHOST":"host.docker.internal","LAGOON_ENVIRONMENT_TYPE":"local","LAGOON_LOCALDEV_URL":"example-project.docker.amazee.io","LAGOON_PROJECT":"example-project","LAGOON_ROUTE":"example-project.docker.amazee.io","PHP_APC_SHM_SIZE":"256M","PHP_MAX_EXECUTION_TIME":"-1","PHP_MAX_INPUT_VARS":"4000","PHP_MEMORY_LIMIT":"2G","XDEBUG_ENABLE":""},"image":"amazeeio/redis:6-21.11.0","labels":{"lagoon.type":"redis"},"networks":{"default":null}},"wait_dependencies":{"command":["mariadb:3306"],"depends_on":{"cli":{"condition":"service_started"},"mariadb":{"condition":"service_started"}},"image":"dadarek/wait-for-dependencies","labels":{"lagoon.type":"none"},"networks":{"default":null}}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test5_default","ipam":{},"external":false}},"volumes":{"app":{"name":"test5_app","external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, @@ -92,6 +107,9 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { {Index: 5, Name: "chrome"}, {Index: 6, Name: "wait_dependencies"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "app"}, + }, }, { name: "test6 docker-compose complex", @@ -99,7 +117,7 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test6/docker-compose.yml", }, want: `{"name":"test6","services":{"chrome":{"depends_on":{"test":{"condition":"service_started"}},"image":"selenium/standalone-chrome","labels":{"lagoon.type":"none"},"networks":{"default":null},"shm_size":"1073741824","volumes":[{"type":"bind","source":"./themes","target":"/app/web/themes/custom","bind":{"create_host_path":true}},{"type":"bind","source":"./files","target":"/app/web/sites/default/files","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/features","target":"/app/tests/behat/features","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/screenshots","target":"/app/tests/behat/screenshots","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/phpunit/tests","target":"/app/tests/phpunit/tests","bind":{"create_host_path":true}},{"type":"bind","source":"./config","target":"/app/config","bind":{"create_host_path":true}}]},"cli":{"build":{"context":".","dockerfile":".docker/Dockerfile.cli","args":{"EXAMPLE_IMAGE_VERSION":"9.x-latest","LAGOON_SAFE_PROJECT":"ca-learning2"}},"environment":{"DEV_MODE":"false","DOCKERHOST":"host.docker.internal","DRUPAL_SHIELD_PASS":"","DRUPAL_SHIELD_USER":"","EXAMPLE_DEPLOY_WORKFLOW_CONFIG":"import","EXAMPLE_IMAGE_VERSION":"9.x-latest","EXAMPLE_PREPARE_XML_SCRIPT":"/app/vendor/bin/example-prepare-xml","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"ca-learning2","LAGOON_ROUTE":"http://ca-learning2.docker.amazee.io","STAGE_FILE_PROXY_URL":"","XDEBUG_ENABLE":"","X_FRAME_OPTIONS":"SameOrigin"},"image":"ca-learning2","labels":{"lagoon.persistent":"/app/web/sites/default/files/","lagoon.persistent.name":"nginx","lagoon.type":"cli-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":"./themes","target":"/app/web/themes/custom","bind":{"create_host_path":true}},{"type":"bind","source":"./files","target":"/app/web/sites/default/files","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/features","target":"/app/tests/behat/features","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/screenshots","target":"/app/tests/behat/screenshots","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/phpunit/tests","target":"/app/tests/phpunit/tests","bind":{"create_host_path":true}},{"type":"bind","source":"./config","target":"/app/config","bind":{"create_host_path":true}}],"volumes_from":["container:amazeeio-ssh-agent"]},"mariadb":{"environment":{"DEV_MODE":"false","DOCKERHOST":"host.docker.internal","DRUPAL_SHIELD_PASS":"","DRUPAL_SHIELD_USER":"","EXAMPLE_DEPLOY_WORKFLOW_CONFIG":"import","EXAMPLE_IMAGE_VERSION":"9.x-latest","EXAMPLE_PREPARE_XML_SCRIPT":"/app/vendor/bin/example-prepare-xml","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"ca-learning2","LAGOON_ROUTE":"http://ca-learning2.docker.amazee.io","STAGE_FILE_PROXY_URL":"","XDEBUG_ENABLE":"","X_FRAME_OPTIONS":"SameOrigin"},"image":"example/mariadb-drupal:9.x-latest","labels":{"lagoon.image":"example/mariadb-drupal:9.x-latest","lagoon.type":"mariadb"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}]},"nginx":{"build":{"context":".","dockerfile":".docker/Dockerfile.nginx-drupal","args":{"CLI_IMAGE":"ca-learning2","EXAMPLE_IMAGE_VERSION":"9.x-latest"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"DEV_MODE":"false","DOCKERHOST":"host.docker.internal","DRUPAL_SHIELD_PASS":"","DRUPAL_SHIELD_USER":"","EXAMPLE_DEPLOY_WORKFLOW_CONFIG":"import","EXAMPLE_IMAGE_VERSION":"9.x-latest","EXAMPLE_PREPARE_XML_SCRIPT":"/app/vendor/bin/example-prepare-xml","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_LOCALDEV_URL":"http://ca-learning2.docker.amazee.io","LAGOON_PROJECT":"ca-learning2","LAGOON_ROUTE":"http://ca-learning2.docker.amazee.io","STAGE_FILE_PROXY_URL":"","XDEBUG_ENABLE":"","X_FRAME_OPTIONS":"SameOrigin"},"labels":{"lagoon.persistent":"/app/web/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"bind","source":"./themes","target":"/app/web/themes/custom","bind":{"create_host_path":true}},{"type":"bind","source":"./files","target":"/app/web/sites/default/files","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/features","target":"/app/tests/behat/features","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/screenshots","target":"/app/tests/behat/screenshots","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/phpunit/tests","target":"/app/tests/phpunit/tests","bind":{"create_host_path":true}},{"type":"bind","source":"./config","target":"/app/config","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":".docker/Dockerfile.php","args":{"CLI_IMAGE":"ca-learning2","EXAMPLE_IMAGE_VERSION":"9.x-latest"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"DEV_MODE":"false","DOCKERHOST":"host.docker.internal","DRUPAL_SHIELD_PASS":"","DRUPAL_SHIELD_USER":"","EXAMPLE_DEPLOY_WORKFLOW_CONFIG":"import","EXAMPLE_IMAGE_VERSION":"9.x-latest","EXAMPLE_PREPARE_XML_SCRIPT":"/app/vendor/bin/example-prepare-xml","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"ca-learning2","LAGOON_ROUTE":"http://ca-learning2.docker.amazee.io","STAGE_FILE_PROXY_URL":"","XDEBUG_ENABLE":"","X_FRAME_OPTIONS":"SameOrigin"},"labels":{"lagoon.name":"nginx","lagoon.persistent":"/app/web/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":"./themes","target":"/app/web/themes/custom","bind":{"create_host_path":true}},{"type":"bind","source":"./files","target":"/app/web/sites/default/files","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/features","target":"/app/tests/behat/features","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/screenshots","target":"/app/tests/behat/screenshots","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/phpunit/tests","target":"/app/tests/phpunit/tests","bind":{"create_host_path":true}},{"type":"bind","source":"./config","target":"/app/config","bind":{"create_host_path":true}}]},"test":{"build":{"context":".","dockerfile":".docker/Dockerfile.test","args":{"CLI_IMAGE":"ca-learning2","EXAMPLE_IMAGE_VERSION":"9.x-latest","SITE_AUDIT_VERSION":"7.x-3.x"}},"depends_on":{"cli":{"condition":"service_started"}},"environment":{"DEV_MODE":"false","DOCKERHOST":"host.docker.internal","DRUPAL_SHIELD_PASS":"","DRUPAL_SHIELD_USER":"","EXAMPLE_DEPLOY_WORKFLOW_CONFIG":"import","EXAMPLE_IMAGE_VERSION":"9.x-latest","EXAMPLE_PREPARE_XML_SCRIPT":"/app/vendor/bin/example-prepare-xml","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"ca-learning2","LAGOON_ROUTE":"http://ca-learning2.docker.amazee.io","STAGE_FILE_PROXY_URL":"","XDEBUG_ENABLE":"","X_FRAME_OPTIONS":"SameOrigin"},"labels":{"lagoon.type":"none"},"networks":{"default":null},"volumes":[{"type":"bind","source":"./themes","target":"/app/web/themes/custom","bind":{"create_host_path":true}},{"type":"bind","source":"./files","target":"/app/web/sites/default/files","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/features","target":"/app/tests/behat/features","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/behat/screenshots","target":"/app/tests/behat/screenshots","bind":{"create_host_path":true}},{"type":"bind","source":"./tests/phpunit/tests","target":"/app/tests/phpunit/tests","bind":{"create_host_path":true}},{"type":"bind","source":"./config","target":"/app/config","bind":{"create_host_path":true}}]}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test6_default","ipam":{},"external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "test"}, {Index: 2, Name: "nginx"}, @@ -107,6 +125,7 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { {Index: 4, Name: "mariadb"}, {Index: 5, Name: "chrome"}, }, + wantVolumeOrder: []OriginalVolumeOrder{}, }, { name: "test7 check an invalid docker-compose with ignoring non-string key errors", @@ -115,12 +134,17 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { ignoreNonStringKeyErrors: true, }, want: `{"name":"test7","services":{"cli":{"build":{"context":".","dockerfile":".lagoon/cli.dockerfile","args":{"DOCKER_CLI_IMAGE_URI":"","ENVIRONMENT_TYPE_ID":""}},"container_name":"_cli","environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.persistent.name":"nginx","lagoon.type":"cli-persistent"},"networks":{"default":null},"user":"root","volumes":[{"type":"bind","source":"./.lagoon/scripts/bash_prompts.rc","target":"/home/.bashrc","bind":{"create_host_path":true}},{"type":"bind","source":"./.lagoon/scripts/color_grid.sh","target":"/home/color_grid.sh","bind":{"create_host_path":true}}],"volumes_from":["container:amazeeio-ssh-agent"]},"mariadb":{"container_name":"_db","environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"image":"amazeeio/mariadb-drupal","labels":{"lagoon.type":"mariadb"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}],"volumes":[{"type":"volume","source":"mysql","target":"/var/lib/mysql","volume":{}}]},"nginx":{"build":{"context":".","dockerfile":".lagoon/nginx.dockerfile","args":{"CLI_IMAGE":"","DOCKER_NGINX_IMAGE_URI":"","LAGOON_GIT_BRANCH":null}},"container_name":"_nginx","depends_on":{"cli":{"condition":"service_started"}},"environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_LOCALDEV_URL":"http://","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.name":"nginx","lagoon.persistent":"/app/docroot/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"bind","source":"./.lagoon/nginx/nginx-http.conf","target":"/etc/nginx/conf.d/000-nginx-http.conf","bind":{"create_host_path":true}},{"type":"bind","source":"./.lagoon/nginx/app.conf","target":"/etc/nginx/conf.d/app.conf","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":".lagoon/php.dockerfile","args":{"CLI_IMAGE":"","DOCKER_PHP_IMAGE_URI":""}},"container_name":"_php","depends_on":{"cli":{"condition":"service_started"}},"environment":{"ENVIRONMENT_TYPE_ID":"","LAGOON_ENVIRONMENT_TYPE":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"http://","PHP_MEMORY_LIMIT":"768M","XDEBUG_ENABLE":""},"labels":{"lagoon.deployment.servicetype":"php","lagoon.name":"nginx","lagoon.persistent":"/app/docroot/sites/default/files","lagoon.type":"nginx-php-persistent"},"networks":{"default":null}}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test7_default","ipam":{},"external":false}},"volumes":{"app":{"name":"test7_app","external":false},"mysql":{"name":"test7_mysql","external":false},"solr7":{"name":"test7_solr7","external":false}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, {Index: 3, Name: "mariadb"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "app"}, + {Index: 1, Name: "mysql"}, + {Index: 2, Name: "solr7"}, + }, }, { name: "test8 check an invalid docker-compose (same as test7 but not ignoring the errors)", @@ -138,13 +162,17 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { ignoreMissingEnvFiles: true, }, want: `{"name":"test9","services":{"cli":{"build":{"context":".","dockerfile":"lagoon/cli.dockerfile"},"container_name":"-cli","environment":{"DRUSH_OPTIONS_URI":"https://","LAGOON_PROJECT":"","LAGOON_ROUTE":"https://","SIMPLETEST_BASE_URL":"http://nginx:8080","SIMPLETEST_DB":"mysql://drupal:drupal@mariadb:3306/drupal","SSMTP_MAILHUB":"host.docker.internal:1025"},"labels":{"lagoon.persistent":"/app/public/sites/default/files/","lagoon.persistent.name":"nginx","lagoon.type":"cli-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}},{"type":"volume","source":"ssh","target":"/tmp/amazeeio_ssh-agent","volume":{}}]},"mariadb":{"container_name":"-db","environment":{"LAGOON_PROJECT":"","LAGOON_ROUTE":"https://","SSMTP_MAILHUB":"host.docker.internal:1025"},"image":"uselagoon/mariadb-drupal:latest","labels":{"lagoon.type":"mariadb"},"networks":{"default":null},"ports":[{"mode":"ingress","target":3306,"protocol":"tcp"}]},"nginx":{"build":{"context":".","dockerfile":"lagoon/nginx.dockerfile","args":{"CLI_IMAGE":""}},"container_name":"-nginx","depends_on":{"cli":{"condition":"service_started"}},"environment":{"LAGOON_LOCALDEV_URL":"","LAGOON_PROJECT":"","LAGOON_ROUTE":"https://","SSMTP_MAILHUB":"host.docker.internal:1025"},"labels":{"lagoon.persistent":"/app/public/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"default":null,"stonehenge-network":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]},"php":{"build":{"context":".","dockerfile":"lagoon/php.dockerfile","args":{"CLI_IMAGE":""}},"container_name":"-php","depends_on":{"cli":{"condition":"service_started"}},"environment":{"LAGOON_PROJECT":"","LAGOON_ROUTE":"https://","SSMTP_MAILHUB":"host.docker.internal:1025"},"labels":{"lagoon.name":"nginx","lagoon.persistent":"/app/public/sites/default/files/","lagoon.type":"nginx-php-persistent"},"networks":{"default":null},"volumes":[{"type":"bind","source":".","target":"/app","bind":{"create_host_path":true}}]},"pma":{"container_name":"-pma","environment":{"PMA_HOST":"mariadb","PMA_PASSWORD":"drupal","PMA_USER":"drupal","UPLOAD_LIMIT":"1G"},"image":"phpmyadmin/phpmyadmin","labels":{"lagoon.type":"none"},"networks":{"default":null,"stonehenge-network":null}}},"networks":{"default":{"name":"test9_default","ipam":{},"external":false},"stonehenge-network":{"name":"stonehenge-network","ipam":{},"external":true}},"volumes":{"es_data":{"name":"test9_es_data","external":false},"ssh":{"name":"stonehenge-ssh","external":true}}}`, - wantOrder: []OriginalServiceOrder{ + wantServiceOrder: []OriginalServiceOrder{ {Index: 0, Name: "cli"}, {Index: 1, Name: "nginx"}, {Index: 2, Name: "php"}, {Index: 3, Name: "mariadb"}, {Index: 4, Name: "pma"}, }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "es_data"}, + {Index: 1, Name: "ssh"}, + }, }, { name: "test10 check an valid docker-compose with missing env_files (same as test9 but not ignoring the errors)", @@ -160,12 +188,30 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test11/docker-compose.yml", }, wantErr: true, - wantErrMsg: "Service name is invalid. Please refer to the documentation regarding service naming requirements", + wantErrMsg: "service name is invalid. Please refer to the documentation regarding service naming requirements", + }, + { + name: "test12 docker-compose service with volumes", + args: args{ + file: "../../internal/testdata/docker-compose/test12/docker-compose.yml", + }, + want: `{"name":"test12","services":{"node":{"build":{"context":".","dockerfile":"node.dockerfile"},"environment":{"LAGOON_LOCALDEV_HTTP_PORT":"3000","LAGOON_ROUTE":"http://node.docker.amazee.io"},"labels":{"lagoon.type":"node"},"networks":{"amazeeio-network":null,"default":null},"volumes":[{"type":"volume","source":"node","target":"/app","volume":{}},{"type":"volume","source":"config","target":"/config","volume":{}},{"type":"volume","source":"files","target":"/files","volume":{}}]}},"networks":{"amazeeio-network":{"name":"amazeeio-network","ipam":{},"external":true},"default":{"name":"test12_default","ipam":{},"external":false}},"volumes":{"config":{"name":"test12_config","external":false,"labels":{"lagoon.type":"persistent"}},"db":{"name":"test12_db","external":false,"labels":{"lagoon.type":"none"}},"files":{"name":"test12_files","external":false,"labels":{"lagoon.persistent.size":"10Gi","lagoon.type":"persistent"}},"logs":{"name":"test12_logs","external":false},"node":{"name":"test12_node","external":false,"labels":{"lagoon.type":"persistent"}},"notused":{"name":"test12_notused","external":false,"labels":{"lagoon.type":"persistent"}}}}`, + wantServiceOrder: []OriginalServiceOrder{ + {Index: 0, Name: "node"}, + }, + wantVolumeOrder: []OriginalVolumeOrder{ + {Index: 0, Name: "node"}, + {Index: 1, Name: "config"}, + {Index: 2, Name: "files"}, + {Index: 3, Name: "db"}, + {Index: 4, Name: "notused"}, + {Index: 5, Name: "logs"}, + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l, dcpo, err := UnmarshaDockerComposeYAML(tt.args.file, tt.args.ignoreNonStringKeyErrors, tt.args.ignoreMissingEnvFiles, map[string]string{}) + l, dcpo, dcvo, err := UnmarshaDockerComposeYAML(tt.args.file, tt.args.ignoreNonStringKeyErrors, tt.args.ignoreMissingEnvFiles, map[string]string{}) if err != nil && !tt.wantErr { t.Errorf("UnmarshaDockerComposeYAML() error = %v, wantErr %v", err, tt.wantErr) } @@ -179,8 +225,11 @@ func TestUnmarshaDockerComposeYAML(t *testing.T) { t.Errorf("UnmarshaDockerComposeYAML() = %v, want %v", string(stra), tt.want) } } - if !cmp.Equal(dcpo, tt.wantOrder) { - t.Errorf("UnmarshaDockerComposeYAML() = %v, want %v", dcpo, tt.wantOrder) + if !cmp.Equal(dcpo, tt.wantServiceOrder) { + t.Errorf("UnmarshaDockerComposeYAML() = %v, want %v", dcpo, tt.wantServiceOrder) + } + if !cmp.Equal(dcvo, tt.wantVolumeOrder) { + t.Errorf("UnmarshaDockerComposeYAML() = %v, want %v", dcvo, tt.wantVolumeOrder) } }) } @@ -211,14 +260,14 @@ func TestCheckLagoonLabel(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := CheckServiceLagoonLabel(tt.args.labels, tt.args.label); got != tt.want { - t.Errorf("CheckServiceLagoonLabel() = %v, want %v", got, tt.want) + if got := CheckDockerComposeLagoonLabel(tt.args.labels, tt.args.label); got != tt.want { + t.Errorf("CheckDockerComposeLagoonLabel() = %v, want %v", got, tt.want) } }) } } -func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) { +func TestValidateUnmarshalDockerComposeYAML(t *testing.T) { type args struct { file string } @@ -228,6 +277,7 @@ func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) { wantErrMsg string wantErr bool }{ + // these tests are specific to yaml validations { name: "test1 docker-compose drupal example", args: args{ @@ -268,7 +318,6 @@ func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test6/docker-compose.yml", }, }, - // these tests are specific to docker-compose validations, but will pass yaml validations { name: "test7 check an invalid docker-compose with ignoring non-string key errors (valid yaml)", args: args{ @@ -299,7 +348,12 @@ func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) { file: "../../internal/testdata/docker-compose/test11/docker-compose.yml", }, }, - // ^^ these tests are specific to docker-compose validations, but will pass yaml validations + { + name: "test12 docker-compose with volumes", + args: args{ + file: "../../internal/testdata/docker-compose/test12/docker-compose.yml", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -317,3 +371,91 @@ func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) { }) } } + +func TestGetVolumeNameFromComposeName(t *testing.T) { + tests := []struct { + name string + c string + n string + want string + }{ + { + name: "test1", + c: "node", + n: "node_volume1", + want: "volume1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetVolumeNameFromComposeName(tt.c, tt.n); got != tt.want { + t.Errorf("GetVolumeNameFromComposeName() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetLagoonVolumeName(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "test1", + input: "volume1", + want: "custom-volume1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetLagoonVolumeName(tt.input); got != tt.want { + t.Errorf("GetLagoonVolumeName() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetVolumeNameFromLagoonVolume(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "test1", + input: "custom-volume1", + want: "volume1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetVolumeNameFromLagoonVolume(tt.input); got != tt.want { + t.Errorf("GetVolumeNameFromLagoonVolume() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetComposeVolumeName(t *testing.T) { + tests := []struct { + name string + c string + n string + want string + }{ + { + name: "test1", + c: "node", + n: "volume1", + want: "node_volume1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetComposeVolumeName(tt.c, tt.n); got != tt.want { + t.Errorf("GetComposeVolumeName() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/templating/services/templates_deployment.go b/internal/templating/services/templates_deployment.go index c9ed2490..d5c76596 100644 --- a/internal/templating/services/templates_deployment.go +++ b/internal/templating/services/templates_deployment.go @@ -240,7 +240,20 @@ func GenerateDeploymentTemplate( deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, volume) } - // if there is a persistent volume attached to this service, handle adding that here + // add any additional volumes with volumes + for _, av := range serviceValues.AdditionalVolumes { + volume := corev1.Volume{ + Name: av.Name, + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: av.Name, + }, + }, + } + deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, volume) + } + + // if there is a persistent volume attached to this service, and no additional volumes, handle adding that here if serviceTypeValues.Volumes.PersistentVolumeSize != "" { volume := corev1.Volume{ Name: serviceValues.PersistentVolumeName, @@ -450,6 +463,15 @@ func GenerateDeploymentTemplate( } container.Container.VolumeMounts = append(container.Container.VolumeMounts, volumeMount) } + + // add any additional volumes with volumemounts + for _, avm := range serviceValues.AdditionalVolumes { + volumeMount := corev1.VolumeMount{ + Name: avm.Name, + MountPath: avm.Path, + } + container.Container.VolumeMounts = append(container.Container.VolumeMounts, volumeMount) + } // handle the default storage volumemount if serviceTypeValues.Volumes.PersistentVolumeSize != "" { volumeMount := corev1.VolumeMount{ @@ -563,6 +585,15 @@ func GenerateDeploymentTemplate( } linkedContainer.Container.VolumeMounts = append(linkedContainer.Container.VolumeMounts, volumeMount) } + + // add any additional volumes with volumemounts + for _, avm := range serviceValues.AdditionalVolumes { + volumeMount := corev1.VolumeMount{ + Name: avm.Name, + MountPath: avm.Path, + } + linkedContainer.Container.VolumeMounts = append(linkedContainer.Container.VolumeMounts, volumeMount) + } if serviceTypeValues.Volumes.PersistentVolumeSize != "" { volumeMount := corev1.VolumeMount{ Name: serviceValues.PersistentVolumeName, diff --git a/internal/templating/services/templates_pvc.go b/internal/templating/services/templates_pvc.go index cf6ca275..59443b1b 100644 --- a/internal/templating/services/templates_pvc.go +++ b/internal/templating/services/templates_pvc.go @@ -6,6 +6,7 @@ import ( "github.com/uselagoon/build-deploy-tool/internal/generator" "github.com/uselagoon/build-deploy-tool/internal/helpers" + "github.com/uselagoon/build-deploy-tool/internal/lagoon" "github.com/uselagoon/build-deploy-tool/internal/servicetypes" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -51,107 +52,213 @@ func GeneratePVCTemplate( for _, serviceValues := range checkedServices { if val, ok := servicetypes.ServiceTypes[serviceValues.Type]; ok { if val.Volumes.PersistentVolumeSize != "" { - if serviceValues.PersistentVolumeName != "" { - if serviceValues.PersistentVolumeName != serviceValues.OverrideName { - // this service base volume is not needed because it is created by a different service - // lagoon legacy templates allowed due to a funny templating issue, for multiple "basic" types to mount one volume - // from one main service, across multiple services of the same type - continue - } - } - serviceTypeValues := &servicetypes.ServiceType{} - helpers.DeepCopy(val, serviceTypeValues) - persistentVolumeSize := serviceTypeValues.Volumes.PersistentVolumeSize - if serviceValues.PersistentVolumeSize != "" { - persistentVolumeSize = serviceValues.PersistentVolumeSize - } - serviceType := &servicetypes.ServiceType{} - helpers.DeepCopy(val, serviceType) - - additionalLabels := map[string]string{} - additionalAnnotations := map[string]string{} - - additionalLabels["app.kubernetes.io/name"] = serviceType.Name - additionalLabels["app.kubernetes.io/instance"] = serviceValues.OverrideName - additionalLabels["lagoon.sh/template"] = fmt.Sprintf("%s-%s", serviceType.Name, "0.1.0") - additionalLabels["lagoon.sh/service"] = serviceValues.OverrideName - additionalLabels["lagoon.sh/service-type"] = serviceType.Name - - // this does both k8up v1 and v2 support - additionalAnnotations["k8up.syn.tools/backup"] = strconv.FormatBool(serviceTypeValues.Volumes.Backup) - additionalAnnotations["k8up.io/backup"] = strconv.FormatBool(serviceTypeValues.Volumes.Backup) - - pvc := &corev1.PersistentVolumeClaim{ - TypeMeta: metav1.TypeMeta{ - Kind: "PersistentVolumeClaim", - APIVersion: corev1.SchemeGroupVersion.Version, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: serviceValues.OverrideName, - }, - } - - labelsCopy := &map[string]string{} - helpers.DeepCopy(labels, labelsCopy) - annotationsCopy := &map[string]string{} - helpers.DeepCopy(annotations, annotationsCopy) - - for key, value := range additionalLabels { - (*labelsCopy)[key] = value - } - // add any additional annotations - for key, value := range additionalAnnotations { - (*annotationsCopy)[key] = value - } - pvc.ObjectMeta.Labels = *labelsCopy - pvc.ObjectMeta.Annotations = *annotationsCopy - // validate any annotations - if err := apivalidation.ValidateAnnotations(pvc.ObjectMeta.Annotations, nil); err != nil { - if len(err) != 0 { - return nil, fmt.Errorf("the annotations for %s are not valid: %v", serviceValues.OverrideName, err) - } - } - // validate any labels - if err := metavalidation.ValidateLabels(pvc.ObjectMeta.Labels, nil); err != nil { - if len(err) != 0 { - return nil, fmt.Errorf("the labels for %s are not valid: %v", serviceValues.OverrideName, err) - } - } - // check length of labels - err := helpers.CheckLabelLength(pvc.ObjectMeta.Labels) + pvc, err := generateDefaultPVC(buildValues, serviceValues, val, labels, annotations) if err != nil { return nil, err } - - // start PVC template - q, err := resource.ParseQuantity(persistentVolumeSize) - if err != nil { - return nil, fmt.Errorf("provided persistent volume size is not valid: %v", err) - } - volumeSize, _ := q.AsInt64() - pvc.Spec = corev1.PersistentVolumeClaimSpec{ - AccessModes: []corev1.PersistentVolumeAccessMode{ - serviceTypeValues.Volumes.PersistentVolumeType, - }, - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - "storage": *resource.NewQuantity(volumeSize, resource.BinarySI), - }, - }, + if pvc != nil { + // end PVC template + result = append(result, *pvc) } - if serviceTypeValues.Volumes.PersistentVolumeType == corev1.ReadWriteMany { - pvc.Spec.StorageClassName = helpers.StrPtr("bulk") - } - if buildValues.RWX2RWO || buildValues.IsCI { - // this should be a rwo volume in CI and if the rwx2rwo flag is enabled - pvc.Spec.AccessModes = []corev1.PersistentVolumeAccessMode{ - corev1.ReadWriteOnce, - } - } - // end PVC template - result = append(result, *pvc) } } } + // check for any additional volumes + for _, vol := range buildValues.Volumes { + exists := false + // check if an existing pvc that will be created as a default persistent volume hasn't also been defined as an additional volume + // this will prevent creating another volume named the same + for _, cpvc := range result { + if lagoon.GetLagoonVolumeName(cpvc.Name) == vol.Name { + exists = true + } + } + if !exists { + pvc, err := generateAdditionalPVC(buildValues, vol, labels, annotations) + if err != nil { + return nil, err + } + result = append(result, *pvc) + } + } return result, nil } + +// generateDefaultPVC default volumes have different labels/annotations to additional values, and also handle some configuration a bit differently +func generateDefaultPVC(buildValues generator.BuildValues, + serviceValues generator.ServiceValues, + val servicetypes.ServiceType, + labels, annotations map[string]string, +) (*corev1.PersistentVolumeClaim, error) { + if serviceValues.PersistentVolumeName != "" { + if serviceValues.PersistentVolumeName != serviceValues.OverrideName { + // this service base volume is not needed because it is created by a different service + // lagoon legacy templates allowed due to a funny templating issue, for multiple "basic" types to mount one volume + // from one main service, across multiple services of the same type + return nil, nil + } + } + serviceTypeValues := &servicetypes.ServiceType{} + helpers.DeepCopy(val, serviceTypeValues) + persistentVolumeSize := serviceTypeValues.Volumes.PersistentVolumeSize + if serviceValues.PersistentVolumeSize != "" { + persistentVolumeSize = serviceValues.PersistentVolumeSize + } + serviceType := &servicetypes.ServiceType{} + helpers.DeepCopy(val, serviceType) + + additionalLabels := map[string]string{} + additionalAnnotations := map[string]string{} + + additionalLabels["app.kubernetes.io/name"] = serviceType.Name + additionalLabels["app.kubernetes.io/instance"] = serviceValues.OverrideName + additionalLabels["lagoon.sh/template"] = fmt.Sprintf("%s-%s", serviceType.Name, "0.1.0") + additionalLabels["lagoon.sh/service"] = serviceValues.OverrideName + additionalLabels["lagoon.sh/service-type"] = serviceType.Name + + additionalAnnotations["k8up.syn.tools/backup"] = strconv.FormatBool(serviceTypeValues.Volumes.Backup) + additionalAnnotations["k8up.io/backup"] = strconv.FormatBool(serviceTypeValues.Volumes.Backup) + + pvc := &corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: corev1.SchemeGroupVersion.Version, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: serviceValues.OverrideName, + }, + } + + if serviceTypeValues.Volumes.PersistentVolumeType == corev1.ReadWriteMany { + pvc.Spec.StorageClassName = helpers.StrPtr("bulk") + } + + // add any remaining changes that are shared between default and additional + err := updatePVC( + pvc, + &buildValues, + serviceValues.OverrideName, + persistentVolumeSize, + serviceTypeValues.Volumes.PersistentVolumeType, + labels, annotations, + additionalLabels, additionalAnnotations, + ) + if err != nil { + return nil, err + } + // end PVC template + return pvc, nil +} + +// generateAdditionalPVC additional volumes have different labels/annotations to a default, and also handle some configuration a bit differently +func generateAdditionalPVC( + buildValues generator.BuildValues, + additionalVolume generator.ComposeVolume, + labels, annotations map[string]string, +) (*corev1.PersistentVolumeClaim, error) { + additionalLabels := map[string]string{} + additionalAnnotations := map[string]string{} + + additionalLabels["app.kubernetes.io/name"] = lagoon.GetVolumeNameFromLagoonVolume(additionalVolume.Name) + additionalLabels["app.kubernetes.io/instance"] = additionalVolume.Name + additionalLabels["lagoon.sh/template"] = fmt.Sprintf("%s-%s", "additional-volume", "0.1.0") + additionalLabels["lagoon.sh/service-type"] = "additional-volume" + + additionalAnnotations["k8up.syn.tools/backup"] = "true" + additionalAnnotations["k8up.io/backup"] = "true" + + pvc := &corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: corev1.SchemeGroupVersion.Version, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: additionalVolume.Name, + }, + } + + // add any remaining changes that are shared between default and additional + err := updatePVC( + pvc, + &buildValues, + additionalVolume.Name, + additionalVolume.Size, + corev1.ReadWriteMany, + labels, annotations, + additionalLabels, additionalAnnotations, + ) + if err != nil { + return nil, err + } + // end PVC template + return pvc, nil +} + +// handle the remaining changes to the pvc that differentiate it from a persistent default volume and an additional volume +func updatePVC( + pvc *corev1.PersistentVolumeClaim, + buildValues *generator.BuildValues, + name, size string, + mode corev1.PersistentVolumeAccessMode, + labels, annotations, additionalLabels, additionalAnnotations map[string]string, +) error { + labelsCopy := &map[string]string{} + helpers.DeepCopy(labels, labelsCopy) + annotationsCopy := &map[string]string{} + helpers.DeepCopy(annotations, annotationsCopy) + + for key, value := range additionalLabels { + (*labelsCopy)[key] = value + } + // add any additional annotations + for key, value := range additionalAnnotations { + (*annotationsCopy)[key] = value + } + pvc.ObjectMeta.Labels = *labelsCopy + pvc.ObjectMeta.Annotations = *annotationsCopy + // validate any annotations + if err := apivalidation.ValidateAnnotations(pvc.ObjectMeta.Annotations, nil); err != nil { + if len(err) != 0 { + return fmt.Errorf("the annotations for %s are not valid: %v", name, err) + } + } + // validate any labels + if err := metavalidation.ValidateLabels(pvc.ObjectMeta.Labels, nil); err != nil { + if len(err) != 0 { + return fmt.Errorf("the labels for %s are not valid: %v", name, err) + } + } + // check length of labels + err := helpers.CheckLabelLength(pvc.ObjectMeta.Labels) + if err != nil { + return err + } + + // start PVC templating + // this error is also checked in composeToServiceValues + q, err := resource.ParseQuantity(size) + if err != nil { + return fmt.Errorf("provided persistent volume size is not valid: %v", err) + } + volumeSize, _ := q.AsInt64() + pvc.Spec = corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{ + mode, + }, + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + "storage": *resource.NewQuantity(volumeSize, resource.BinarySI), + }, + }, + } + if mode == corev1.ReadWriteMany { + pvc.Spec.StorageClassName = helpers.StrPtr("bulk") + } + if buildValues.RWX2RWO || buildValues.IsCI { + // this should be a rwo volume in CI and if the rwx2rwo flag is enabled + pvc.Spec.AccessModes = []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteOnce, + } + } + return nil +} From 2d07e299d46447c1aa5b38cc906d87ae2aa53d3c Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 Jul 2024 09:23:31 +1000 Subject: [PATCH 03/10] test: add test data for additional volumes --- cmd/validate_compose.go | 2 +- internal/generator/services.go | 4 +- internal/generator/services_test.go | 11 +- .../docker-compose.multiple-volumes-2.yml | 51 +++++++ .../basic/docker-compose.multiple-volumes.yml | 53 +++++++ .../basic/lagoon.multiple-volumes-2.yml | 10 ++ .../basic/lagoon.multiple-volumes.yml | 10 ++ .../service7/deployment-node.yaml | 47 +++--- .../service7/pvc-custom-config.yaml | 29 ++++ .../service7/pvc-custom-files.yaml | 29 ++++ .../service7/pvc-custom-notused.yaml | 29 ++++ .../service-templates/service7/pvc-node.yaml | 30 ++++ .../service7/service-node.yaml | 22 +-- .../docker-compose.multiple-volumes.yml | 72 +++++++++ .../complex/lagoon.multiple-volumes.yml | 10 ++ .../service5/deployment-cli.yaml | 27 ++-- .../service5/deployment-mariadb.yaml | 95 ++++++++++++ .../service5/deployment-nginx.yaml | 141 ++++++++++++++++++ .../service5/pvc-custom-files.yaml | 29 ++++ .../service5/pvc-mariadb.yaml | 29 ++++ .../service-templates/service5/pvc-nginx.yaml | 30 ++++ .../service5/service-mariadb.yaml | 31 ++++ .../service5/service-nginx.yaml | 31 ++++ .../docker-compose/test12/docker-compose.yml | 43 ++++++ 24 files changed, 809 insertions(+), 56 deletions(-) create mode 100644 internal/testdata/basic/docker-compose.multiple-volumes-2.yml create mode 100644 internal/testdata/basic/docker-compose.multiple-volumes.yml create mode 100644 internal/testdata/basic/lagoon.multiple-volumes-2.yml create mode 100644 internal/testdata/basic/lagoon.multiple-volumes.yml create mode 100644 internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml create mode 100644 internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml create mode 100644 internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml create mode 100644 internal/testdata/basic/service-templates/service7/pvc-node.yaml create mode 100644 internal/testdata/complex/docker-compose.multiple-volumes.yml create mode 100644 internal/testdata/complex/lagoon.multiple-volumes.yml create mode 100644 internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml create mode 100644 internal/testdata/complex/service-templates/service5/deployment-nginx.yaml create mode 100644 internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml create mode 100644 internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml create mode 100644 internal/testdata/complex/service-templates/service5/pvc-nginx.yaml create mode 100644 internal/testdata/complex/service-templates/service5/service-mariadb.yaml create mode 100644 internal/testdata/complex/service-templates/service5/service-nginx.yaml create mode 100644 internal/testdata/docker-compose/test12/docker-compose.yml diff --git a/cmd/validate_compose.go b/cmd/validate_compose.go index ad7d55e3..02ea7086 100644 --- a/cmd/validate_compose.go +++ b/cmd/validate_compose.go @@ -60,7 +60,7 @@ var validateDockerComposeWithErrors = &cobra.Command{ // ValidateDockerCompose validate a docker-compose file func ValidateDockerCompose(file string, ignoreErrors, ignoreMisEnvFiles bool) error { - _, _, err := lagoon.UnmarshaDockerComposeYAML(file, ignoreErrors, ignoreMisEnvFiles, map[string]string{}) + _, _, _, err := lagoon.UnmarshaDockerComposeYAML(file, ignoreErrors, ignoreMisEnvFiles, map[string]string{}) if err != nil { return err } diff --git a/internal/generator/services.go b/internal/generator/services.go index 58a3964c..856b9824 100644 --- a/internal/generator/services.go +++ b/internal/generator/services.go @@ -286,11 +286,11 @@ func composeToServiceValues( } } - baseimage := lagoon.CheckServiceLagoonLabel(composeServiceValues.Labels, "lagoon.base.image") + baseimage := lagoon.CheckDockerComposeLagoonLabel(composeServiceValues.Labels, "lagoon.base.image") if baseimage != "" { // First, let's ensure that the structure of the base image is valid if !reference.ReferenceRegexp.MatchString(baseimage) { - return ServiceValues{}, fmt.Errorf("the 'lagoon.base.image' label defined on service %s in the docker-compose file is invalid ('%s') - please ensure it conforms to the structure `[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG|@DIGEST]`", composeService, baseimage) + return nil, fmt.Errorf("the 'lagoon.base.image' label defined on service %s in the docker-compose file is invalid ('%s') - please ensure it conforms to the structure `[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG|@DIGEST]`", composeService, baseimage) } buildValues.ForcePullImages = append(buildValues.ForcePullImages, baseimage) } diff --git a/internal/generator/services_test.go b/internal/generator/services_test.go index 19c03796..f262b137 100644 --- a/internal/generator/services_test.go +++ b/internal/generator/services_test.go @@ -2,13 +2,14 @@ package generator import ( "encoding/json" + "reflect" + "testing" + "time" + composetypes "github.com/compose-spec/compose-go/types" "github.com/uselagoon/build-deploy-tool/internal/dbaasclient" "github.com/uselagoon/build-deploy-tool/internal/helpers" "github.com/uselagoon/build-deploy-tool/internal/lagoon" - "reflect" - "testing" - "time" ) func Test_composeToServiceValues(t *testing.T) { @@ -755,7 +756,7 @@ func Test_composeToServiceValues(t *testing.T) { }, }, }, - want: ServiceValues{ + want: &ServiceValues{ Name: "nginx", OverrideName: "nginx", Type: "nginx", @@ -1231,7 +1232,7 @@ func Test_composeToServiceValues(t *testing.T) { Image: "uselagoon/fake-redis:7", }, }, - want: ServiceValues{}, + want: nil, wantErr: true, }, } diff --git a/internal/testdata/basic/docker-compose.multiple-volumes-2.yml b/internal/testdata/basic/docker-compose.multiple-volumes-2.yml new file mode 100644 index 00000000..86bea115 --- /dev/null +++ b/internal/testdata/basic/docker-compose.multiple-volumes-2.yml @@ -0,0 +1,51 @@ +version: '2' +services: + node: + networks: + - amazeeio-network + - default + build: + context: internal/testdata/basic/docker + dockerfile: basic.dockerfile + labels: + lagoon.type: basic + lagoon.volumes.files.path: /app/files/ + lagoon.volumes.config.path: /config + lagoon.volumes.node.path: /data + volumes: + - node:/data + - files:/app/files + - config:/config + + mariadb: + image: uselagoon/mariadb-10.5-drupal:latest + labels: + lagoon.type: none + volumes: + - db:/var/lib/mysql + +networks: + amazeeio-network: + external: true + +volumes: + node: + labels: + lagoon.type: persistent + config: + labels: + lagoon.type: persistent + files: + labels: + lagoon.type: persistent + lagoon.persistent.size: 10Gi + db: + labels: + # this label is not technically needed, but explicit + lagoon.type: none + notused: + labels: + # will create a pvc, but as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be mounted + lagoon.type: persistent + logs: + {} \ No newline at end of file diff --git a/internal/testdata/basic/docker-compose.multiple-volumes.yml b/internal/testdata/basic/docker-compose.multiple-volumes.yml new file mode 100644 index 00000000..90f7ec34 --- /dev/null +++ b/internal/testdata/basic/docker-compose.multiple-volumes.yml @@ -0,0 +1,53 @@ +version: '2' +services: + node: + networks: + - amazeeio-network + - default + build: + context: internal/testdata/basic/docker + dockerfile: basic.dockerfile + labels: + lagoon.type: basic-persistent + lagoon.persistent: /data + lagoon.persistent.name: node # this is only required if shared between services + lagoon.volumes.files.path: /app/files/ + lagoon.volumes.config.path: /config + lagoon.volumes.node.path: /data # this is ignored if the default persistent volume has the same name + volumes: + - files:/app/files + - config:/config + + mariadb: + image: uselagoon/mariadb-10.5-drupal:latest + labels: + lagoon.type: none + volumes: + - db:/var/lib/mysql + +networks: + amazeeio-network: + external: true + +volumes: + node: + labels: + # this is ignored if a default persistent volume has the same name + lagoon.type: persistent + config: + labels: + lagoon.type: persistent + files: + labels: + lagoon.type: persistent + lagoon.persistent.size: 10Gi + db: + labels: + # this label is not technically needed, but explicit + lagoon.type: none + notused: + labels: + # will create a pvc, but as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be mounted + lagoon.type: persistent + logs: + {} \ No newline at end of file diff --git a/internal/testdata/basic/lagoon.multiple-volumes-2.yml b/internal/testdata/basic/lagoon.multiple-volumes-2.yml new file mode 100644 index 00000000..41e77072 --- /dev/null +++ b/internal/testdata/basic/lagoon.multiple-volumes-2.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: internal/testdata/basic/docker-compose.multiple-volumes-2.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com diff --git a/internal/testdata/basic/lagoon.multiple-volumes.yml b/internal/testdata/basic/lagoon.multiple-volumes.yml new file mode 100644 index 00000000..ddff9f9a --- /dev/null +++ b/internal/testdata/basic/lagoon.multiple-volumes.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: internal/testdata/basic/docker-compose.multiple-volumes.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com diff --git a/internal/testdata/basic/service-templates/service7/deployment-node.yaml b/internal/testdata/basic/service-templates/service7/deployment-node.yaml index a2d01522..5567c6ba 100644 --- a/internal/testdata/basic/service-templates/service7/deployment-node.yaml +++ b/internal/testdata/basic/service-templates/service7/deployment-node.yaml @@ -9,21 +9,21 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 name: node spec: replicas: 1 selector: matchLabels: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent strategy: {} template: metadata: @@ -35,22 +35,20 @@ spec: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 spec: containers: - env: - name: LAGOON_GIT_SHA value: abcdefg123456 - name: CRONJOBS - value: | - 3,18,33,48 0 * * * drush cron - name: SERVICE_NAME value: node envFrom: @@ -61,31 +59,42 @@ spec: livenessProbe: initialDelaySeconds: 60 tcpSocket: - port: 1234 + port: 3000 timeoutSeconds: 10 name: basic ports: - - containerPort: 1234 - name: tcp-1234 + - containerPort: 3000 + name: http protocol: TCP - - containerPort: 8191 - name: tcp-8191 - protocol: TCP - - containerPort: 9001 - name: udp-9001 - protocol: UDP readinessProbe: initialDelaySeconds: 1 tcpSocket: - port: 1234 + port: 3000 timeoutSeconds: 1 resources: requests: cpu: 10m memory: 10Mi securityContext: {} + volumeMounts: + - mountPath: /config + name: custom-config + - mountPath: /app/files/ + name: custom-files + - mountPath: /data + name: node enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production + volumes: + - name: custom-config + persistentVolumeClaim: + claimName: custom-config + - name: custom-files + persistentVolumeClaim: + claimName: custom-files + - name: node + persistentVolumeClaim: + claimName: node status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml b/internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml new file mode 100644 index 00000000..c1465784 --- /dev/null +++ b/internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-config + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: config + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-config +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml b/internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml new file mode 100644 index 00000000..dfe9d701 --- /dev/null +++ b/internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-files + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: files + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-files +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 10Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml b/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml new file mode 100644 index 00000000..3b092073 --- /dev/null +++ b/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-notused + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: notused + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-notused +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-node.yaml b/internal/testdata/basic/service-templates/service7/pvc-node.yaml new file mode 100644 index 00000000..44cfd035 --- /dev/null +++ b/internal/testdata/basic/service-templates/service7/pvc-node.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 + name: node +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service7/service-node.yaml b/internal/testdata/basic/service-templates/service7/service-node.yaml index 6b286993..fa68a29f 100644 --- a/internal/testdata/basic/service-templates/service7/service-node.yaml +++ b/internal/testdata/basic/service-templates/service7/service-node.yaml @@ -9,31 +9,23 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 name: node spec: ports: - - name: tcp-1234 - port: 1234 + - name: http + port: 3000 protocol: TCP - targetPort: tcp-1234 - - name: tcp-8191 - port: 8191 - protocol: TCP - targetPort: tcp-8191 - - name: udp-9001 - port: 9001 - protocol: UDP - targetPort: udp-9001 + targetPort: http selector: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent status: loadBalancer: {} diff --git a/internal/testdata/complex/docker-compose.multiple-volumes.yml b/internal/testdata/complex/docker-compose.multiple-volumes.yml new file mode 100644 index 00000000..e56fde53 --- /dev/null +++ b/internal/testdata/complex/docker-compose.multiple-volumes.yml @@ -0,0 +1,72 @@ +version: '2' +services: + cli: + build: + context: internal/testdata/complex/docker + dockerfile: builder.dockerfile + image: builder + labels: + lagoon.type: cli-persistent + lagoon.persistent: /app/web/sites/default/files/ + lagoon.persistent.name: nginx + lagoon.volumes.files.path: /app/otherfiles/ + environment: + LAGOON_PROJECT: ci-drupal + LAGOON_ROUTE: drupal9-mariadb.docker.amazee.io + volumes: + - ./web:/app/web:delegated + nginx: + networks: + - amazeeio-network + - default + build: + context: internal/testdata/complex/docker + dockerfile: nginx.dockerfile + labels: + lagoon.type: nginx-php-persistent + lagoon.persistent: /app/web/sites/default/files/ + lagoon.persistent.size: 1Gi + lagoon.name: nginx + lagoon.deployment.servicetype: nginx + lagoon.volumes.files.path: /app/otherfiles/ + volumes: + - ./web:/app/web:delegated + depends_on: + - cli + expose: + - "8080" + environment: + LAGOON_LOCALDEV_URL: drupal9-mariadb.docker.amazee.io + php: + build: + context: internal/testdata/complex/docker + dockerfile: php.dockerfile + labels: + lagoon.type: nginx-php-persistent + lagoon.persistent: /app/web/sites/default/files/ + lagoon.name: nginx + lagoon.deployment.servicetype: php + lagoon.volumes.files.path: /app/otherfiles/ + volumes: + - ./web:/app/web:delegated + depends_on: + - cli + mariadb: + build: + context: internal/testdata/complex/docker + dockerfile: mariadb.dockerfile + labels: + lagoon.type: mariadb-single +networks: + amazeeio-network: + external: true + +volumes: + nginx: + labels: + # this is ignored if a default persistent volume has the same name + lagoon.type: persistent + files: + labels: + lagoon.type: persistent + lagoon.persistent.size: 10Gi \ No newline at end of file diff --git a/internal/testdata/complex/lagoon.multiple-volumes.yml b/internal/testdata/complex/lagoon.multiple-volumes.yml new file mode 100644 index 00000000..7c618c24 --- /dev/null +++ b/internal/testdata/complex/lagoon.multiple-volumes.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: internal/testdata/complex/docker-compose.multiple-volumes.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com diff --git a/internal/testdata/complex/service-templates/service5/deployment-cli.yaml b/internal/testdata/complex/service-templates/service5/deployment-cli.yaml index ac370e98..af6122d3 100644 --- a/internal/testdata/complex/service-templates/service5/deployment-cli.yaml +++ b/internal/testdata/complex/service-templates/service5/deployment-cli.yaml @@ -47,10 +47,8 @@ spec: containers: - env: - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" + value: abcdefg123456 - name: CRONJOBS - value: | - 3,18,33,48 * * * * drush cron - name: SERVICE_NAME value: cli envFrom: @@ -78,26 +76,27 @@ spec: - mountPath: /var/run/secrets/lagoon/sshkey/ name: lagoon-sshkey readOnly: true - - mountPath: /app/docroot/sites/default/files//php - name: nginx-php-twig - - mountPath: /app/docroot/sites/default/files/ - name: nginx-php + - mountPath: /app/otherfiles/ + name: custom-files + - mountPath: /app/web/sites/default/files//php + name: nginx-twig + - mountPath: /app/web/sites/default/files/ + name: nginx enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 volumes: + - name: custom-files + persistentVolumeClaim: + claimName: custom-files - name: lagoon-sshkey secret: defaultMode: 420 secretName: lagoon-sshkey - emptyDir: {} - name: nginx-php-twig - - name: nginx-php + name: nginx-twig + - name: nginx persistentVolumeClaim: - claimName: nginx-php + claimName: nginx status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml b/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml new file mode 100644 index 00000000..ef5a6710 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml @@ -0,0 +1,95 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: mariadb-single + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: mariadb + lagoon.sh/service-type: mariadb-single + lagoon.sh/template: mariadb-single-0.1.0 + name: mariadb +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/name: mariadb-single + strategy: + type: Recreate + template: + metadata: + annotations: + k8up.syn.tools/backupcommand: /bin/sh -c 'mysqldump --max-allowed-packet=1G + --events --routines --quick --add-locks --no-autocommit --single-transaction + --all-databases' + k8up.syn.tools/file-extension: .mariadb.sql + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: mariadb-single + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: mariadb + lagoon.sh/service-type: mariadb-single + lagoon.sh/template: mariadb-single-0.1.0 + spec: + containers: + - env: + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: CRONJOBS + - name: SERVICE_NAME + value: mariadb + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/mariadb@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + livenessProbe: + initialDelaySeconds: 120 + periodSeconds: 5 + tcpSocket: + port: 3306 + name: mariadb-single + ports: + - containerPort: 3306 + name: 3306-tcp + protocol: TCP + readinessProbe: + initialDelaySeconds: 1 + tcpSocket: + port: 3306 + timeoutSeconds: 1 + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + volumeMounts: + - mountPath: /var/lib/mysql + name: mariadb + enableServiceLinks: true + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + volumes: + - name: mariadb + persistentVolumeClaim: + claimName: mariadb +status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml b/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml new file mode 100644 index 00000000..1ad26dc9 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml @@ -0,0 +1,141 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: nginx + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: nginx-php-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: nginx + lagoon.sh/service-type: nginx-php-persistent + lagoon.sh/template: nginx-php-persistent-0.1.0 + name: nginx +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/instance: nginx + app.kubernetes.io/name: nginx-php-persistent + strategy: {} + template: + metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: nginx + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: nginx-php-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: nginx + lagoon.sh/service-type: nginx-php-persistent + lagoon.sh/template: nginx-php-persistent-0.1.0 + spec: + containers: + - env: + - name: NGINX_FASTCGI_PASS + value: 127.0.0.1 + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: CRONJOBS + - name: SERVICE_NAME + value: nginx + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/nginx@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + livenessProbe: + failureThreshold: 5 + httpGet: + path: /nginx_status + port: 50000 + initialDelaySeconds: 900 + timeoutSeconds: 3 + name: nginx + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: /nginx_status + port: 50000 + initialDelaySeconds: 1 + timeoutSeconds: 3 + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + volumeMounts: + - mountPath: /app/otherfiles/ + name: custom-files + - mountPath: /app/web/sites/default/files/ + name: nginx + - env: + - name: NGINX_FASTCGI_PASS + value: 127.0.0.1 + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: SERVICE_NAME + value: nginx + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/php@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + livenessProbe: + initialDelaySeconds: 60 + periodSeconds: 10 + tcpSocket: + port: 9000 + name: php + ports: + - containerPort: 9000 + name: http + protocol: TCP + readinessProbe: + initialDelaySeconds: 2 + periodSeconds: 10 + tcpSocket: + port: 9000 + resources: + requests: + cpu: 10m + memory: 100Mi + securityContext: {} + volumeMounts: + - mountPath: /app/otherfiles/ + name: custom-files + - mountPath: /app/web/sites/default/files/ + name: nginx + - mountPath: /app/web/sites/default/files//php + name: nginx-twig + enableServiceLinks: false + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + volumes: + - name: custom-files + persistentVolumeClaim: + claimName: custom-files + - name: nginx + persistentVolumeClaim: + claimName: nginx + - emptyDir: {} + name: nginx-twig +status: {} diff --git a/internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml b/internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml new file mode 100644 index 00000000..dfe9d701 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-files + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: files + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-files +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 10Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml b/internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml new file mode 100644 index 00000000..cc1cd892 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "false" + k8up.syn.tools/backup: "false" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: mariadb-single + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: mariadb + lagoon.sh/service-type: mariadb-single + lagoon.sh/template: mariadb-single-0.1.0 + name: mariadb +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +status: {} diff --git a/internal/testdata/complex/service-templates/service5/pvc-nginx.yaml b/internal/testdata/complex/service-templates/service5/pvc-nginx.yaml new file mode 100644 index 00000000..73fa588d --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/pvc-nginx.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: nginx + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: nginx-php-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: nginx + lagoon.sh/service-type: nginx-php-persistent + lagoon.sh/template: nginx-php-persistent-0.1.0 + name: nginx +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/complex/service-templates/service5/service-mariadb.yaml b/internal/testdata/complex/service-templates/service5/service-mariadb.yaml new file mode 100644 index 00000000..d0b63661 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/service-mariadb.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: mariadb-single + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: mariadb + lagoon.sh/service-type: mariadb-single + lagoon.sh/template: mariadb-single-0.1.0 + name: mariadb +spec: + ports: + - name: 3306-tcp + port: 3306 + protocol: TCP + targetPort: 3306 + selector: + app.kubernetes.io/instance: mariadb + app.kubernetes.io/name: mariadb-single +status: + loadBalancer: {} diff --git a/internal/testdata/complex/service-templates/service5/service-nginx.yaml b/internal/testdata/complex/service-templates/service5/service-nginx.yaml new file mode 100644 index 00000000..57cb9386 --- /dev/null +++ b/internal/testdata/complex/service-templates/service5/service-nginx.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: nginx + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: nginx-php-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: nginx + lagoon.sh/service-type: nginx-php-persistent + lagoon.sh/template: nginx-php-persistent-0.1.0 + name: nginx +spec: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: nginx + app.kubernetes.io/name: nginx-php-persistent +status: + loadBalancer: {} diff --git a/internal/testdata/docker-compose/test12/docker-compose.yml b/internal/testdata/docker-compose/test12/docker-compose.yml new file mode 100644 index 00000000..4d85b9d6 --- /dev/null +++ b/internal/testdata/docker-compose/test12/docker-compose.yml @@ -0,0 +1,43 @@ +version: '2' +services: + node: + networks: + - amazeeio-network + - default + build: + context: . + dockerfile: node.dockerfile + labels: + lagoon.type: node + volumes: + - node:/app + - config:/config + - files:/files + environment: + - LAGOON_LOCALDEV_HTTP_PORT=3000 + - LAGOON_ROUTE=http://node.docker.amazee.io + +networks: + amazeeio-network: + external: true + +volumes: + node: + labels: + lagoon.type: persistent + config: + labels: + lagoon.type: persistent + files: + labels: + lagoon.type: persistent + lagoon.persistent.size: 10Gi + db: + labels: + # this label is not technically needed, but explicit + lagoon.type: none + notused: + labels: + lagoon.type: persistent + logs: + {} \ No newline at end of file From c054b507473acdb5c06fd6341f95a6eb24236f70 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 Jul 2024 09:24:05 +1000 Subject: [PATCH 04/10] chore: update cmd tests and validation for docker-compose --- cmd/template_lagoonservices_test.go | 81 ++++++--- ...ob-cronjob-node-some-other-drush-cron.yaml | 77 --------- .../service9/deployment-node.yaml} | 64 +++++--- .../service9/pvc-custom-config.yaml} | 11 +- .../service9/pvc-custom-files.yaml | 29 ++++ .../service9/pvc-custom-node.yaml | 29 ++++ .../service9/pvc-custom-notused.yaml | 29 ++++ .../service9/service-node.yaml} | 22 +-- .../cronjob-cronjob-cli-drush-cron2.yaml | 103 ------------ .../service5/deployment-mariadb.yaml | 2 + .../service5/deployment-nginx-php.yaml | 155 ------------------ .../service5/deployment-nginx.yaml | 4 +- .../service5/deployment-redis.yaml | 87 ---------- .../service5/service-nginx-php.yaml | 31 ---- .../service5/service-varnish.yaml | 35 ---- 15 files changed, 198 insertions(+), 561 deletions(-) delete mode 100644 internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml rename internal/testdata/{complex/service-templates/service5/deployment-varnish.yaml => basic/service-templates/service9/deployment-node.yaml} (57%) rename internal/testdata/{complex/service-templates/service5/pvc-nginx-php.yaml => basic/service-templates/service9/pvc-custom-config.yaml} (69%) create mode 100644 internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml create mode 100644 internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml create mode 100644 internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml rename internal/testdata/{complex/service-templates/service5/service-redis.yaml => basic/service-templates/service9/service-node.yaml} (57%) delete mode 100644 internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml delete mode 100644 internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml delete mode 100644 internal/testdata/complex/service-templates/service5/deployment-redis.yaml delete mode 100644 internal/testdata/complex/service-templates/service5/service-nginx-php.yaml delete mode 100644 internal/testdata/complex/service-templates/service5/service-varnish.yaml diff --git a/cmd/template_lagoonservices_test.go b/cmd/template_lagoonservices_test.go index 3519cc2f..d96db288 100644 --- a/cmd/template_lagoonservices_test.go +++ b/cmd/template_lagoonservices_test.go @@ -100,32 +100,6 @@ func TestTemplateLagoonServices(t *testing.T) { templatePath: "testoutput", want: "internal/testdata/complex/service-templates/service1", }, - { - name: "test2b nginx-php deployment - rootless", - args: testdata.GetSeedData( - testdata.TestData{ - ProjectName: "example-project", - EnvironmentName: "main", - Branch: "main", - LagoonYAML: "internal/testdata/complex/lagoon.varnish.yml", - ImageReferences: map[string]string{ - "nginx": "harbor.example/example-project/main/nginx@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", - "php": "harbor.example/example-project/main/php@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", - "cli": "harbor.example/example-project/main/cli@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", - "redis": "harbor.example/example-project/main/redis@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", - "varnish": "harbor.example/example-project/main/varnish@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", - }, - ProjectVariables: []lagoon.EnvironmentVariable{ - { - Name: "LAGOON_FEATURE_FLAG_ROOTLESS_WORKLOAD", - Value: "enabled", - Scope: "build", - }, - }, - }, true), - templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service2", - }, { name: "test2b nginx-php deployment - rootless workloads enabled", args: testdata.GetSeedData( @@ -150,7 +124,7 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service5", + want: "internal/testdata/complex/service-templates/service2", }, { name: "test2c nginx-php deployment - spot workloads enabled", @@ -365,6 +339,59 @@ func TestTemplateLagoonServices(t *testing.T) { templatePath: "testoutput", want: "internal/testdata/basic/service-templates/service8", }, + { + name: "test11 basic-persistent deployment multiple volumes", + args: testdata.GetSeedData( + testdata.TestData{ + ProjectName: "example-project", + EnvironmentName: "main", + Branch: "main", + BuildType: "branch", + LagoonYAML: "internal/testdata/basic/lagoon.multiple-volumes.yml", + ImageReferences: map[string]string{ + "node": "harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + }, + }, true), + templatePath: "testoutput", + want: "internal/testdata/basic/service-templates/service7", + }, + { + name: "test12 basic deployment multiple volumes", + args: testdata.GetSeedData( + testdata.TestData{ + ProjectName: "example-project", + EnvironmentName: "main", + Branch: "main", + BuildType: "branch", + LagoonYAML: "internal/testdata/basic/lagoon.multiple-volumes-2.yml", + ImageReferences: map[string]string{ + "node": "harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + }, + }, true), + templatePath: "testoutput", + want: "internal/testdata/basic/service-templates/service9", + }, + { + name: "test13 complex deployment multiple volumes", + args: testdata.GetSeedData( + testdata.TestData{ + ProjectName: "example-project", + EnvironmentName: "main", + Branch: "main", + BuildType: "branch", + LagoonYAML: "internal/testdata/complex/lagoon.multiple-volumes.yml", + ImageReferences: map[string]string{ + "nginx": "harbor.example/example-project/main/nginx@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + "php": "harbor.example/example-project/main/php@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + "cli": "harbor.example/example-project/main/cli@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + "nginx2": "harbor.example/example-project/main/nginx2@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + "php2": "harbor.example/example-project/main/php2@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + "mariadb": "harbor.example/example-project/main/mariadb@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + }, + }, true), + templatePath: "testoutput", + want: "internal/testdata/complex/service-templates/service5", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml b/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml deleted file mode 100644 index 225aa2ce..00000000 --- a/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml +++ /dev/null @@ -1,77 +0,0 @@ ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: build-deploy-tool - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 - name: cronjob-node-some-other-drush-cron -spec: - concurrencyPolicy: Forbid - failedJobsHistoryLimit: 1 - jobTemplate: - metadata: - creationTimestamp: null - spec: - template: - metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/configMapSha: abcdefg1234567890 - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: build-deploy-tool - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 - spec: - containers: - - command: - - /lagoon/cronjob.sh - - drush cron - env: - - name: LAGOON_GIT_SHA - value: abcdefg123456 - - name: SERVICE_NAME - value: node - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - name: cronjob-node-some-other-drush-cron - resources: - requests: - cpu: 10m - memory: 10Mi - securityContext: {} - dnsConfig: - options: - - name: timeout - value: "60" - - name: attempts - value: "10" - enableServiceLinks: false - imagePullSecrets: - - name: lagoon-internal-registry-secret - priorityClassName: lagoon-priority-production - restartPolicy: Never - schedule: 10 2 * * * - startingDeadlineSeconds: 240 - successfulJobsHistoryLimit: 0 -status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-varnish.yaml b/internal/testdata/basic/service-templates/service9/deployment-node.yaml similarity index 57% rename from internal/testdata/complex/service-templates/service5/deployment-varnish.yaml rename to internal/testdata/basic/service-templates/service9/deployment-node.yaml index a1f2743d..023013ad 100644 --- a/internal/testdata/complex/service-templates/service5/deployment-varnish.yaml +++ b/internal/testdata/basic/service-templates/service9/deployment-node.yaml @@ -7,23 +7,23 @@ metadata: lagoon.sh/version: v2.7.x creationTimestamp: null labels: - app.kubernetes.io/instance: varnish + app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: varnish + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project - lagoon.sh/service: varnish - lagoon.sh/service-type: varnish - lagoon.sh/template: varnish-0.1.0 - name: varnish + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node spec: replicas: 1 selector: matchLabels: - app.kubernetes.io/instance: varnish - app.kubernetes.io/name: varnish + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic strategy: {} template: metadata: @@ -33,58 +33,68 @@ spec: lagoon.sh/version: v2.7.x creationTimestamp: null labels: - app.kubernetes.io/instance: varnish + app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: varnish + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project - lagoon.sh/service: varnish - lagoon.sh/service-type: varnish - lagoon.sh/template: varnish-0.1.0 + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 spec: containers: - env: - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" + value: abcdefg123456 - name: CRONJOBS - name: SERVICE_NAME - value: varnish + value: node envFrom: - configMapRef: name: lagoon-env - image: harbor.example/example-project/main/varnish@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + image: harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 imagePullPolicy: Always livenessProbe: initialDelaySeconds: 60 tcpSocket: - port: 8080 + port: 3000 timeoutSeconds: 10 - name: varnish + name: basic ports: - - containerPort: 8080 + - containerPort: 3000 name: http protocol: TCP - - containerPort: 6082 - name: controlport - protocol: TCP readinessProbe: initialDelaySeconds: 1 tcpSocket: - port: 8080 + port: 3000 timeoutSeconds: 1 resources: requests: cpu: 10m memory: 10Mi securityContext: {} + volumeMounts: + - mountPath: /data + name: custom-node + - mountPath: /config + name: custom-config + - mountPath: /app/files/ + name: custom-files enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 + volumes: + - name: custom-node + persistentVolumeClaim: + claimName: custom-node + - name: custom-config + persistentVolumeClaim: + claimName: custom-config + - name: custom-files + persistentVolumeClaim: + claimName: custom-files status: {} diff --git a/internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml b/internal/testdata/basic/service-templates/service9/pvc-custom-config.yaml similarity index 69% rename from internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml rename to internal/testdata/basic/service-templates/service9/pvc-custom-config.yaml index 9705d159..c1465784 100644 --- a/internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml +++ b/internal/testdata/basic/service-templates/service9/pvc-custom-config.yaml @@ -9,17 +9,16 @@ metadata: lagoon.sh/version: v2.7.x creationTimestamp: null labels: - app.kubernetes.io/instance: nginx-php + app.kubernetes.io/instance: custom-config app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: nginx-php-persistent + app.kubernetes.io/name: config lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project - lagoon.sh/service: nginx-php - lagoon.sh/service-type: nginx-php-persistent - lagoon.sh/template: nginx-php-persistent-0.1.0 - name: nginx-php + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-config spec: accessModes: - ReadWriteMany diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml b/internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml new file mode 100644 index 00000000..dfe9d701 --- /dev/null +++ b/internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-files + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: files + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-files +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 10Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml b/internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml new file mode 100644 index 00000000..d83a6615 --- /dev/null +++ b/internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: node + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-node +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml b/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml new file mode 100644 index 00000000..3b092073 --- /dev/null +++ b/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-notused + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: notused + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-notused +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/complex/service-templates/service5/service-redis.yaml b/internal/testdata/basic/service-templates/service9/service-node.yaml similarity index 57% rename from internal/testdata/complex/service-templates/service5/service-redis.yaml rename to internal/testdata/basic/service-templates/service9/service-node.yaml index e0c26762..3d4d875d 100644 --- a/internal/testdata/complex/service-templates/service5/service-redis.yaml +++ b/internal/testdata/basic/service-templates/service9/service-node.yaml @@ -7,25 +7,25 @@ metadata: lagoon.sh/version: v2.7.x creationTimestamp: null labels: - app.kubernetes.io/instance: redis + app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: redis + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project - lagoon.sh/service: redis - lagoon.sh/service-type: redis - lagoon.sh/template: redis-0.1.0 - name: redis + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node spec: ports: - - name: 6379-tcp - port: 6379 + - name: http + port: 3000 protocol: TCP - targetPort: 6379 + targetPort: http selector: - app.kubernetes.io/instance: redis - app.kubernetes.io/name: redis + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic status: loadBalancer: {} diff --git a/internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml b/internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml deleted file mode 100644 index 0f77f760..00000000 --- a/internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml +++ /dev/null @@ -1,103 +0,0 @@ ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: cronjob-cli - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: cronjob-cli-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: cli - lagoon.sh/service-type: cli-persistent - lagoon.sh/template: cli-persistent-0.1.0 - name: cronjob-cli-drush-cron2 -spec: - concurrencyPolicy: Forbid - failedJobsHistoryLimit: 1 - jobTemplate: - metadata: - creationTimestamp: null - spec: - template: - metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/configMapSha: abcdefg1234567890 - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: cronjob-cli - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: cronjob-cli-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: cli - lagoon.sh/service-type: cli-persistent - lagoon.sh/template: cli-persistent-0.1.0 - spec: - containers: - - command: - - /lagoon/cronjob.sh - - drush cron - env: - - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" - - name: SERVICE_NAME - value: cli - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/cli@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - name: cronjob-cli-drush-cron2 - resources: - requests: - cpu: 10m - memory: 10Mi - securityContext: {} - volumeMounts: - - mountPath: /var/run/secrets/lagoon/sshkey/ - name: lagoon-sshkey - readOnly: true - - mountPath: /app/docroot/sites/default/files//php - name: nginx-php-twig - - mountPath: /app/docroot/sites/default/files/ - name: nginx-php - dnsConfig: - options: - - name: timeout - value: "60" - - name: attempts - value: "10" - enableServiceLinks: false - imagePullSecrets: - - name: lagoon-internal-registry-secret - priorityClassName: lagoon-priority-production - restartPolicy: Never - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 - volumes: - - name: lagoon-sshkey - secret: - defaultMode: 420 - secretName: lagoon-sshkey - - emptyDir: {} - name: nginx-php-twig - - name: nginx-php - persistentVolumeClaim: - claimName: nginx-php - schedule: 18,48 * * * * - startingDeadlineSeconds: 240 - successfulJobsHistoryLimit: 0 -status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml b/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml index ef5a6710..3c3d4f5f 100644 --- a/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml +++ b/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml @@ -88,6 +88,8 @@ spec: imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production + securityContext: + fsGroup: 0 volumes: - name: mariadb persistentVolumeClaim: diff --git a/internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml b/internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml deleted file mode 100644 index 71cdbbae..00000000 --- a/internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml +++ /dev/null @@ -1,155 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: nginx-php - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: nginx-php-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: nginx-php - lagoon.sh/service-type: nginx-php-persistent - lagoon.sh/template: nginx-php-persistent-0.1.0 - name: nginx-php -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/instance: nginx-php - app.kubernetes.io/name: nginx-php-persistent - strategy: {} - template: - metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/configMapSha: abcdefg1234567890 - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: nginx-php - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: nginx-php-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: nginx-php - lagoon.sh/service-type: nginx-php-persistent - lagoon.sh/template: nginx-php-persistent-0.1.0 - spec: - containers: - - env: - - name: NGINX_FASTCGI_PASS - value: 127.0.0.1 - - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" - - name: CRONJOBS - - name: SERVICE_NAME - value: nginx-php - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/nginx@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - livenessProbe: - failureThreshold: 5 - httpGet: - path: /nginx_status - port: 50000 - initialDelaySeconds: 900 - timeoutSeconds: 3 - name: nginx - ports: - - containerPort: 8080 - name: http - protocol: TCP - readinessProbe: - httpGet: - path: /nginx_status - port: 50000 - initialDelaySeconds: 1 - timeoutSeconds: 3 - resources: - requests: - cpu: 10m - memory: 10Mi - securityContext: {} - volumeMounts: - - mountPath: /app/docroot/sites/default/files/ - name: nginx-php - - env: - - name: NGINX_FASTCGI_PASS - value: 127.0.0.1 - - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" - - name: SERVICE_NAME - value: nginx-php - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/php@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - livenessProbe: - initialDelaySeconds: 60 - periodSeconds: 10 - tcpSocket: - port: 9000 - name: php - ports: - - containerPort: 9000 - name: php - protocol: TCP - readinessProbe: - initialDelaySeconds: 2 - periodSeconds: 10 - tcpSocket: - port: 9000 - resources: - requests: - cpu: 10m - memory: 100Mi - securityContext: {} - volumeMounts: - - mountPath: /app/docroot/sites/default/files/ - name: nginx-php - - mountPath: /app/docroot/sites/default/files//php - name: nginx-php-twig - enableServiceLinks: false - imagePullSecrets: - - name: lagoon-internal-registry-secret - initContainers: - - command: - - sh - - -c - - "set -e\nSENTINEL=\"/storage/.lagoon-rootless-migration-complete\"\nif ! - [ -f \"$SENTINEL\" ]; then\n\tfind /storage -exec chown 10000:0 {} +\n\tfind - /storage -exec chmod a+r,u+w {} +\n\tfind /storage -type d -exec chmod a+x - {} +\n\ttouch \"$SENTINEL\"\nfi" - image: library/busybox:musl - imagePullPolicy: IfNotPresent - name: fix-storage-permissions - resources: {} - securityContext: - runAsUser: 0 - volumeMounts: - - mountPath: /storage - name: nginx-php - priorityClassName: lagoon-priority-production - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 - volumes: - - name: nginx-php - persistentVolumeClaim: - claimName: nginx-php - - emptyDir: {} - name: nginx-php-twig -status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml b/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml index 1ad26dc9..69c99ce7 100644 --- a/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml +++ b/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml @@ -19,7 +19,7 @@ metadata: lagoon.sh/template: nginx-php-persistent-0.1.0 name: nginx spec: - replicas: 2 + replicas: 1 selector: matchLabels: app.kubernetes.io/instance: nginx @@ -106,7 +106,7 @@ spec: name: php ports: - containerPort: 9000 - name: http + name: php protocol: TCP readinessProbe: initialDelaySeconds: 2 diff --git a/internal/testdata/complex/service-templates/service5/deployment-redis.yaml b/internal/testdata/complex/service-templates/service5/deployment-redis.yaml deleted file mode 100644 index 605ae453..00000000 --- a/internal/testdata/complex/service-templates/service5/deployment-redis.yaml +++ /dev/null @@ -1,87 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: redis - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: redis - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: redis - lagoon.sh/service-type: redis - lagoon.sh/template: redis-0.1.0 - name: redis -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/instance: redis - app.kubernetes.io/name: redis - strategy: {} - template: - metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/configMapSha: abcdefg1234567890 - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: redis - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: redis - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: redis - lagoon.sh/service-type: redis - lagoon.sh/template: redis-0.1.0 - spec: - containers: - - env: - - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" - - name: CRONJOBS - - name: SERVICE_NAME - value: redis - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/redis@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - livenessProbe: - initialDelaySeconds: 120 - tcpSocket: - port: 6379 - timeoutSeconds: 1 - name: redis - ports: - - containerPort: 6379 - name: 6379-tcp - protocol: TCP - readinessProbe: - initialDelaySeconds: 1 - tcpSocket: - port: 6379 - timeoutSeconds: 1 - resources: - requests: - cpu: 10m - memory: 10Mi - securityContext: {} - enableServiceLinks: false - imagePullSecrets: - - name: lagoon-internal-registry-secret - priorityClassName: lagoon-priority-production - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 -status: {} diff --git a/internal/testdata/complex/service-templates/service5/service-nginx-php.yaml b/internal/testdata/complex/service-templates/service5/service-nginx-php.yaml deleted file mode 100644 index 0e8aba6e..00000000 --- a/internal/testdata/complex/service-templates/service5/service-nginx-php.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: nginx-php - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: nginx-php-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: nginx-php - lagoon.sh/service-type: nginx-php-persistent - lagoon.sh/template: nginx-php-persistent-0.1.0 - name: nginx-php -spec: - ports: - - name: http - port: 8080 - protocol: TCP - targetPort: http - selector: - app.kubernetes.io/instance: nginx-php - app.kubernetes.io/name: nginx-php-persistent -status: - loadBalancer: {} diff --git a/internal/testdata/complex/service-templates/service5/service-varnish.yaml b/internal/testdata/complex/service-templates/service5/service-varnish.yaml deleted file mode 100644 index 9a9ae6c8..00000000 --- a/internal/testdata/complex/service-templates/service5/service-varnish.yaml +++ /dev/null @@ -1,35 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: varnish - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: varnish - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: varnish - lagoon.sh/service-type: varnish - lagoon.sh/template: varnish-0.1.0 - name: varnish -spec: - ports: - - name: http - port: 8080 - protocol: TCP - targetPort: http - - name: controlport - port: 6082 - protocol: TCP - targetPort: controlport - selector: - app.kubernetes.io/instance: varnish - app.kubernetes.io/name: varnish -status: - loadBalancer: {} From 11c546005ead1a980cd13492c2d8fba439232f14 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 26 Jul 2024 10:29:02 +1000 Subject: [PATCH 05/10] refactor: dont create volumes that arent referenced by a service --- internal/generator/buildvalues.go | 5 ++-- internal/generator/services.go | 2 +- internal/generator/volumes.go | 9 ++++-- internal/templating/services/templates_pvc.go | 26 +++++++++-------- .../docker-compose.multiple-volumes-2.yml | 2 +- .../basic/docker-compose.multiple-volumes.yml | 2 +- .../service7/pvc-custom-notused.yaml | 29 ------------------- .../service9/pvc-custom-notused.yaml | 29 ------------------- 8 files changed, 26 insertions(+), 78 deletions(-) delete mode 100644 internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml delete mode 100644 internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index 12a48fab..5d56891b 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -150,8 +150,9 @@ type ImageCacheBuildArguments struct { } type ComposeVolume struct { - Name string `json:"name" description:"name is the name the volume, when creating in kubernetes will have a prefix"` - Size string `json:"size" description:"the size of the volume to request if the system enforces it"` + Name string `json:"name" description:"name is the name the volume, when creating in kubernetes will have a prefix"` + Size string `json:"size" description:"the size of the volume to request if the system enforces it"` + Create bool `json:"unused" description:"flag to determine if this volume is to be created or not"` } type ServiceVolume struct { diff --git a/internal/generator/services.go b/internal/generator/services.go index 856b9824..bd25c00a 100644 --- a/internal/generator/services.go +++ b/internal/generator/services.go @@ -383,7 +383,7 @@ func composeToServiceValues( // calculate if this service needs any additional volumes attached from the calculated build volumes // additional volumes can only be attached to certain - serviceVolumes, err := calculateServiceVolumes(buildValues.Volumes, lagoonType, servicePersistentName, composeServiceValues.Labels) + serviceVolumes, err := calculateServiceVolumes(buildValues, lagoonType, servicePersistentName, composeServiceValues.Labels) if err != nil { return nil, err } diff --git a/internal/generator/volumes.go b/internal/generator/volumes.go index 43f9dd5d..8b95842c 100644 --- a/internal/generator/volumes.go +++ b/internal/generator/volumes.go @@ -88,10 +88,11 @@ func composeToVolumeValues( // calculateServiceVolumes checks if a service type is allowed to have additional volumes attached, and if any volumes from docker compose // are to be attached to this service or not -func calculateServiceVolumes(buildVolumes []ComposeVolume, lagoonType, servicePersistentName string, serviceLabels composetypes.Labels) ([]ServiceVolume, error) { +func calculateServiceVolumes(buildValues *BuildValues, lagoonType, servicePersistentName string, serviceLabels composetypes.Labels) ([]ServiceVolume, error) { serviceVolumes := []ServiceVolume{} if val, ok := servicetypes.ServiceTypes[lagoonType]; ok { - for _, vol := range buildVolumes { + for i := 0; i < len(buildValues.Volumes); i++ { + vol := &buildValues.Volumes[i] volName := lagoon.GetVolumeNameFromLagoonVolume(vol.Name) // if there is a `lagoon.volumes..path` for a custom volume that matches the default persistent volume // don't add it again as a service volume @@ -100,9 +101,11 @@ func calculateServiceVolumes(buildVolumes []ComposeVolume, lagoonType, servicePe if volumePath != "" { if val.AllowAdditionalVolumes { sVol := ServiceVolume{ - ComposeVolume: vol, + ComposeVolume: *vol, Path: volumePath, } + // if the volume is attached to a service, then add the flag to create the persistent volume claim + vol.Create = true serviceVolumes = append(serviceVolumes, sVol) } else { // if the service type is not allowed additional volumes, return an error diff --git a/internal/templating/services/templates_pvc.go b/internal/templating/services/templates_pvc.go index 59443b1b..ee1020b8 100644 --- a/internal/templating/services/templates_pvc.go +++ b/internal/templating/services/templates_pvc.go @@ -65,20 +65,22 @@ func GeneratePVCTemplate( } // check for any additional volumes for _, vol := range buildValues.Volumes { - exists := false - // check if an existing pvc that will be created as a default persistent volume hasn't also been defined as an additional volume - // this will prevent creating another volume named the same - for _, cpvc := range result { - if lagoon.GetLagoonVolumeName(cpvc.Name) == vol.Name { - exists = true + if vol.Create { + exists := false + // check if an existing pvc that will be created as a default persistent volume hasn't also been defined as an additional volume + // this will prevent creating another volume named the same + for _, cpvc := range result { + if lagoon.GetLagoonVolumeName(cpvc.Name) == vol.Name { + exists = true + } } - } - if !exists { - pvc, err := generateAdditionalPVC(buildValues, vol, labels, annotations) - if err != nil { - return nil, err + if !exists { + pvc, err := generateAdditionalPVC(buildValues, vol, labels, annotations) + if err != nil { + return nil, err + } + result = append(result, *pvc) } - result = append(result, *pvc) } } return result, nil diff --git a/internal/testdata/basic/docker-compose.multiple-volumes-2.yml b/internal/testdata/basic/docker-compose.multiple-volumes-2.yml index 86bea115..59076c3d 100644 --- a/internal/testdata/basic/docker-compose.multiple-volumes-2.yml +++ b/internal/testdata/basic/docker-compose.multiple-volumes-2.yml @@ -45,7 +45,7 @@ volumes: lagoon.type: none notused: labels: - # will create a pvc, but as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be mounted + # as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be created or mounted lagoon.type: persistent logs: {} \ No newline at end of file diff --git a/internal/testdata/basic/docker-compose.multiple-volumes.yml b/internal/testdata/basic/docker-compose.multiple-volumes.yml index 90f7ec34..851a7612 100644 --- a/internal/testdata/basic/docker-compose.multiple-volumes.yml +++ b/internal/testdata/basic/docker-compose.multiple-volumes.yml @@ -47,7 +47,7 @@ volumes: lagoon.type: none notused: labels: - # will create a pvc, but as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be mounted + # as there is no `lagoon.volumes.notused.path` defined anywhere, it will not be created or mounted lagoon.type: persistent logs: {} \ No newline at end of file diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml b/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml deleted file mode 100644 index 3b092073..00000000 --- a/internal/testdata/basic/service-templates/service7/pvc-custom-notused.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - annotations: - k8up.io/backup: "true" - k8up.syn.tools/backup: "true" - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: custom-notused - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: notused - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service-type: additional-volume - lagoon.sh/template: additional-volume-0.1.0 - name: custom-notused -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 5Gi - storageClassName: bulk -status: {} diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml b/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml deleted file mode 100644 index 3b092073..00000000 --- a/internal/testdata/basic/service-templates/service9/pvc-custom-notused.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - annotations: - k8up.io/backup: "true" - k8up.syn.tools/backup: "true" - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: custom-notused - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: notused - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service-type: additional-volume - lagoon.sh/template: additional-volume-0.1.0 - name: custom-notused -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 5Gi - storageClassName: bulk -status: {} From 6c53ccde4cfdc0ba0caf21ff0f87c406c86d1c49 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 29 Jul 2024 08:05:11 +1000 Subject: [PATCH 06/10] chore: fix error wording --- internal/generator/images.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/generator/images.go b/internal/generator/images.go index b74b0ce2..6224038a 100644 --- a/internal/generator/images.go +++ b/internal/generator/images.go @@ -46,7 +46,7 @@ func generateImageBuild(buildValues BuildValues, composeServiceValues composetyp // no dockerfile determined, this must be a pull through image if composeServiceValues.Image == "" { return imageBuild, fmt.Errorf( - "defined Dockerfile or Image for service %s defined", composeService, + "no defined Dockerfile or Image for service %s", composeService, ) } // check docker-compose override image From 0c3e5fe92a7bb3dd9f8beb9738918e3ec55faae8 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Thu, 8 Aug 2024 10:04:43 +1000 Subject: [PATCH 07/10] chore: adjust after rebase main --- cmd/template_lagoonservices_test.go | 27 +++-- .../service10/deployment-node.yaml | 100 +++++++++++++++++ .../pvc-custom-config.yaml | 0 .../pvc-custom-files.yaml | 0 .../pvc-custom-node.yaml | 0 .../service10/service-node.yaml | 31 ++++++ ...ob-cronjob-node-some-other-drush-cron.yaml | 81 ++++++++++++++ .../service7/deployment-node.yaml | 47 ++++---- .../service7/service-node.yaml | 22 ++-- .../service9/deployment-node.yaml | 24 ++--- .../{service7 => service9}/pvc-node.yaml | 0 .../service9/service-node.yaml | 8 +- .../service5/deployment-cli.yaml | 27 ++--- .../service7/deployment-cli.yaml | 102 ++++++++++++++++++ .../deployment-mariadb.yaml | 0 .../deployment-nginx.yaml | 0 .../pvc-custom-files.yaml | 0 .../{service5 => service7}/pvc-mariadb.yaml | 0 .../{service5 => service7}/pvc-nginx.yaml | 0 .../service-mariadb.yaml | 0 .../{service5 => service7}/service-nginx.yaml | 0 .../docker-compose/test12/docker-compose.yml | 2 +- 22 files changed, 400 insertions(+), 71 deletions(-) create mode 100644 internal/testdata/basic/service-templates/service10/deployment-node.yaml rename internal/testdata/basic/service-templates/{service7 => service10}/pvc-custom-config.yaml (100%) rename internal/testdata/basic/service-templates/{service7 => service10}/pvc-custom-files.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => service10}/pvc-custom-node.yaml (100%) create mode 100644 internal/testdata/basic/service-templates/service10/service-node.yaml create mode 100644 internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml rename internal/testdata/basic/service-templates/{service7 => service9}/pvc-node.yaml (100%) create mode 100644 internal/testdata/complex/service-templates/service7/deployment-cli.yaml rename internal/testdata/complex/service-templates/{service5 => service7}/deployment-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/deployment-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/pvc-custom-files.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/pvc-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/pvc-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/service-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => service7}/service-nginx.yaml (100%) diff --git a/cmd/template_lagoonservices_test.go b/cmd/template_lagoonservices_test.go index d96db288..0e3e196d 100644 --- a/cmd/template_lagoonservices_test.go +++ b/cmd/template_lagoonservices_test.go @@ -340,7 +340,22 @@ func TestTemplateLagoonServices(t *testing.T) { want: "internal/testdata/basic/service-templates/service8", }, { - name: "test11 basic-persistent deployment multiple volumes", + name: "test11 basic deployment polysite cronjobs", + args: testdata.GetSeedData( + testdata.TestData{ + ProjectName: "example-project", + EnvironmentName: "main", + Branch: "main", + LagoonYAML: "internal/testdata/basic/lagoon.polysite-cronjobs.yml", + ImageReferences: map[string]string{ + "node": "harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + }, + }, true), + templatePath: "testoutput", + want: "internal/testdata/basic/service-templates/service7", + }, + { + name: "test12 basic-persistent deployment multiple volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -353,10 +368,10 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service7", + want: "internal/testdata/basic/service-templates/service9", }, { - name: "test12 basic deployment multiple volumes", + name: "test13 basic deployment multiple volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -369,10 +384,10 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service9", + want: "internal/testdata/basic/service-templates/service10", }, { - name: "test13 complex deployment multiple volumes", + name: "test14 complex deployment multiple volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -390,7 +405,7 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service5", + want: "internal/testdata/complex/service-templates/service7", }, } for _, tt := range tests { diff --git a/internal/testdata/basic/service-templates/service10/deployment-node.yaml b/internal/testdata/basic/service-templates/service10/deployment-node.yaml new file mode 100644 index 00000000..023013ad --- /dev/null +++ b/internal/testdata/basic/service-templates/service10/deployment-node.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic + strategy: {} + template: + metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + spec: + containers: + - env: + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: CRONJOBS + - name: SERVICE_NAME + value: node + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + livenessProbe: + initialDelaySeconds: 60 + tcpSocket: + port: 3000 + timeoutSeconds: 10 + name: basic + ports: + - containerPort: 3000 + name: http + protocol: TCP + readinessProbe: + initialDelaySeconds: 1 + tcpSocket: + port: 3000 + timeoutSeconds: 1 + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + volumeMounts: + - mountPath: /data + name: custom-node + - mountPath: /config + name: custom-config + - mountPath: /app/files/ + name: custom-files + enableServiceLinks: false + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + volumes: + - name: custom-node + persistentVolumeClaim: + claimName: custom-node + - name: custom-config + persistentVolumeClaim: + claimName: custom-config + - name: custom-files + persistentVolumeClaim: + claimName: custom-files +status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml b/internal/testdata/basic/service-templates/service10/pvc-custom-config.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/pvc-custom-config.yaml rename to internal/testdata/basic/service-templates/service10/pvc-custom-config.yaml diff --git a/internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml b/internal/testdata/basic/service-templates/service10/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/pvc-custom-files.yaml rename to internal/testdata/basic/service-templates/service10/pvc-custom-files.yaml diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml b/internal/testdata/basic/service-templates/service10/pvc-custom-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/pvc-custom-node.yaml rename to internal/testdata/basic/service-templates/service10/pvc-custom-node.yaml diff --git a/internal/testdata/basic/service-templates/service10/service-node.yaml b/internal/testdata/basic/service-templates/service10/service-node.yaml new file mode 100644 index 00000000..3d4d875d --- /dev/null +++ b/internal/testdata/basic/service-templates/service10/service-node.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node +spec: + ports: + - name: http + port: 3000 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic +status: + loadBalancer: {} diff --git a/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml b/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml new file mode 100644 index 00000000..5133d082 --- /dev/null +++ b/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml @@ -0,0 +1,81 @@ +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: cronjob-node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: cronjob-basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: cronjob-node-some-other-drush-cron +spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + jobTemplate: + metadata: + creationTimestamp: null + spec: + template: + metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: cronjob-node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: cronjob-basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + spec: + containers: + - command: + - /lagoon/cronjob.sh + - drush cron + env: + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: SERVICE_NAME + value: node + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + name: cronjob-node-some-other-drush-cron + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + dnsConfig: + options: + - name: timeout + value: "60" + - name: attempts + value: "10" + enableServiceLinks: false + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + restartPolicy: Never + schedule: 10 2 * * * + startingDeadlineSeconds: 240 + successfulJobsHistoryLimit: 0 +status: {} diff --git a/internal/testdata/basic/service-templates/service7/deployment-node.yaml b/internal/testdata/basic/service-templates/service7/deployment-node.yaml index 5567c6ba..a2d01522 100644 --- a/internal/testdata/basic/service-templates/service7/deployment-node.yaml +++ b/internal/testdata/basic/service-templates/service7/deployment-node.yaml @@ -9,21 +9,21 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic-persistent + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic-persistent - lagoon.sh/template: basic-persistent-0.1.0 + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 name: node spec: replicas: 1 selector: matchLabels: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic-persistent + app.kubernetes.io/name: basic strategy: {} template: metadata: @@ -35,20 +35,22 @@ spec: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic-persistent + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic-persistent - lagoon.sh/template: basic-persistent-0.1.0 + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 spec: containers: - env: - name: LAGOON_GIT_SHA value: abcdefg123456 - name: CRONJOBS + value: | + 3,18,33,48 0 * * * drush cron - name: SERVICE_NAME value: node envFrom: @@ -59,42 +61,31 @@ spec: livenessProbe: initialDelaySeconds: 60 tcpSocket: - port: 3000 + port: 1234 timeoutSeconds: 10 name: basic ports: - - containerPort: 3000 - name: http + - containerPort: 1234 + name: tcp-1234 protocol: TCP + - containerPort: 8191 + name: tcp-8191 + protocol: TCP + - containerPort: 9001 + name: udp-9001 + protocol: UDP readinessProbe: initialDelaySeconds: 1 tcpSocket: - port: 3000 + port: 1234 timeoutSeconds: 1 resources: requests: cpu: 10m memory: 10Mi securityContext: {} - volumeMounts: - - mountPath: /config - name: custom-config - - mountPath: /app/files/ - name: custom-files - - mountPath: /data - name: node enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production - volumes: - - name: custom-config - persistentVolumeClaim: - claimName: custom-config - - name: custom-files - persistentVolumeClaim: - claimName: custom-files - - name: node - persistentVolumeClaim: - claimName: node status: {} diff --git a/internal/testdata/basic/service-templates/service7/service-node.yaml b/internal/testdata/basic/service-templates/service7/service-node.yaml index fa68a29f..6b286993 100644 --- a/internal/testdata/basic/service-templates/service7/service-node.yaml +++ b/internal/testdata/basic/service-templates/service7/service-node.yaml @@ -9,23 +9,31 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic-persistent + app.kubernetes.io/name: basic lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic-persistent - lagoon.sh/template: basic-persistent-0.1.0 + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 name: node spec: ports: - - name: http - port: 3000 + - name: tcp-1234 + port: 1234 protocol: TCP - targetPort: http + targetPort: tcp-1234 + - name: tcp-8191 + port: 8191 + protocol: TCP + targetPort: tcp-8191 + - name: udp-9001 + port: 9001 + protocol: UDP + targetPort: udp-9001 selector: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic-persistent + app.kubernetes.io/name: basic status: loadBalancer: {} diff --git a/internal/testdata/basic/service-templates/service9/deployment-node.yaml b/internal/testdata/basic/service-templates/service9/deployment-node.yaml index 023013ad..5567c6ba 100644 --- a/internal/testdata/basic/service-templates/service9/deployment-node.yaml +++ b/internal/testdata/basic/service-templates/service9/deployment-node.yaml @@ -9,21 +9,21 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 name: node spec: replicas: 1 selector: matchLabels: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent strategy: {} template: metadata: @@ -35,14 +35,14 @@ spec: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 spec: containers: - env: @@ -77,24 +77,24 @@ spec: memory: 10Mi securityContext: {} volumeMounts: - - mountPath: /data - name: custom-node - mountPath: /config name: custom-config - mountPath: /app/files/ name: custom-files + - mountPath: /data + name: node enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production volumes: - - name: custom-node - persistentVolumeClaim: - claimName: custom-node - name: custom-config persistentVolumeClaim: claimName: custom-config - name: custom-files persistentVolumeClaim: claimName: custom-files + - name: node + persistentVolumeClaim: + claimName: node status: {} diff --git a/internal/testdata/basic/service-templates/service7/pvc-node.yaml b/internal/testdata/basic/service-templates/service9/pvc-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/pvc-node.yaml rename to internal/testdata/basic/service-templates/service9/pvc-node.yaml diff --git a/internal/testdata/basic/service-templates/service9/service-node.yaml b/internal/testdata/basic/service-templates/service9/service-node.yaml index 3d4d875d..fa68a29f 100644 --- a/internal/testdata/basic/service-templates/service9/service-node.yaml +++ b/internal/testdata/basic/service-templates/service9/service-node.yaml @@ -9,14 +9,14 @@ metadata: labels: app.kubernetes.io/instance: node app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent lagoon.sh/buildType: branch lagoon.sh/environment: main lagoon.sh/environmentType: production lagoon.sh/project: example-project lagoon.sh/service: node - lagoon.sh/service-type: basic - lagoon.sh/template: basic-0.1.0 + lagoon.sh/service-type: basic-persistent + lagoon.sh/template: basic-persistent-0.1.0 name: node spec: ports: @@ -26,6 +26,6 @@ spec: targetPort: http selector: app.kubernetes.io/instance: node - app.kubernetes.io/name: basic + app.kubernetes.io/name: basic-persistent status: loadBalancer: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-cli.yaml b/internal/testdata/complex/service-templates/service5/deployment-cli.yaml index af6122d3..ac370e98 100644 --- a/internal/testdata/complex/service-templates/service5/deployment-cli.yaml +++ b/internal/testdata/complex/service-templates/service5/deployment-cli.yaml @@ -47,8 +47,10 @@ spec: containers: - env: - name: LAGOON_GIT_SHA - value: abcdefg123456 + value: "0000000000000000000000000000000000000000" - name: CRONJOBS + value: | + 3,18,33,48 * * * * drush cron - name: SERVICE_NAME value: cli envFrom: @@ -76,27 +78,26 @@ spec: - mountPath: /var/run/secrets/lagoon/sshkey/ name: lagoon-sshkey readOnly: true - - mountPath: /app/otherfiles/ - name: custom-files - - mountPath: /app/web/sites/default/files//php - name: nginx-twig - - mountPath: /app/web/sites/default/files/ - name: nginx + - mountPath: /app/docroot/sites/default/files//php + name: nginx-php-twig + - mountPath: /app/docroot/sites/default/files/ + name: nginx-php enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production + securityContext: + fsGroup: 10001 + runAsGroup: 0 + runAsUser: 10000 volumes: - - name: custom-files - persistentVolumeClaim: - claimName: custom-files - name: lagoon-sshkey secret: defaultMode: 420 secretName: lagoon-sshkey - emptyDir: {} - name: nginx-twig - - name: nginx + name: nginx-php-twig + - name: nginx-php persistentVolumeClaim: - claimName: nginx + claimName: nginx-php status: {} diff --git a/internal/testdata/complex/service-templates/service7/deployment-cli.yaml b/internal/testdata/complex/service-templates/service7/deployment-cli.yaml new file mode 100644 index 00000000..af6122d3 --- /dev/null +++ b/internal/testdata/complex/service-templates/service7/deployment-cli.yaml @@ -0,0 +1,102 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: cli + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: cli-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: cli + lagoon.sh/service-type: cli-persistent + lagoon.sh/template: cli-persistent-0.1.0 + name: cli +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: cli + app.kubernetes.io/name: cli-persistent + strategy: {} + template: + metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: cli + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: cli-persistent + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: cli + lagoon.sh/service-type: cli-persistent + lagoon.sh/template: cli-persistent-0.1.0 + spec: + containers: + - env: + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: CRONJOBS + - name: SERVICE_NAME + value: cli + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/cli@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + name: cli + readinessProbe: + exec: + command: + - /bin/sh + - -c + - if [ -x /bin/entrypoint-readiness ]; then /bin/entrypoint-readiness; + fi + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 2 + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + volumeMounts: + - mountPath: /var/run/secrets/lagoon/sshkey/ + name: lagoon-sshkey + readOnly: true + - mountPath: /app/otherfiles/ + name: custom-files + - mountPath: /app/web/sites/default/files//php + name: nginx-twig + - mountPath: /app/web/sites/default/files/ + name: nginx + enableServiceLinks: false + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + volumes: + - name: custom-files + persistentVolumeClaim: + claimName: custom-files + - name: lagoon-sshkey + secret: + defaultMode: 420 + secretName: lagoon-sshkey + - emptyDir: {} + name: nginx-twig + - name: nginx + persistentVolumeClaim: + claimName: nginx +status: {} diff --git a/internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml b/internal/testdata/complex/service-templates/service7/deployment-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-mariadb.yaml rename to internal/testdata/complex/service-templates/service7/deployment-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service5/deployment-nginx.yaml b/internal/testdata/complex/service-templates/service7/deployment-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-nginx.yaml rename to internal/testdata/complex/service-templates/service7/deployment-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml b/internal/testdata/complex/service-templates/service7/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/pvc-custom-files.yaml rename to internal/testdata/complex/service-templates/service7/pvc-custom-files.yaml diff --git a/internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml b/internal/testdata/complex/service-templates/service7/pvc-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/pvc-mariadb.yaml rename to internal/testdata/complex/service-templates/service7/pvc-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service5/pvc-nginx.yaml b/internal/testdata/complex/service-templates/service7/pvc-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/pvc-nginx.yaml rename to internal/testdata/complex/service-templates/service7/pvc-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service5/service-mariadb.yaml b/internal/testdata/complex/service-templates/service7/service-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/service-mariadb.yaml rename to internal/testdata/complex/service-templates/service7/service-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service5/service-nginx.yaml b/internal/testdata/complex/service-templates/service7/service-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/service-nginx.yaml rename to internal/testdata/complex/service-templates/service7/service-nginx.yaml diff --git a/internal/testdata/docker-compose/test12/docker-compose.yml b/internal/testdata/docker-compose/test12/docker-compose.yml index 4d85b9d6..e0af48bd 100644 --- a/internal/testdata/docker-compose/test12/docker-compose.yml +++ b/internal/testdata/docker-compose/test12/docker-compose.yml @@ -35,7 +35,7 @@ volumes: db: labels: # this label is not technically needed, but explicit - lagoon.type: none + lagoon.type: none notused: labels: lagoon.type: persistent From 99139aa69f753d344a710731b35c876798777704 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 16 Aug 2024 20:28:45 +1000 Subject: [PATCH 08/10] chore: remove duplicate test --- cmd/template_lagoonservices_test.go | 4 +- .../cronjob-cronjob-cli-drush-cron2.yaml | 0 .../deployment-nginx-php.yaml | 0 .../deployment-redis.yaml | 0 .../deployment-varnish.yaml | 0 .../{service6 => service5}/pvc-nginx-php.yaml | 0 .../service-nginx-php.yaml | 0 .../{service6 => service5}/service-redis.yaml | 0 .../service-varnish.yaml | 0 .../service6/deployment-cli.yaml | 27 +++-- .../deployment-mariadb.yaml | 0 .../deployment-nginx.yaml | 0 .../pvc-custom-files.yaml | 0 .../{service7 => service6}/pvc-mariadb.yaml | 0 .../{service7 => service6}/pvc-nginx.yaml | 0 .../service-mariadb.yaml | 0 .../{service7 => service6}/service-nginx.yaml | 0 .../service7/deployment-cli.yaml | 102 ------------------ 18 files changed, 15 insertions(+), 118 deletions(-) rename internal/testdata/complex/service-templates/{service6 => service5}/cronjob-cronjob-cli-drush-cron2.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/deployment-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/deployment-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/deployment-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/pvc-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/service-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/service-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => service5}/service-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/deployment-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/deployment-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/pvc-custom-files.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/pvc-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/pvc-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/service-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service7 => service6}/service-nginx.yaml (100%) delete mode 100644 internal/testdata/complex/service-templates/service7/deployment-cli.yaml diff --git a/cmd/template_lagoonservices_test.go b/cmd/template_lagoonservices_test.go index 0e3e196d..73f0a2d8 100644 --- a/cmd/template_lagoonservices_test.go +++ b/cmd/template_lagoonservices_test.go @@ -165,7 +165,7 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service6", + want: "internal/testdata/complex/service-templates/service5", }, { name: "test3 - funky pvcs", @@ -405,7 +405,7 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service7", + want: "internal/testdata/complex/service-templates/service6", }, } for _, tt := range tests { diff --git a/internal/testdata/complex/service-templates/service6/cronjob-cronjob-cli-drush-cron2.yaml b/internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/cronjob-cronjob-cli-drush-cron2.yaml rename to internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-nginx-php.yaml b/internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-nginx-php.yaml rename to internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-redis.yaml b/internal/testdata/complex/service-templates/service5/deployment-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-redis.yaml rename to internal/testdata/complex/service-templates/service5/deployment-redis.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-varnish.yaml b/internal/testdata/complex/service-templates/service5/deployment-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-varnish.yaml rename to internal/testdata/complex/service-templates/service5/deployment-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service6/pvc-nginx-php.yaml b/internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/pvc-nginx-php.yaml rename to internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service6/service-nginx-php.yaml b/internal/testdata/complex/service-templates/service5/service-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/service-nginx-php.yaml rename to internal/testdata/complex/service-templates/service5/service-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service6/service-redis.yaml b/internal/testdata/complex/service-templates/service5/service-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/service-redis.yaml rename to internal/testdata/complex/service-templates/service5/service-redis.yaml diff --git a/internal/testdata/complex/service-templates/service6/service-varnish.yaml b/internal/testdata/complex/service-templates/service5/service-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/service-varnish.yaml rename to internal/testdata/complex/service-templates/service5/service-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-cli.yaml b/internal/testdata/complex/service-templates/service6/deployment-cli.yaml index ac370e98..af6122d3 100644 --- a/internal/testdata/complex/service-templates/service6/deployment-cli.yaml +++ b/internal/testdata/complex/service-templates/service6/deployment-cli.yaml @@ -47,10 +47,8 @@ spec: containers: - env: - name: LAGOON_GIT_SHA - value: "0000000000000000000000000000000000000000" + value: abcdefg123456 - name: CRONJOBS - value: | - 3,18,33,48 * * * * drush cron - name: SERVICE_NAME value: cli envFrom: @@ -78,26 +76,27 @@ spec: - mountPath: /var/run/secrets/lagoon/sshkey/ name: lagoon-sshkey readOnly: true - - mountPath: /app/docroot/sites/default/files//php - name: nginx-php-twig - - mountPath: /app/docroot/sites/default/files/ - name: nginx-php + - mountPath: /app/otherfiles/ + name: custom-files + - mountPath: /app/web/sites/default/files//php + name: nginx-twig + - mountPath: /app/web/sites/default/files/ + name: nginx enableServiceLinks: false imagePullSecrets: - name: lagoon-internal-registry-secret priorityClassName: lagoon-priority-production - securityContext: - fsGroup: 10001 - runAsGroup: 0 - runAsUser: 10000 volumes: + - name: custom-files + persistentVolumeClaim: + claimName: custom-files - name: lagoon-sshkey secret: defaultMode: 420 secretName: lagoon-sshkey - emptyDir: {} - name: nginx-php-twig - - name: nginx-php + name: nginx-twig + - name: nginx persistentVolumeClaim: - claimName: nginx-php + claimName: nginx status: {} diff --git a/internal/testdata/complex/service-templates/service7/deployment-mariadb.yaml b/internal/testdata/complex/service-templates/service6/deployment-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/deployment-mariadb.yaml rename to internal/testdata/complex/service-templates/service6/deployment-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service7/deployment-nginx.yaml b/internal/testdata/complex/service-templates/service6/deployment-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/deployment-nginx.yaml rename to internal/testdata/complex/service-templates/service6/deployment-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service7/pvc-custom-files.yaml b/internal/testdata/complex/service-templates/service6/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/pvc-custom-files.yaml rename to internal/testdata/complex/service-templates/service6/pvc-custom-files.yaml diff --git a/internal/testdata/complex/service-templates/service7/pvc-mariadb.yaml b/internal/testdata/complex/service-templates/service6/pvc-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/pvc-mariadb.yaml rename to internal/testdata/complex/service-templates/service6/pvc-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service7/pvc-nginx.yaml b/internal/testdata/complex/service-templates/service6/pvc-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/pvc-nginx.yaml rename to internal/testdata/complex/service-templates/service6/pvc-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service7/service-mariadb.yaml b/internal/testdata/complex/service-templates/service6/service-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/service-mariadb.yaml rename to internal/testdata/complex/service-templates/service6/service-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service7/service-nginx.yaml b/internal/testdata/complex/service-templates/service6/service-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service7/service-nginx.yaml rename to internal/testdata/complex/service-templates/service6/service-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service7/deployment-cli.yaml b/internal/testdata/complex/service-templates/service7/deployment-cli.yaml deleted file mode 100644 index af6122d3..00000000 --- a/internal/testdata/complex/service-templates/service7/deployment-cli.yaml +++ /dev/null @@ -1,102 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: cli - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: cli-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: cli - lagoon.sh/service-type: cli-persistent - lagoon.sh/template: cli-persistent-0.1.0 - name: cli -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/instance: cli - app.kubernetes.io/name: cli-persistent - strategy: {} - template: - metadata: - annotations: - lagoon.sh/branch: main - lagoon.sh/configMapSha: abcdefg1234567890 - lagoon.sh/version: v2.7.x - creationTimestamp: null - labels: - app.kubernetes.io/instance: cli - app.kubernetes.io/managed-by: build-deploy-tool - app.kubernetes.io/name: cli-persistent - lagoon.sh/buildType: branch - lagoon.sh/environment: main - lagoon.sh/environmentType: production - lagoon.sh/project: example-project - lagoon.sh/service: cli - lagoon.sh/service-type: cli-persistent - lagoon.sh/template: cli-persistent-0.1.0 - spec: - containers: - - env: - - name: LAGOON_GIT_SHA - value: abcdefg123456 - - name: CRONJOBS - - name: SERVICE_NAME - value: cli - envFrom: - - configMapRef: - name: lagoon-env - image: harbor.example/example-project/main/cli@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 - imagePullPolicy: Always - name: cli - readinessProbe: - exec: - command: - - /bin/sh - - -c - - if [ -x /bin/entrypoint-readiness ]; then /bin/entrypoint-readiness; - fi - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 2 - resources: - requests: - cpu: 10m - memory: 10Mi - securityContext: {} - volumeMounts: - - mountPath: /var/run/secrets/lagoon/sshkey/ - name: lagoon-sshkey - readOnly: true - - mountPath: /app/otherfiles/ - name: custom-files - - mountPath: /app/web/sites/default/files//php - name: nginx-twig - - mountPath: /app/web/sites/default/files/ - name: nginx - enableServiceLinks: false - imagePullSecrets: - - name: lagoon-internal-registry-secret - priorityClassName: lagoon-priority-production - volumes: - - name: custom-files - persistentVolumeClaim: - claimName: custom-files - - name: lagoon-sshkey - secret: - defaultMode: 420 - secretName: lagoon-sshkey - - emptyDir: {} - name: nginx-twig - - name: nginx - persistentVolumeClaim: - claimName: nginx -status: {} From bd5799ffb057c7224c9751d31a2f8ef0d6a62926 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 26 Aug 2024 08:42:41 +1000 Subject: [PATCH 09/10] test: rename tests and directories to reduce future conflict issues --- cmd/template_lagoonservices_test.go | 87 +++++++++++-------- .../deployment-node.yaml | 0 .../lagoon-private-registry-dockerhub.yaml | 0 ...n-private-registry-my-custom-registry.yaml | 0 ...private-registry-my-hardcode-registry.yaml | 0 ...on-private-registry-my-other-registry.yaml | 0 .../service-node.yaml | 0 .../deployment-node.yaml | 0 .../service-node.yaml | 0 ...ob-cronjob-node-some-other-drush-cron.yaml | 0 .../deployment-node.yaml | 0 .../service-node.yaml | 0 .../deployment-node.yaml | 0 .../pvc-custom-config.yaml | 0 .../pvc-custom-files.yaml | 0 .../pvc-node.yaml | 0 .../service-node.yaml | 0 .../deployment-node.yaml | 0 .../pvc-custom-config.yaml | 0 .../pvc-custom-files.yaml | 0 .../pvc-custom-node.yaml | 0 .../service-node.yaml | 0 .../deployment-lnd.yaml | 0 .../deployment-thunderhub.yaml | 0 .../deployment-tor.yaml | 0 .../pvc-lnd.yaml | 0 .../service-lnd.yaml | 0 .../service-thunderhub.yaml | 0 .../service-tor.yaml | 0 .../deployment-lnd.yaml | 0 .../deployment-tor.yaml | 0 .../pvc-lnd.yaml | 0 .../service-lnd.yaml | 0 .../deployment-node.yaml | 0 .../service-node.yaml | 0 .../deployment-node.yaml | 0 .../isolation-network-policy.yaml | 0 .../service-node.yaml | 0 .../deployment-node.yaml | 0 ...n-private-registry-my-custom-registry.yaml | 0 .../service-node.yaml | 0 .../deployment-cli.yaml | 0 .../deployment-mariadb.yaml | 0 .../deployment-nginx.yaml | 0 .../pvc-custom-files.yaml | 0 .../pvc-mariadb.yaml | 0 .../pvc-nginx.yaml | 0 .../service-mariadb.yaml | 0 .../service-nginx.yaml | 0 .../cronjob-cronjob-cli-drush-cron2.yaml | 0 .../deployment-cli.yaml | 0 .../deployment-nginx-php.yaml | 0 .../deployment-redis.yaml | 0 .../deployment-varnish.yaml | 0 .../pvc-nginx-php.yaml | 0 .../service-nginx-php.yaml | 0 .../service-redis.yaml | 0 .../service-varnish.yaml | 0 .../cronjob-cronjob-cli-drush-cron2.yaml | 0 .../deployment-cli.yaml | 0 .../deployment-nginx-php.yaml | 0 .../deployment-redis.yaml | 0 .../deployment-varnish.yaml | 0 .../pvc-nginx-php.yaml | 0 .../service-nginx-php.yaml | 0 .../service-redis.yaml | 0 .../service-varnish.yaml | 0 .../cronjob-cronjob-cli-drush-cron2.yaml | 0 .../deployment-cli.yaml | 0 .../deployment-nginx-php.yaml | 0 .../deployment-redis.yaml | 0 .../deployment-varnish.yaml | 0 .../pvc-nginx-php.yaml | 0 .../service-nginx-php.yaml | 0 .../service-redis.yaml | 0 .../service-varnish.yaml | 0 .../deployment-mariadb-10-5.yaml | 0 .../deployment-opensearch-2.yaml | 0 .../deployment-postgres-11.yaml | 0 .../deployment-redis-6.yaml | 0 .../deployment-redis-7.yaml | 0 .../deployment-solr-8.yaml | 0 .../deployment-web.yaml | 0 .../pvc-mariadb-10-5.yaml | 0 .../pvc-opensearch-2.yaml | 0 .../pvc-postgres-11.yaml | 0 .../pvc-solr-8.yaml | 0 .../pvc-web.yaml | 0 .../service-mariadb-10-5.yaml | 0 .../service-opensearch-2.yaml | 0 .../service-postgres-11.yaml | 0 .../service-redis-6.yaml | 0 .../service-redis-7.yaml | 0 .../service-solr-8.yaml | 0 .../service-web.yaml | 0 .../deployment-mariadb-10-11.yaml | 0 .../deployment-mariadb-10-5.yaml | 0 .../deployment-mongo-4.yaml | 0 .../deployment-postgres-11.yaml | 0 .../deployment-postgres-15.yaml | 0 .../pvc-mariadb-10-11.yaml | 0 .../pvc-mariadb-10-5.yaml | 0 .../pvc-mongo-4.yaml | 0 .../pvc-postgres-11.yaml | 0 .../pvc-postgres-15.yaml | 0 .../service-mariadb-10-11.yaml | 0 .../service-mariadb-10-5.yaml | 0 .../service-mongo-4.yaml | 0 .../service-postgres-11.yaml | 0 .../service-postgres-15.yaml | 0 110 files changed, 52 insertions(+), 35 deletions(-) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/lagoon-private-registry-dockerhub.yaml (100%) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/lagoon-private-registry-my-custom-registry.yaml (100%) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/lagoon-private-registry-my-hardcode-registry.yaml (100%) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/lagoon-private-registry-my-other-registry.yaml (100%) rename internal/testdata/basic/service-templates/{service1 => test1-basic-deployment}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service8 => test10-basic-no-native-cronjobs}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service6 => test10-basic-no-native-cronjobs}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service7 => test11-basic-polysite-cronjobs}/cronjob-cronjob-node-some-other-drush-cron.yaml (100%) rename internal/testdata/basic/service-templates/{service7 => test11-basic-polysite-cronjobs}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service7 => test11-basic-polysite-cronjobs}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => test12-basic-persistent-custom-volumes}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service10 => test12-basic-persistent-custom-volumes}/pvc-custom-config.yaml (100%) rename internal/testdata/basic/service-templates/{service10 => test12-basic-persistent-custom-volumes}/pvc-custom-files.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => test12-basic-persistent-custom-volumes}/pvc-node.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => test12-basic-persistent-custom-volumes}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service10 => test13-basic-custom-volumes}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => test13-basic-custom-volumes}/pvc-custom-config.yaml (100%) rename internal/testdata/basic/service-templates/{service9 => test13-basic-custom-volumes}/pvc-custom-files.yaml (100%) rename internal/testdata/basic/service-templates/{service10 => test13-basic-custom-volumes}/pvc-custom-node.yaml (100%) rename internal/testdata/basic/service-templates/{service10 => test13-basic-custom-volumes}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/deployment-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/deployment-thunderhub.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/deployment-tor.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/pvc-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/service-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/service-thunderhub.yaml (100%) rename internal/testdata/basic/service-templates/{service2 => test3-funky-pvcs}/service-tor.yaml (100%) rename internal/testdata/basic/service-templates/{service3 => test4-basic-worker}/deployment-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service3 => test4-basic-worker}/deployment-tor.yaml (100%) rename internal/testdata/basic/service-templates/{service3 => test4-basic-worker}/pvc-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service3 => test4-basic-worker}/service-lnd.yaml (100%) rename internal/testdata/basic/service-templates/{service4 => test5-basic-promote}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service4 => test5-basic-promote}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service5 => test6-basic-networkpolicy}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service5 => test6-basic-networkpolicy}/isolation-network-policy.yaml (100%) rename internal/testdata/basic/service-templates/{service5 => test6-basic-networkpolicy}/service-node.yaml (100%) rename internal/testdata/basic/service-templates/{service6 => test7-basic-dynamic-secrets}/deployment-node.yaml (100%) rename internal/testdata/basic/service-templates/{service6 => test7-basic-dynamic-secrets}/lagoon-private-registry-my-custom-registry.yaml (100%) rename internal/testdata/basic/service-templates/{service8 => test7-basic-dynamic-secrets}/service-node.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/deployment-cli.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/deployment-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/deployment-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/pvc-custom-files.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/pvc-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/pvc-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/service-mariadb.yaml (100%) rename internal/testdata/complex/service-templates/{service6 => test14-complex-custom-volumes}/service-nginx.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/cronjob-cronjob-cli-drush-cron2.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/deployment-cli.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/deployment-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/deployment-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/deployment-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/pvc-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/service-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/service-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service1 => test2-nginx-php}/service-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/cronjob-cronjob-cli-drush-cron2.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/deployment-cli.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/deployment-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/deployment-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/deployment-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/pvc-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/service-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/service-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service2 => test2b-nginx-php}/service-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/cronjob-cronjob-cli-drush-cron2.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/deployment-cli.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/deployment-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/deployment-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/deployment-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/pvc-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/service-nginx-php.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/service-redis.yaml (100%) rename internal/testdata/complex/service-templates/{service5 => test2c-nginx-php}/service-varnish.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-opensearch-2.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-redis-6.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-redis-7.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-solr-8.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/deployment-web.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/pvc-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/pvc-opensearch-2.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/pvc-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/pvc-solr-8.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/pvc-web.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-opensearch-2.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-redis-6.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-redis-7.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-solr-8.yaml (100%) rename internal/testdata/complex/service-templates/{service3 => test8-multiple-services}/service-web.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/deployment-mariadb-10-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/deployment-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/deployment-mongo-4.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/deployment-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/deployment-postgres-15.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/pvc-mariadb-10-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/pvc-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/pvc-mongo-4.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/pvc-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/pvc-postgres-15.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/service-mariadb-10-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/service-mariadb-10-5.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/service-mongo-4.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/service-postgres-11.yaml (100%) rename internal/testdata/complex/service-templates/{service4 => test9-meta-dbaas-types}/service-postgres-15.yaml (100%) diff --git a/cmd/template_lagoonservices_test.go b/cmd/template_lagoonservices_test.go index 73f0a2d8..9d8a3515 100644 --- a/cmd/template_lagoonservices_test.go +++ b/cmd/template_lagoonservices_test.go @@ -27,7 +27,8 @@ func TestTemplateLagoonServices(t *testing.T) { vars []helpers.EnvironmentVariable }{ { - name: "test1 basic deployment", + name: "test1-basic-deployment", + description: "tests a basic deployment", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -66,10 +67,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service1", + want: "internal/testdata/basic/service-templates/test1-basic-deployment", }, { - name: "test2a nginx-php deployment", + name: "test2-nginx-php", + description: "tests an nginx-php deployment", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -85,10 +87,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service1", + want: "internal/testdata/complex/service-templates/test2-nginx-php", }, { - name: "test2a1 nginx-php deployment using images from images.yaml file (same as test2a result)", + name: "test2a-nginx-php", + description: "tests an nginx-php deployment using images from images.yaml (same result as test2)", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -98,10 +101,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, true), imageData: "internal/testdata/complex/images-service1.yaml", templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service1", + want: "internal/testdata/complex/service-templates/test2-nginx-php", }, { - name: "test2b nginx-php deployment - rootless workloads enabled", + name: "test2b-nginx-php", + description: "tests an nginx-php deployment with rootless workloads enabled", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -124,10 +128,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service2", + want: "internal/testdata/complex/service-templates/test2b-nginx-php", }, { - name: "test2c nginx-php deployment - spot workloads enabled", + name: "test2c-nginx-php", + description: "tests an nginx-php deployment with spot workloads enabled", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -165,10 +170,10 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service5", + want: "internal/testdata/complex/service-templates/test2c-nginx-php", }, { - name: "test3 - funky pvcs", + name: "test3-funky-pvcs", description: "only create pvcs of the requested persistent-name in the docker-compose file", args: testdata.GetSeedData( testdata.TestData{ @@ -190,10 +195,10 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service2", + want: "internal/testdata/basic/service-templates/test3-funky-pvcs", }, { - name: "test4 - basic-persistent with worker-persistent", + name: "test4-basic-worker", description: "create a basic-persistent that gets a pvc and mount that volume on a worker-persistent type", args: testdata.GetSeedData( testdata.TestData{ @@ -214,10 +219,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service3", + want: "internal/testdata/basic/service-templates/test4-basic-worker", }, { - name: "test5 basic deployment promote", + name: "test5-basic-promote", + description: "create a basic deployment of the promote build type", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -230,10 +236,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service4", + want: "internal/testdata/basic/service-templates/test5-basic-promote", }, { - name: "test6 basic deployment pr with isolation network policy", + name: "test6-basic-networkpolicy", + description: "create basic deployment pullrequest with isolation network policy", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -257,10 +264,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service5", + want: "internal/testdata/basic/service-templates/test6-basic-networkpolicy", }, { - name: "test7 basic deployment with dynamic secrets", + name: "test7-basic-dynamic-secrets", + description: "create a basic deployment with dynamic secrets support", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -274,10 +282,11 @@ func TestTemplateLagoonServices(t *testing.T) { DynamicDBaaSSecrets: []string{"mariadb-dbaas-a4hs12h3"}, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service6", + want: "internal/testdata/basic/service-templates/test7-basic-dynamic-secrets", }, { - name: "test8 services deployment", + name: "test8-multiple-services", + description: "create a deployment with multiple services of various types", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -295,10 +304,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service3", + want: "internal/testdata/complex/service-templates/test8-multiple-services", }, { - name: "test9 compact services meta dbaas deployment", + name: "test9-meta-dbaas-types", + description: "create a deployment with meta dbaas types", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -313,7 +323,10 @@ func TestTemplateLagoonServices(t *testing.T) { "mongo-4": "harbor.example/example-project/main/mongo-4@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", }, ProjectVariables: []lagoon.EnvironmentVariable{ - {Name: "LAGOON_DBAAS_ENVIRONMENT_TYPES", Value: "postgres-15:production-postgres,mongo-4:production-mongo,mariadb-10-11:production-mariadb", Scope: "build"}, + { + Name: "LAGOON_DBAAS_ENVIRONMENT_TYPES", + Value: "postgres-15:production-postgres,mongo-4:production-mongo,mariadb-10-11:production-mariadb", + Scope: "build"}, { Name: "LAGOON_SYSTEM_CORE_VERSION", Value: "v2.19.0", @@ -322,10 +335,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service4", + want: "internal/testdata/complex/service-templates/test9-meta-dbaas-types", }, { - name: "test10 basic deployment native cronjobs disabled", + name: "test10-basic-no-native-cronjobs", + description: "create a basic deployment with native cronjobs disabled", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -337,10 +351,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service8", + want: "internal/testdata/basic/service-templates/test10-basic-no-native-cronjobs", }, { - name: "test11 basic deployment polysite cronjobs", + name: "test11-basic-polysite-cronjobs", + description: "create a basic deployment polysite with cronjobs", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -352,10 +367,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service7", + want: "internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs", }, { - name: "test12 basic-persistent deployment multiple volumes", + name: "test12-basic-persistent-custom-volumes", + description: "create a basic persistent with the seed volume and other custom volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -368,10 +384,11 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service9", + want: "internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes", }, { - name: "test13 basic deployment multiple volumes", + name: "test13-basic-custom-volumes", + description: "create a basic with custom volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -384,10 +401,10 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/basic/service-templates/service10", + want: "internal/testdata/basic/service-templates/test13-basic-custom-volumes", }, { - name: "test14 complex deployment multiple volumes", + name: "test14-complex-custom-volumes", args: testdata.GetSeedData( testdata.TestData{ ProjectName: "example-project", @@ -405,7 +422,7 @@ func TestTemplateLagoonServices(t *testing.T) { }, }, true), templatePath: "testoutput", - want: "internal/testdata/complex/service-templates/service6", + want: "internal/testdata/complex/service-templates/test14-complex-custom-volumes", }, } for _, tt := range tests { diff --git a/internal/testdata/basic/service-templates/service1/deployment-node.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/deployment-node.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service1/lagoon-private-registry-dockerhub.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-dockerhub.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/lagoon-private-registry-dockerhub.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-dockerhub.yaml diff --git a/internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-custom-registry.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-custom-registry.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-custom-registry.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-custom-registry.yaml diff --git a/internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-hardcode-registry.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-hardcode-registry.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-hardcode-registry.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-hardcode-registry.yaml diff --git a/internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-other-registry.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-other-registry.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/lagoon-private-registry-my-other-registry.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/lagoon-private-registry-my-other-registry.yaml diff --git a/internal/testdata/basic/service-templates/service1/service-node.yaml b/internal/testdata/basic/service-templates/test1-basic-deployment/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service1/service-node.yaml rename to internal/testdata/basic/service-templates/test1-basic-deployment/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service8/deployment-node.yaml b/internal/testdata/basic/service-templates/test10-basic-no-native-cronjobs/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service8/deployment-node.yaml rename to internal/testdata/basic/service-templates/test10-basic-no-native-cronjobs/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service6/service-node.yaml b/internal/testdata/basic/service-templates/test10-basic-no-native-cronjobs/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service6/service-node.yaml rename to internal/testdata/basic/service-templates/test10-basic-no-native-cronjobs/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml b/internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/cronjob-cronjob-node-some-other-drush-cron.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/cronjob-cronjob-node-some-other-drush-cron.yaml rename to internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/cronjob-cronjob-node-some-other-drush-cron.yaml diff --git a/internal/testdata/basic/service-templates/service7/deployment-node.yaml b/internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/deployment-node.yaml rename to internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service7/service-node.yaml b/internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service7/service-node.yaml rename to internal/testdata/basic/service-templates/test11-basic-polysite-cronjobs/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service9/deployment-node.yaml b/internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/deployment-node.yaml rename to internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service10/pvc-custom-config.yaml b/internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-custom-config.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service10/pvc-custom-config.yaml rename to internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-custom-config.yaml diff --git a/internal/testdata/basic/service-templates/service10/pvc-custom-files.yaml b/internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service10/pvc-custom-files.yaml rename to internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-custom-files.yaml diff --git a/internal/testdata/basic/service-templates/service9/pvc-node.yaml b/internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/pvc-node.yaml rename to internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/pvc-node.yaml diff --git a/internal/testdata/basic/service-templates/service9/service-node.yaml b/internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/service-node.yaml rename to internal/testdata/basic/service-templates/test12-basic-persistent-custom-volumes/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service10/deployment-node.yaml b/internal/testdata/basic/service-templates/test13-basic-custom-volumes/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service10/deployment-node.yaml rename to internal/testdata/basic/service-templates/test13-basic-custom-volumes/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-config.yaml b/internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-config.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/pvc-custom-config.yaml rename to internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-config.yaml diff --git a/internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml b/internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service9/pvc-custom-files.yaml rename to internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-files.yaml diff --git a/internal/testdata/basic/service-templates/service10/pvc-custom-node.yaml b/internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service10/pvc-custom-node.yaml rename to internal/testdata/basic/service-templates/test13-basic-custom-volumes/pvc-custom-node.yaml diff --git a/internal/testdata/basic/service-templates/service10/service-node.yaml b/internal/testdata/basic/service-templates/test13-basic-custom-volumes/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service10/service-node.yaml rename to internal/testdata/basic/service-templates/test13-basic-custom-volumes/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service2/deployment-lnd.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/deployment-lnd.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service2/deployment-thunderhub.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-thunderhub.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/deployment-thunderhub.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-thunderhub.yaml diff --git a/internal/testdata/basic/service-templates/service2/deployment-tor.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-tor.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/deployment-tor.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/deployment-tor.yaml diff --git a/internal/testdata/basic/service-templates/service2/pvc-lnd.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/pvc-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/pvc-lnd.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/pvc-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service2/service-lnd.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/service-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/service-lnd.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/service-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service2/service-thunderhub.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/service-thunderhub.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/service-thunderhub.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/service-thunderhub.yaml diff --git a/internal/testdata/basic/service-templates/service2/service-tor.yaml b/internal/testdata/basic/service-templates/test3-funky-pvcs/service-tor.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service2/service-tor.yaml rename to internal/testdata/basic/service-templates/test3-funky-pvcs/service-tor.yaml diff --git a/internal/testdata/basic/service-templates/service3/deployment-lnd.yaml b/internal/testdata/basic/service-templates/test4-basic-worker/deployment-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service3/deployment-lnd.yaml rename to internal/testdata/basic/service-templates/test4-basic-worker/deployment-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service3/deployment-tor.yaml b/internal/testdata/basic/service-templates/test4-basic-worker/deployment-tor.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service3/deployment-tor.yaml rename to internal/testdata/basic/service-templates/test4-basic-worker/deployment-tor.yaml diff --git a/internal/testdata/basic/service-templates/service3/pvc-lnd.yaml b/internal/testdata/basic/service-templates/test4-basic-worker/pvc-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service3/pvc-lnd.yaml rename to internal/testdata/basic/service-templates/test4-basic-worker/pvc-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service3/service-lnd.yaml b/internal/testdata/basic/service-templates/test4-basic-worker/service-lnd.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service3/service-lnd.yaml rename to internal/testdata/basic/service-templates/test4-basic-worker/service-lnd.yaml diff --git a/internal/testdata/basic/service-templates/service4/deployment-node.yaml b/internal/testdata/basic/service-templates/test5-basic-promote/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service4/deployment-node.yaml rename to internal/testdata/basic/service-templates/test5-basic-promote/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service4/service-node.yaml b/internal/testdata/basic/service-templates/test5-basic-promote/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service4/service-node.yaml rename to internal/testdata/basic/service-templates/test5-basic-promote/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service5/deployment-node.yaml b/internal/testdata/basic/service-templates/test6-basic-networkpolicy/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service5/deployment-node.yaml rename to internal/testdata/basic/service-templates/test6-basic-networkpolicy/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service5/isolation-network-policy.yaml b/internal/testdata/basic/service-templates/test6-basic-networkpolicy/isolation-network-policy.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service5/isolation-network-policy.yaml rename to internal/testdata/basic/service-templates/test6-basic-networkpolicy/isolation-network-policy.yaml diff --git a/internal/testdata/basic/service-templates/service5/service-node.yaml b/internal/testdata/basic/service-templates/test6-basic-networkpolicy/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service5/service-node.yaml rename to internal/testdata/basic/service-templates/test6-basic-networkpolicy/service-node.yaml diff --git a/internal/testdata/basic/service-templates/service6/deployment-node.yaml b/internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/deployment-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service6/deployment-node.yaml rename to internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/deployment-node.yaml diff --git a/internal/testdata/basic/service-templates/service6/lagoon-private-registry-my-custom-registry.yaml b/internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/lagoon-private-registry-my-custom-registry.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service6/lagoon-private-registry-my-custom-registry.yaml rename to internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/lagoon-private-registry-my-custom-registry.yaml diff --git a/internal/testdata/basic/service-templates/service8/service-node.yaml b/internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/service-node.yaml similarity index 100% rename from internal/testdata/basic/service-templates/service8/service-node.yaml rename to internal/testdata/basic/service-templates/test7-basic-dynamic-secrets/service-node.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-cli.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-cli.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-cli.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-cli.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-mariadb.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-mariadb.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service6/deployment-nginx.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/deployment-nginx.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/deployment-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service6/pvc-custom-files.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-custom-files.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/pvc-custom-files.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-custom-files.yaml diff --git a/internal/testdata/complex/service-templates/service6/pvc-mariadb.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/pvc-mariadb.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service6/pvc-nginx.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/pvc-nginx.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/pvc-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service6/service-mariadb.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/service-mariadb.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/service-mariadb.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/service-mariadb.yaml diff --git a/internal/testdata/complex/service-templates/service6/service-nginx.yaml b/internal/testdata/complex/service-templates/test14-complex-custom-volumes/service-nginx.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service6/service-nginx.yaml rename to internal/testdata/complex/service-templates/test14-complex-custom-volumes/service-nginx.yaml diff --git a/internal/testdata/complex/service-templates/service1/cronjob-cronjob-cli-drush-cron2.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/cronjob-cronjob-cli-drush-cron2.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml diff --git a/internal/testdata/complex/service-templates/service1/deployment-cli.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/deployment-cli.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/deployment-cli.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/deployment-cli.yaml diff --git a/internal/testdata/complex/service-templates/service1/deployment-nginx-php.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/deployment-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/deployment-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/deployment-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service1/deployment-redis.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/deployment-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/deployment-redis.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/deployment-redis.yaml diff --git a/internal/testdata/complex/service-templates/service1/deployment-varnish.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/deployment-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/deployment-varnish.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/deployment-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service1/pvc-nginx-php.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/pvc-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/pvc-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/pvc-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service1/service-nginx-php.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/service-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/service-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/service-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service1/service-redis.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/service-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/service-redis.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/service-redis.yaml diff --git a/internal/testdata/complex/service-templates/service1/service-varnish.yaml b/internal/testdata/complex/service-templates/test2-nginx-php/service-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service1/service-varnish.yaml rename to internal/testdata/complex/service-templates/test2-nginx-php/service-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service2/cronjob-cronjob-cli-drush-cron2.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/cronjob-cronjob-cli-drush-cron2.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml diff --git a/internal/testdata/complex/service-templates/service2/deployment-cli.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/deployment-cli.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/deployment-cli.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/deployment-cli.yaml diff --git a/internal/testdata/complex/service-templates/service2/deployment-nginx-php.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/deployment-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/deployment-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/deployment-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service2/deployment-redis.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/deployment-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/deployment-redis.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/deployment-redis.yaml diff --git a/internal/testdata/complex/service-templates/service2/deployment-varnish.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/deployment-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/deployment-varnish.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/deployment-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service2/pvc-nginx-php.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/pvc-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/pvc-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/pvc-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service2/service-nginx-php.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/service-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/service-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/service-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service2/service-redis.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/service-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/service-redis.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/service-redis.yaml diff --git a/internal/testdata/complex/service-templates/service2/service-varnish.yaml b/internal/testdata/complex/service-templates/test2b-nginx-php/service-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service2/service-varnish.yaml rename to internal/testdata/complex/service-templates/test2b-nginx-php/service-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/cronjob-cronjob-cli-drush-cron2.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/cronjob-cronjob-cli-drush-cron2.yaml diff --git a/internal/testdata/complex/service-templates/service5/deployment-cli.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/deployment-cli.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-cli.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/deployment-cli.yaml diff --git a/internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/deployment-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/deployment-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service5/deployment-redis.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/deployment-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-redis.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/deployment-redis.yaml diff --git a/internal/testdata/complex/service-templates/service5/deployment-varnish.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/deployment-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/deployment-varnish.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/deployment-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/pvc-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/pvc-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/pvc-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service5/service-nginx-php.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/service-nginx-php.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/service-nginx-php.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/service-nginx-php.yaml diff --git a/internal/testdata/complex/service-templates/service5/service-redis.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/service-redis.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/service-redis.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/service-redis.yaml diff --git a/internal/testdata/complex/service-templates/service5/service-varnish.yaml b/internal/testdata/complex/service-templates/test2c-nginx-php/service-varnish.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service5/service-varnish.yaml rename to internal/testdata/complex/service-templates/test2c-nginx-php/service-varnish.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-opensearch-2.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-opensearch-2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-opensearch-2.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-opensearch-2.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-postgres-11.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-postgres-11.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-redis-6.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-redis-6.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-redis-6.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-redis-6.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-redis-7.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-redis-7.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-redis-7.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-redis-7.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-solr-8.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-solr-8.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-solr-8.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-solr-8.yaml diff --git a/internal/testdata/complex/service-templates/service3/deployment-web.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/deployment-web.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/deployment-web.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/deployment-web.yaml diff --git a/internal/testdata/complex/service-templates/service3/pvc-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/pvc-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/pvc-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/pvc-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service3/pvc-opensearch-2.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/pvc-opensearch-2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/pvc-opensearch-2.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/pvc-opensearch-2.yaml diff --git a/internal/testdata/complex/service-templates/service3/pvc-postgres-11.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/pvc-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/pvc-postgres-11.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/pvc-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service3/pvc-solr-8.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/pvc-solr-8.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/pvc-solr-8.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/pvc-solr-8.yaml diff --git a/internal/testdata/complex/service-templates/service3/pvc-web.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/pvc-web.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/pvc-web.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/pvc-web.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-opensearch-2.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-opensearch-2.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-opensearch-2.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-opensearch-2.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-postgres-11.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-postgres-11.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-redis-6.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-redis-6.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-redis-6.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-redis-6.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-redis-7.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-redis-7.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-redis-7.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-redis-7.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-solr-8.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-solr-8.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-solr-8.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-solr-8.yaml diff --git a/internal/testdata/complex/service-templates/service3/service-web.yaml b/internal/testdata/complex/service-templates/test8-multiple-services/service-web.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service3/service-web.yaml rename to internal/testdata/complex/service-templates/test8-multiple-services/service-web.yaml diff --git a/internal/testdata/complex/service-templates/service4/deployment-mariadb-10-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mariadb-10-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/deployment-mariadb-10-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mariadb-10-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/deployment-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/deployment-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service4/deployment-mongo-4.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mongo-4.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/deployment-mongo-4.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-mongo-4.yaml diff --git a/internal/testdata/complex/service-templates/service4/deployment-postgres-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/deployment-postgres-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/deployment-postgres-15.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-postgres-15.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/deployment-postgres-15.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/deployment-postgres-15.yaml diff --git a/internal/testdata/complex/service-templates/service4/pvc-mariadb-10-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mariadb-10-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/pvc-mariadb-10-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mariadb-10-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/pvc-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/pvc-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service4/pvc-mongo-4.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mongo-4.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/pvc-mongo-4.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-mongo-4.yaml diff --git a/internal/testdata/complex/service-templates/service4/pvc-postgres-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/pvc-postgres-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/pvc-postgres-15.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-postgres-15.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/pvc-postgres-15.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/pvc-postgres-15.yaml diff --git a/internal/testdata/complex/service-templates/service4/service-mariadb-10-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mariadb-10-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/service-mariadb-10-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mariadb-10-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/service-mariadb-10-5.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mariadb-10-5.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/service-mariadb-10-5.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mariadb-10-5.yaml diff --git a/internal/testdata/complex/service-templates/service4/service-mongo-4.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mongo-4.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/service-mongo-4.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-mongo-4.yaml diff --git a/internal/testdata/complex/service-templates/service4/service-postgres-11.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-postgres-11.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/service-postgres-11.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-postgres-11.yaml diff --git a/internal/testdata/complex/service-templates/service4/service-postgres-15.yaml b/internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-postgres-15.yaml similarity index 100% rename from internal/testdata/complex/service-templates/service4/service-postgres-15.yaml rename to internal/testdata/complex/service-templates/test9-meta-dbaas-types/service-postgres-15.yaml From 8be0bc9ff3624e19942c914448c26d98ce34e0e7 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 26 Aug 2024 09:36:41 +1000 Subject: [PATCH 10/10] feat: support label on volume to disable backups for that volume --- cmd/template_lagoonservices_test.go | 17 ++++ internal/generator/buildvalues.go | 3 +- internal/generator/services.go | 2 +- internal/generator/volumes.go | 12 ++- internal/templating/services/templates_pvc.go | 5 +- .../docker-compose.multiple-volumes-3.yml | 40 ++++++++ .../basic/lagoon.multiple-volumes-3.yml | 10 ++ .../deployment-node.yaml | 95 +++++++++++++++++++ .../pvc-custom-node.yaml | 29 ++++++ .../pvc-custom-scratch.yaml | 29 ++++++ .../service-node.yaml | 31 ++++++ 11 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 internal/testdata/basic/docker-compose.multiple-volumes-3.yml create mode 100644 internal/testdata/basic/lagoon.multiple-volumes-3.yml create mode 100644 internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/deployment-node.yaml create mode 100644 internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-node.yaml create mode 100644 internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-scratch.yaml create mode 100644 internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/service-node.yaml diff --git a/cmd/template_lagoonservices_test.go b/cmd/template_lagoonservices_test.go index 9d8a3515..561f2ea4 100644 --- a/cmd/template_lagoonservices_test.go +++ b/cmd/template_lagoonservices_test.go @@ -424,6 +424,23 @@ func TestTemplateLagoonServices(t *testing.T) { templatePath: "testoutput", want: "internal/testdata/complex/service-templates/test14-complex-custom-volumes", }, + { + name: "test15-basic-custom-volume-no-backup", + description: "create a basic with custom volumes with one volume flagged to not be backed up", + args: testdata.GetSeedData( + testdata.TestData{ + ProjectName: "example-project", + EnvironmentName: "main", + Branch: "main", + BuildType: "branch", + LagoonYAML: "internal/testdata/basic/lagoon.multiple-volumes-3.yml", + ImageReferences: map[string]string{ + "node": "harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8", + }, + }, true), + templatePath: "testoutput", + want: "internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/generator/buildvalues.go b/internal/generator/buildvalues.go index 5d56891b..887b88aa 100644 --- a/internal/generator/buildvalues.go +++ b/internal/generator/buildvalues.go @@ -152,7 +152,8 @@ type ImageCacheBuildArguments struct { type ComposeVolume struct { Name string `json:"name" description:"name is the name the volume, when creating in kubernetes will have a prefix"` Size string `json:"size" description:"the size of the volume to request if the system enforces it"` - Create bool `json:"unused" description:"flag to determine if this volume is to be created or not"` + Create bool `json:"create" description:"flag to determine if this volume is to be created or not"` + Backup bool `json:"Backup" description:"flag to determine if this volume has backups enabled or not"` } type ServiceVolume struct { diff --git a/internal/generator/services.go b/internal/generator/services.go index bd25c00a..bcf06538 100644 --- a/internal/generator/services.go +++ b/internal/generator/services.go @@ -108,7 +108,7 @@ func generateServicesFromDockerCompose( } // convert docker-compose volumes to buildvolumes, - err = convertVolumes(buildValues, lCompose, lComposeVolumes, debug) + err = convertVolumes(buildValues, lCompose, lComposeVolumes) if err != nil { return err } diff --git a/internal/generator/volumes.go b/internal/generator/volumes.go index 8b95842c..00740d15 100644 --- a/internal/generator/volumes.go +++ b/internal/generator/volumes.go @@ -15,7 +15,7 @@ var ( ) // convertVolumes handles converting docker compose volumes into lagoon volumes and adds them to build values -func convertVolumes(buildValues *BuildValues, lCompose *composetypes.Project, lComposeVolumes []lagoon.OriginalVolumeOrder, debug bool) error { +func convertVolumes(buildValues *BuildValues, lCompose *composetypes.Project, lComposeVolumes []lagoon.OriginalVolumeOrder) error { // convert docker-compose volumes to buildvolumes, // range over the volumes and add them to build values for _, vol := range lComposeVolumes { @@ -23,7 +23,7 @@ func convertVolumes(buildValues *BuildValues, lCompose *composetypes.Project, lC // check that the volumename from the ordered volumes matches (with the composestack name prefix) if lagoon.GetComposeVolumeName(lCompose.Name, vol.Name) == composeVolumeValues.Name { // if so, check that the volume returns values correctly - cVolume, err := composeToVolumeValues(lCompose.Name, composeVolumeValues, debug) + cVolume, err := composeToVolumeValues(lCompose.Name, composeVolumeValues) if err != nil { return err } @@ -45,7 +45,6 @@ func convertVolumes(buildValues *BuildValues, lCompose *composetypes.Project, lC func composeToVolumeValues( composeName string, composeVolumeValues composetypes.VolumeConfig, - debug bool, ) (*ComposeVolume, error) { // if there are no labels, then this is probably not going to end up in Lagoon // the lagoonType check will skip to the end and return an empty service definition @@ -79,6 +78,13 @@ func composeToVolumeValues( // use the lagoonVolumename which contains the `custom-` prefix Name: lagoonVolumeName, Size: volumeSize, + // backup volumes by default + Backup: true, + } + // allow volumes to have the backup flag to disable it from being backed up + volumeBackup := lagoon.CheckDockerComposeLagoonLabel(composeVolumeValues.Labels, "lagoon.backup") + if volumeBackup == "false" { + cVolume.Backup = false } return cVolume, nil } diff --git a/internal/templating/services/templates_pvc.go b/internal/templating/services/templates_pvc.go index ee1020b8..7f0da966 100644 --- a/internal/templating/services/templates_pvc.go +++ b/internal/templating/services/templates_pvc.go @@ -166,8 +166,9 @@ func generateAdditionalPVC( additionalLabels["lagoon.sh/template"] = fmt.Sprintf("%s-%s", "additional-volume", "0.1.0") additionalLabels["lagoon.sh/service-type"] = "additional-volume" - additionalAnnotations["k8up.syn.tools/backup"] = "true" - additionalAnnotations["k8up.io/backup"] = "true" + // if the volume has backups, set the backup annotations + additionalAnnotations["k8up.syn.tools/backup"] = strconv.FormatBool(additionalVolume.Backup) + additionalAnnotations["k8up.io/backup"] = strconv.FormatBool(additionalVolume.Backup) pvc := &corev1.PersistentVolumeClaim{ TypeMeta: metav1.TypeMeta{ diff --git a/internal/testdata/basic/docker-compose.multiple-volumes-3.yml b/internal/testdata/basic/docker-compose.multiple-volumes-3.yml new file mode 100644 index 00000000..ceb6102d --- /dev/null +++ b/internal/testdata/basic/docker-compose.multiple-volumes-3.yml @@ -0,0 +1,40 @@ +version: '2' +services: + node: + networks: + - amazeeio-network + - default + build: + context: internal/testdata/basic/docker + dockerfile: basic.dockerfile + labels: + lagoon.type: basic + lagoon.volumes.scratch.path: /scratch + lagoon.volumes.node.path: /data + volumes: + - node:/data + - scratch:/scratch + + mariadb: + image: uselagoon/mariadb-10.5-drupal:latest + labels: + lagoon.type: none + volumes: + - db:/var/lib/mysql + +networks: + amazeeio-network: + external: true + +volumes: + node: + labels: + lagoon.type: persistent + scratch: + labels: + lagoon.type: persistent + lagoon.backup: false + db: + labels: + # this label is not technically needed, but explicit + lagoon.type: none \ No newline at end of file diff --git a/internal/testdata/basic/lagoon.multiple-volumes-3.yml b/internal/testdata/basic/lagoon.multiple-volumes-3.yml new file mode 100644 index 00000000..3c343a4b --- /dev/null +++ b/internal/testdata/basic/lagoon.multiple-volumes-3.yml @@ -0,0 +1,10 @@ +docker-compose-yaml: internal/testdata/basic/docker-compose.multiple-volumes-3.yml + +environment_variables: + git_sha: "true" + +environments: + main: + routes: + - node: + - example.com diff --git a/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/deployment-node.yaml b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/deployment-node.yaml new file mode 100644 index 00000000..7ca41d5a --- /dev/null +++ b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/deployment-node.yaml @@ -0,0 +1,95 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic + strategy: {} + template: + metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/configMapSha: abcdefg1234567890 + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + spec: + containers: + - env: + - name: LAGOON_GIT_SHA + value: abcdefg123456 + - name: CRONJOBS + - name: SERVICE_NAME + value: node + envFrom: + - configMapRef: + name: lagoon-env + image: harbor.example/example-project/main/node@sha256:b2001babafaa8128fe89aa8fd11832cade59931d14c3de5b3ca32e2a010fbaa8 + imagePullPolicy: Always + livenessProbe: + initialDelaySeconds: 60 + tcpSocket: + port: 3000 + timeoutSeconds: 10 + name: basic + ports: + - containerPort: 3000 + name: http + protocol: TCP + readinessProbe: + initialDelaySeconds: 1 + tcpSocket: + port: 3000 + timeoutSeconds: 1 + resources: + requests: + cpu: 10m + memory: 10Mi + securityContext: {} + volumeMounts: + - mountPath: /data + name: custom-node + - mountPath: /scratch + name: custom-scratch + enableServiceLinks: false + imagePullSecrets: + - name: lagoon-internal-registry-secret + priorityClassName: lagoon-priority-production + volumes: + - name: custom-node + persistentVolumeClaim: + claimName: custom-node + - name: custom-scratch + persistentVolumeClaim: + claimName: custom-scratch +status: {} diff --git a/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-node.yaml b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-node.yaml new file mode 100644 index 00000000..d83a6615 --- /dev/null +++ b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-node.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "true" + k8up.syn.tools/backup: "true" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: node + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-node +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-scratch.yaml b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-scratch.yaml new file mode 100644 index 00000000..637f7eaf --- /dev/null +++ b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/pvc-custom-scratch.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: + k8up.io/backup: "false" + k8up.syn.tools/backup: "false" + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: custom-scratch + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: scratch + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service-type: additional-volume + lagoon.sh/template: additional-volume-0.1.0 + name: custom-scratch +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + storageClassName: bulk +status: {} diff --git a/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/service-node.yaml b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/service-node.yaml new file mode 100644 index 00000000..3d4d875d --- /dev/null +++ b/internal/testdata/basic/service-templates/test15-basic-custom-volume-no-backup/service-node.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + lagoon.sh/branch: main + lagoon.sh/version: v2.7.x + creationTimestamp: null + labels: + app.kubernetes.io/instance: node + app.kubernetes.io/managed-by: build-deploy-tool + app.kubernetes.io/name: basic + lagoon.sh/buildType: branch + lagoon.sh/environment: main + lagoon.sh/environmentType: production + lagoon.sh/project: example-project + lagoon.sh/service: node + lagoon.sh/service-type: basic + lagoon.sh/template: basic-0.1.0 + name: node +spec: + ports: + - name: http + port: 3000 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: node + app.kubernetes.io/name: basic +status: + loadBalancer: {}