Skip to content

Commit c8ba07d

Browse files
authored
Merge pull request #33 from cloudogu/feature/plain-cronjobs
Implement plain deployments for CronJobs
2 parents bc86674 + 8dfe9de commit c8ba07d

File tree

8 files changed

+119
-94
lines changed

8 files changed

+119
-94
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Make `deployments.plain` work with `CronJob
12+
1013
## [0.4.0](https://github.com/cloudogu/gitops-build-lib/releases/tag/0.4.0) - 2023-03-21
1114

1215
### Added

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,10 @@ def gitopsConfig = [
563563

564564
In plain pipelines, the library creates the deployment resources by updating the image tag within the deployment.
565565

566-
---
566+
Note that this works with Kubernetes `Deployment`s, `StatefulSet`s and `CronJob`s. For all other kinds of resources the
567+
library tries to find the `containers` at the following YAML path: `spec.template.spec.containers`. This might fail, of course. If you encounter a case
568+
like this, please create an issue. Eventually, we're planning to provide a `fieldPath` option just like in helm releases.
569+
567570

568571
### Helm deployment
569572
Besides plain k8s resources you can also use helm charts to generate the resources. You can choose between these types

src/com/cloudogu/gitopsbuildlib/deployment/plain/Plain.groovy

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.cloudogu.gitopsbuildlib.deployment.plain
33
import com.cloudogu.gitopsbuildlib.deployment.Deployment
44
import com.cloudogu.gitopsbuildlib.deployment.SourceType
55

6-
class Plain extends Deployment{
6+
class Plain extends Deployment {
77

88
Plain(def script, def gitopsConfig) {
99
super(script, gitopsConfig)
@@ -30,14 +30,35 @@ class Plain extends Deployment{
3030
private updateImage(String stage) {
3131
def destinationPath = getDestinationFolder(getFolderStructureStrategy(), stage)
3232

33+
script.echo "About Updating images in plain deployment: ${gitopsConfig.deployments.plain.updateImages}"
3334
gitopsConfig.deployments.plain.updateImages.each {
35+
script.echo "Replacing image '${it['imageName']}' in file: ${it['filename']}"
3436
def deploymentFilePath = "${destinationPath}/${it['filename']}"
3537
def data = script.readYaml file: deploymentFilePath
36-
def containers = data.spec.template.spec.containers
38+
String kind = data.kind
39+
def containers = findContainers(data, kind)
40+
script.echo "Found containers '${containers}' in YAML: ${it['filename']}"
3741
def containerName = it['containerName']
3842
def updateContainer = containers.find { it.name == containerName }
3943
updateContainer.image = it['imageName']
4044
script.writeYaml file: deploymentFilePath, data: data, overwrite: true
45+
script.echo "Wrote file ${deploymentFilePath} with yaml:\n${data}"
46+
}
47+
}
48+
49+
def findContainers(def data, String kind) {
50+
//noinspection GroovyFallthrough
51+
switch (kind) {
52+
case 'Deployment':
53+
// Falling through because Deployment and StatefulSet's paths are the same
54+
case 'StatefulSet':
55+
return data.spec.template.spec.containers
56+
case 'CronJob':
57+
return data.spec.jobTemplate.spec.template.spec.containers
58+
default:
59+
script.echo "Warning: Kind '$kind' is unknown, using best effort to find 'containers' in YAML"
60+
// Best effort: Try the same as for Deployment and StatefulSet
61+
return data.spec.template.spec.containers
4162
}
4263
}
4364
}

test/com/cloudogu/gitopsbuildlib/ScriptMock.groovy

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,7 @@ class ScriptMock {
1616
List<String> actualReadYamlArgs = new LinkedList<>()
1717
List<String> actualGitArgs = new LinkedList<>()
1818
List<String> actualDir = new LinkedList<>()
19-
def configYaml = '''\
20-
---
21-
#this part is only for PlainTest regarding updating the image name
22-
spec:
23-
template:
24-
spec:
25-
containers:
26-
- name: 'application'
27-
image: 'oldImageName'
28-
#this part is only for HelmTest regarding changing the yaml values
29-
to:
30-
be:
31-
changed: 'oldValue'
32-
'''
19+
def configYaml = ''
3320
List<String> actualWriteYamlArgs = new LinkedList<>()
3421
List<String> actualReadFileArgs = new LinkedList<>()
3522
List<String> actualWriteFileArgs = new LinkedList<>()

test/com/cloudogu/gitopsbuildlib/deployment/HelmTest.groovy

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ class HelmTest {
9999
def helmHelm = new Helm(scriptMock.mock, getGitopsConfig(helmRepo))
100100
def helmLocal = new Helm(scriptMock.mock, getGitopsConfig(localRepo, 'ARGO'))
101101

102+
@BeforeEach
103+
void init () {
104+
scriptMock.configYaml = '''
105+
to:
106+
be:
107+
changed: 'oldValue'
108+
'''
109+
}
110+
102111
@Test
103112
void 'creating helm release with git repo'() {
104113
helmGit.preValidation('staging')
@@ -121,15 +130,7 @@ spec:
121130
ref: null
122131
path: chartPath
123132
values:
124-
---
125-
#this part is only for PlainTest regarding updating the image name
126-
spec:
127-
template:
128-
spec:
129-
containers:
130-
- name: \'application\'
131-
image: \'oldImageName\'
132-
#this part is only for HelmTest regarding changing the yaml values
133+
133134
to:
134135
be:
135136
changed: \'oldValue\'
@@ -160,15 +161,7 @@ spec:
160161
name: chartName
161162
version: 1.0
162163
values:
163-
---
164-
#this part is only for PlainTest regarding updating the image name
165-
spec:
166-
template:
167-
spec:
168-
containers:
169-
- name: \'application\'
170-
image: \'oldImageName\'
171-
#this part is only for HelmTest regarding changing the yaml values
164+
172165
to:
173166
be:
174167
changed: \'oldValue\'
@@ -200,15 +193,7 @@ spec:
200193
ref: null
201194
path: chartPath
202195
values:
203-
---
204-
#this part is only for PlainTest regarding updating the image name
205-
spec:
206-
template:
207-
spec:
208-
containers:
209-
- name: \'application\'
210-
image: \'oldImageName\'
211-
#this part is only for HelmTest regarding changing the yaml values
196+
212197
to:
213198
be:
214199
changed: \'oldValue\'
@@ -242,15 +227,7 @@ spec:
242227
name: chartName
243228
version: 1.0
244229
values:
245-
---
246-
#this part is only for PlainTest regarding updating the image name
247-
spec:
248-
template:
249-
spec:
250-
containers:
251-
- name: \'application\'
252-
image: \'oldImageName\'
253-
#this part is only for HelmTest regarding changing the yaml values
230+
254231
to:
255232
be:
256233
changed: \'oldValue\'

test/com/cloudogu/gitopsbuildlib/deployment/PlainTest.groovy

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import com.cloudogu.gitopsbuildlib.deployment.plain.Plain
55
import com.cloudogu.gitopsbuildlib.validation.HelmKubeval
66
import com.cloudogu.gitopsbuildlib.validation.Kubeval
77
import com.cloudogu.gitopsbuildlib.validation.Yamllint
8-
import org.junit.jupiter.api.*
9-
import static org.assertj.core.api.Assertions.assertThat
8+
import org.junit.jupiter.api.BeforeEach
9+
import org.junit.jupiter.api.Test
1010

11+
import static org.assertj.core.api.Assertions.assertThat
1112

1213
class PlainTest {
1314

@@ -52,22 +53,77 @@ class PlainTest {
5253
],
5354
])
5455

56+
String deploymentYaml = '''
57+
kind: Deployment
58+
spec:
59+
template:
60+
spec:
61+
containers:
62+
- name: 'application'
63+
image: 'oldImageName'
64+
'''
65+
66+
String cronJobYaml = '''
67+
kind: CronJob
68+
spec:
69+
jobTemplate:
70+
spec:
71+
template:
72+
spec:
73+
containers:
74+
- name: 'application'
75+
image: 'oldImageName'
76+
- name: 'other'
77+
image: 'otherImageName'
78+
'''
79+
80+
@BeforeEach
81+
void init () {
82+
scriptMock.configYaml = deploymentYaml
83+
}
84+
5585
@Test
5686
void 'successful update'() {
5787

5888
plain.preValidation('staging')
5989
assertThat(scriptMock.actualReadYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml]')
60-
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml, data:[spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]], to:[be:[changed:oldValue]]], overwrite:true]')
90+
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml, data:[kind:Deployment, spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]]], overwrite:true]')
6191
}
6292

93+
@Test
94+
void 'successful update with statefulSet'() {
95+
scriptMock.configYaml = scriptMock.configYaml.replace('kind: Deployment', 'kind: StatefulSet')
96+
plain.preValidation('staging')
97+
assertThat(scriptMock.actualReadYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml]')
98+
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml, data:[kind:StatefulSet, spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]]], overwrite:true]')
99+
}
100+
101+
@Test
102+
void 'successful update with cronjob'() {
103+
scriptMock.configYaml = cronJobYaml
104+
105+
plain.preValidation('staging')
106+
assertThat(scriptMock.actualReadYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml]')
107+
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml, data:[kind:CronJob, spec:[jobTemplate:[spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application], [image:otherImageName, name:other]]]]]]]], overwrite:true]')
108+
}
109+
110+
@Test
111+
void 'successful update with other resource'() {
112+
scriptMock.configYaml = scriptMock.configYaml.replace('kind: Deployment', 'kind: SomethingElse')
113+
plain.preValidation('staging')
114+
assertThat(scriptMock.actualReadYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml]')
115+
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:staging/app/deployment.yaml, data:[kind:SomethingElse, spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]]], overwrite:true]')
116+
assertThat(scriptMock.actualEchoArgs).contains('Warning: Kind \'SomethingElse\' is unknown, using best effort to find \'containers\' in YAML')
117+
}
118+
63119
@Test
64120
void 'successful update with ENV_PER_APP and other destinationRootPath '() {
65121
plain.gitopsConfig['folderStructureStrategy'] = 'ENV_PER_APP'
66122
plain.gitopsConfig['deployments']['destinationRootPath'] = 'apps'
67123

68124
plain.preValidation('staging')
69125
assertThat(scriptMock.actualReadYamlArgs[0]).isEqualTo('[file:apps/app/staging/deployment.yaml]')
70-
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:apps/app/staging/deployment.yaml, data:[spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]], to:[be:[changed:oldValue]]], overwrite:true]')
126+
assertThat(scriptMock.actualWriteYamlArgs[0]).isEqualTo('[file:apps/app/staging/deployment.yaml, data:[kind:Deployment, spec:[template:[spec:[containers:[[image:imageNameReplacedTest, name:application]]]]]], overwrite:true]')
71127
}
72128

73129
@Test

test/com/cloudogu/gitopsbuildlib/deployment/helm/helmrelease/FluxV1ReleaseTest.groovy

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease
22

33
import com.cloudogu.gitopsbuildlib.ScriptMock
4+
import org.junit.jupiter.api.BeforeEach
45
import org.junit.jupiter.api.Test
56

67
import static org.assertj.core.api.Assertions.assertThat
@@ -10,6 +11,11 @@ class FluxV1ReleaseTest {
1011
def scriptMock = new ScriptMock()
1112
def fluxV1Release = new FluxV1Release(scriptMock.mock)
1213

14+
@BeforeEach
15+
void init () {
16+
scriptMock.configYaml = 'a: b'
17+
}
18+
1319
@Test
1420
void 'correct helm release with git repo'() {
1521
def output = fluxV1Release.create([
@@ -39,18 +45,7 @@ spec:
3945
ref: 1.0
4046
path: .
4147
values:
42-
---
43-
#this part is only for PlainTest regarding updating the image name
44-
spec:
45-
template:
46-
spec:
47-
containers:
48-
- name: 'application'
49-
image: 'oldImageName'
50-
#this part is only for HelmTest regarding changing the yaml values
51-
to:
52-
be:
53-
changed: 'oldValue'
48+
a: b
5449
""")
5550
}
5651

@@ -84,18 +79,7 @@ spec:
8479
name: chartName
8580
version: 1.0
8681
values:
87-
---
88-
#this part is only for PlainTest regarding updating the image name
89-
spec:
90-
template:
91-
spec:
92-
containers:
93-
- name: 'application'
94-
image: 'oldImageName'
95-
#this part is only for HelmTest regarding changing the yaml values
96-
to:
97-
be:
98-
changed: 'oldValue'
82+
a: b
9983
""")
10084
}
10185
}

test/com/cloudogu/gitopsbuildlib/deployment/helm/helmrelease/HelmReleaseTest.groovy

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease
22

33
import com.cloudogu.gitopsbuildlib.ScriptMock
4+
import org.junit.jupiter.api.BeforeEach
45
import org.junit.jupiter.api.Test
56

67
import static org.assertj.core.api.Assertions.assertThat
@@ -10,23 +11,16 @@ class HelmReleaseTest {
1011
def scriptMock = new ScriptMock()
1112
def repoType = new HelmReleaseUnderTest(scriptMock.mock)
1213

14+
@BeforeEach
15+
void init () {
16+
scriptMock.configYaml = 'a: b'
17+
}
18+
1319
@Test
1420
void 'inline yaml test'() {
1521
def output = repoType.fileToInlineYaml('filepath')
1622
assertThat(scriptMock.actualReadFileArgs[0]).isEqualTo('filepath')
17-
assertThat(output).isEqualTo('''\
18-
---
19-
#this part is only for PlainTest regarding updating the image name
20-
spec:
21-
template:
22-
spec:
23-
containers:
24-
- name: 'application\'
25-
image: 'oldImageName'
26-
#this part is only for HelmTest regarding changing the yaml values
27-
to:
28-
be:
29-
changed: 'oldValue\'''')
23+
assertThat(output).isEqualTo(' a: b')
3024
}
3125

3226
class HelmReleaseUnderTest extends HelmRelease {

0 commit comments

Comments
 (0)