Skip to content

Commit 10d9832

Browse files
authored
Merge pull request #246 from aws-samples/feat-dora-metrics
Measuring Platform Success
2 parents ce88f63 + 3bdee8d commit 10d9832

File tree

42 files changed

+1936
-242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1936
-242
lines changed

deployment/addons/kubevela/templates/traits/component-policy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ spec:
4848
metadata: name: "\(context.appName)-\(context.name)-iam-policy"
4949
spec: {
5050
name: "\(context.appName)-\(context.name)-iam-policy"
51-
forProvider: policy: "\(policy)"
51+
forProvider: policy: "\(parameter.policy)"
5252
}
5353
}
5454
}

packages/argocd/dev/appproject-modern-engg.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ spec:
2424
server: https://kubernetes.default.svc
2525
- namespace: dapr-system
2626
server: https://kubernetes.default.svc
27+
- namespace: devlake
28+
server: https://kubernetes.default.svc
2729
- namespace: ingress-nginx
2830
server: https://kubernetes.default.svc
2931
- namespace: kyverno

packages/devlake/base/values.yaml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# dependency chart values
2+
grafana:
3+
enabled: false
4+
external:
5+
url: "http://localhost:4000" # Set to AMG Endpoint in setup-environments - doesn't work - need some sort of ingress maybe?
6+
7+
mysql:
8+
useExternal: true
9+
externalServer: "devlake-mysql-service"
10+
externalPort: "3306"
11+
12+
option:
13+
database: mysql
14+
connectionSecretName: "devlake-mysql-auth"
15+
autoCreateSecret: false
16+
17+
18+
lake:
19+
image:
20+
repository: devlake.docker.scarf.sh/apache/devlake
21+
pullPolicy: Always
22+
tag: v1.0.3-beta1
23+
# storage for config
24+
encryptionSecret:
25+
# The name of secret which contains keys named ENCRYPTION_SECRET
26+
secretName: devlake-encryption-secret
27+
autoCreateSecret: false
28+
29+
securityContext:
30+
runAsNonRoot: true
31+
runAsUser: 1010
32+
runAsGroup: 1010
33+
fsGroup: 1010
34+
35+
containerSecurityContext:
36+
allowPrivilegeEscalation: false
37+
runAsNonRoot: true
38+
capabilities:
39+
drop: ["ALL"]
40+
seccompProfile:
41+
type: RuntimeDefault
42+
43+
44+
alpine:
45+
securityContext:
46+
runAsNonRoot: true
47+
runAsUser: 1000
48+
runAsGroup: 1000
49+
50+
containerSecurityContext:
51+
allowPrivilegeEscalation: false
52+
runAsNonRoot: true
53+
capabilities:
54+
drop: ["ALL"]
55+
seccompProfile:
56+
type: RuntimeDefault
57+
58+
ui:
59+
image:
60+
repository: devlake.docker.scarf.sh/apache/devlake-config-ui
61+
pullPolicy: Always
62+
tag: v1.0.3-beta1
63+
64+
securityContext:
65+
runAsNonRoot: true
66+
67+
containerSecurityContext:
68+
allowPrivilegeEscalation: false
69+
runAsNonRoot: true
70+
capabilities:
71+
drop: ["ALL"]
72+
seccompProfile:
73+
type: RuntimeDefault
74+
75+
# Look into adding an auth proxy like here: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment/docker-compose-keycloak.yaml
76+
77+
service:
78+
# service type: NodePort/ClusterIP
79+
type: ClusterIP
80+
81+
ingress:
82+
enabled: false
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
apiVersion: external-secrets.io/v1beta1
3+
kind: ExternalSecret
4+
metadata:
5+
name: devlake-encryption-secret
6+
namespace: devlake
7+
spec:
8+
refreshInterval: 5m
9+
secretStoreRef:
10+
name: devlake
11+
kind: SecretStore
12+
target:
13+
name: devlake-encryption-secret
14+
creationPolicy: Owner
15+
data:
16+
- secretKey: ENCRYPTION_SECRET
17+
remoteRef:
18+
key: modern-engg/devlake/encryption
19+
property: ENCRYPTION_SECRET
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: kustomize.config.k8s.io/v1beta1
2+
kind: Kustomization
3+
resources:
4+
- external-secrets.yaml
5+
- mysql-setup-workflow.yaml
6+
- rds-mysql.yaml
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: devlake-mysql-setup-sa
5+
namespace: devlake
6+
---
7+
apiVersion: rbac.authorization.k8s.io/v1
8+
kind: ClusterRoleBinding
9+
metadata:
10+
name: devlake-mysql-setup-access-binding
11+
subjects:
12+
- kind: ServiceAccount
13+
name: devlake-mysql-setup-sa
14+
namespace: devlake
15+
roleRef:
16+
kind: ClusterRole
17+
name: cluster-admin
18+
apiGroup: rbac.authorization.k8s.io
19+
---
20+
apiVersion: argoproj.io/v1alpha1
21+
kind: Workflow
22+
metadata:
23+
name: mysql-setup-workflow
24+
namespace: devlake
25+
spec:
26+
serviceAccountName: devlake-mysql-setup-sa
27+
entrypoint: mysql-setup
28+
templates:
29+
- name: mysql-setup
30+
dag:
31+
tasks:
32+
- name: create-secrets
33+
template: create-secrets
34+
- name: wait-for-mysql
35+
template: wait-for-mysql
36+
dependencies: [create-secrets]
37+
- name: create-users
38+
template: create-users
39+
dependencies: [wait-for-mysql]
40+
41+
- name: create-secrets
42+
container:
43+
image: bitnami/kubectl
44+
command: ["/bin/bash", "-c"]
45+
args:
46+
- |
47+
while true; do
48+
CONN_SECRET_NAME=$(kubectl get secrets -n crossplane-system -o custom-columns=NAME:.metadata.name | grep "^devlake-mysql.*cluster-mysql-connection$" || true)
49+
if [ -n "$CONN_SECRET_NAME" ]; then
50+
break
51+
fi
52+
echo "Waiting for secret to be available..."
53+
sleep 10
54+
done
55+
56+
echo "Secret found: ${CONN_SECRET_NAME}"
57+
while true; do
58+
endpoint=$(kubectl get secret ${CONN_SECRET_NAME} -n crossplane-system -o jsonpath='{.data.endpoint}' | base64 --decode)
59+
if [ -n "$endpoint" ]; then
60+
break
61+
fi
62+
echo "Waiting for endpoint to be available..."
63+
sleep 10
64+
done
65+
echo "Retrieved endpoint: $endpoint"
66+
67+
# Create service pointing to the RDS endpoint
68+
kubectl create service externalname devlake-mysql-service --external-name=${endpoint} -n devlake --dry-run=client -o yaml | kubectl apply -f -
69+
70+
while true; do
71+
password=$(kubectl get secret ${CONN_SECRET_NAME} -n crossplane-system -o jsonpath='{.data.attribute\.master_password}' | base64 --decode)
72+
if [ -n "$password" ]; then
73+
break
74+
fi
75+
echo "Waiting for password to be available..."
76+
sleep 10
77+
done
78+
echo "Password retrieved (first 2 chars): ${password:0:2}..."
79+
80+
# Create auth secret with credentials
81+
kubectl create secret generic devlake-mysql-auth -n devlake \
82+
--from-literal=MYSQL_USER=merico \
83+
--from-literal=MYSQL_PASSWORD=merico \
84+
--from-literal=MYSQL_DATABASE=lake \
85+
--from-literal=MYSQL_ROOT_PASSWORD=$password \
86+
--from-literal=DB_URL="mysql://merico:merico@devlake-mysql-service:3306/lake?charset=utf8mb4&parseTime=True" --dry-run=client -o yaml | kubectl apply -f -
87+
88+
- name: wait-for-mysql
89+
retryStrategy:
90+
limit: 40
91+
retryPolicy: "Always"
92+
backoff:
93+
duration: "10"
94+
factor: 2
95+
maxDuration: "300s"
96+
container:
97+
image: mysql:8
98+
command: ["/bin/bash", "-c"]
99+
args:
100+
- |
101+
echo "Waiting for MySQL to be fully initialized..."
102+
sleep 60 # Initial delay to allow RDS to initialize
103+
104+
if mysql -h devlake-mysql-service -P 3306 -u root -p${MYSQL_ROOT_PASSWORD} -e "SELECT 1"; then
105+
echo "MySQL is ready!"
106+
exit 0
107+
else
108+
echo "MySQL not ready yet, will retry..."
109+
exit 1
110+
fi
111+
env:
112+
- name: MYSQL_ROOT_PASSWORD
113+
valueFrom:
114+
secretKeyRef:
115+
name: devlake-mysql-auth
116+
key: MYSQL_ROOT_PASSWORD
117+
118+
- name: create-users
119+
container:
120+
image: mysql:8
121+
command: ["/bin/bash", "-c"]
122+
args:
123+
- |
124+
echo "Creating lake database..."
125+
mysql -h devlake-mysql-service -P 3306 -u root -p${MYSQL_ROOT_PASSWORD} -e "
126+
CREATE DATABASE IF NOT EXISTS lake;
127+
"
128+
129+
echo "Creating devlake user..."
130+
mysql -h devlake-mysql-service -P 3306 -u root -p${MYSQL_ROOT_PASSWORD} -e "
131+
CREATE USER IF NOT EXISTS 'merico' IDENTIFIED BY 'merico';
132+
GRANT ALL PRIVILEGES ON lake.* TO 'merico';
133+
FLUSH PRIVILEGES;
134+
"
135+
136+
echo "Creating Grafana user..."
137+
mysql -h devlake-mysql-service -P 3306 -u root -p${MYSQL_ROOT_PASSWORD} -e "
138+
CREATE USER IF NOT EXISTS 'grafanaReader' IDENTIFIED BY 'grafana_password';
139+
GRANT SELECT ON lake.* TO 'grafanaReader';
140+
FLUSH PRIVILEGES;
141+
"
142+
143+
echo "User creation completed."
144+
env:
145+
- name: MYSQL_ROOT_PASSWORD
146+
valueFrom:
147+
secretKeyRef:
148+
name: devlake-mysql-auth
149+
key: MYSQL_ROOT_PASSWORD
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
apiVersion: core.oam.dev/v1beta1
2+
kind: Application
3+
metadata:
4+
name: devlake-rds-mysql
5+
namespace: devlake
6+
spec:
7+
components:
8+
- name: devlake-mysql-db
9+
type: rds-cluster-mysql
10+
properties:
11+
deploy: mgmt
12+
traits:
13+
- type: component-iam-policy
14+
properties:
15+
service: rds-db
16+
policy: |
17+
{
18+
"Version": "2012-10-17",
19+
"Statement": [
20+
{
21+
"Effect": "Allow",
22+
"Action": [
23+
"rds-db:connect"
24+
],
25+
"Resource": "*"
26+
}
27+
]
28+
}
29+
30+
31+
- name: devlake-mysql-access
32+
type: dp-service-account
33+
properties:
34+
clusterName: modern-engineering
35+
clusterRegion: us-west-2
36+
componentNamesForAccess:
37+
- devlake-mysql-db
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
apiVersion: grafana.integreatly.org/v1beta1
3+
kind: GrafanaDashboard
4+
metadata:
5+
name: dora-grafanadashboard
6+
namespace: grafana-operator
7+
spec:
8+
folder: "DORA Dashboards"
9+
instanceSelector:
10+
matchLabels:
11+
dashboards: "external-grafana"
12+
url: "https://raw.githubusercontent.com/apache/incubator-devlake/refs/heads/main/grafana/dashboards/DORA.json"
13+
---
14+
apiVersion: grafana.integreatly.org/v1beta1
15+
kind: GrafanaDashboard
16+
metadata:
17+
name: dora-deploymentfreq-grafanadashboard
18+
namespace: grafana-operator
19+
spec:
20+
folder: "DORA Dashboards"
21+
instanceSelector:
22+
matchLabels:
23+
dashboards: "external-grafana"
24+
url: "https://raw.githubusercontent.com/apache/incubator-devlake/refs/heads/main/grafana/dashboards/DORADetails-DeploymentFrequency.json"
25+
---
26+
apiVersion: grafana.integreatly.org/v1beta1
27+
kind: GrafanaDashboard
28+
metadata:
29+
name: dora-changefailure-grafanadashboard
30+
namespace: grafana-operator
31+
spec:
32+
folder: "DORA Dashboards"
33+
instanceSelector:
34+
matchLabels:
35+
dashboards: "external-grafana"
36+
url: "https://raw.githubusercontent.com/apache/incubator-devlake/refs/heads/main/grafana/dashboards/DORADetails-ChangeFailureRate.json"
37+
---
38+
apiVersion: grafana.integreatly.org/v1beta1
39+
kind: GrafanaDashboard
40+
metadata:
41+
name: dora-recoverytime-grafanadashboard
42+
namespace: grafana-operator
43+
spec:
44+
folder: "DORA Dashboards"
45+
instanceSelector:
46+
matchLabels:
47+
dashboards: "external-grafana"
48+
url: "https://raw.githubusercontent.com/apache/incubator-devlake/refs/heads/main/grafana/dashboards/DORADetails-FailedDeploymentRecoveryTime.json"
49+
---
50+
apiVersion: grafana.integreatly.org/v1beta1
51+
kind: GrafanaDashboard
52+
metadata:
53+
name: dora-leadtime-grafanadashboard
54+
namespace: grafana-operator
55+
spec:
56+
folder: "DORA Dashboards"
57+
instanceSelector:
58+
matchLabels:
59+
dashboards: "external-grafana"
60+
url: "https://raw.githubusercontent.com/apache/incubator-devlake/refs/heads/main/grafana/dashboards/DORADetails-LeadTimeforChanges.json"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resources:
2+
- devlake.yaml
3+
- mysql.yaml
4+
- rust.yaml
5+

0 commit comments

Comments
 (0)