Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b275a2c
create cm in case of cluster event instead of secret
prakash100198 May 22, 2025
962054e
gpu-workload-chart
rupinSec May 23, 2025
59c8ff8
migration for gpu-workloads
rupinSec May 23, 2025
1ea23e3
bump cpmmon lib
prakash100198 May 23, 2025
5977a88
Merge branch 'develop' into create-cm-on-cluster-action-oss
prakash100198 May 23, 2025
2ba594e
bump common lib
prakash100198 May 23, 2025
3d992e9
bump common lib
prakash100198 May 23, 2025
6ce9b77
fixes after testing
rupinSec May 23, 2025
1283179
fix
prakash100198 May 23, 2025
489871b
changes in json schema
rupinSec May 23, 2025
7fa7e39
k8s supported label label
prakash100198 May 23, 2025
8237884
small fix
prakash100198 May 23, 2025
fc54e9a
few changes after testing
rupinSec May 26, 2025
976f93b
bump common lib
prakash100198 May 27, 2025
2d09f1f
Merge branch 'develop' into create-cm-on-cluster-action-oss
prakash100198 May 27, 2025
bb12ab9
bump common lib
prakash100198 May 27, 2025
60012ce
Merge branch 'develop' into create-cm-on-cluster-action-oss
prakash100198 May 27, 2025
f159e78
bump
prakash100198 May 27, 2025
9a085b5
code review level 2
prakash100198 May 28, 2025
12778bd
misc: update sample dockerfiles use non-root user (UID 2002) and base…
badal773 Jun 5, 2025
5d22708
Merge branch 'main' into gpu-workload-chart
rupinSec Jun 5, 2025
3bf4b72
updated migration no.
rupinSec Jun 5, 2025
a61bf2f
Merge pull request #6608 from devtron-labs/gpu-workload-chart
rupinSec Jun 5, 2025
69a5263
feat: Added Cronjob chart 1-6-0 (#6650)
akshatsinha007 Jun 9, 2025
6e196cb
Merge branch 'main' into create-cm-on-cluster-action-oss
prakash100198 Jun 9, 2025
85c29e5
main merge
prakash100198 Jun 9, 2025
a667752
Merge branch 'develop' into create-cm-on-cluster-action-oss
prakash100198 Jun 9, 2025
c0a4705
make
prakash100198 Jun 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ require (
replace (
github.com/argoproj/argo-workflows/v3 v3.5.13 => github.com/devtron-labs/argo-workflows/v3 v3.5.13
github.com/cyphar/filepath-securejoin v0.4.1 => github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64
github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64
github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73
github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73
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
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzq
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/devtron-labs/argo-workflows/v3 v3.5.13 h1:3pINq0gXOSeTw2z/vYe+j80lRpSN5Rp/8mfQORh8SmU=
github.com/devtron-labs/argo-workflows/v3 v3.5.13/go.mod h1:/vqxcovDPT4zqr4DjR5v7CF8ggpY1l3TSa2CIG3jmjA=
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64 h1:p61fSzpy5CFCV481Egs8eTjiKvvm7oBfuCjTx/WHdMA=
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250605114955-3c18ccee2f64/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU=
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64 h1:NzO5vd+xy0/q0kePeTTVCCybYQXyt9L2h5JKhC3MC80=
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250605114955-3c18ccee2f64/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA=
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73 h1:pEXT25dlNGu5+xfEeqnuDt6X8kAsywWMvbWHxnK+Y2c=
github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250609102534-69e3ce614c73/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU=
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73 h1:22oC4Ii7+Rz6rl1OO7YNhzsFwQ+wobSdlmql/kNdVH0=
github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250609102534-69e3ce614c73/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA=
github.com/devtron-labs/go-bitbucket v0.9.60-beta h1:VEx1jvDgdtDPS6A1uUFoaEi0l1/oLhbr+90xOwr6sDU=
github.com/devtron-labs/go-bitbucket v0.9.60-beta/go.mod h1:GnuiCesvh8xyHeMCb+twm8lBR/kQzJYSKL28ZfObp1Y=
github.com/devtron-labs/protos v0.0.3-0.20250323220609-ecf8a0f7305e h1:U6UdYbW8a7xn5IzFPd8cywjVVPfutGJCudjePAfL/Hs=
Expand Down
52 changes: 20 additions & 32 deletions pkg/cluster/ClusterService.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import (
"github.com/devtron-labs/common-lib/async"
informerBean "github.com/devtron-labs/common-lib/informer"
"github.com/devtron-labs/common-lib/utils/k8s/commonBean"
configMap2 "github.com/devtron-labs/common-lib/utils/k8s/configMap"
bean3 "github.com/devtron-labs/devtron/pkg/argoApplication/bean"
"github.com/devtron-labs/devtron/pkg/cluster/adapter"
"github.com/devtron-labs/devtron/pkg/cluster/bean"
repository2 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository"
"github.com/devtron-labs/devtron/pkg/cluster/helper"
"github.com/devtron-labs/devtron/pkg/cluster/read"
cronUtil "github.com/devtron-labs/devtron/util/cron"
"github.com/robfig/cron/v3"
Expand Down Expand Up @@ -231,22 +234,9 @@ func (impl *ClusterServiceImpl) Save(parent context.Context, bean *bean.ClusterB
impl.SyncNsInformer(bean)
}
impl.logger.Info("saving secret for cluster informer")
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
if err != nil {
impl.logger.Errorw("error in getting k8s Client in cluster", "err", err, "clusterName", bean.ClusterName)
return bean, nil
}
//creating cluster secret, this secret will be read informer in kubelink to know that a new cluster has been added
secretName := ParseSecretNameForKubelinkInformer(bean.Id)

data := make(map[string][]byte)
data[informerBean.SecretFieldClusterId] = []byte(fmt.Sprintf("%v", bean.Id))
data[informerBean.SecretFieldAction] = []byte(informerBean.ClusterActionAdd)
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
// TODO Asutosh: Why not UPSERT ??
_, err = impl.K8sUtil.CreateSecret(clusterBean.DefaultNamespace, data, secretName, informerBean.ClusterModifyEventSecretType, k8sClient, nil, nil)
if err != nil {
impl.logger.Errorw("error in creating secret for informers", "secretName", secretName, "err", err)
cmData, labels := helper.CreateClusterModifyEventData(bean.Id, informerBean.ClusterActionAdd)
if err = impl.upsertClusterConfigMap(bean, cmData, labels); err != nil {
impl.logger.Errorw("error upserting cluster secret", "cmData", cmData, "err", err)
return bean, nil
}
return bean, nil
Expand Down Expand Up @@ -473,42 +463,40 @@ func (impl *ClusterServiceImpl) Update(ctx context.Context, bean *bean.ClusterBe
}
impl.logger.Infow("saving secret for cluster informer")
if bean.HasConfigOrUrlChanged {
data := make(map[string][]byte)
data[informerBean.SecretFieldClusterId] = []byte(fmt.Sprintf("%v", bean.Id))
data[informerBean.SecretFieldAction] = []byte(informerBean.ClusterActionUpdate)
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
if err = impl.upsertClusterSecret(bean, data); err != nil {
impl.logger.Errorw("error upserting cluster secret", "data", data, "err", err)
cmData, labels := helper.CreateClusterModifyEventData(bean.Id, informerBean.ClusterActionUpdate)
if err = impl.upsertClusterConfigMap(bean, cmData, labels); err != nil {
impl.logger.Errorw("error upserting cluster secret", "cmData", cmData, "err", err)
// TODO Asutosh: why error is not propagated ??
return bean, nil
}
}
return bean, nil
}

func (impl *ClusterServiceImpl) upsertClusterSecret(bean *bean.ClusterBean, data map[string][]byte) error {
func (impl *ClusterServiceImpl) upsertClusterConfigMap(bean *bean.ClusterBean, data, labels map[string]string) error {
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
if err != nil {
impl.logger.Errorw("error in getting k8s client", "err", err)
return err
}
// below secret will act as an event for informer running on a secret object in kubelink and kubewatch
secretName := ParseSecretNameForKubelinkInformer(bean.Id)
secret, err := impl.K8sUtil.GetSecret(clusterBean.DefaultNamespace, secretName, k8sClient)
// below cm will act as an event for informer running on a secret object in kubelink and kubewatch
cmName := ParseCmNameForK8sInformerOnClusterEvent(bean.Id)
configMap, err := impl.K8sUtil.GetConfigMap(bean3.DevtronCDNamespae, cmName, k8sClient)
if err != nil && !k8sError.IsNotFound(err) {
impl.logger.Errorw("error in getting cluster secret", "secretName", secretName, "err", err)
impl.logger.Errorw("error in getting cluster config map", "cmName", cmName, "err", err)
return err
} else if k8sError.IsNotFound(err) {
_, err = impl.K8sUtil.CreateSecret(clusterBean.DefaultNamespace, data, secretName, informerBean.ClusterModifyEventSecretType, k8sClient, nil, nil)
_, err = impl.K8sUtil.CreateConfigMapObject(cmName, bean3.DevtronCDNamespae, k8sClient, configMap2.WithData(data), configMap2.WithLabels(labels))
if err != nil {
impl.logger.Errorw("error in creating secret for informers", "secretName", secretName, "err", err)
impl.logger.Errorw("error in creating cm object for informer", "cmName", cmName, "err", err)
return err
}
} else {
secret.Data = data
secret, err = impl.K8sUtil.UpdateSecret(clusterBean.DefaultNamespace, secret, k8sClient)
configMap.Labels = labels
configMap.Data = data
configMap, err = impl.K8sUtil.UpdateConfigMap(bean3.DevtronCDNamespae, configMap, k8sClient)
if err != nil {
impl.logger.Errorw("error in updating secret for informers", "secretName", secretName, "err", err)
impl.logger.Errorw("error in updating cm for informers", "cmName", cmName, "err", err)
return err
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cluster/bean/bean.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ type DefaultClusterComponent struct {
}

const (
DefaultNamespace = "default"
SecretFieldUpdatedOn = "updated_on"
DefaultNamespace = "default"
CmFieldUpdatedOn = "updated_on"
)
6 changes: 3 additions & 3 deletions pkg/cluster/clusterUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package cluster
import "fmt"

const (
SecretName = "cluster-event"
CmName = "cluster-event"
)

func ParseSecretNameForKubelinkInformer(clusterId int) string {
return fmt.Sprintf("%s-%d", SecretName, clusterId)
func ParseCmNameForK8sInformerOnClusterEvent(clusterId int) string {
return fmt.Sprintf("%s-%d", CmName, clusterId)
}
20 changes: 20 additions & 0 deletions pkg/cluster/helper/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package helper

import (
"fmt"
informerBean "github.com/devtron-labs/common-lib/informer"
clusterBean "github.com/devtron-labs/devtron/pkg/cluster/bean"
"time"
)

func CreateClusterModifyEventData(clusterId int, action string) (map[string]string, map[string]string) {
data := make(map[string]string)
data[informerBean.CmFieldClusterId] = fmt.Sprintf("%v", clusterId)
data[informerBean.CmFieldAction] = action
data[clusterBean.CmFieldUpdatedOn] = time.Now().String()

labels := make(map[string]string)
labels[informerBean.ClusterModifyEventSecretTypeKey] = informerBean.ClusterModifyEventCmLabelValue

return data, labels
}
28 changes: 21 additions & 7 deletions pkg/delete/DeleteService.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
dockerRegistryRepository "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry"
"github.com/devtron-labs/devtron/internal/util"
"github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository"
bean4 "github.com/devtron-labs/devtron/pkg/argoApplication/bean"
"github.com/devtron-labs/devtron/pkg/chartRepo"
"github.com/devtron-labs/devtron/pkg/cluster"
bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean"
Expand All @@ -35,6 +36,7 @@ import (
bean3 "github.com/devtron-labs/devtron/pkg/team/bean"
"github.com/go-pg/pg"
"go.uber.org/zap"
k8sError "k8s.io/apimachinery/pkg/api/errors"
http2 "net/http"
)

Expand All @@ -45,7 +47,7 @@ type DeleteService interface {
DeleteChartRepo(deleteRequest *chartRepo.ChartRepoDto) error
DeleteDockerRegistryConfig(deleteRequest *types.DockerArtifactStoreBean) error
CanDeleteChartRegistryPullConfig(storeId string) bool
DeleteClusterSecret(deleteRequest *bean2.ClusterBean, err error) error
DeleteClusterConfigMap(deleteRequest *bean2.ClusterBean) error
}

type DeleteServiceImpl struct {
Expand Down Expand Up @@ -95,26 +97,38 @@ func (impl DeleteServiceImpl) DeleteCluster(deleteRequest *bean2.ClusterBean, us
impl.logger.Errorw("error im deleting cluster", "err", err, "deleteRequest", deleteRequest)
return err
}
err = impl.DeleteClusterSecret(deleteRequest, err)
// 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
err = impl.DeleteClusterConfigMap(deleteRequest)
if err != nil {
impl.logger.Errorw("error in deleting cluster secret", "clusterId", deleteRequest.Id, "error", err)
impl.logger.Errorw("error in deleting cluster cm", "clusterId", deleteRequest.Id, "error", err)
// 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.
//return err
}
impl.k8sInformerFactory.DeleteClusterFromCache(clusterName)
return nil
}

func (impl DeleteServiceImpl) DeleteClusterSecret(deleteRequest *bean2.ClusterBean, err error) error {
func (impl DeleteServiceImpl) DeleteClusterConfigMap(deleteRequest *bean2.ClusterBean) error {
// kubelink informers are listening this secret, deleting this secret will inform kubelink that this cluster is deleted
k8sClient, err := impl.K8sUtil.GetCoreV1ClientInCluster()
if err != nil {
impl.logger.Errorw("error in getting in cluster k8s client", "err", err, "clusterName", deleteRequest.ClusterName)
return nil
}
secretName := cluster.ParseSecretNameForKubelinkInformer(deleteRequest.Id)
err = impl.K8sUtil.DeleteSecret(bean2.DefaultNamespace, secretName, k8sClient)
return err
cmName := cluster.ParseCmNameForK8sInformerOnClusterEvent(deleteRequest.Id)
err = impl.K8sUtil.DeleteConfigMap(bean4.DevtronCDNamespae, cmName, k8sClient)
if k8sError.IsNotFound(err) {
// when cm not found in devtroncd ns then delete the secret in default ns(secret name would be the same as cm name)
err = impl.K8sUtil.DeleteSecret(bean2.DefaultNamespace, cmName, k8sClient)
if err != nil {
impl.logger.Errorw("error in deleting cluster secret in default ns ", "secretName", cmName, "err", err)
return err
}
} else if err != nil {
impl.logger.Errorw("error in deleting cluster config map in devtroncd ns ", "cmName", cmName, "err", err)
return err
}
return nil
}

func (impl DeleteServiceImpl) DeleteEnvironment(deleteRequest *bean.EnvironmentBean, userId int32) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/delete/DeleteServiceExtended.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (impl DeleteServiceExtendedImpl) DeleteCluster(deleteRequest *bean2.Cluster
impl.logger.Errorw("error im deleting cluster", "err", err, "deleteRequest", deleteRequest)
return err
}
err = impl.DeleteClusterSecret(deleteRequest, err)
err = impl.DeleteClusterConfigMap(deleteRequest)
if err != nil {
impl.logger.Errorw("error in deleting cluster secret", "clusterId", deleteRequest.Id, "error", err)
// 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.
Expand Down
61 changes: 30 additions & 31 deletions sample-docker-templates/django/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,48 +1,47 @@
# Dockerfile
# Base Image - slim Python
FROM python:3.13-slim

# Base Image
FROM python:3.8
# Environment settings
ENV PYTHONUNBUFFERED=1 LANG=C.UTF-8

# set default environment variables
ENV PYTHONUNBUFFERED 1
ENV LANG C.UTF-8

# to take runtime arguments and set env variables
# Django superuser build args
ARG DJANGO_SUPERUSER_USERNAME
ENV DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME}

ARG DJANGO_SUPERUSER_PASSWORD
ENV DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}

ARG DJANGO_SUPERUSER_EMAIL
ENV DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME}
ENV DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
ENV DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL}

# create and set working directory
RUN mkdir /app
# Set workdir
WORKDIR /app

RUN chown -R www-data:www-data /app

# Add current directory code to working directory
COPY . /app/

# install environment dependencies
RUN pip install -r requirements.txt

# install nginx
RUN apt-get update && apt-get install nginx vim -y --no-install-recommends
# Install system dependencies and nginx, then install Python deps
COPY requirements.txt .
RUN apt-get update && \
apt-get install -y --no-install-recommends nginx vim && \
pip install --no-cache-dir -r requirements.txt && \
rm -rf /var/lib/apt/lists/*

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

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

# Expose port 8080
EXPOSE 8080

# start server
EXPOSE 8000
# Switch to non-root
USER nonroot

# Stop signal for graceful shutdown
# https://docs.docker.com/reference/dockerfile/#stopsignal
STOPSIGNAL SIGTERM

# Refer https://github.com/devtron-labs/devtron/blob/main/sample-docker-templates/django/start-server.sh for sample start-server.sh file
# Start server (migrations, superuser, gunicorn, nginx)
CMD ["/app/start-server.sh"]
36 changes: 36 additions & 0 deletions sample-docker-templates/django/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
worker_processes auto;
error_log /tmp/nginx-logs/error.log warn;
pid /tmp/nginx-logs/nginx.pid;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

access_log /tmp/nginx-logs/access.log;

client_body_temp_path /tmp/nginx-logs/client_temp;
proxy_temp_path /tmp/nginx-logs/proxy_temp;
fastcgi_temp_path /tmp/nginx-logs/fastcgi_temp;
uwsgi_temp_path /tmp/nginx-logs/uwsgi_temp;
scgi_temp_path /tmp/nginx-logs/scgi_temp;

server {
listen 8080;
server_name localhost;

location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /static/ {
root /app;
}
}
}
15 changes: 0 additions & 15 deletions sample-docker-templates/django/nginx.default

This file was deleted.

Loading
Loading