Skip to content

Commit cf2a8b9

Browse files
committed
feat: initial pass at service cleanup
1 parent 24d525b commit cf2a8b9

File tree

5 files changed

+264
-0
lines changed

5 files changed

+264
-0
lines changed

cmd/identify_ingress_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"reflect"
66
"testing"
77

8+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
89
"github.com/uselagoon/build-deploy-tool/internal/lagoon"
910
"github.com/uselagoon/build-deploy-tool/internal/testdata"
1011
)
@@ -378,6 +379,9 @@ func TestIdentifyRoute(t *testing.T) {
378379
if string(retJSON) != tt.wantJSON {
379380
t.Errorf("returned autogen %v doesn't match want %v", string(retJSON), tt.wantJSON)
380381
}
382+
t.Cleanup(func() {
383+
helpers.UnsetEnvVars(nil)
384+
})
381385
})
382386
}
383387
}

cmd/identify_services.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/spf13/cobra"
8+
generator "github.com/uselagoon/build-deploy-tool/internal/generator"
9+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
10+
)
11+
12+
type identifyServices struct {
13+
Name string `json:"name"`
14+
Type string `json:"type"`
15+
}
16+
17+
var servicesIdentify = &cobra.Command{
18+
Use: "services",
19+
Aliases: []string{"s"},
20+
Short: "Identify services that this build would create",
21+
RunE: func(cmd *cobra.Command, args []string) error {
22+
generator, err := generator.GenerateInput(*rootCmd, false)
23+
if err != nil {
24+
return err
25+
}
26+
ret, _, err := IdentifyServices(generator)
27+
if err != nil {
28+
return err
29+
}
30+
retJSON, _ := json.Marshal(ret)
31+
fmt.Println(string(retJSON))
32+
return nil
33+
},
34+
}
35+
36+
// IdentifyServices identifies services that this build would create
37+
func IdentifyServices(g generator.GeneratorInput) ([]string, []identifyServices, error) {
38+
lagoonBuild, err := generator.NewGenerator(
39+
g,
40+
)
41+
if err != nil {
42+
return nil, nil, err
43+
}
44+
45+
services := []string{}
46+
serviceTypes := []identifyServices{}
47+
for _, service := range lagoonBuild.BuildValues.Services {
48+
if service.Type != "" {
49+
services = helpers.AppendIfMissing(services, service.OverrideName)
50+
serviceTypes = AppendIfMissing(serviceTypes, identifyServices{
51+
Name: service.OverrideName,
52+
Type: service.Type,
53+
})
54+
}
55+
}
56+
return services, serviceTypes, nil
57+
}
58+
59+
func init() {
60+
identifyCmd.AddCommand(servicesIdentify)
61+
}
62+
63+
func AppendIfMissing(slice []identifyServices, i identifyServices) []identifyServices {
64+
for _, ele := range slice {
65+
if ele.Name == i.Name {
66+
return slice
67+
}
68+
}
69+
return append(slice, i)
70+
}

cmd/identify_services_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package cmd
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
8+
"github.com/uselagoon/build-deploy-tool/internal/lagoon"
9+
"github.com/uselagoon/build-deploy-tool/internal/testdata"
10+
)
11+
12+
func TestIdentifyServices(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
args testdata.TestData
16+
templatePath string
17+
want []string
18+
wantServices []identifyServices
19+
wantErr bool
20+
}{
21+
{
22+
name: "test1 single service",
23+
args: testdata.GetSeedData(
24+
testdata.TestData{
25+
ProjectName: "example-project",
26+
EnvironmentName: "main",
27+
Branch: "main",
28+
LagoonYAML: "../internal/testdata/node/lagoon.yml",
29+
}, true),
30+
templatePath: "testdata/output",
31+
want: []string{"node"},
32+
wantServices: []identifyServices{{Name: "node", Type: "node"}},
33+
},
34+
{
35+
name: "test2 complex servives",
36+
args: testdata.GetSeedData(
37+
testdata.TestData{
38+
ProjectName: "example-project",
39+
EnvironmentName: "main",
40+
Branch: "main",
41+
EnvironmentType: "development",
42+
LagoonYAML: "../internal/testdata/complex/lagoon.yml",
43+
}, true),
44+
templatePath: "testdata/output",
45+
want: []string{"cli", "nginx-php", "mariadb", "redis"},
46+
wantServices: []identifyServices{
47+
{Name: "cli", Type: "cli-persistent"},
48+
{Name: "nginx-php", Type: "nginx-php-persistent"},
49+
{Name: "mariadb", Type: "mariadb-dbaas"},
50+
{Name: "redis", Type: "redis"},
51+
},
52+
},
53+
{
54+
name: "test3 complex servives where one is removed",
55+
args: testdata.GetSeedData(
56+
testdata.TestData{
57+
ProjectName: "example-project",
58+
EnvironmentName: "main",
59+
Branch: "main",
60+
EnvironmentType: "development",
61+
LagoonYAML: "../internal/testdata/complex/lagoon.yml",
62+
EnvVariables: []lagoon.EnvironmentVariable{
63+
{
64+
Name: "LAGOON_SERVICE_TYPES",
65+
Value: "redis:none",
66+
Scope: "build",
67+
},
68+
},
69+
}, true),
70+
templatePath: "testdata/output",
71+
want: []string{"cli", "nginx-php", "mariadb"},
72+
wantServices: []identifyServices{
73+
{Name: "cli", Type: "cli-persistent"},
74+
{Name: "nginx-php", Type: "nginx-php-persistent"},
75+
{Name: "mariadb", Type: "mariadb-dbaas"},
76+
},
77+
},
78+
}
79+
for _, tt := range tests {
80+
t.Run(tt.name, func(t *testing.T) {
81+
// set the environment variables from args
82+
savedTemplates := tt.templatePath
83+
generator, err := testdata.SetupEnvironment(*rootCmd, savedTemplates, tt.args)
84+
if err != nil {
85+
t.Errorf("%v", err)
86+
}
87+
got, got2, err := IdentifyServices(generator)
88+
if (err != nil) != tt.wantErr {
89+
t.Errorf("IdentifyServices() error = %v, wantErr %v", err, tt.wantErr)
90+
return
91+
}
92+
if !reflect.DeepEqual(got, tt.want) {
93+
t.Errorf("IdentifyServices() = %v, want %v", got, tt.want)
94+
}
95+
if !reflect.DeepEqual(got2, tt.wantServices) {
96+
t.Errorf("IdentifyServices() = %v, want %v", got2, tt.wantServices)
97+
}
98+
t.Cleanup(func() {
99+
helpers.UnsetEnvVars(nil)
100+
})
101+
})
102+
}
103+
}

internal/helpers/helpers.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,12 @@ func DeepCopy(src, dist interface{}) (err error) {
236236
}
237237
return gob.NewDecoder(&buf).Decode(dist)
238238
}
239+
240+
func AppendIfMissing(slice []string, i string) []string {
241+
for _, ele := range slice {
242+
if ele == i {
243+
return slice
244+
}
245+
}
246+
return append(slice, i)
247+
}

legacy/build-deploy-docker-compose.sh

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,84 @@ set +x
18321832
currentStepEnd="$(date +"%Y-%m-%d %H:%M:%S")"
18331833
patchBuildStep "${buildStartTime}" "${previousStepEnd}" "${currentStepEnd}" "${NAMESPACE}" "deploymentApplyComplete" "Applying Deployments" "false"
18341834
previousStepEnd=${currentStepEnd}
1835+
beginBuildStep "Service/Deployment Cleanup" "cleanupServices"
1836+
1837+
##############################################
1838+
### CLEANUP services which have been removed from docker-compose.yaml
1839+
##############################################s
1840+
1841+
set +x
1842+
# collect the current routes, its possible to exclude ingress by adding a label 'route.lagoon.sh/remove=false' and it won't get deleted
1843+
CURRENT_SERVICES=$(kubectl -n ${NAMESPACE} get deployments -l "lagoon.sh/service-type" -l "lagoon.sh/service" --no-headers | cut -d " " -f 1 | xargs)
1844+
# collect the routes that Lagoon thinks it should have based on the .lagoon.yml and any routes that have come from the api
1845+
# using the build-deploy-tool generator
1846+
SERVICES_TO_JSON=$(build-deploy-tool identify services | jq -r '.[]')
1847+
1848+
MATCHED_SERVICE=false
1849+
DELETE_SERVICE=()
1850+
# loop over the routes from kubernetes
1851+
for EXIST_SERVICE in ${CURRENT_SERVICES}; do
1852+
# loop over the routes that Lagoon thinks it should have
1853+
for SERVICE in ${SERVICES_TO_JSON}; do
1854+
if [ "${EXIST_SERVICE}" == "${SERVICE}" ]; then
1855+
MATCHED_SERVICE=true
1856+
continue
1857+
fi
1858+
done
1859+
if [ "${MATCHED_SERVICE}" != "true" ]; then
1860+
DELETE_SERVICE+=($EXIST_SERVICE)
1861+
fi
1862+
MATCHED_SERVICE=false
1863+
done
1864+
1865+
SERVICE_CLEANUP_WARNINGS="false"
1866+
if [ ${#DELETE_SERVICE[@]} -ne 0 ]; then
1867+
SERVICE_CLEANUP_WARNINGS="true"
1868+
((++BUILD_WARNING_COUNT))
1869+
echo ">> Lagoon detected services that have been removed from the docker-compose file"
1870+
if [ "$(featureFlag CLEANUP_REMOVED_LAGOON_SERVICES)" != enabled ]; then
1871+
echo "> You can remove these in the next build by setting the flag 'LAGOON_FEATURE_FLAG_CLEANUP_REMOVED_LAGOON_SERVICES=enabled' as a GLOBAL scoped variable to this environment or project"
1872+
fi
1873+
for DS in ${DELETE_SERVICE[@]}
1874+
do
1875+
if [ "$(featureFlag CLEANUP_REMOVED_LAGOON_SERVICES)" = enabled ]; then
1876+
echo ">> Removing deployment ${DS}"
1877+
if kubectl -n ${NAMESPACE} get deployments ${DS} &> /dev/null; then
1878+
kubectl -n ${NAMESPACE} delete deployment ${DS}
1879+
fi
1880+
if kubectl -n ${NAMESPACE} get service ${DS} &> /dev/null; then
1881+
echo ">>> Removing associated service ${DS}"
1882+
kubectl -n ${NAMESPACE} delete service ${DS}
1883+
fi
1884+
if kubectl -n ${NAMESPACE} get ingress ${DS} &> /dev/null; then
1885+
echo ">>> Removing associated ingress ${DS}"
1886+
kubectl -n ${NAMESPACE} delete ingress ${DS}
1887+
fi
1888+
if kubectl -n ${NAMESPACE} get pvc ${DS} &> /dev/null; then
1889+
echo ">>> Removing associated persistent volume ${DS}"
1890+
kubectl -n ${NAMESPACE} delete pvc ${DS}
1891+
fi
1892+
#delete anything else?
1893+
else
1894+
echo ">> The deployment '${DS}' would be removed"
1895+
if kubectl -n ${NAMESPACE} get service ${DS} &> /dev/null; then
1896+
echo ">>> The associated service '${DS}' would be removed"
1897+
fi
1898+
if kubectl -n ${NAMESPACE} get ingress ${DS} &> /dev/null; then
1899+
echo ">>> The associated ingress '${DS}' would be removed"
1900+
fi
1901+
if kubectl -n ${NAMESPACE} get pvc ${DS} &> /dev/null; then
1902+
echo ">>> The associated persistent volume '${DS}' would be removed"
1903+
fi
1904+
fi
1905+
done
1906+
else
1907+
echo "No service cleanup required"
1908+
fi
1909+
1910+
currentStepEnd="$(date +"%Y-%m-%d %H:%M:%S")"
1911+
patchBuildStep "${buildStartTime}" "${previousStepEnd}" "${currentStepEnd}" "${NAMESPACE}" "serviceCleanupComplete" "Service/Deployment Cleanup" "${SERVICE_CLEANUP_WARNINGS}"
1912+
previousStepEnd=${currentStepEnd}
18351913
beginBuildStep "Cronjob Cleanup" "cleaningUpCronjobs"
18361914
set -x
18371915

0 commit comments

Comments
 (0)