Skip to content

Commit 83cda87

Browse files
authored
Jenkins demo (#23)
* Create Jenkinsfile * Update Jenkinsfile * Update init_examples.go * Update init_examples.go * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Create README.md * Create deploy.sh * Create values.yaml * Create jenkins-pvc.yaml * Update values.yaml * revert init_examples.go * Update README.md
1 parent 6662574 commit 83cda87

6 files changed

Lines changed: 319 additions & 2 deletions

File tree

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
- After the temporary folder is ready, it executes `terraform` or `tofu` with specified parameters
88
- Maintains separate state files for each environment/layer, automatically providing configuration for remote state management (different path on the storage regarding configured layers/dimensions). So the deployed set (configuration + terraform) is stored in different `tfstate` files in remote storage (S3, GCS)
99

10-
## Quick start with demo configuration
10+
## Quick start with Jenkins and demo configuration
11+
12+
You will need any Kubernetes cluster (best small temporary like Podman+Kind or MiniKube).
13+
Check that kubectl context poiting to this test cluster! Not Production!
14+
15+
For a full end-to-end example of using TofuGu in a CI/CD pipeline, see the pre-configured Jenkins deployment in [examples/jenkins/README.md](examples/jenkins/README.md).
16+
17+
## Quick start locally with demo configuration
1118

1219
1. [Download release](https://github.com/alt-dima/tofugu/releases) version >= 0.5.0
1320
2. Install [OpenTofu](https://opentofu.org/docs/intro/install/)
@@ -108,7 +115,7 @@ With the correct `toasterurl`, TofuGu will connect and receive all the required
108115
An additional parameter could be passed to tofugu `-w workspacename`. In general, `workspacename` is the branch name of the source repo where the dimension is stored. If TofuGu-Toaster does not find the dimension with the specified `workspacename`, it will try to return the dimension from the `master` workspace/branch!
109116

110117
**Toaster-ToasterDB** provides additional features for your CI and CD pipelines. For example, you need to receive a [first-app.json](examples/inventory/demo-org/application/first-app.json) in the CI pipeline, to check the application configuration.
111-
Or you need a list of all the datacenters in the [datacenter dimension](examples/inventory/demo-org/datacenter) in a [Jenkins drop-down](https://github.com/alt-dima/tofugu/issues/10#issuecomment-2090932416) list to select to which datacenter to deploy the application.
118+
Or you need a list of all the datacenters in the [datacenter dimension](examples/inventory/demo-org/datacenter) in a [Jenkins drop-down](examples/jenkins/README.md) list to select to which datacenter to deploy the application.
112119

113120
<img width="800" alt="Screenshot_20250915_222357" src="https://github.com/user-attachments/assets/735a4045-eb74-4fc0-b46d-aa01f655c7d0" />
114121

examples/jenkins/Jenkinsfile

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
properties([
2+
parameters([
3+
[
4+
$class: 'CascadeChoiceParameter',
5+
choiceType: 'PT_SINGLE_SELECT',
6+
name: 'Account',
7+
description: 'Select the account',
8+
script: [
9+
$class: 'GroovyScript',
10+
fallbackScript: [
11+
classpath: [],
12+
sandbox: true,
13+
script: 'return ["ERROR: Failed to fetch accounts"]'
14+
],
15+
script: [
16+
classpath: [],
17+
sandbox: true,
18+
script: '''
19+
import groovy.json.JsonSlurper
20+
21+
try {
22+
def url = new URL('https://toaster.altuhov.su/api/dimension/example-org/account?workspace=master&fallbacktomaster=true&needdimdata=false')
23+
def connection = url.openConnection()
24+
connection.setRequestProperty('Authorization', 'Basic NjYyY2FiN2M1ZTExNjgxOTczOGIwMWZlOnN1cGVydG9hc3Rlcg==')
25+
connection.requestMethod = 'GET'
26+
27+
def response = connection.content.text
28+
def result = new JsonSlurper().parseText(response)
29+
30+
if (result.Dimensions) {
31+
return result.Dimensions.collect { it.DimValue }.unique()
32+
} else {
33+
return ["No accounts found"]
34+
}
35+
} catch (Exception e) {
36+
return ["Error: ${e.message}"]
37+
}
38+
'''
39+
]
40+
]
41+
],
42+
[
43+
$class: 'CascadeChoiceParameter',
44+
choiceType: 'PT_SINGLE_SELECT',
45+
name: 'DataCenter',
46+
description: 'Select the Data Center',
47+
script: [
48+
$class: 'GroovyScript',
49+
fallbackScript: [
50+
classpath: [],
51+
sandbox: true,
52+
script: 'return ["ERROR: Failed to fetch data centers"]'
53+
],
54+
script: [
55+
classpath: [],
56+
sandbox: true,
57+
script: '''
58+
import groovy.json.JsonSlurper
59+
60+
try {
61+
def url = new URL('https://toaster.altuhov.su/api/dimension/example-org/datacenter?workspace=master&fallbacktomaster=true&needdimdata=false')
62+
def connection = url.openConnection()
63+
connection.setRequestProperty('Authorization', 'Basic NjYyY2FiN2M1ZTExNjgxOTczOGIwMWZlOnN1cGVydG9hc3Rlcg==')
64+
connection.requestMethod = 'GET'
65+
66+
def response = connection.content.text
67+
def result = new JsonSlurper().parseText(response)
68+
69+
if (result.Dimensions) {
70+
return result.Dimensions.collect { it.DimValue }.unique()
71+
} else {
72+
return ["No accounts found"]
73+
}
74+
} catch (Exception e) {
75+
return ["Error: ${e.message}"]
76+
}
77+
'''
78+
]
79+
]
80+
]
81+
])
82+
])
83+
84+
pipeline {
85+
agent any
86+
stages {
87+
stage('Build') {
88+
steps {
89+
git url: 'https://github.com/alt-dima/tofugu.git', branch: 'main'
90+
echo "Selected account: ${params.Account}"
91+
echo "Selected data center: ${params.DataCenter}"
92+
}
93+
}
94+
stage('Install OpenTofu and TofuGu') {
95+
steps {
96+
script {
97+
def arch = sh(script: 'uname -m', returnStdout: true).trim()
98+
def archSuffix
99+
if (arch == 'aarch64' || arch == 'arm64') {
100+
archSuffix = 'arm64'
101+
} else if (arch == 'x86_64') {
102+
archSuffix = 'amd64'
103+
} else {
104+
error "Unsupported architecture: ${arch}"
105+
}
106+
107+
sh "curl -L -o tofu_1.10.7_linux_${archSuffix}.tar.gz https://github.com/opentofu/opentofu/releases/download/v1.10.7/tofu_1.10.7_linux_${archSuffix}.tar.gz"
108+
sh "tar -xvf tofu_1.10.7_linux_${archSuffix}.tar.gz -C /tmp"
109+
110+
sh "curl -L -o tofugu_0.5.1_linux_${archSuffix}.tar.gz https://github.com/alt-dima/tofugu/releases/download/v0.5.1/tofugu_0.5.1_linux_${archSuffix}.tar.gz"
111+
sh "tar -xvf tofugu_0.5.1_linux_${archSuffix}.tar.gz"
112+
}
113+
}
114+
}
115+
stage('Create .tofugu config') {
116+
steps {
117+
writeFile file: '.tofugu', text: '''
118+
defaults:
119+
tofies_path: examples/tofies
120+
inventory_path: examples/inventory
121+
cmd_to_exec: /tmp/tofu
122+
'''
123+
}
124+
}
125+
stage('TofuGu Plan') {
126+
environment {
127+
toasterurl = 'https://662cab7c5e116819738b01fe:supertoaster@toaster.altuhov.su'
128+
}
129+
steps {
130+
ansiColor('xterm') {
131+
sh "./tofugu cook -o example-org -d account:${params.Account} -d datacenter:${params.DataCenter} -t demo -- init"
132+
sh "./tofugu cook -o example-org -d account:${params.Account} -d datacenter:${params.DataCenter} -t demo -- plan"
133+
}
134+
}
135+
}
136+
stage('Approval') {
137+
steps {
138+
input 'Do you want to apply the changes?'
139+
}
140+
}
141+
stage('TofuGu Apply') {
142+
environment {
143+
toasterurl = 'https://662cab7c5e116819738b01fe:supertoaster@toaster.altuhov.su'
144+
}
145+
steps {
146+
ansiColor('xterm') {
147+
sh "./tofugu cook -o example-org -d account:${params.Account} -d datacenter:${params.DataCenter} -t demo -- apply -auto-approve"
148+
}
149+
}
150+
}
151+
}
152+
}

examples/jenkins/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Pre-configured Jenkins for TofuGu and Tofugu Toaster Demo
2+
3+
This project provides a way to deploy a pre-configured Jenkins instance to any Kubernetes cluster (especially local ones like Kind or Minikube). It's designed to demonstrate an end-to-end workflow using TofuGu and Tofugu Toaster with a demo OpenTofu unit/tofie.
4+
5+
## Steps to setup
6+
7+
1. Execute the deployment script:
8+
```bash
9+
bash deploy.sh
10+
```
11+
12+
2. Get the password for the Jenkins admin user:
13+
```bash
14+
kubectl exec --namespace jenkins -it svc/jenkins-dev -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo
15+
```
16+
17+
3. Start port-forwarding to access the Jenkins UI:
18+
```bash
19+
kubectl port-forward --namespace jenkins svc/jenkins-dev 8080:8080
20+
```
21+
22+
4. Navigate your browser to [http://127.0.0.1:8080](http://127.0.0.1:8080).
23+
24+
5. Log in with the username `admin` and the password obtained in step 2.
25+
26+
6. Go to the `tofugu-pipeline` job page: [http://127.0.0.1:8080/job/tofugu-pipeline/](http://127.0.0.1:8080/job/tofugu-pipeline/).
27+
28+
7. On the left menu, click on **Build**. This will download and execute the `Jenkinsfile` from the repository.
29+
30+
8. Build #1 should start. Click on the build link to open the console output: [http://127.0.0.1:8080/job/tofugu-pipeline/1/console](http://127.0.0.1:8080/job/tofugu-pipeline/1/console).
31+
32+
9. Scroll to the end of the console output. You should see a plan output from OpenTofu and a question: "Do you want to apply the changes?".
33+
34+
10. Click **Proceed** and watch as the apply stage is performed.

examples/jenkins/deploy.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
3+
# Exit immediately if a command exits with a non-zero status.
4+
set -e
5+
6+
# Define variables
7+
HELM_REPO_NAME="jenkinsci"
8+
HELM_REPO_URL="https://charts.jenkins.io"
9+
HELM_CHART_NAME="jenkins"
10+
RELEASE_NAME="jenkins-dev"
11+
NAMESPACE="jenkins"
12+
13+
# Add the Jenkins Helm repository
14+
echo "Adding Jenkins Helm repository..."
15+
helm repo add $HELM_REPO_NAME $HELM_REPO_URL
16+
17+
# Update your local Helm chart repository cache
18+
echo "Updating Helm repositories..."
19+
helm repo update
20+
21+
# Create the namespace if it doesn't exist
22+
echo "Creating namespace '$NAMESPACE' if it doesn't exist..."
23+
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
24+
25+
# Create PersistentVolume and PersistentVolumeClaim for Jenkins data
26+
# echo "Creating PersistentVolume and PersistentVolumeClaim for Jenkins data..."
27+
# kubectl apply -f jenkins-pvc.yaml -n $NAMESPACE
28+
29+
# Deploy the latest Jenkins chart with custom values
30+
echo "Deploying Jenkins to namespace '$NAMESPACE'..."
31+
helm upgrade --install $RELEASE_NAME $HELM_REPO_NAME/$HELM_CHART_NAME \
32+
--namespace $NAMESPACE \
33+
--values values.yaml
34+
35+
# Wait for the deployment to be ready
36+
echo "Waiting for Jenkins to be ready..."
37+
kubectl wait --namespace $NAMESPACE \
38+
--for=condition=ready pod \
39+
--selector=app.kubernetes.io/component=jenkins-controller \
40+
--timeout=300s
41+
42+
echo "Jenkins has been deployed."
43+
echo "You can access it by port-forwarding the service:"
44+
echo "kubectl --namespace $NAMESPACE port-forward svc/$RELEASE_NAME 8080:8080"
45+
46+
echo "To get the admin password, run:"
47+
echo "kubectl exec --namespace $NAMESPACE -it svc/$RELEASE_NAME -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo"

examples/jenkins/jenkins-pvc.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: v1
2+
kind: PersistentVolume
3+
metadata:
4+
name: jenkins-pv
5+
spec:
6+
capacity:
7+
storage: 1Gi
8+
volumeMode: Filesystem
9+
accessModes:
10+
- ReadWriteOnce
11+
persistentVolumeReclaimPolicy: Retain
12+
hostPath:
13+
path: /var/jenkins_data
14+
type: DirectoryOrCreate
15+
---
16+
apiVersion: v1
17+
kind: PersistentVolumeClaim
18+
metadata:
19+
name: jenkins-pvc
20+
namespace: jenkins
21+
spec:
22+
accessModes:
23+
- ReadWriteOnce
24+
resources:
25+
requests:
26+
storage: 1Gi

examples/jenkins/values.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
controller:
2+
jenkinsUrl: http://127.0.0.1:8080/
3+
# Jenkins Configuration as Code (JCasC)
4+
JCasC:
5+
configScripts:
6+
welcome-message: |
7+
jenkins:
8+
systemMessage: "Jenkins For TofuGu Toaster Demo"
9+
pipeline-job: |
10+
jobs:
11+
- script: >
12+
pipelineJob('tofugu-pipeline') {
13+
definition {
14+
cpsScm {
15+
scm {
16+
git {
17+
remote {
18+
url('https://github.com/alt-dima/tofugu.git')
19+
credentials('')
20+
}
21+
branch('main')
22+
}
23+
}
24+
scriptPath('examples/jenkins/Jenkinsfile')
25+
lightweight()
26+
}
27+
}
28+
}
29+
additionalPlugins:
30+
- uno-choice:2.8.8
31+
- job-dsl:1.93
32+
- ansicolor:1.0.6
33+
scriptApproval:
34+
- "method java.net.HttpURLConnection setRequestMethod java.lang.String"
35+
- "method java.net.URL openConnection"
36+
- "method java.net.URLConnection getContent"
37+
- "method java.net.URLConnection setRequestProperty java.lang.String java.lang.String"
38+
- "staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods getText java.io.InputStream"
39+
resources:
40+
requests:
41+
cpu: "50m"
42+
memory: "256Mi"
43+
limits:
44+
cpu: "3"
45+
memory: "2Gi"
46+
47+
# Configure persistent storage using host path for development and testing
48+
persistence:
49+
enabled: false
50+
# You could use file jenkins-pvc.yaml to create a PV and PVC with hostPath and use pvc here:
51+
# existingClaim: jenkins-pvc

0 commit comments

Comments
 (0)