Skip to content

Commit c1038ba

Browse files
Merge pull request #6607 from devtron-labs/create-cm-on-cluster-action-oss
chore: when a cluster event occurs, create config map instead of secret
2 parents 9f5bdbd + c0a4705 commit c1038ba

File tree

112 files changed

+11789
-412
lines changed

Some content is hidden

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

112 files changed

+11789
-412
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ require (
315315
replace (
316316
github.com/argoproj/argo-workflows/v3 v3.5.13 => github.com/devtron-labs/argo-workflows/v3 v3.5.13
317317
github.com/cyphar/filepath-securejoin v0.4.1 => github.com/cyphar/filepath-securejoin v0.3.6 // indirect
318-
github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64
319-
github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64
318+
github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73
319+
github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73
320320
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
321321
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzq
237237
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
238238
github.com/devtron-labs/argo-workflows/v3 v3.5.13 h1:3pINq0gXOSeTw2z/vYe+j80lRpSN5Rp/8mfQORh8SmU=
239239
github.com/devtron-labs/argo-workflows/v3 v3.5.13/go.mod h1:/vqxcovDPT4zqr4DjR5v7CF8ggpY1l3TSa2CIG3jmjA=
240-
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64 h1:p61fSzpy5CFCV481Egs8eTjiKvvm7oBfuCjTx/WHdMA=
241-
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU=
242-
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64 h1:NzO5vd+xy0/q0kePeTTVCCybYQXyt9L2h5JKhC3MC80=
243-
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA=
240+
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73 h1:pEXT25dlNGu5+xfEeqnuDt6X8kAsywWMvbWHxnK+Y2c=
241+
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU=
242+
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73 h1:22oC4Ii7+Rz6rl1OO7YNhzsFwQ+wobSdlmql/kNdVH0=
243+
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA=
244244
github.com/devtron-labs/go-bitbucket v0.9.60-beta h1:VEx1jvDgdtDPS6A1uUFoaEi0l1/oLhbr+90xOwr6sDU=
245245
github.com/devtron-labs/go-bitbucket v0.9.60-beta/go.mod h1:GnuiCesvh8xyHeMCb+twm8lBR/kQzJYSKL28ZfObp1Y=
246246
github.com/devtron-labs/protos v0.0.3-0.20250323220609-ecf8a0f7305e h1:U6UdYbW8a7xn5IzFPd8cywjVVPfutGJCudjePAfL/Hs=

pkg/cluster/ClusterService.go

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ import (
2323
"github.com/devtron-labs/common-lib/async"
2424
informerBean "github.com/devtron-labs/common-lib/informer"
2525
"github.com/devtron-labs/common-lib/utils/k8s/commonBean"
26+
configMap2 "github.com/devtron-labs/common-lib/utils/k8s/configMap"
27+
bean3 "github.com/devtron-labs/devtron/pkg/argoApplication/bean"
2628
"github.com/devtron-labs/devtron/pkg/cluster/adapter"
2729
"github.com/devtron-labs/devtron/pkg/cluster/bean"
2830
repository2 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository"
31+
"github.com/devtron-labs/devtron/pkg/cluster/helper"
2932
"github.com/devtron-labs/devtron/pkg/cluster/read"
3033
cronUtil "github.com/devtron-labs/devtron/util/cron"
3134
"github.com/robfig/cron/v3"
@@ -231,22 +234,9 @@ func (impl *ClusterServiceImpl) Save(parent context.Context, bean *bean.ClusterB
231234
impl.SyncNsInformer(bean)
232235
}
233236
impl.logger.Info("saving secret for cluster informer")
234-
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
235-
if err != nil {
236-
impl.logger.Errorw("error in getting k8s Client in cluster", "err", err, "clusterName", bean.ClusterName)
237-
return bean, nil
238-
}
239-
//creating cluster secret, this secret will be read informer in kubelink to know that a new cluster has been added
240-
secretName := ParseSecretNameForKubelinkInformer(bean.Id)
241-
242-
data := make(map[string][]byte)
243-
data[informerBean.SecretFieldClusterId] = []byte(fmt.Sprintf("%v", bean.Id))
244-
data[informerBean.SecretFieldAction] = []byte(informerBean.ClusterActionAdd)
245-
data[clusterBean.SecretFieldUpdatedOn] = []byte(time.Now().String()) // this field will ensure that informer detects change as other fields can be constant even if cluster config changes
246-
// TODO Asutosh: Why not UPSERT ??
247-
_, err = impl.K8sUtil.CreateSecret(clusterBean.DefaultNamespace, data, secretName, informerBean.ClusterModifyEventSecretType, k8sClient, nil, nil)
248-
if err != nil {
249-
impl.logger.Errorw("error in creating secret for informers", "secretName", secretName, "err", err)
237+
cmData, labels := helper.CreateClusterModifyEventData(bean.Id, informerBean.ClusterActionAdd)
238+
if err = impl.upsertClusterConfigMap(bean, cmData, labels); err != nil {
239+
impl.logger.Errorw("error upserting cluster secret", "cmData", cmData, "err", err)
250240
return bean, nil
251241
}
252242
return bean, nil
@@ -473,42 +463,40 @@ func (impl *ClusterServiceImpl) Update(ctx context.Context, bean *bean.ClusterBe
473463
}
474464
impl.logger.Infow("saving secret for cluster informer")
475465
if bean.HasConfigOrUrlChanged {
476-
data := make(map[string][]byte)
477-
data[informerBean.SecretFieldClusterId] = []byte(fmt.Sprintf("%v", bean.Id))
478-
data[informerBean.SecretFieldAction] = []byte(informerBean.ClusterActionUpdate)
479-
data[clusterBean.SecretFieldUpdatedOn] = []byte(time.Now().String()) // this field will ensure that informer detects change as other fields can be constant even if cluster config changes
480-
if err = impl.upsertClusterSecret(bean, data); err != nil {
481-
impl.logger.Errorw("error upserting cluster secret", "data", data, "err", err)
466+
cmData, labels := helper.CreateClusterModifyEventData(bean.Id, informerBean.ClusterActionUpdate)
467+
if err = impl.upsertClusterConfigMap(bean, cmData, labels); err != nil {
468+
impl.logger.Errorw("error upserting cluster secret", "cmData", cmData, "err", err)
482469
// TODO Asutosh: why error is not propagated ??
483470
return bean, nil
484471
}
485472
}
486473
return bean, nil
487474
}
488475

489-
func (impl *ClusterServiceImpl) upsertClusterSecret(bean *bean.ClusterBean, data map[string][]byte) error {
476+
func (impl *ClusterServiceImpl) upsertClusterConfigMap(bean *bean.ClusterBean, data, labels map[string]string) error {
490477
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
491478
if err != nil {
492479
impl.logger.Errorw("error in getting k8s client", "err", err)
493480
return err
494481
}
495-
// below secret will act as an event for informer running on a secret object in kubelink and kubewatch
496-
secretName := ParseSecretNameForKubelinkInformer(bean.Id)
497-
secret, err := impl.K8sUtil.GetSecret(clusterBean.DefaultNamespace, secretName, k8sClient)
482+
// below cm will act as an event for informer running on a secret object in kubelink and kubewatch
483+
cmName := ParseCmNameForK8sInformerOnClusterEvent(bean.Id)
484+
configMap, err := impl.K8sUtil.GetConfigMap(bean3.DevtronCDNamespae, cmName, k8sClient)
498485
if err != nil && !k8sError.IsNotFound(err) {
499-
impl.logger.Errorw("error in getting cluster secret", "secretName", secretName, "err", err)
486+
impl.logger.Errorw("error in getting cluster config map", "cmName", cmName, "err", err)
500487
return err
501488
} else if k8sError.IsNotFound(err) {
502-
_, err = impl.K8sUtil.CreateSecret(clusterBean.DefaultNamespace, data, secretName, informerBean.ClusterModifyEventSecretType, k8sClient, nil, nil)
489+
_, err = impl.K8sUtil.CreateConfigMapObject(cmName, bean3.DevtronCDNamespae, k8sClient, configMap2.WithData(data), configMap2.WithLabels(labels))
503490
if err != nil {
504-
impl.logger.Errorw("error in creating secret for informers", "secretName", secretName, "err", err)
491+
impl.logger.Errorw("error in creating cm object for informer", "cmName", cmName, "err", err)
505492
return err
506493
}
507494
} else {
508-
secret.Data = data
509-
secret, err = impl.K8sUtil.UpdateSecret(clusterBean.DefaultNamespace, secret, k8sClient)
495+
configMap.Labels = labels
496+
configMap.Data = data
497+
configMap, err = impl.K8sUtil.UpdateConfigMap(bean3.DevtronCDNamespae, configMap, k8sClient)
510498
if err != nil {
511-
impl.logger.Errorw("error in updating secret for informers", "secretName", secretName, "err", err)
499+
impl.logger.Errorw("error in updating cm for informers", "cmName", cmName, "err", err)
512500
return err
513501
}
514502
}

pkg/cluster/bean/bean.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@ type DefaultClusterComponent struct {
8383
}
8484

8585
const (
86-
DefaultNamespace = "default"
87-
SecretFieldUpdatedOn = "updated_on"
86+
DefaultNamespace = "default"
87+
CmFieldUpdatedOn = "updated_on"
8888
)

pkg/cluster/clusterUtil.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package cluster
33
import "fmt"
44

55
const (
6-
SecretName = "cluster-event"
6+
CmName = "cluster-event"
77
)
88

9-
func ParseSecretNameForKubelinkInformer(clusterId int) string {
10-
return fmt.Sprintf("%s-%d", SecretName, clusterId)
9+
func ParseCmNameForK8sInformerOnClusterEvent(clusterId int) string {
10+
return fmt.Sprintf("%s-%d", CmName, clusterId)
1111
}

pkg/cluster/helper/helper.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package helper
2+
3+
import (
4+
"fmt"
5+
informerBean "github.com/devtron-labs/common-lib/informer"
6+
clusterBean "github.com/devtron-labs/devtron/pkg/cluster/bean"
7+
"time"
8+
)
9+
10+
func CreateClusterModifyEventData(clusterId int, action string) (map[string]string, map[string]string) {
11+
data := make(map[string]string)
12+
data[informerBean.CmFieldClusterId] = fmt.Sprintf("%v", clusterId)
13+
data[informerBean.CmFieldAction] = action
14+
data[clusterBean.CmFieldUpdatedOn] = time.Now().String()
15+
16+
labels := make(map[string]string)
17+
labels[informerBean.ClusterModifyEventSecretTypeKey] = informerBean.ClusterModifyEventCmLabelValue
18+
19+
return data, labels
20+
}

pkg/delete/DeleteService.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
dockerRegistryRepository "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry"
2424
"github.com/devtron-labs/devtron/internal/util"
2525
"github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository"
26+
bean4 "github.com/devtron-labs/devtron/pkg/argoApplication/bean"
2627
"github.com/devtron-labs/devtron/pkg/chartRepo"
2728
"github.com/devtron-labs/devtron/pkg/cluster"
2829
bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean"
@@ -35,6 +36,7 @@ import (
3536
bean3 "github.com/devtron-labs/devtron/pkg/team/bean"
3637
"github.com/go-pg/pg"
3738
"go.uber.org/zap"
39+
k8sError "k8s.io/apimachinery/pkg/api/errors"
3840
http2 "net/http"
3941
)
4042

@@ -45,7 +47,7 @@ type DeleteService interface {
4547
DeleteChartRepo(deleteRequest *chartRepo.ChartRepoDto) error
4648
DeleteDockerRegistryConfig(deleteRequest *types.DockerArtifactStoreBean) error
4749
CanDeleteChartRegistryPullConfig(storeId string) bool
48-
DeleteClusterSecret(deleteRequest *bean2.ClusterBean, err error) error
50+
DeleteClusterConfigMap(deleteRequest *bean2.ClusterBean) error
4951
}
5052

5153
type DeleteServiceImpl struct {
@@ -95,26 +97,38 @@ func (impl DeleteServiceImpl) DeleteCluster(deleteRequest *bean2.ClusterBean, us
9597
impl.logger.Errorw("error im deleting cluster", "err", err, "deleteRequest", deleteRequest)
9698
return err
9799
}
98-
err = impl.DeleteClusterSecret(deleteRequest, err)
100+
// deleting a cluster config map created at time of cluster creation/updation so that informer in kubelink and kubewatch can delete the cluster from cache
101+
err = impl.DeleteClusterConfigMap(deleteRequest)
99102
if err != nil {
100-
impl.logger.Errorw("error in deleting cluster secret", "clusterId", deleteRequest.Id, "error", err)
103+
impl.logger.Errorw("error in deleting cluster cm", "clusterId", deleteRequest.Id, "error", err)
101104
// We are not returning error as it is not a blocking call as cluster can be unreachable at that time, and we have already deleted cluster from db.
102105
//return err
103106
}
104107
impl.k8sInformerFactory.DeleteClusterFromCache(clusterName)
105108
return nil
106109
}
107110

108-
func (impl DeleteServiceImpl) DeleteClusterSecret(deleteRequest *bean2.ClusterBean, err error) error {
111+
func (impl DeleteServiceImpl) DeleteClusterConfigMap(deleteRequest *bean2.ClusterBean) error {
109112
// kubelink informers are listening this secret, deleting this secret will inform kubelink that this cluster is deleted
110113
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
111114
if err != nil {
112115
impl.logger.Errorw("error in getting in cluster k8s client", "err", err, "clusterName", deleteRequest.ClusterName)
113116
return nil
114117
}
115-
secretName := cluster.ParseSecretNameForKubelinkInformer(deleteRequest.Id)
116-
err = impl.K8sUtil.DeleteSecret(bean2.DefaultNamespace, secretName, k8sClient)
117-
return err
118+
cmName := cluster.ParseCmNameForK8sInformerOnClusterEvent(deleteRequest.Id)
119+
err = impl.K8sUtil.DeleteConfigMap(bean4.DevtronCDNamespae, cmName, k8sClient)
120+
if k8sError.IsNotFound(err) {
121+
// when cm not found in devtroncd ns then delete the secret in default ns(secret name would be the same as cm name)
122+
err = impl.K8sUtil.DeleteSecret(bean2.DefaultNamespace, cmName, k8sClient)
123+
if err != nil {
124+
impl.logger.Errorw("error in deleting cluster secret in default ns ", "secretName", cmName, "err", err)
125+
return err
126+
}
127+
} else if err != nil {
128+
impl.logger.Errorw("error in deleting cluster config map in devtroncd ns ", "cmName", cmName, "err", err)
129+
return err
130+
}
131+
return nil
118132
}
119133

120134
func (impl DeleteServiceImpl) DeleteEnvironment(deleteRequest *bean.EnvironmentBean, userId int32) error {

pkg/delete/DeleteServiceExtended.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (impl DeleteServiceExtendedImpl) DeleteCluster(deleteRequest *bean2.Cluster
9696
impl.logger.Errorw("error im deleting cluster", "err", err, "deleteRequest", deleteRequest)
9797
return err
9898
}
99-
err = impl.DeleteClusterSecret(deleteRequest, err)
99+
err = impl.DeleteClusterConfigMap(deleteRequest)
100100
if err != nil {
101101
impl.logger.Errorw("error in deleting cluster secret", "clusterId", deleteRequest.Id, "error", err)
102102
// We are not returning error as it is not a blocking call as cluster can be unreachable at that time, and we have already deleted cluster from db.
Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,47 @@
1-
# Dockerfile
1+
# Base Image - slim Python
2+
FROM python:3.13-slim
23

3-
# Base Image
4-
FROM python:3.8
4+
# Environment settings
5+
ENV PYTHONUNBUFFERED=1 LANG=C.UTF-8
56

6-
# set default environment variables
7-
ENV PYTHONUNBUFFERED 1
8-
ENV LANG C.UTF-8
9-
10-
# to take runtime arguments and set env variables
7+
# Django superuser build args
118
ARG DJANGO_SUPERUSER_USERNAME
12-
ENV DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME}
13-
149
ARG DJANGO_SUPERUSER_PASSWORD
15-
ENV DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
16-
1710
ARG DJANGO_SUPERUSER_EMAIL
11+
ENV DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME}
12+
ENV DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
1813
ENV DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL}
1914

20-
# create and set working directory
21-
RUN mkdir /app
15+
# Set workdir
2216
WORKDIR /app
2317

24-
RUN chown -R www-data:www-data /app
25-
26-
# Add current directory code to working directory
27-
COPY . /app/
28-
29-
# install environment dependencies
30-
RUN pip install -r requirements.txt
31-
32-
# install nginx
33-
RUN apt-get update && apt-get install nginx vim -y --no-install-recommends
18+
# Install system dependencies and nginx, then install Python deps
19+
COPY requirements.txt .
20+
RUN apt-get update && \
21+
apt-get install -y --no-install-recommends nginx vim && \
22+
pip install --no-cache-dir -r requirements.txt && \
23+
rm -rf /var/lib/apt/lists/*
3424

35-
#Refer https://github.com/devtron-labs/devtron/blob/main/sample-docker-templates/django/nginx.default for sample nginx.default file
36-
COPY nginx.default /etc/nginx/sites-available/default
25+
# Copy app code, nginx.conf, and start script
26+
COPY app/ ./
27+
COPY nginx.conf /etc/nginx/nginx.conf
28+
RUN chmod +x start-server.sh
3729

38-
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
39-
&& ln -sf /dev/stderr /var/log/nginx/error.log
30+
# Create non-root user and set permissions
31+
RUN groupadd -g 2002 nonroot && \
32+
useradd -u 2002 -g nonroot -s /bin/bash -m nonroot && \
33+
mkdir -p /tmp/nginx-logs && \
34+
chown -R nonroot:nonroot /app /tmp/nginx-logs
4035

36+
# Expose port 8080
37+
EXPOSE 8080
4138

42-
# start server
43-
EXPOSE 8000
39+
# Switch to non-root
40+
USER nonroot
4441

42+
# Stop signal for graceful shutdown
43+
# https://docs.docker.com/reference/dockerfile/#stopsignal
4544
STOPSIGNAL SIGTERM
4645

47-
# Refer https://github.com/devtron-labs/devtron/blob/main/sample-docker-templates/django/start-server.sh for sample start-server.sh file
46+
# Start server (migrations, superuser, gunicorn, nginx)
4847
CMD ["/app/start-server.sh"]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
worker_processes auto;
2+
error_log /tmp/nginx-logs/error.log warn;
3+
pid /tmp/nginx-logs/nginx.pid;
4+
5+
events {
6+
worker_connections 1024;
7+
}
8+
9+
http {
10+
include mime.types;
11+
default_type application/octet-stream;
12+
13+
access_log /tmp/nginx-logs/access.log;
14+
15+
client_body_temp_path /tmp/nginx-logs/client_temp;
16+
proxy_temp_path /tmp/nginx-logs/proxy_temp;
17+
fastcgi_temp_path /tmp/nginx-logs/fastcgi_temp;
18+
uwsgi_temp_path /tmp/nginx-logs/uwsgi_temp;
19+
scgi_temp_path /tmp/nginx-logs/scgi_temp;
20+
21+
server {
22+
listen 8080;
23+
server_name localhost;
24+
25+
location / {
26+
proxy_pass http://127.0.0.1:8000;
27+
proxy_set_header Host $host;
28+
proxy_set_header X-Real-IP $remote_addr;
29+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
30+
}
31+
32+
location /static/ {
33+
root /app;
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)