Skip to content

Commit 0750d79

Browse files
authored
Merge pull request #42 from wunderio/feature/concurrency-fixes
Concurrency fixes
2 parents a45a94e + 5827b15 commit 0750d79

8 files changed

Lines changed: 102 additions & 4597 deletions

File tree

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
FROM golang:1.19-alpine AS builder
22
RUN apk update && apk add --no-cache git make bash
33
WORKDIR $GOPATH/src/silta-deployment-remover
4+
45
COPY /app .
6+
57
RUN go mod download \
68
&& CGO_ENABLED=0 GOOS=linux go build -a -gcflags=-trimpath=$(go env GOPATH) -asmflags=-trimpath=$(go env GOPATH) -ldflags '-extldflags "-static"' -o silta-deployment-remover
79

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Tag a new release in github, docker hub integration will build and publish the i
4646

4747
```bash
4848
docker build --tag 'wunderio/silta-deployment-remover:latest' --tag 'wunderio/silta-deployment-remover:v1' --tag 'wunderio/silta-deployment-remover:v1.X' --tag 'wunderio/silta-deployment-remover:v1.X.Y' .
49+
docker push wunderio/silta-deployment-remover:latest
4950
docker push wunderio/silta-deployment-remover:v1
5051
docker push wunderio/silta-deployment-remover:v1.X
5152
docker push wunderio/silta-deployment-remover:v1.X.Y

app/.dockerignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

app/delete-deployment.sh

Lines changed: 0 additions & 36 deletions
This file was deleted.

app/main.go

Lines changed: 99 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import (
99
"encoding/hex"
1010
"encoding/json"
1111
"flag"
12-
"fmt"
1312
"io/ioutil"
1413
"log"
1514
"net/http"
1615
"os"
1716
"path/filepath"
1817
"regexp"
1918
"strings"
19+
"time"
2020

2121
"context"
2222

@@ -57,11 +57,18 @@ func debugEnabled() bool {
5757

5858
func removeRelease(namespace string, branchName string) {
5959

60+
log.Printf("[%s/%s] Waiting 15 minutes before removal to make sure builds are finished\n", namespace, branchName)
61+
62+
// Sleep for 15 minutes to make sure builds in progress are finished
63+
time.Sleep(15 * time.Minute)
64+
6065
if namespace == "" || branchName == "" {
61-
log.Println("Namespace or branch name not found in request, exiting")
66+
log.Printf("[%s/%s] Namespace or branch name not found in request, exiting\n", namespace, branchName)
6267
return
6368
}
6469

70+
log.Printf("[%s/%s] Removing release\n", namespace, branchName)
71+
6572
// Use the current context in kubeconfig
6673
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
6774
if err != nil {
@@ -71,14 +78,14 @@ func removeRelease(namespace string, branchName string) {
7178
config, err = rest.InClusterConfig()
7279
if err != nil {
7380
// Still fails, might as well trigger panic() to fail pod
74-
log.Println("Error loading kubernetes cluster configuration:", err)
81+
log.Printf("[%s/%s] Error loading kubernetes cluster configuration: %s\n", namespace, branchName, err)
7582
}
7683
}
7784

7885
// create the clientset
7986
clientset, err := kubernetes.NewForConfig(config)
8087
if err != nil {
81-
log.Println("Error creating clientset:", err)
88+
log.Printf("[%s/%s] Error creating clientset: %s\n", namespace, branchName, err)
8289
}
8390

8491
// Get pods to verify kube connection
@@ -102,108 +109,117 @@ func removeRelease(namespace string, branchName string) {
102109

103110
helmClient, err := helmclient.NewClientFromRestConf(opt)
104111
if err != nil {
105-
log.Printf("Kubernetes connection failure: %s", err)
112+
log.Printf("[%s/%s] Kubernetes connection failure: %s\n", namespace, branchName, err)
106113
}
107114
_ = helmClient
108115

109116
// Find kubernetes configmap by name
110117
// TODO: Change silta-release subchart, add special label or annotation to silta-release configmaps
111-
cm, err := clientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
118+
cms, err := clientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
112119
if err != nil {
113-
log.Println("Error loading configmaps:", err)
120+
log.Printf("[%s/%s] Error loading configmaps: %s", namespace, branchName, err)
114121
}
115122

116123
var releasesFound = 0
124+
releaseList := []string{}
117125

118126
// Iterate cm.Items
119-
for _, cm := range cm.Items {
120-
if cm.Data["branchName"] == branchName {
127+
for _, cm := range cms.Items {
128+
129+
// Do a case-insensitive comparison
130+
if branchName != "" && strings.ToLower(cm.Data["branchName"]) == strings.ToLower(branchName) {
121131

122132
releasesFound++
123133
releaseName := cm.Labels["release"]
134+
releaseList = append(releaseList, releaseName)
124135

125-
log.Println("Found silta-release configmap for branchName:", branchName)
126-
log.Println("Release name:", cm.Labels["release"])
136+
log.Printf("[%s/%s] Found release [%d] %s\n", namespace, branchName, releasesFound, releaseName)
137+
}
138+
}
127139

128-
// Delete helm release
129-
if debug {
130-
log.Println("Debug mode, not removing release")
131-
} else {
132-
uninstallErr := helmClient.UninstallReleaseByName(cm.Labels["release"])
133-
if uninstallErr != nil {
134-
log.Fatalf("Error removing a release:%s", uninstallErr)
135-
}
140+
if releasesFound == 0 {
141+
log.Printf("[%s/%s] No releases found for branch name %s\n", namespace, branchName, branchName)
142+
}
143+
144+
// Remove releases
145+
for n, releaseName := range releaseList {
146+
147+
log.Printf("[%s/%s] Removing release %s [%d of %d]\n", namespace, branchName, releaseName, (n + 1), len(releaseList))
148+
149+
// Delete helm release
150+
if debug {
151+
log.Printf("[%s/%s] Debug mode, not removing release\n", namespace, branchName)
152+
} else {
153+
uninstallErr := helmClient.UninstallReleaseByName(releaseName)
154+
if uninstallErr != nil {
155+
log.Printf("[%s/%s] Error removing a release: %s\n", namespace, branchName, uninstallErr)
136156
}
157+
}
137158

138-
// Remove post-install job
139-
if debug {
140-
// List jobs
141-
postrelease, err := clientset.BatchV1().Jobs(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: "release=" + releaseName})
142-
if err != nil {
143-
log.Printf("Error listing post-release job: %s", err)
144-
} else {
145-
log.Printf("There are %d jobs with label %s in the namespace", len(postrelease.Items), "release="+releaseName)
146-
}
159+
// Remove post-install job
160+
if debug {
161+
// List jobs
162+
postrelease, err := clientset.BatchV1().Jobs(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: "release=" + releaseName})
163+
if err != nil {
164+
log.Printf("[%s/%s] Error listing post-release job: %s\n", namespace, branchName, err)
147165
} else {
148-
// Actually delete job
149-
propagationPolicy := metav1.DeletePropagationBackground
150-
deleteErr := clientset.BatchV1().Jobs(namespace).Delete(context.TODO(), releaseName+"-post-release", metav1.DeleteOptions{PropagationPolicy: &propagationPolicy})
151-
if deleteErr != nil {
152-
if errs.IsNotFound(deleteErr) {
153-
//Resource doesnt exist, skip printing a message
154-
} else {
155-
log.Printf("Cannot delete post-release job: %s", deleteErr)
156-
}
166+
log.Printf("[%s/%s] There are %d jobs with label %s in the namespace\n", namespace, branchName, len(postrelease.Items), "release="+releaseName)
167+
}
168+
} else {
169+
// Actually delete job
170+
propagationPolicy := metav1.DeletePropagationBackground
171+
deleteErr := clientset.BatchV1().Jobs(namespace).Delete(context.TODO(), releaseName+"-post-release", metav1.DeleteOptions{PropagationPolicy: &propagationPolicy})
172+
if deleteErr != nil {
173+
if errs.IsNotFound(deleteErr) {
174+
//Resource doesnt exist, skip printing a message
175+
} else {
176+
log.Printf("[%s/%s] Cannot delete post-release job: %s\n", namespace, branchName, deleteErr)
157177
}
158178
}
179+
}
159180

160-
PVC_client := clientset.CoreV1().PersistentVolumeClaims(namespace)
181+
PVC_client := clientset.CoreV1().PersistentVolumeClaims(namespace)
161182

162-
selectorLabels := []string{
163-
"app",
164-
"release",
165-
"app.kubernetes.io/instance",
166-
}
183+
selectorLabels := []string{
184+
"app",
185+
"release",
186+
"app.kubernetes.io/instance",
187+
}
167188

168-
for _, l := range selectorLabels {
189+
for _, l := range selectorLabels {
169190

170-
// Find PVC's by release name label
191+
// Find PVC's by release name label
171192

172-
selector := l + "=" + releaseName
173-
if l == "app" {
174-
selector = l + "=" + releaseName + "-es"
175-
}
176-
177-
list, err := PVC_client.List(context.TODO(), metav1.ListOptions{
178-
LabelSelector: selector,
179-
})
180-
if err != nil {
181-
log.Fatalf("Error getting the list of PVCs: %s", err)
182-
}
193+
selector := l + "=" + releaseName
194+
if l == "app" {
195+
selector = l + "=" + releaseName + "-es"
196+
}
183197

198+
list, err := PVC_client.List(context.TODO(), metav1.ListOptions{
199+
LabelSelector: selector,
200+
})
201+
if err != nil {
202+
log.Printf("[%s/%s] Error getting the list of PVCs: %s\n", namespace, branchName, err)
203+
} else {
184204
// Iterate pvc's
185205
for _, v := range list.Items {
186-
log.Printf("PVC name: %s", v.Name)
206+
log.Printf("[%s/%s] PVC name: %s\n", namespace, branchName, v.Name)
187207
if debug {
188-
log.Println(" Debug mode, not removing PVC")
208+
log.Printf("[%s/%s] Debug mode, not removing PVC %s\n", namespace, branchName, v.Name)
189209
} else {
190210
// Delete PVC's
191211
PVC_client.Delete(context.TODO(), v.Name, metav1.DeleteOptions{})
192-
log.Println(" PVC deleted:", v.Name)
212+
log.Printf("[%s/%s] PVC deleted: %s\n", namespace, branchName, v.Name)
193213
}
194214
}
195215
}
196-
197-
if debug {
198-
log.Printf("Debug mode, not removing release %s/%s", namespace, releaseName)
199-
} else {
200-
log.Printf("Release %s/%s removed", namespace, releaseName)
201-
}
202216
}
203-
}
204217

205-
if releasesFound == 0 {
206-
log.Printf("No releases found for branch %s", branchName)
218+
if debug {
219+
log.Printf("[%s/%s] Debug mode, not removing release %s/%s", namespace, branchName, namespace, releaseName)
220+
} else {
221+
log.Printf("[%s/%s] Release %s/%s removed", namespace, branchName, namespace, releaseName)
222+
}
207223
}
208224
}
209225

@@ -258,6 +274,9 @@ func getEventType(req *http.Request, webhookData RequestData) (event string) {
258274
}
259275
}
260276

277+
// convert event name to lowercase
278+
event = strings.ToLower(event)
279+
261280
return event
262281
}
263282

@@ -318,6 +337,12 @@ func isValidSignature(req *http.Request, key string) bool {
318337

319338
func handleWebhook(w http.ResponseWriter, req *http.Request) {
320339

340+
// Only allow POST requests
341+
if req.Method != "POST" {
342+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
343+
return
344+
}
345+
321346
log.Println("Received webhook request ...")
322347
w.Header().Set("Content-Type", "application/json")
323348

@@ -330,9 +355,9 @@ func handleWebhook(w http.ResponseWriter, req *http.Request) {
330355

331356
// Check signature
332357
if isValidSignature(req, webhooks_secret) {
333-
fmt.Println("Github signature is valid")
358+
log.Println("Github signature is valid")
334359
} else {
335-
fmt.Println("Github signature is invalid. You might need to switch deliveries to application/json.")
360+
log.Println("Github signature is invalid. You might need to switch deliveries to application/json.")
336361
return
337362
}
338363
} else {
@@ -346,13 +371,13 @@ func handleWebhook(w http.ResponseWriter, req *http.Request) {
346371
passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1)
347372
// Compare hashes
348373
if passwordMatch {
349-
fmt.Println("Basic authentication is valid")
374+
log.Println("Basic authentication is valid")
350375
} else {
351-
fmt.Println("Basic authentication is invalid")
376+
log.Println("Basic authentication is invalid")
352377
return
353378
}
354379
} else {
355-
fmt.Println("Authentication is invalid")
380+
log.Println("Authentication is invalid")
356381
if debug {
357382
log.Println("Debug mode, skipping authentication validation")
358383
} else {
@@ -386,7 +411,7 @@ func handleWebhook(w http.ResponseWriter, req *http.Request) {
386411
var branch = getBranchName(webhookData)
387412
var event = getEventType(req, webhookData)
388413

389-
fmt.Printf("Event: %s, Repository: %s, Branch: %s \n", event, repository, branch)
414+
log.Printf("[%s/%s] Event: %s, Repository: %s, Branch: %s \n", repository, branch, event, repository, branch)
390415

391416
// Respond to ping event
392417
if event == "ping" {

0 commit comments

Comments
 (0)