Skip to content

Commit 1b83d72

Browse files
committed
feat: initial pass at service cleanup
1 parent a429aff commit 1b83d72

File tree

5 files changed

+322
-0
lines changed

5 files changed

+322
-0
lines changed

cmd/identify_ingress_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/uselagoon/build-deploy-tool/internal/dbaasclient"
11+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
1112
)
1213

1314
func TestIdentifyRoute(t *testing.T) {
@@ -530,6 +531,9 @@ func TestIdentifyRoute(t *testing.T) {
530531
if string(retJSON) != tt.wantJSON {
531532
t.Errorf("returned autogen %v doesn't match want %v", string(retJSON), tt.wantJSON)
532533
}
534+
t.Cleanup(func() {
535+
helpers.UnsetEnvVars(nil)
536+
})
533537
})
534538
}
535539
}

cmd/identify_services.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 serviceIdentifyJSON 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 := generatorInput(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, error) {
38+
lagoonBuild, err := generator.NewGenerator(
39+
g,
40+
)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
services := []string{}
46+
for _, service := range lagoonBuild.BuildValues.Services {
47+
if service.Type != "" {
48+
services = helpers.AppendIfMissing(services, service.OverrideName)
49+
}
50+
}
51+
return services, nil
52+
}
53+
54+
func init() {
55+
identifyCmd.AddCommand(servicesIdentify)
56+
}

cmd/identify_services_test.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
"reflect"
6+
"testing"
7+
"time"
8+
9+
"github.com/uselagoon/build-deploy-tool/internal/dbaasclient"
10+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
11+
)
12+
13+
func TestIdentifyServices(t *testing.T) {
14+
type args struct {
15+
alertContact string
16+
statusPageID string
17+
projectName string
18+
environmentName string
19+
branch string
20+
prNumber string
21+
prHeadBranch string
22+
prBaseBranch string
23+
environmentType string
24+
buildType string
25+
activeEnvironment string
26+
standbyEnvironment string
27+
cacheNoCache string
28+
serviceID string
29+
secretPrefix string
30+
projectVars string
31+
envVars string
32+
lagoonVersion string
33+
lagoonYAML string
34+
valuesFilePath string
35+
templatePath string
36+
}
37+
tests := []struct {
38+
name string
39+
args args
40+
want []string
41+
wantErr bool
42+
}{
43+
{
44+
name: "test1 check LAGOON_FASTLY_SERVICE_IDS with secret no values",
45+
args: args{
46+
alertContact: "alertcontact",
47+
statusPageID: "statuspageid",
48+
projectName: "example-project",
49+
environmentName: "main",
50+
environmentType: "production",
51+
buildType: "branch",
52+
lagoonVersion: "v2.7.x",
53+
branch: "main",
54+
projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${service}-${project}-${environment}.example.com","scope":"internal_system"},{"name":"LAGOON_FASTLY_SERVICE_IDS","value":"example.com:service-id:true:annotationscom","scope":"build"}]`,
55+
envVars: `[]`,
56+
lagoonYAML: "../test-resources/identify-ingress/test1/lagoon.yml",
57+
templatePath: "../test-resources/output",
58+
},
59+
want: []string{"node"},
60+
},
61+
{
62+
name: "test16 autogenerated routes where lagoon.name of service does not match service names",
63+
args: args{
64+
alertContact: "alertcontact",
65+
statusPageID: "statuspageid",
66+
projectName: "content-example-com",
67+
environmentName: "feature-migration",
68+
environmentType: "development",
69+
buildType: "branch",
70+
lagoonVersion: "v2.7.x",
71+
branch: "feature/migration",
72+
projectVars: `[{"name":"LAGOON_SYSTEM_ROUTER_PATTERN","value":"${environment}.${project}.example.com","scope":"internal_system"}]`,
73+
envVars: `[]`,
74+
lagoonYAML: "../test-resources/identify-ingress/test16/lagoon.yml",
75+
templatePath: "../test-resources/output",
76+
},
77+
want: []string{"cli", "nginx-php", "mariadb", "redis"},
78+
},
79+
}
80+
for _, tt := range tests {
81+
t.Run(tt.name, func(t *testing.T) {
82+
// set the environment variables from args
83+
err := os.Setenv("MONITORING_ALERTCONTACT", tt.args.alertContact)
84+
if err != nil {
85+
t.Errorf("%v", err)
86+
}
87+
err = os.Setenv("MONITORING_STATUSPAGEID", tt.args.statusPageID)
88+
if err != nil {
89+
t.Errorf("%v", err)
90+
}
91+
err = os.Setenv("PROJECT", tt.args.projectName)
92+
if err != nil {
93+
t.Errorf("%v", err)
94+
}
95+
err = os.Setenv("ENVIRONMENT", tt.args.environmentName)
96+
if err != nil {
97+
t.Errorf("%v", err)
98+
}
99+
err = os.Setenv("BRANCH", tt.args.branch)
100+
if err != nil {
101+
t.Errorf("%v", err)
102+
}
103+
err = os.Setenv("LAGOON_GIT_BRANCH", tt.args.branch)
104+
if err != nil {
105+
t.Errorf("%v", err)
106+
}
107+
err = os.Setenv("PR_NUMBER", tt.args.prNumber)
108+
if err != nil {
109+
t.Errorf("%v", err)
110+
}
111+
err = os.Setenv("PR_HEAD_BRANCH", tt.args.prHeadBranch)
112+
if err != nil {
113+
t.Errorf("%v", err)
114+
}
115+
err = os.Setenv("PR_BASE_BRANCH", tt.args.prBaseBranch)
116+
if err != nil {
117+
t.Errorf("%v", err)
118+
}
119+
err = os.Setenv("ENVIRONMENT_TYPE", tt.args.environmentType)
120+
if err != nil {
121+
t.Errorf("%v", err)
122+
}
123+
err = os.Setenv("BUILD_TYPE", tt.args.buildType)
124+
if err != nil {
125+
t.Errorf("%v", err)
126+
}
127+
err = os.Setenv("ACTIVE_ENVIRONMENT", tt.args.activeEnvironment)
128+
if err != nil {
129+
t.Errorf("%v", err)
130+
}
131+
err = os.Setenv("STANDBY_ENVIRONMENT", tt.args.standbyEnvironment)
132+
if err != nil {
133+
t.Errorf("%v", err)
134+
}
135+
err = os.Setenv("LAGOON_FASTLY_NOCACHE_SERVICE_ID", tt.args.cacheNoCache)
136+
if err != nil {
137+
t.Errorf("%v", err)
138+
}
139+
err = os.Setenv("LAGOON_PROJECT_VARIABLES", tt.args.projectVars)
140+
if err != nil {
141+
t.Errorf("%v", err)
142+
}
143+
err = os.Setenv("LAGOON_ENVIRONMENT_VARIABLES", tt.args.envVars)
144+
if err != nil {
145+
t.Errorf("%v", err)
146+
}
147+
err = os.Setenv("LAGOON_VERSION", tt.args.lagoonVersion)
148+
if err != nil {
149+
t.Errorf("%v", err)
150+
}
151+
generator, err := generatorInput(false)
152+
if err != nil {
153+
t.Errorf("%v", err)
154+
}
155+
generator.LagoonYAML = tt.args.lagoonYAML
156+
// add dbaasclient overrides for tests
157+
generator.DBaaSClient = dbaasclient.NewClient(dbaasclient.Client{
158+
RetryMax: 5,
159+
RetryWaitMin: time.Duration(10) * time.Millisecond,
160+
RetryWaitMax: time.Duration(50) * time.Millisecond,
161+
})
162+
got, err := IdentifyServices(generator)
163+
if (err != nil) != tt.wantErr {
164+
t.Errorf("IdentifyServices() error = %v, wantErr %v", err, tt.wantErr)
165+
return
166+
}
167+
if !reflect.DeepEqual(got, tt.want) {
168+
t.Errorf("IdentifyServices() = %v, want %v", got, tt.want)
169+
}
170+
t.Cleanup(func() {
171+
helpers.UnsetEnvVars(nil)
172+
})
173+
})
174+
}
175+
}

internal/helpers/helpers.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,12 @@ func DeepCopy(src, dist interface{}) (err error) {
219219
}
220220
return gob.NewDecoder(&buf).Decode(dist)
221221
}
222+
223+
func AppendIfMissing(slice []string, i string) []string {
224+
for _, ele := range slice {
225+
if ele == i {
226+
return slice
227+
}
228+
}
229+
return append(slice, i)
230+
}

legacy/build-deploy-docker-compose.sh

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,84 @@ set +x
17571757
currentStepEnd="$(date +"%Y-%m-%d %H:%M:%S")"
17581758
patchBuildStep "${buildStartTime}" "${previousStepEnd}" "${currentStepEnd}" "${NAMESPACE}" "deploymentApplyComplete" "Applying Deployments" "false"
17591759
previousStepEnd=${currentStepEnd}
1760+
beginBuildStep "Service/Deployment Cleanup" "cleanupServices"
1761+
1762+
##############################################
1763+
### CLEANUP services which have been removed from docker-compose.yaml
1764+
##############################################s
1765+
1766+
set +x
1767+
# collect the current routes, its possible to exclude ingress by adding a label 'route.lagoon.sh/remove=false' and it won't get deleted
1768+
CURRENT_SERVICES=$(kubectl -n ${NAMESPACE} get deployments -l "lagoon.sh/service-type" -l "lagoon.sh/service" --no-headers | cut -d " " -f 1 | xargs)
1769+
# collect the routes that Lagoon thinks it should have based on the .lagoon.yml and any routes that have come from the api
1770+
# using the build-deploy-tool generator
1771+
SERVICES_TO_JSON=$(build-deploy-tool identify services | jq -r '.[]')
1772+
1773+
MATCHED_SERVICE=false
1774+
DELETE_SERVICE=()
1775+
# loop over the routes from kubernetes
1776+
for EXIST_SERVICE in ${CURRENT_SERVICES}; do
1777+
# loop over the routes that Lagoon thinks it should have
1778+
for SERVICE in ${SERVICES_TO_JSON}; do
1779+
if [ "${EXIST_SERVICE}" == "${SERVICE}" ]; then
1780+
MATCHED_SERVICE=true
1781+
continue
1782+
fi
1783+
done
1784+
if [ "${MATCHED_SERVICE}" != "true" ]; then
1785+
DELETE_SERVICE+=($EXIST_SERVICE)
1786+
fi
1787+
MATCHED_SERVICE=false
1788+
done
1789+
1790+
SERVICE_CLEANUP_WARNINGS="false"
1791+
if [ ${#DELETE_SERVICE[@]} -ne 0 ]; then
1792+
SERVICE_CLEANUP_WARNINGS="true"
1793+
((++BUILD_WARNING_COUNT))
1794+
echo ">> Lagoon detected services that have been removed from the docker-compose file"
1795+
if [ "$(featureFlag CLEANUP_REMOVED_LAGOON_SERVICES)" != enabled ]; then
1796+
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"
1797+
fi
1798+
for DS in ${DELETE_SERVICE[@]}
1799+
do
1800+
if [ "$(featureFlag CLEANUP_REMOVED_LAGOON_SERVICES)" = enabled ]; then
1801+
echo ">> Removing deployment ${DS}"
1802+
if kubectl -n ${NAMESPACE} get deployments ${DS} &> /dev/null; then
1803+
kubectl -n ${NAMESPACE} delete deployment ${DS}
1804+
fi
1805+
if kubectl -n ${NAMESPACE} get service ${DS} &> /dev/null; then
1806+
echo ">>> Removing associated service ${DS}"
1807+
kubectl -n ${NAMESPACE} delete service ${DS}
1808+
fi
1809+
if kubectl -n ${NAMESPACE} get ingress ${DS} &> /dev/null; then
1810+
echo ">>> Removing associated ingress ${DS}"
1811+
kubectl -n ${NAMESPACE} delete ingress ${DS}
1812+
fi
1813+
if kubectl -n ${NAMESPACE} get pvc ${DS} &> /dev/null; then
1814+
echo ">>> Removing associated persistent volume ${DS}"
1815+
kubectl -n ${NAMESPACE} delete pvc ${DS}
1816+
fi
1817+
#delete anything else?
1818+
else
1819+
echo ">> The deployment '${DS}' would be removed"
1820+
if kubectl -n ${NAMESPACE} get service ${DS} &> /dev/null; then
1821+
echo ">>> The associated service '${DS}' would be removed"
1822+
fi
1823+
if kubectl -n ${NAMESPACE} get ingress ${DS} &> /dev/null; then
1824+
echo ">>> The associated ingress '${DS}' would be removed"
1825+
fi
1826+
if kubectl -n ${NAMESPACE} get pvc ${DS} &> /dev/null; then
1827+
echo ">>> The associated persistent volume '${DS}' would be removed"
1828+
fi
1829+
fi
1830+
done
1831+
else
1832+
echo "No service cleanup required"
1833+
fi
1834+
1835+
currentStepEnd="$(date +"%Y-%m-%d %H:%M:%S")"
1836+
patchBuildStep "${buildStartTime}" "${previousStepEnd}" "${currentStepEnd}" "${NAMESPACE}" "serviceCleanupComplete" "Service/Deployment Cleanup" "${SERVICE_CLEANUP_WARNINGS}"
1837+
previousStepEnd=${currentStepEnd}
17601838
beginBuildStep "Cronjob Cleanup" "cleaningUpCronjobs"
17611839
set -x
17621840

0 commit comments

Comments
 (0)