diff --git a/Makefile b/Makefile index f5514e61d2..354aeb4011 100755 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: fetch-all-env build -TARGET_BRANCH?=main +TARGET_BRANCH?=develop TAG?=$(shell bash -c 'git log --pretty=format:'%h' -n 1') FLAGS= ENVVAR= diff --git a/Wire.go b/Wire.go index 9e0bbff87b..ce32204c37 100644 --- a/Wire.go +++ b/Wire.go @@ -93,6 +93,7 @@ import ( "github.com/devtron-labs/devtron/client/cron" "github.com/devtron-labs/devtron/client/dashboard" eClient "github.com/devtron-labs/devtron/client/events" + "github.com/devtron-labs/devtron/client/fluxcd" "github.com/devtron-labs/devtron/client/gitSensor" "github.com/devtron-labs/devtron/client/grafana" "github.com/devtron-labs/devtron/client/lens" @@ -223,6 +224,7 @@ func InitializeApp() (*App, error) { policyGovernance.PolicyGovernanceWireSet, resourceScan.ScanningResultWireSet, executor.ExecutorWireSet, + fluxcd.DeploymentWireSet, // -------wireset end ---------- // ------- gitSensor.GetConfig, @@ -754,6 +756,10 @@ func InitializeApp() (*App, error) { deployment3.NewFullModeDeploymentServiceImpl, wire.Bind(new(deployment3.FullModeDeploymentService), new(*deployment3.FullModeDeploymentServiceImpl)), + + deployment3.NewFullModeFluxDeploymentServiceImpl, + wire.Bind(new(deployment3.FullModeFluxDeploymentService), new(*deployment3.FullModeFluxDeploymentServiceImpl)), + // util2.NewGoJsonSchemaCustomFormatChecker, //history starts diff --git a/api/fluxApplication/FluxApplicationRestHandler.go b/api/fluxApplication/FluxApplicationRestHandler.go index 7d947b2aae..f1ef3d616c 100644 --- a/api/fluxApplication/FluxApplicationRestHandler.go +++ b/api/fluxApplication/FluxApplicationRestHandler.go @@ -45,6 +45,8 @@ func (handler *FluxApplicationRestHandlerImpl) ListFluxApplications(w http.Respo var clusterIds []int var err error + noStream := v.Get("noStream") == "true" + //handling when the clusterIds string is empty ,it will not support the if len(clusterIdString) == 0 { handler.logger.Errorw("error in getting cluster ids", "error", err, "clusterIds", clusterIds) @@ -57,7 +59,7 @@ func (handler *FluxApplicationRestHandlerImpl) ListFluxApplications(w http.Respo return } handler.logger.Debugw("extracted ClusterIds successfully ", "clusterIds", clusterIds) - handler.fluxApplicationService.ListFluxApplications(r.Context(), clusterIds, w) + handler.fluxApplicationService.ListFluxApplications(r.Context(), clusterIds, noStream, w) } func (handler *FluxApplicationRestHandlerImpl) GetApplicationDetail(w http.ResponseWriter, r *http.Request) { diff --git a/api/helm-app/gRPC/applist.pb.go b/api/helm-app/gRPC/applist.pb.go index b1fb98d703..1e93b7a828 100644 --- a/api/helm-app/gRPC/applist.pb.go +++ b/api/helm-app/gRPC/applist.pb.go @@ -581,9 +581,11 @@ type FluxAppDetail struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FluxApplication *FluxApplication `protobuf:"bytes,1,opt,name=fluxApplication,proto3" json:"fluxApplication,omitempty"` - FluxAppStatusDetail *FluxAppStatusDetail `protobuf:"bytes,2,opt,name=FluxAppStatusDetail,proto3" json:"FluxAppStatusDetail,omitempty"` - ResourceTreeResponse *ResourceTreeResponse `protobuf:"bytes,3,opt,name=resourceTreeResponse,proto3" json:"resourceTreeResponse,omitempty"` + FluxApplication *FluxApplication `protobuf:"bytes,1,opt,name=fluxApplication,proto3" json:"fluxApplication,omitempty"` + FluxAppStatusDetail *FluxAppStatusDetail `protobuf:"bytes,2,opt,name=FluxAppStatusDetail,proto3" json:"FluxAppStatusDetail,omitempty"` + ResourceTreeResponse *ResourceTreeResponse `protobuf:"bytes,3,opt,name=resourceTreeResponse,proto3" json:"resourceTreeResponse,omitempty"` + ApplicationStatus string `protobuf:"bytes,4,opt,name=applicationStatus,proto3" json:"applicationStatus,omitempty"` + LastObservedGeneration string `protobuf:"bytes,5,opt,name=lastObservedGeneration,proto3" json:"lastObservedGeneration,omitempty"` } func (x *FluxAppDetail) Reset() { @@ -639,6 +641,20 @@ func (x *FluxAppDetail) GetResourceTreeResponse() *ResourceTreeResponse { return nil } +func (x *FluxAppDetail) GetApplicationStatus() string { + if x != nil { + return x.ApplicationStatus + } + return "" +} + +func (x *FluxAppDetail) GetLastObservedGeneration() string { + if x != nil { + return x.LastObservedGeneration + } + return "" +} + type FluxAppStatusDetail struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -4303,8 +4319,8 @@ var file_api_helm_app_gRPC_applist_proto_rawDesc = []byte{ 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x49, 0x73, 0x4b, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x41, 0x70, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x49, 0x73, 0x4b, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x41, 0x70, 0x70, 0x22, 0xde, - 0x01, 0x0a, 0x0d, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x49, 0x73, 0x4b, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x41, 0x70, 0x70, 0x22, 0xc4, + 0x02, 0x0a, 0x0d, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x3a, 0x0a, 0x0f, 0x66, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x6c, 0x75, @@ -4317,182 +4333,137 @@ var file_api_helm_app_gRPC_applist_proto_rawDesc = []byte{ 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x5f, 0x0a, 0x13, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0xa7, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, - 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x52, 0x11, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, - 0x12, 0x18, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x22, 0xe4, 0x02, 0x0a, 0x11, 0x44, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x72, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x72, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x12, 0x41, 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x6e, - 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, - 0x52, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x12, 0x3e, 0x0a, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x6d, - 0x65, 0x22, 0x72, 0x0a, 0x12, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, - 0x0a, 0x0b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x43, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x99, 0x03, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, - 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3e, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, - 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x49, 0x0a, - 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x12, 0x65, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x12, 0x65, 0x6e, 0x76, 0x69, 0x72, - 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x22, 0x0a, - 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x22, 0xc1, 0x01, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, - 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x22, 0x63, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x0d, 0x43, - 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, - 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, - 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, - 0x6f, 0x74, 0x65, 0x73, 0x22, 0x6b, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, - 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, - 0x73, 0x12, 0x2e, 0x0a, 0x0b, 0x70, 0x6f, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, 0x6f, 0x64, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x6f, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x22, 0xa9, 0x04, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x6f, - 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x0a, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x52, 0x0a, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0e, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, - 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x69, 0x73, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x12, 0x28, - 0x0a, 0x0f, 0x63, 0x61, 0x6e, 0x42, 0x65, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x61, 0x6e, 0x42, 0x65, 0x48, 0x69, - 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, - 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0f, 0x20, - 0x03, 0x28, 0x03, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x48, - 0x6f, 0x6f, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x48, 0x6f, 0x6f, - 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x6f, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x6f, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x22, 0x34, 0x0a, - 0x08, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x40, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x90, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x3b, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, - 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x36, 0x0a, + 0x16, 0x6c, 0x61, 0x73, 0x74, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x6c, + 0x61, 0x73, 0x74, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5f, 0x0a, 0x13, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa7, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x44, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, + 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x11, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, + 0x22, 0xe4, 0x02, 0x0a, 0x11, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x72, 0x74, 0x41, 0x76, 0x61, + 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x72, 0x74, + 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x41, 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x3e, 0x0a, 0x0c, 0x4c, 0x61, 0x73, + 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x4c, 0x61, 0x73, + 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, 0x61, + 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, + 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x22, 0x72, 0x0a, 0x12, 0x45, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x20, 0x0a, + 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x10, + 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x43, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, + 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x99, 0x03, 0x0a, 0x09, + 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, + 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0d, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3e, 0x0a, + 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x12, 0x34, 0x0a, + 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x49, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, + 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, + 0x0a, 0x12, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, + 0x12, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x45, 0x78, + 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x22, 0xc1, 0x01, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x4c, + 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x4c, + 0x61, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x22, 0x63, 0x0a, 0x0d, 0x52, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0xb7, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x6b, 0x0a, 0x14, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x0b, 0x70, 0x6f, 0x64, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, + 0x6f, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x6f, 0x64, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa9, 0x04, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, @@ -4501,469 +4472,520 @@ var file_api_helm_app_gRPC_applist_proto_rawDesc = []byte{ 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, - 0x22, 0xdc, 0x01, 0x0a, 0x0b, 0x50, 0x6f, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x43, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, - 0x69, 0x6e, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x69, 0x73, 0x4e, 0x65, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, - 0x73, 0x4e, 0x65, 0x77, 0x12, 0x49, 0x0a, 0x13, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, - 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x13, 0x65, 0x70, 0x68, 0x65, - 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, - 0x4c, 0x0a, 0x16, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x87, 0x01, - 0x0a, 0x10, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x10, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x88, 0x01, 0x0a, 0x10, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x22, 0x7e, 0x0a, 0x0f, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, - 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, - 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x11, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, - 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x22, 0x9b, 0x02, 0x0a, 0x17, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x34, 0x0a, - 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x6f, 0x63, 0x6b, 0x65, - 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x3a, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, - 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x42, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x42, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x62, 0x0a, 0x18, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x11, 0x64, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x72, 0x79, 0x22, 0x85, 0x02, 0x0a, 0x0b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, - 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, - 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, - 0x2a, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, - 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x22, 0xd2, 0x01, 0x0a, 0x0d, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, - 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x52, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x22, 0x35, 0x0a, 0x17, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, - 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, - 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x18, 0x55, 0x6e, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x97, 0x01, - 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, + 0x12, 0x2c, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x66, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x73, 0x12, 0x3f, + 0x0a, 0x0e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x0e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x06, 0x68, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, + 0x61, 0x74, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x61, 0x6e, 0x42, 0x65, 0x48, 0x69, 0x62, + 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, + 0x61, 0x6e, 0x42, 0x65, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1d, + 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, + 0x6e, 0x66, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x03, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x69, 0x73, 0x48, 0x6f, 0x6f, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x06, 0x69, 0x73, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x6f, 0x6b, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x6f, 0x6b, 0x54, + 0x79, 0x70, 0x65, 0x22, 0x34, 0x0a, 0x08, 0x49, 0x6e, 0x66, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x40, 0x0a, 0x0c, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x90, 0x01, 0x0a, 0x16, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, + 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x2e, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, + 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, + 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, 0xdc, 0x01, 0x0a, 0x0b, 0x50, 0x6f, 0x64, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, + 0x69, 0x6e, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x4e, 0x65, 0x77, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x4e, 0x65, 0x77, 0x12, 0x49, 0x0a, 0x13, 0x65, 0x70, + 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, + 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x13, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x4c, 0x0a, 0x16, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, + 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x22, 0x87, 0x01, 0x0a, 0x10, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, + 0x0a, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x88, 0x01, + 0x0a, 0x10, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x7e, 0x0a, 0x0f, 0x48, 0x69, 0x62, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x11, 0x48, 0x69, 0x62, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x9b, 0x02, 0x0a, 0x17, 0x48, 0x65, 0x6c, 0x6d, + 0x41, 0x70, 0x70, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x68, 0x61, + 0x72, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x72, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x6f, 0x63, + 0x6b, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0c, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x42, + 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, + 0x64, 0x42, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, 0x0a, 0x18, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x48, + 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x85, 0x02, 0x0a, 0x0b, 0x52, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x11, 0x64, 0x65, 0x70, + 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, + 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x72, + 0x69, 0x64, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x65, 0x72, + 0x67, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, + 0x6e, 0x22, 0xd2, 0x01, 0x0a, 0x0d, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x88, 0x02, 0x0a, 0x15, 0x55, 0x70, 0x67, 0x72, - 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, - 0x61, 0x6d, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, - 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4d, 0x61, 0x78, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, - 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, - 0x74, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x16, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x10, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x35, 0x0a, 0x17, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, + 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x22, 0x34, 0x0a, + 0x18, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0d, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x88, 0x02, + 0x0a, 0x15, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, + 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, + 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, 0x73, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4b, 0x38, + 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x16, 0x55, 0x70, 0x67, 0x72, + 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x89, 0x01, 0x0a, + 0x17, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x64, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x56, 0x0a, 0x18, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, + 0x22, 0xa9, 0x01, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x38, 0x0a, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa7, 0x04, 0x0a, + 0x15, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, + 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, + 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x3a, 0x0a, 0x0f, 0x63, 0x68, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4b, 0x38, 0x73, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x4d, 0x61, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x43, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x49, + 0x73, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x70, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x49, 0x73, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x3e, 0x0a, 0x1a, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1a, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, + 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, + 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x71, 0x0a, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x19, + 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x16, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x29, 0x0a, + 0x0f, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x74, 0x0a, 0x16, 0x52, 0x6f, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0x56, 0x0a, 0x18, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x0f, 0x43, - 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x38, 0x0a, 0x17, - 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa7, 0x04, 0x0a, 0x15, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, - 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, - 0x6d, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x3a, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x0f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, - 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5f, + 0x0a, 0x15, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x61, 0x6e, + 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x22, + 0x71, 0x0a, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, + 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x19, + 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0xeb, 0x01, 0x0a, 0x18, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x12, + 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, + 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, - 0x12, 0x43, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x52, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x4f, 0x43, 0x49, 0x52, 0x65, - 0x70, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, 0x4f, 0x43, 0x49, 0x52, - 0x65, 0x70, 0x6f, 0x12, 0x3e, 0x0a, 0x1a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x41, 0x70, - 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x79, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, - 0x22, 0x71, 0x0a, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, - 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x16, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x22, 0x35, 0x0a, 0x19, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x29, 0x0a, 0x0f, 0x42, 0x6f, 0x6f, 0x6c, 0x65, - 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x22, 0x74, 0x0a, 0x16, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x11, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5f, 0x0a, 0x15, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x61, - 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x71, 0x0a, 0x19, 0x42, 0x75, 0x6c, - 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x52, 0x19, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xeb, 0x01, 0x0a, - 0x18, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x68, 0x61, - 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0d, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x0c, - 0x63, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x11, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x43, 0x74, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x4b, 0x38, - 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x4b, 0x38, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x35, 0x0a, 0x19, 0x48, 0x65, - 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x22, 0x28, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x49, 0x0a, 0x03, 0x47, - 0x76, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x6d, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x03, 0x67, 0x76, 0x6b, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x47, 0x76, 0x6b, 0x52, 0x03, 0x67, 0x76, 0x6b, - 0x12, 0x43, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x06, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x88, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, - 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0c, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x28, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x72, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x22, 0x49, 0x0a, 0x03, 0x47, 0x76, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, + 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x6d, 0x0a, 0x0e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x16, + 0x0a, 0x03, 0x67, 0x76, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x47, 0x76, + 0x6b, 0x52, 0x03, 0x67, 0x76, 0x6b, 0x12, 0x43, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x52, 0x0c, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x39, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x12, 0x43, - 0x68, 0x61, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x22, 0xeb, 0x03, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x20, - 0x0a, 0x0b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x55, 0x72, 0x6c, - 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x77, 0x73, 0x52, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x77, 0x73, - 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, - 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, - 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x54, 0x79, - 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x70, 0x6f, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x70, 0x6f, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x4f, - 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xd5, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x4f, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x17, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x12, 0x2e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x3a, 0x0a, 0x0f, 0x53, 0x53, 0x48, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x53, 0x53, 0x48, - 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x53, 0x53, - 0x48, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x29, 0x0a, - 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, - 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x72, 0x6c, 0x22, 0xa1, 0x01, 0x0a, 0x0f, 0x53, 0x53, 0x48, - 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2a, 0x0a, 0x10, - 0x53, 0x53, 0x48, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x53, 0x53, 0x48, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x53, 0x48, 0x55, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, - 0x53, 0x48, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x53, - 0x48, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x53, 0x53, 0x48, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x53, 0x53, 0x48, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x53, 0x53, 0x48, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x35, 0x0a, 0x13, + 0x65, 0x72, 0x12, 0x37, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x37, 0x0a, + 0x0c, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x73, 0x22, 0x2a, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x22, 0xeb, 0x03, + 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x55, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x41, 0x77, 0x73, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x41, 0x77, 0x73, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x52, 0x65, 0x70, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x52, 0x65, 0x70, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x12, 0x4f, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x16, 0x52, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xd5, 0x01, 0x0a, 0x16, + 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, + 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x78, + 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x0f, 0x53, 0x53, 0x48, 0x54, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x53, 0x53, 0x48, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x0f, 0x53, 0x53, 0x48, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x22, 0x29, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x72, 0x6c, 0x22, 0xa1, + 0x01, 0x0a, 0x0f, 0x53, 0x53, 0x48, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x2a, 0x0a, 0x10, 0x53, 0x53, 0x48, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x53, 0x53, + 0x48, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x53, 0x53, 0x48, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x53, 0x48, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x53, 0x48, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x53, 0x48, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x53, 0x48, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x53, 0x53, 0x48, 0x41, 0x75, 0x74, 0x68, 0x4b, + 0x65, 0x79, 0x22, 0x35, 0x0a, 0x13, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x73, 0x4c, + 0x6f, 0x67, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x49, + 0x73, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x2a, 0x38, 0x0a, 0x16, 0x52, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x10, 0x00, 0x12, 0x07, + 0x0a, 0x03, 0x53, 0x53, 0x48, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x49, 0x52, 0x45, 0x43, + 0x54, 0x10, 0x02, 0x32, 0xd9, 0x0d, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x10, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, + 0x2e, 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x10, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, + 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6c, 0x75, + 0x78, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, + 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, + 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x41, 0x70, + 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0c, 0x47, 0x65, 0x74, + 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x41, + 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x32, 0x12, 0x11, 0x2e, 0x41, + 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x0a, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x34, 0x0a, + 0x09, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x48, 0x69, 0x62, + 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0b, 0x55, 0x6e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, + 0x74, 0x65, 0x12, 0x11, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x14, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, + 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x2e, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x10, 0x55, 0x6e, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x2e, + 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x1a, 0x19, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, + 0x0a, 0x0e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x12, 0x16, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, + 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x2e, 0x44, 0x65, 0x70, + 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x12, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x1b, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, + 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x43, 0x68, 0x61, 0x72, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x12, 0x49, 0x73, 0x52, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x12, + 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x1a, 0x10, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0f, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x17, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0d, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x12, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x11, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x12, 0x1a, + 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x42, 0x75, 0x6c, + 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x1d, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x48, 0x65, 0x6c, 0x6d, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x39, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x16, + 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x6f, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, + 0x1d, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x57, + 0x69, 0x74, 0x68, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x74, 0x12, 0x16, + 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, + 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x42, 0x0a, 0x13, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x49, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x73, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x64, 0x49, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x49, 0x73, 0x4c, 0x6f, 0x67, 0x67, 0x65, - 0x64, 0x49, 0x6e, 0x2a, 0x38, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x09, 0x0a, - 0x05, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x53, 0x48, 0x10, - 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x10, 0x02, 0x32, 0xd9, 0x0d, - 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x41, 0x70, 0x70, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x44, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, - 0x41, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x41, 0x70, 0x70, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, - 0x30, 0x01, 0x12, 0x2f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x56, 0x32, 0x12, 0x11, 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x41, 0x70, 0x70, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x09, 0x48, 0x69, 0x62, 0x65, 0x72, - 0x6e, 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x36, 0x0a, - 0x0b, 0x55, 0x6e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x48, - 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x12, 0x2e, 0x48, 0x69, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x11, 0x2e, - 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x41, 0x70, 0x70, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, - 0x0d, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x11, - 0x2e, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0c, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, - 0x00, 0x12, 0x40, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, - 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, - 0x64, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x10, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x19, 0x2e, 0x55, 0x6e, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x55, 0x70, 0x67, 0x72, - 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x16, 0x2e, 0x55, 0x70, 0x67, - 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0e, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x16, 0x2e, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x50, 0x0a, 0x1b, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x43, 0x68, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, - 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x12, 0x49, 0x73, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x10, 0x2e, 0x42, - 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x3e, 0x0a, 0x0f, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x12, 0x17, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x42, - 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x0d, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, - 0x74, 0x12, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x11, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x61, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x12, 0x1a, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x58, 0x0a, 0x1d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, - 0x61, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, - 0x2e, 0x48, 0x65, 0x6c, 0x6d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x08, - 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x13, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x1d, 0x55, 0x70, 0x67, 0x72, 0x61, - 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x43, 0x75, 0x73, - 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x74, 0x12, 0x16, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, - 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x13, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x4f, 0x43, 0x49, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x5c, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, - 0x65, 0x65, 0x46, 0x6f, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, - 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, - 0x10, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x12, 0x15, 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, - 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x11, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, - 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x1a, 0x12, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, - 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x65, 0x76, 0x74, 0x72, 0x6f, 0x6e, 0x2d, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x62, 0x65, - 0x61, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x46, 0x6f, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, + 0x72, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, + 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x15, 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, + 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, + 0x2e, 0x46, 0x6c, 0x75, 0x78, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x00, + 0x12, 0x3d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x12, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x12, 0x2e, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x65, 0x64, 0x41, 0x70, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x00, 0x42, + 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x65, + 0x76, 0x74, 0x72, 0x6f, 0x6e, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x6c, + 0x69, 0x6e, 0x6b, 0x2f, 0x62, 0x65, 0x61, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x52, + 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/helm-app/gRPC/applist.proto b/api/helm-app/gRPC/applist.proto index c3b6b54c7e..37a2147413 100644 --- a/api/helm-app/gRPC/applist.proto +++ b/api/helm-app/gRPC/applist.proto @@ -86,6 +86,8 @@ message FluxAppDetail{ FluxApplication fluxApplication=1; FluxAppStatusDetail FluxAppStatusDetail = 2; ResourceTreeResponse resourceTreeResponse =3; + string applicationStatus = 4; + string lastObservedGeneration = 5; } message FluxAppStatusDetail{ diff --git a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go index d784037519..04124d8221 100644 --- a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go +++ b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go @@ -2472,6 +2472,11 @@ func (handler *PipelineConfigRestHandlerImpl) ValidateExternalAppLinkRequest(w h common.WriteJsonResp(w, err, response, http.StatusOK) return // handle helm deployment types + } else if request.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX { + response := handler.pipelineBuilder.ValidateLinkFluxAppRequest(ctx, &request) + common.WriteJsonResp(w, err, response, http.StatusOK) + return + // handle helm deployment types } common.WriteJsonResp(w, errors.New("invalid deployment app type in request"), nil, http.StatusBadRequest) return diff --git a/client/cron/CdApplicationStatusUpdateHandler.go b/client/cron/CdApplicationStatusUpdateHandler.go index dd2dc461de..cef93f1db4 100644 --- a/client/cron/CdApplicationStatusUpdateHandler.go +++ b/client/cron/CdApplicationStatusUpdateHandler.go @@ -110,7 +110,7 @@ func NewCdApplicationStatusUpdateHandlerImpl(logger *zap.SugaredLogger, appServi logger.Errorw("error in starting argo application status update cron job", "err", err) return nil } - _, err = cron.AddFunc("@every 1m", impl.ArgoPipelineTimelineUpdate) + _, err = cron.AddFunc("@every 1m", impl.FluxApplicationStatusUpdate) if err != nil { logger.Errorw("error in starting argo application status update cron job", "err", err) return nil @@ -137,6 +137,30 @@ func (impl *CdApplicationStatusUpdateHandlerImpl) HelmApplicationStatusUpdate() return } +func (impl *CdApplicationStatusUpdateHandlerImpl) FluxApplicationStatusUpdate() { + cronProcessStartTime := time.Now() + defer func() { + middleware.DeploymentStatusCronDuration.WithLabelValues(pipeline.DEVTRON_APP_FLUX_PIPELINE_STATUS_UPDATE_CRON).Observe(time.Since(cronProcessStartTime).Seconds()) + }() + getPipelineDeployedWithinHours := impl.AppStatusConfig.GetPipelineDeployedWithinHours + FluxCDPipelineStatusCheckEligibleTime, err := strconv.Atoi(impl.AppStatusConfig.FluxCDPipelineStatusCheckEligibleTime) + if err != nil { + impl.logger.Errorw("error in converting string to int", "err", err) + return + } + cdPipelineTimeoutDuration, err := strconv.Atoi(impl.AppStatusConfig.CdPipelineStatusTimeoutDuration) + if err != nil { + impl.logger.Errorw("error in converting string to int", "err", err) + return + } + err = impl.workflowStatusService.CheckFluxAppStatusPeriodicallyAndUpdateInDb(FluxCDPipelineStatusCheckEligibleTime, getPipelineDeployedWithinHours, cdPipelineTimeoutDuration) + if err != nil { + impl.logger.Errorw("error helm app status update - cron job", "err", err) + return + } + return +} + func (impl *CdApplicationStatusUpdateHandlerImpl) ArgoApplicationStatusUpdate() { cronProcessStartTime := time.Now() defer func() { diff --git a/client/fluxcd/fluxDeploymentService.go b/client/fluxcd/fluxDeploymentService.go new file mode 100644 index 0000000000..02acf8afe0 --- /dev/null +++ b/client/fluxcd/fluxDeploymentService.go @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fluxcd + +import ( + "context" + "fmt" + "github.com/devtron-labs/common-lib/utils/k8s" + "github.com/devtron-labs/devtron/pkg/deployment/common/bean" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + "github.com/fluxcd/pkg/apis/meta" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + "go.opentelemetry.io/otel" + "go.uber.org/zap" + v1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "path" + "sigs.k8s.io/controller-runtime/pkg/client" + "time" +) + +type DeploymentService interface { + DeployFluxCdApp(ctx context.Context, request *DeploymentRequest) error + DeleteFluxDeploymentApp(ctx context.Context, request *DeploymentAppDeleteRequest) error +} + +type DeploymentServiceImpl struct { + logger *zap.SugaredLogger + K8sUtil *k8s.K8sServiceImpl + gitOpsConfigReadService config.GitOpsConfigReadService +} + +func NewDeploymentService(logger *zap.SugaredLogger, + K8sUtil *k8s.K8sServiceImpl, + gitOpsConfigReadService config.GitOpsConfigReadService) *DeploymentServiceImpl { + return &DeploymentServiceImpl{ + logger: logger, + K8sUtil: K8sUtil, + gitOpsConfigReadService: gitOpsConfigReadService, + } +} + +const ( + gitRepositoryReconcileInterval = 1 * time.Minute + helmReleaseReconcileInterval = 1 * time.Minute +) + +type DeploymentRequest struct { + ClusterConfig *k8s.ClusterConfig + DeploymentConfig *bean.DeploymentConfig + IsAppCreated bool +} + +type DeploymentAppDeleteRequest struct { + ClusterConfig *k8s.ClusterConfig + DeploymentConfig *bean.DeploymentConfig +} + +func GetValuesFileArrForDevtronInlineApps(chartLocation string) []string { + //order matters here, last file will override previous file + //for external flux apps this array might have some other data and we will add our devtronValueFileName (format: _{envId}-values.yaml) along with this array + return []string{path.Join(chartLocation, "values.yaml")} +} + +func (impl *DeploymentServiceImpl) DeployFluxCdApp(ctx context.Context, request *DeploymentRequest) error { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "HandlerServiceImpl.deployFluxCdApp") + defer span.End() + fluxCdSpec := request.DeploymentConfig.ReleaseConfiguration.FluxCDSpec + clusterId := request.ClusterConfig.ClusterId + gitOpsSecret, err := impl.upsertGitRepoSecret(newCtx, fluxCdSpec, request.ClusterConfig) + if err != nil { + impl.logger.Errorw("error in creating git repo secret", "clusterId", clusterId, "err", err) + return err + } + restConfig, err := impl.K8sUtil.GetRestConfigByCluster(request.ClusterConfig) + if err != nil { + impl.logger.Errorw("error in getting rest config", "clusterId", clusterId, "err", err) + return err + } + apiClient, err := getClient(restConfig) + if err != nil { + impl.logger.Errorw("error in creating k8s client", "clusterId", clusterId, "err", err) + return err + } + //create/update gitOps secret + if !request.IsAppCreated { + err := impl.createFluxCdApp(newCtx, fluxCdSpec, gitOpsSecret.GetName(), apiClient) + if err != nil { + impl.logger.Errorw("error in creating flux-cd application", "err", err) + return err + } + } else { + err := impl.updateFluxCdApp(newCtx, fluxCdSpec, gitOpsSecret.GetName(), apiClient) + if err != nil { + impl.logger.Errorw("error in updating flux-cd application", "err", err) + return err + } + } + return nil +} + +func (impl *DeploymentServiceImpl) upsertGitRepoSecret(ctx context.Context, fluxCdSpec bean.FluxCDSpec, clusterConfig *k8s.ClusterConfig) (*v1.Secret, error) { + gitOpsConfig, err := impl.gitOpsConfigReadService.GetGitOpsProviderByRepoURL(fluxCdSpec.RepoUrl) + if err != nil { + impl.logger.Errorw("error fetching gitops config by repo url", "repoUrl", fluxCdSpec.RepoUrl, "err", err) + return nil, err + } + + data := map[string][]byte{ + "username": []byte(gitOpsConfig.Username), + "password": []byte(gitOpsConfig.Token), + } + + labels := map[string]string{ + "managed-by": "devtron", + "providerId": gitOpsConfig.Provider, + } + + namespace := fluxCdSpec.GitRepositoryNamespace + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: fluxCdSpec.GitOpsSecretName, + Namespace: fluxCdSpec.GitRepositoryNamespace, + Labels: labels, + }, + Type: v1.SecretTypeBasicAuth, + Data: data, + } + + coreV1Client, err := impl.K8sUtil.GetCoreV1Client(clusterConfig) + if err != nil { + impl.logger.Errorw("error in getting core v1 client", "clusterId", clusterConfig.ClusterId, "err", err) + return nil, err + } + // Try to create the secret first + createdSecret, err := coreV1Client.Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) + if err == nil { + return createdSecret, nil + } + if !k8serrors.IsAlreadyExists(err) { + impl.logger.Errorw("error creating secret", "namespace", namespace, "name", secret.GetName(), "err", err) + return nil, err + } + + // Secret already exists, get and update + existingSecret, err := coreV1Client.Secrets(namespace).Get(ctx, secret.GetName(), metav1.GetOptions{}) + if err != nil { + impl.logger.Errorw("error getting existing secret", "namespace", namespace, "name", secret.GetName(), "err", err) + return nil, err + } + + // Update data and labels + existingSecret.Data = data + if existingSecret.Labels == nil { + existingSecret.Labels = make(map[string]string) + } + for k, v := range labels { + existingSecret.Labels[k] = v + } + + updatedSecret, err := coreV1Client.Secrets(namespace).Update(ctx, existingSecret, metav1.UpdateOptions{}) + if err != nil { + impl.logger.Errorw("error updating secret", "namespace", namespace, "name", secret.GetName(), "err", err) + return nil, err + } + + return updatedSecret, nil +} + +func (impl *DeploymentServiceImpl) createFluxCdApp(ctx context.Context, fluxCdSpec bean.FluxCDSpec, + gitOpsSecretName string, apiClient client.Client) error { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "HandlerServiceImpl.createFluxCdApp") + defer span.End() + _, err := impl.CreateGitRepository(newCtx, fluxCdSpec, gitOpsSecretName, apiClient) + if err != nil { + impl.logger.Errorw("error in creating git repository", "fluxCdSpec", fluxCdSpec, "err", err) + return err + } + + _, err = impl.CreateHelmRelease(newCtx, fluxCdSpec, apiClient) + if err != nil { + impl.logger.Errorw("error in creating helm release", "fluxCdSpec", fluxCdSpec, "err", err) + return err + } + return nil +} + +func (impl *DeploymentServiceImpl) updateFluxCdApp(ctx context.Context, fluxCdSpec bean.FluxCDSpec, + gitOpsSecretName string, apiClient client.Client) error { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "HandlerServiceImpl.updateFluxCdApp") + defer span.End() + _, err := impl.UpdateGitRepository(newCtx, fluxCdSpec, gitOpsSecretName, apiClient) + if err != nil { + impl.logger.Errorw("error in updating git repository", "fluxCdSpec", fluxCdSpec, "err", err) + return err + } + + _, err = impl.UpdateHelmRelease(newCtx, fluxCdSpec, apiClient) + if err != nil { + impl.logger.Errorw("error in updating helm release", "fluxCdSpec", fluxCdSpec, "err", err) + return err + } + return nil +} + +func (impl *DeploymentServiceImpl) CreateGitRepository(ctx context.Context, fluxCdSpec bean.FluxCDSpec, secretName string, apiClient client.Client) (*sourcev1.GitRepository, error) { + name, namespace := fluxCdSpec.GitRepositoryName, fluxCdSpec.GitRepositoryNamespace + gitRepo := &sourcev1.GitRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: sourcev1.GitRepositorySpec{ + Interval: metav1.Duration{Duration: gitRepositoryReconcileInterval}, + URL: fluxCdSpec.RepoUrl, + SecretRef: &meta.LocalObjectReference{ + Name: secretName, + }, + Reference: &sourcev1.GitRepositoryRef{ + Branch: fluxCdSpec.RevisionTarget, + }, + }, + } + err := apiClient.Create(ctx, gitRepo) + if err != nil { + impl.logger.Errorw("error creating GitRepository", "name", name, "namespace", namespace, "err", err) + return nil, err + } + return gitRepo, nil +} + +func (impl *DeploymentServiceImpl) UpdateGitRepository(ctx context.Context, fluxCdSpec bean.FluxCDSpec, + secretName string, apiClient client.Client) (*sourcev1.GitRepository, error) { + name, namespace := fluxCdSpec.GitRepositoryName, fluxCdSpec.GitRepositoryNamespace + key := types.NamespacedName{Name: name, Namespace: namespace} + existing := &sourcev1.GitRepository{} + + err := apiClient.Get(ctx, key, existing) + if err != nil { + impl.logger.Errorw("error in getting git repository", "name", name, "namespace", namespace, "err", err) + return nil, err + } + existing.Spec.URL = fluxCdSpec.RepoUrl + existing.Spec.Interval = metav1.Duration{Duration: gitRepositoryReconcileInterval} + existing.Spec.SecretRef = &meta.LocalObjectReference{Name: secretName} + existing.Spec.Reference = &sourcev1.GitRepositoryRef{Branch: fluxCdSpec.RevisionTarget} + + err = apiClient.Update(ctx, existing) + if err != nil { + impl.logger.Errorw("error in updating git repository", "name", name, "namespace", namespace, "err", err) + return nil, err + } + return existing, nil +} + +func (impl *DeploymentServiceImpl) CreateHelmRelease(ctx context.Context, fluxCdSpec bean.FluxCDSpec, + apiClient client.Client) (*helmv2.HelmRelease, error) { + name, namespace := fluxCdSpec.GitRepositoryName, fluxCdSpec.HelmReleaseNamespace + helmRelease := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "managed-by": "devtron", + }, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: helmReleaseReconcileInterval}, //TODO + DriftDetection: &helmv2.DriftDetection{ + Mode: helmv2.DriftDetectionEnabled, + }, + Chart: &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + ReconcileStrategy: "Revision", + Chart: fluxCdSpec.ChartLocation, + Version: fluxCdSpec.ChartVersion, + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: sourcev1.GitRepositoryKind, + Name: name, //using same name for git repository and helm release which will be = deploymentAppName + Namespace: namespace, + }, + ValuesFiles: fluxCdSpec.GetFinalValuesFilePathArray(), + }, + }, + }, + } + err := apiClient.Create(ctx, helmRelease) + if err != nil { + impl.logger.Errorw("error in creating helm release", "name", name, "namespace", namespace, "err", err) + return nil, fmt.Errorf("failed to create HelmRelease: %w", err) + } + return helmRelease, nil +} + +func (impl *DeploymentServiceImpl) UpdateHelmRelease(ctx context.Context, fluxCdSpec bean.FluxCDSpec, + apiClient client.Client) (*helmv2.HelmRelease, error) { + name, namespace := fluxCdSpec.HelmReleaseName, fluxCdSpec.HelmReleaseNamespace + key := types.NamespacedName{Name: name, Namespace: namespace} + existing := &helmv2.HelmRelease{} + + gitRepositoryName, gitRepositoryNamespace := fluxCdSpec.GitRepositoryName, fluxCdSpec.GitRepositoryNamespace + + err := apiClient.Get(ctx, key, existing) + if err != nil { + impl.logger.Errorw("error in getting helm release", "name", name, "namespace", namespace, "err", err) + return nil, fmt.Errorf("failed to get HelmRelease: %w", err) + } + existing.Spec.DriftDetection = &helmv2.DriftDetection{ + Mode: helmv2.DriftDetectionEnabled, + } + existing.Spec.Interval = metav1.Duration{Duration: helmReleaseReconcileInterval} + existing.Spec.Chart = &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + ReconcileStrategy: "Revision", + Chart: fluxCdSpec.ChartLocation, + Version: fluxCdSpec.ChartVersion, + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: sourcev1.GitRepositoryKind, + Name: gitRepositoryName, + Namespace: gitRepositoryNamespace, + }, + ValuesFiles: fluxCdSpec.GetFinalValuesFilePathArray(), + }, + } + err = apiClient.Update(ctx, existing) + if err != nil { + impl.logger.Errorw("error in updating helm release", "name", name, "namespace", namespace, "err", err) + return nil, fmt.Errorf("failed to update HelmRelease: %w", err) + } + return existing, nil +} + +func (impl *DeploymentServiceImpl) DeleteFluxDeploymentApp(ctx context.Context, request *DeploymentAppDeleteRequest) error { + fluxCdSpec := request.DeploymentConfig.ReleaseConfiguration.FluxCDSpec + clusterId := fluxCdSpec.ClusterId + restConfig, err := impl.K8sUtil.GetRestConfigByCluster(request.ClusterConfig) + if err != nil { + impl.logger.Errorw("error in getting rest config", "clusterId", clusterId, "err", err) + return err + } + apiClient, err := getClient(restConfig) + if err != nil { + impl.logger.Errorw("error in creating k8s client", "clusterId", clusterId, "err", err) + return err + } + name, namespace := fluxCdSpec.HelmReleaseName, fluxCdSpec.HelmReleaseNamespace + key := types.NamespacedName{Name: name, Namespace: namespace} + + existingHelmRelease := &helmv2.HelmRelease{} + err = apiClient.Get(ctx, key, existingHelmRelease) + if err != nil { + impl.logger.Errorw("error in getting helm release", "key", key, "err", err) + return err + } + err = apiClient.Delete(ctx, existingHelmRelease) + if err != nil { + impl.logger.Errorw("error in deleting helm release", "key", key, "err", err) + return err + } + + key = types.NamespacedName{Name: fluxCdSpec.GitRepositoryName, Namespace: fluxCdSpec.GitRepositoryNamespace} + existingGitRepository := &sourcev1.GitRepository{} + err = apiClient.Get(ctx, key, existingGitRepository) + if err != nil { + impl.logger.Errorw("error in getting git repository", "key", key, "err", err) + return err + } + err = apiClient.Delete(ctx, existingGitRepository) + if err != nil { + impl.logger.Errorw("error in deleting git repository", "name", name, "namespace", namespace, "err", err) + return err + } + return nil +} + +func getClient(config *rest.Config) (client.Client, error) { + return client.New(config, client.Options{Scheme: getSchemeWithFluxCRDTypes()}) +} + +func getSchemeWithFluxCRDTypes() *runtime.Scheme { + scheme := runtime.NewScheme() + // Register core Kubernetes types + _ = v1.AddToScheme(scheme) + // Register Flux types + _ = sourcev1.AddToScheme(scheme) + _ = helmv2.AddToScheme(scheme) + return scheme +} diff --git a/client/fluxcd/wire_fluxcdDeployment.go b/client/fluxcd/wire_fluxcdDeployment.go new file mode 100644 index 0000000000..0d9761f72b --- /dev/null +++ b/client/fluxcd/wire_fluxcdDeployment.go @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fluxcd + +import ( + "github.com/google/wire" +) + +var DeploymentWireSet = wire.NewSet( + NewDeploymentService, + wire.Bind(new(DeploymentService), new(*DeploymentServiceImpl)), +) diff --git a/cmd/external-app/wire.go b/cmd/external-app/wire.go index 9213d08eea..27acccd70e 100644 --- a/cmd/external-app/wire.go +++ b/cmd/external-app/wire.go @@ -208,6 +208,8 @@ func InitializeApp() (*App, error) { // binding gitops to helm (for hyperion) wire.Bind(new(deployment.FullModeDeploymentService), new(*deployment2.EAModeDeploymentServiceImpl)), + wire.Bind(new(deployment.FullModeFluxDeploymentService), new(*deployment2.EAModeDeploymentServiceImpl)), + router.NewTelemetryRouterImpl, wire.Bind(new(router.TelemetryRouter), new(*router.TelemetryRouterImpl)), restHandler.NewTelemetryRestHandlerImpl, diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index 8c20cdd737..2810331a30 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run github.com/google/wire/cmd/wire +//go:generate go run -mod=mod github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject @@ -356,8 +356,8 @@ func InitializeApp() (*App, error) { return nil, err } deletePostProcessorImpl := service2.NewDeletePostProcessorImpl(sugaredLogger) - appStoreDeploymentServiceImpl := service2.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, installedAppDBServiceImpl, appStoreDeploymentDBServiceImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, appRepositoryImpl, eaModeDeploymentServiceImpl, eaModeDeploymentServiceImpl, environmentServiceImpl, helmAppServiceImpl, installedAppVersionHistoryRepositoryImpl, environmentVariables, acdConfig, gitOpsConfigReadServiceImpl, deletePostProcessorImpl, appStoreValidatorImpl, deploymentConfigServiceImpl, ociRegistryConfigRepositoryImpl) - fluxApplicationServiceImpl := fluxApplication.NewFluxApplicationServiceImpl(sugaredLogger, helmAppReadServiceImpl, clusterServiceImpl, helmAppClientImpl, pumpImpl) + appStoreDeploymentServiceImpl := service2.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, installedAppDBServiceImpl, appStoreDeploymentDBServiceImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, appRepositoryImpl, eaModeDeploymentServiceImpl, eaModeDeploymentServiceImpl, eaModeDeploymentServiceImpl, environmentServiceImpl, helmAppServiceImpl, installedAppVersionHistoryRepositoryImpl, environmentVariables, acdConfig, gitOpsConfigReadServiceImpl, deletePostProcessorImpl, appStoreValidatorImpl, deploymentConfigServiceImpl, ociRegistryConfigRepositoryImpl) + fluxApplicationServiceImpl := fluxApplication.NewFluxApplicationServiceImpl(sugaredLogger, helmAppReadServiceImpl, clusterServiceImpl, helmAppClientImpl, pumpImpl, pipelineRepositoryImpl, installedAppRepositoryImpl) k8sResourceHistoryRepositoryImpl := repository10.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) k8sResourceHistoryServiceImpl := kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl(k8sResourceHistoryRepositoryImpl, sugaredLogger, appRepositoryImpl, environmentRepositoryImpl) argoApplicationConfigServiceImpl := config3.NewArgoApplicationConfigServiceImpl(sugaredLogger, k8sServiceImpl, clusterRepositoryImpl) diff --git a/env_gen.json b/env_gen.json index 5b9da56042..632315e93e 100644 --- a/env_gen.json +++ b/env_gen.json @@ -1 +1 @@ -[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time to check the pipeline status ","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time for CD pipeline status","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"Timeout for CD pipeline to get healthy","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"This flag is used to fetch the deployment status of the application. It retrieves the status of deployments that occurred between 12 hours and 10 minutes prior to the current time. It fetches non-terminal statuses.","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"Context timeout for gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"Context timeout for no gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE","EnvType":"bool","EnvValue":"false","EnvDescription":"enable migration of external argocd application to devtron pipeline","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle.","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled then cd pipeline and helm apps will not need the deployment app type mandatorily. Couple this flag with HIDE_GITOPS_OR_HELM_OPTION (in Dashborad) and if gitops is configured and allowed for the env, pipeline/ helm app will gitops else no-gitops.","Example":"","Deprecated":"false"},{"Env":"MIGRATE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"migrate deployment config data from charts table to deployment_config table","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"Time to mark a pipeline degraded if not healthy in defined time","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"Count for devtron application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"Count for external helm application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"To set the history limit for the helm app being deployed through devtron","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_LINKED_HELM_APP","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOULD_CHECK_NAMESPACE_ON_CLONE","EnvType":"bool","EnvValue":"false","EnvDescription":"should we check if namespace exists or not while cloning app","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"use deployment config data from deployment_config table","Example":"","Deprecated":"true"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"If blob storage is being used of azure then pass the secret key to access the bucket","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"Account name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"Cache bucket name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"Log bucket for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"Azure gateway connection allows insecure if true","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"Sent to CI runner for blob","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"Used to store, download logs of ci workflow, artifact","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"GCP cred json for GCS blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"Blob storage provider name(AWS/GCP/Azure)","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"S3 access key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable buctet versioning for blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"S3 endpoint URL for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"To use insecure s3 endpoint","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Secret key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"Path for the buildx cache","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"To enable the k8s driver and pass args for k8s driver in buildx","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"provinance is set to true by default by docker. this will add some build related data in generated build manifest.it also adds some unknown:unknown key:value pair which may not be compatible by some container registries. with buildx k8s driver , provinenance=true is causing issue when push manifest to quay registry, so setting it to false","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"This is the time that the pods of ci/pre-cd/post-cd live after completion state.","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"Cache limit.","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for Pre/Post cd ","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"Toleration key for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"Toleration value for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for Pre/Post CD(AWF,System)","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"Service account to be used in Pre/Post CD pod","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for CI","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CI","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"Ignoring docker cache ","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for build logs","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Toleration key for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"Toleration value for CI","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"this is to control the bytes of inofrmation passed in a network packet in ci-runner. default is -1 (defaults to the underlying node mtu value)","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"this is to control the no of linked pipelines should be hanled in one go when a ci-success event of an parent ci is received","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"additional volume mount data for CI and JOB","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for CI(AWF,System)","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"Key location for artifacts being created","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"Bucket prefix for build logs","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"Bucket name for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"Build Cache bucket region","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"Bucket prefix for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"Namespace for devtron stack","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"Timeout for Pre/Post-Cd to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"To pass the ci-runner image","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"Default architecture for buildx","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"Path to store cache of docker build (/var/lib/docker-\u003e for legacy docker build, /var/lib/devtron-\u003e for buildx)","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable build context in Devtron.","Example":"","Deprecated":"false"},{"Env":"ENABLE_WORKFLOW_EXECUTION_STAGE","EnvType":"bool","EnvValue":"true","EnvDescription":"if enabled then we will display build stages separately for CI/Job/Pre-Post CD","Example":"true","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"name of the config map(contains bucket name, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"name of the secret(contains password, accessId,passKeys, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"This is an array of strings used when submitting a workflow for pre or post-CD execution. If the ","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"External CI API secret.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"External CI payload with project details.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"default is {{HOST_URL}}/orchestrator/webhook/ext-ci. It is used for external ci.","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"Ignore CM/CS in CI-pipeline as Job","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"push artifact(image) in ci retry count ","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"image retry interval takes value in seconds","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"Image-scanner micro-service URL","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"Max retry count for image-scanning","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay for the image-scaning to start","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"Used in case of argo workflow is enabled. If enabled logs push will be managed by us, else will be managed by argo workflow.","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time pre/post-cd-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time CI-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"Orchestrator micro-service URL ","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"Orchestrator token","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"Cache path for Pre CI tasks","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable showing the args passed for CI in build logs","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"To skip cache Push/Pull for ci job","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"By disabling this ECR repo won't get created if it's not available on ECR from build configuration","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"this is the time given to workflow pods to shutdown. (grace full termination time)","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 query for listing artifacts","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post cd","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post ci","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable buildx feature globally","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"when user do not pass the digest then this flag controls , finding the image digest using docker API or not. if set to true we get the digest from docker API call else use docker pull command. [logic in ci-runner]","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"It is used in case of Pre/ Post Cd with run in application mode. If enabled the node lebels are read from EXTERNAL_CD_NODE_LABEL_SELECTOR else from CD_NODE_LABEL_SELECTOR MODE: if the vale is DEV, it will read the local kube config file or else from the cluser location.","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"To use the same tag in container image as that of git tag","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"Workflow controller instance ID.","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"flag is used to configure how Docker caches are handled during a CI/CD ","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"-","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ADDITIONAL_NODE_GROUP_LABELS","EnvType":"","EnvValue":"","EnvDescription":"Add comma separated list of additional node group labels to default labels","Example":"karpenter.sh/nodepool,cloud.google.com/gke-nodepool","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"For the app sync image, this image will be used in app-manual sync job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"To pass the resource of app sync","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"Service account to be used in app sync Job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SHUTDOWN_WAIT_DURATION","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled all argocd application will have auto sync enabled","Example":"true","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"Delay on retrying the maifest commit the on gitops","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"4","EnvDescription":"Retry count for registering a GitOps repository to ArgoCD","Example":"3","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay (in Seconds) between the retries for registering a GitOps repository to ArgoCD","Example":"5","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async container image cache export","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"there is feature to get URL's of services/ingresses. so to extract those, we need to parse all the servcie and ingress objects of the application. this BATCH_SIZE flag controls the no of these objects get parsed in one go.","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"To set build cache mode to minimum in buildx","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host for the devtron stack","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"Port for pre/post-cd","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"Caching expiration time.","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"For image poll plugin","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"Cron schedule for CI pipeline status","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"Used in git cli opeartion timeout","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"Cron schedule for cluster status on resource browser","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"float64","EnvValue":"3600","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"Path to devtron-bom.yaml of devtron charts, used for module installation and devtron upgrade","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of dex secret","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Name of the Devtron Helm release. ","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of the Devtron Helm release","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"Devtron Installation type(EA/Full)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_MODULES_PATH","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"Path to devtron installer modules, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_RELEASE_PATH","EnvType":"string","EnvValue":"installer.release","EnvDescription":"Path to devtron installer release, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_OPERATOR_BASE_PATH","EnvType":"string","EnvValue":"","EnvDescription":"Base path for devtron operator, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"devtron operator version identifier in helm values yaml","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"dex client id ","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX CSTOREKEY.","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX JWT key. ","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"Dex redirect URL(http://argocd-dex-server.devtroncd:8080/callback)","Example":"","Deprecated":"false"},{"Env":"DEX_SCOPES","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"Dex secret","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"Dex service endpoint with dex path(http://argocd-dex-server.devtroncd:5556/dex)","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"Prefix for ECR repo to be created in does not exist","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of no-gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_NOTIFIER_V2","EnvType":"bool","EnvValue":"false","EnvDescription":"enable notifier v2","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"ephemeral containers support version regex that is compared with k8sServerVersion","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"Notifier service url","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"checks for any nil pointer in wire.go","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"To expose CI metrics","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"restart workload retrieval batch size ","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"restart workload retrieval pool size","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"By enabling this no one can disable image scaning on ci-pipeline from UI","Example":"","Deprecated":"false"},{"Env":"GITHUB_ORG_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_USERNAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for Gitops repo being creation for argocd application","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace for grafana","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"Org ID for grafana for application metrics","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"Password for grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"Port for grafana micro-service","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"Username for grafana ","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"Flag to hide the hard delete option in the image tagging service","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"flag for ignoring auth check in autocomplete apis.","Example":"","Deprecated":"false"},{"Env":"INSTALLED_MODULES","EnvType":"","EnvValue":"","EnvDescription":"List of installed modules given in helm values/yaml are written in cm and used by devtron to know which modules are given","Example":"security.trivy,security.clair","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"namespace where Custom Resource Definitions get installed","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"Devtron installer CRD group name, partially deprecated.","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"Devtron installer CRD resource name, partially deprecated","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"version of the CRDs. default is v1alpha1","Example":"","Deprecated":"false"},{"Env":"IS_AIR_GAP_ENVIRONMENT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"JWT expiration time.","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Lens microservice timeout.","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"Lens micro-service URL","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"Enables a different logger theme.","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"max no of cluster terminal pods can be created by an user","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"Modules list and meta info will be fetched from this server, that is central api server of devtron.","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"notification medium","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"Opentelemetry URL ","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"App manual sync job parallel tag processing count.","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"Handles image retrieval from a container repository and triggers subsequent CI processes upon detecting new images.Current default plugin name: Pull Images from Container Repository.","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"Add additional propagate labels like api.devtron.ai/appName, api.devtron.ai/envName, api.devtron.ai/project along with the user defined ones.","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"Proxy configuration for micro-service to be accessible on orhcestrator ingress","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"To restrict the cluster terminal from user having non-super admin acceess","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable scoped variable option","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"Its a scope format for varialbe name.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"This describe should we handle primitives or not in scoped variable template parsing.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"Regex for scoped variable name that must passed this regex.","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"The server closes a session when a client receiving connection have not been seen for a while.This delay is configured by this setting. By default the session is closed when a receiving connection wasn't seen for 5 seconds.","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active and send a heartbeat packet once in a while. This setting controls how often this is done. By default a heartbeat packet is sent every 25 seconds.","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"Scoped variable prefix, variable name must have this prefix.","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"Cluster terminal default namespace","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"Timeout for cluster terminal to be inactive","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"this is the time interval at which the status of the cluster terminal pod","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"Timeout for Failed CI build ","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"timeout to compute the urls from services and ingress objects of an application","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 API for listing artifacts in Listing the images in pipeline","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable git cli","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 for RBAC creation","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"This is used to control caching of all the scope variables defined in the system.","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"Scoped variable expression regex","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"If you want to continue using jenkins for CI then please provide this for authentication of requests","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"Name of the argocd CM","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"To pass the argocd namespace","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"Password for the Argocd (deprecated)","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"User name for argocd","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"devtron-gitops-secret","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"this holds the list of k8s resource names which support replicas key. this list used in hibernate/un hibernate process","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"this the batch size to control no of above resources can be parsed in one go to determine hibernate status","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Dashboard micro-service URL","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Dashboard micro-service namespace","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"Port for dashboard micro-service","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"Protocol to connect with git-sensor micro-service","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"pick_first\"}","EnvDescription":"git-sensor grpc service config","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Timeout for getting response from the git-sensor","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"git-sensor micro-service url ","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"Kubelink micro-service url ","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"round_robin\"}","EnvDescription":"kubelink grpc service config","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"Database for casbin","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"Time out for read operation in postgres","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"Time out for write operation in postgres","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable enforcer cache.","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"Expiration time (in seconds) for enforcer cache. ","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"Maximum batch size for the enforcer.","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable casbin V2 API","Example":"","Deprecated":"false"}]}] \ No newline at end of file +[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"CD_FLUX_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time to check the pipeline status for flux cd pipeline","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time to check the pipeline status ","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time for CD pipeline status","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"Timeout for CD pipeline to get healthy","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"This flag is used to fetch the deployment status of the application. It retrieves the status of deployments that occurred between 12 hours and 10 minutes prior to the current time. It fetches non-terminal statuses.","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"Context timeout for gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"Context timeout for no gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE","EnvType":"bool","EnvValue":"false","EnvDescription":"enable migration of external argocd application to devtron pipeline","Example":"","Deprecated":"false"},{"Env":"FEATURE_MIGRATE_FLUX_APPLICATION_ENABLE","EnvType":"bool","EnvValue":"false","EnvDescription":"enable flux application services","Example":"","Deprecated":"false"},{"Env":"FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"eligible time for checking flux app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle.","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle.","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled then cd pipeline and helm apps will not need the deployment app type mandatorily. Couple this flag with HIDE_GITOPS_OR_HELM_OPTION (in Dashborad) and if gitops is configured and allowed for the env, pipeline/ helm app will gitops else no-gitops.","Example":"","Deprecated":"false"},{"Env":"MIGRATE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"migrate deployment config data from charts table to deployment_config table","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"Time to mark a pipeline degraded if not healthy in defined time","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"Count for devtron application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"Count for external helm application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"To set the history limit for the helm app being deployed through devtron","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_LINKED_HELM_APP","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOULD_CHECK_NAMESPACE_ON_CLONE","EnvType":"bool","EnvValue":"false","EnvDescription":"should we check if namespace exists or not while cloning app","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"use deployment config data from deployment_config table","Example":"","Deprecated":"true"},{"Env":"VALIDATE_EXT_APP_CHART_TYPE","EnvType":"bool","EnvValue":"false","EnvDescription":"validate external flux app chart","Example":"","Deprecated":"false"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"If blob storage is being used of azure then pass the secret key to access the bucket","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"Account name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"Cache bucket name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"Log bucket for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"Azure gateway connection allows insecure if true","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"Sent to CI runner for blob","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"Used to store, download logs of ci workflow, artifact","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"GCP cred json for GCS blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"Blob storage provider name(AWS/GCP/Azure)","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"S3 access key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable buctet versioning for blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"S3 endpoint URL for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"To use insecure s3 endpoint","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Secret key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"Path for the buildx cache","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"To enable the k8s driver and pass args for k8s driver in buildx","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"provinance is set to true by default by docker. this will add some build related data in generated build manifest.it also adds some unknown:unknown key:value pair which may not be compatible by some container registries. with buildx k8s driver , provinenance=true is causing issue when push manifest to quay registry, so setting it to false","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"This is the time that the pods of ci/pre-cd/post-cd live after completion state.","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"Cache limit.","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for Pre/Post cd ","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"Toleration key for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"Toleration value for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for Pre/Post CD(AWF,System)","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"Service account to be used in Pre/Post CD pod","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for CI","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CI","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"Ignoring docker cache ","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for build logs","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Toleration key for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"Toleration value for CI","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"this is to control the bytes of inofrmation passed in a network packet in ci-runner. default is -1 (defaults to the underlying node mtu value)","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"this is to control the no of linked pipelines should be hanled in one go when a ci-success event of an parent ci is received","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"additional volume mount data for CI and JOB","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for CI(AWF,System)","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"Key location for artifacts being created","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"Bucket prefix for build logs","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"Bucket name for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"Build Cache bucket region","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"Bucket prefix for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"Namespace for devtron stack","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"Timeout for Pre/Post-Cd to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"To pass the ci-runner image","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"Default architecture for buildx","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"Path to store cache of docker build (/var/lib/docker-\u003e for legacy docker build, /var/lib/devtron-\u003e for buildx)","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable build context in Devtron.","Example":"","Deprecated":"false"},{"Env":"ENABLE_WORKFLOW_EXECUTION_STAGE","EnvType":"bool","EnvValue":"true","EnvDescription":"if enabled then we will display build stages separately for CI/Job/Pre-Post CD","Example":"true","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"name of the config map(contains bucket name, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"name of the secret(contains password, accessId,passKeys, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"This is an array of strings used when submitting a workflow for pre or post-CD execution. If the ","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"External CI API secret.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"External CI payload with project details.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"default is {{HOST_URL}}/orchestrator/webhook/ext-ci. It is used for external ci.","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"Ignore CM/CS in CI-pipeline as Job","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"push artifact(image) in ci retry count ","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"image retry interval takes value in seconds","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"Image-scanner micro-service URL","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"Max retry count for image-scanning","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay for the image-scaning to start","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"Used in case of argo workflow is enabled. If enabled logs push will be managed by us, else will be managed by argo workflow.","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time pre/post-cd-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time CI-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"Orchestrator micro-service URL ","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"Orchestrator token","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"Cache path for Pre CI tasks","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable showing the args passed for CI in build logs","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"To skip cache Push/Pull for ci job","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"By disabling this ECR repo won't get created if it's not available on ECR from build configuration","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"this is the time given to workflow pods to shutdown. (grace full termination time)","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 query for listing artifacts","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post cd","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post ci","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable buildx feature globally","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"when user do not pass the digest then this flag controls , finding the image digest using docker API or not. if set to true we get the digest from docker API call else use docker pull command. [logic in ci-runner]","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"It is used in case of Pre/ Post Cd with run in application mode. If enabled the node lebels are read from EXTERNAL_CD_NODE_LABEL_SELECTOR else from CD_NODE_LABEL_SELECTOR MODE: if the vale is DEV, it will read the local kube config file or else from the cluser location.","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"To use the same tag in container image as that of git tag","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"Workflow controller instance ID.","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"flag is used to configure how Docker caches are handled during a CI/CD ","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"-","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ADDITIONAL_NODE_GROUP_LABELS","EnvType":"","EnvValue":"","EnvDescription":"Add comma separated list of additional node group labels to default labels","Example":"karpenter.sh/nodepool,cloud.google.com/gke-nodepool","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"For the app sync image, this image will be used in app-manual sync job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"To pass the resource of app sync","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"Service account to be used in app sync Job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SHUTDOWN_WAIT_DURATION","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled all argocd application will have auto sync enabled","Example":"true","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"Delay on retrying the maifest commit the on gitops","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"4","EnvDescription":"Retry count for registering a GitOps repository to ArgoCD","Example":"3","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay (in Seconds) between the retries for registering a GitOps repository to ArgoCD","Example":"5","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async container image cache export","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"there is feature to get URL's of services/ingresses. so to extract those, we need to parse all the servcie and ingress objects of the application. this BATCH_SIZE flag controls the no of these objects get parsed in one go.","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"To set build cache mode to minimum in buildx","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host for the devtron stack","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"Port for pre/post-cd","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"Caching expiration time.","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"For image poll plugin","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"Cron schedule for CI pipeline status","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"Used in git cli opeartion timeout","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"Cron schedule for cluster status on resource browser","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"float64","EnvValue":"3600","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"Path to devtron-bom.yaml of devtron charts, used for module installation and devtron upgrade","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of dex secret","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Name of the Devtron Helm release. ","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of the Devtron Helm release","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"Devtron Installation type(EA/Full)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_MODULES_PATH","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"Path to devtron installer modules, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_RELEASE_PATH","EnvType":"string","EnvValue":"installer.release","EnvDescription":"Path to devtron installer release, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_OPERATOR_BASE_PATH","EnvType":"string","EnvValue":"","EnvDescription":"Base path for devtron operator, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"devtron operator version identifier in helm values yaml","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"dex client id ","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX CSTOREKEY.","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX JWT key. ","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"Dex redirect URL(http://argocd-dex-server.devtroncd:8080/callback)","Example":"","Deprecated":"false"},{"Env":"DEX_SCOPES","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"Dex secret","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"Dex service endpoint with dex path(http://argocd-dex-server.devtroncd:5556/dex)","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"Prefix for ECR repo to be created in does not exist","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of no-gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_NOTIFIER_V2","EnvType":"bool","EnvValue":"false","EnvDescription":"enable notifier v2","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"ephemeral containers support version regex that is compared with k8sServerVersion","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"Notifier service url","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"checks for any nil pointer in wire.go","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"To expose CI metrics","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"restart workload retrieval batch size ","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"restart workload retrieval pool size","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"By enabling this no one can disable image scaning on ci-pipeline from UI","Example":"","Deprecated":"false"},{"Env":"GITHUB_ORG_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_USERNAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for Gitops repo being creation for argocd application","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace for grafana","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"Org ID for grafana for application metrics","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"Password for grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"Port for grafana micro-service","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"Username for grafana ","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"Flag to hide the hard delete option in the image tagging service","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"flag for ignoring auth check in autocomplete apis.","Example":"","Deprecated":"false"},{"Env":"INSTALLED_MODULES","EnvType":"","EnvValue":"","EnvDescription":"List of installed modules given in helm values/yaml are written in cm and used by devtron to know which modules are given","Example":"security.trivy,security.clair","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"namespace where Custom Resource Definitions get installed","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"Devtron installer CRD group name, partially deprecated.","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"Devtron installer CRD resource name, partially deprecated","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"version of the CRDs. default is v1alpha1","Example":"","Deprecated":"false"},{"Env":"IS_AIR_GAP_ENVIRONMENT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"JWT expiration time.","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Lens microservice timeout.","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"Lens micro-service URL","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"Enables a different logger theme.","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"max no of cluster terminal pods can be created by an user","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"Modules list and meta info will be fetched from this server, that is central api server of devtron.","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"notification medium","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"Opentelemetry URL ","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"App manual sync job parallel tag processing count.","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"Handles image retrieval from a container repository and triggers subsequent CI processes upon detecting new images.Current default plugin name: Pull Images from Container Repository.","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"Add additional propagate labels like api.devtron.ai/appName, api.devtron.ai/envName, api.devtron.ai/project along with the user defined ones.","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"Proxy configuration for micro-service to be accessible on orhcestrator ingress","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"To restrict the cluster terminal from user having non-super admin acceess","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable scoped variable option","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"Its a scope format for varialbe name.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"This describe should we handle primitives or not in scoped variable template parsing.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"Regex for scoped variable name that must passed this regex.","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"The server closes a session when a client receiving connection have not been seen for a while.This delay is configured by this setting. By default the session is closed when a receiving connection wasn't seen for 5 seconds.","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active and send a heartbeat packet once in a while. This setting controls how often this is done. By default a heartbeat packet is sent every 25 seconds.","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"Scoped variable prefix, variable name must have this prefix.","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"Cluster terminal default namespace","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"Timeout for cluster terminal to be inactive","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"this is the time interval at which the status of the cluster terminal pod","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"Timeout for Failed CI build ","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"timeout to compute the urls from services and ingress objects of an application","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 API for listing artifacts in Listing the images in pipeline","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable git cli","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 for RBAC creation","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"This is used to control caching of all the scope variables defined in the system.","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"Scoped variable expression regex","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"If you want to continue using jenkins for CI then please provide this for authentication of requests","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"Name of the argocd CM","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"To pass the argocd namespace","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"Password for the Argocd (deprecated)","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"User name for argocd","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"devtron-gitops-secret","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"this holds the list of k8s resource names which support replicas key. this list used in hibernate/un hibernate process","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"this the batch size to control no of above resources can be parsed in one go to determine hibernate status","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Dashboard micro-service URL","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Dashboard micro-service namespace","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"Port for dashboard micro-service","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"Protocol to connect with git-sensor micro-service","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"pick_first\"}","EnvDescription":"git-sensor grpc service config","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Timeout for getting response from the git-sensor","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"git-sensor micro-service url ","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"Kubelink micro-service url ","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"round_robin\"}","EnvDescription":"kubelink grpc service config","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"Database for casbin","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"Time out for read operation in postgres","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"Time out for write operation in postgres","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable enforcer cache.","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"Expiration time (in seconds) for enforcer cache. ","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"Maximum batch size for the enforcer.","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable casbin V2 API","Example":"","Deprecated":"false"}]}] \ No newline at end of file diff --git a/env_gen.md b/env_gen.md index 3f65efa0c4..9b4ba07db4 100644 --- a/env_gen.md +++ b/env_gen.md @@ -4,6 +4,7 @@ | Key | Type | Default Value | Description | Example | Deprecated | |-------|----------|-------------------|-------------------|-----------------------|------------------| | ARGO_APP_MANUAL_SYNC_TIME | int |3 | retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins) | | false | + | CD_FLUX_PIPELINE_STATUS_CRON_TIME | string |*/2 * * * * | Cron time to check the pipeline status for flux cd pipeline | | false | | CD_HELM_PIPELINE_STATUS_CRON_TIME | string |*/2 * * * * | Cron time to check the pipeline status | | false | | CD_PIPELINE_STATUS_CRON_TIME | string |*/2 * * * * | Cron time for CD pipeline status | | false | | CD_PIPELINE_STATUS_TIMEOUT_DURATION | string |20 | Timeout for CD pipeline to get healthy | | false | @@ -12,6 +13,8 @@ | DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT | int |6 | Context timeout for no gitops concurrent async deployments | | false | | EXPOSE_CD_METRICS | bool |false | | | false | | FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE | bool |false | enable migration of external argocd application to devtron pipeline | | false | + | FEATURE_MIGRATE_FLUX_APPLICATION_ENABLE | bool |false | enable flux application services | | false | + | FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME | string |120 | eligible time for checking flux app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle. | | false | | HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME | string |120 | eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle. | | false | | IS_INTERNAL_USE | bool |true | If enabled then cd pipeline and helm apps will not need the deployment app type mandatorily. Couple this flag with HIDE_GITOPS_OR_HELM_OPTION (in Dashborad) and if gitops is configured and allowed for the env, pipeline/ helm app will gitops else no-gitops. | | false | | MIGRATE_DEPLOYMENT_CONFIG_DATA | bool |false | migrate deployment config data from charts table to deployment_config table | | false | @@ -23,6 +26,7 @@ | RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS | bool |false | | | false | | SHOULD_CHECK_NAMESPACE_ON_CLONE | bool |false | should we check if namespace exists or not while cloning app | | false | | USE_DEPLOYMENT_CONFIG_DATA | bool |false | use deployment config data from deployment_config table | | true | + | VALIDATE_EXT_APP_CHART_TYPE | bool |false | validate external flux app chart | | false | ## CI_RUNNER Related Environment Variables diff --git a/go.mod b/go.mod index 26f10cea11..6eaa39d610 100644 --- a/go.mod +++ b/go.mod @@ -262,7 +262,13 @@ require ( xorm.io/xorm v1.0.3 // indirect ) -require github.com/docker/distribution v2.8.2+incompatible +require ( + github.com/docker/distribution v2.8.2+incompatible + github.com/fluxcd/helm-controller/api v0.0.0-00010101000000-000000000000 + github.com/fluxcd/pkg/apis/meta v1.10.0 + github.com/fluxcd/source-controller/api v0.0.0-00010101000000-000000000000 + sigs.k8s.io/controller-runtime v0.20.1 +) require ( cel.dev/expr v0.24.0 // indirect @@ -297,6 +303,9 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/fluxcd/pkg/apis/acl v0.6.0 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/google/go-github/v66 v66.0.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -315,7 +324,10 @@ 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-20250624130631-fd0c2f8fd85c - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250624130631-fd0c2f8fd85c + github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250702065121-52f00968ef48 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250702065121-52f00968ef48 + github.com/fluxcd/helm-controller/api => github.com/fluxcd/helm-controller/api v1.2.0 + github.com/fluxcd/pkg/apis/meta => github.com/fluxcd/pkg/apis/meta v1.10.0 + github.com/fluxcd/source-controller/api => github.com/fluxcd/source-controller/api v1.5.0 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 ) diff --git a/go.sum b/go.sum index 35ba5fb087..a034e4f82e 100644 --- a/go.sum +++ b/go.sum @@ -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-20250624130631-fd0c2f8fd85c h1:v+laregD1jjF1c7DUs9Aoo1alEOaOSSidgSFDAWv4uM= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250624130631-fd0c2f8fd85c/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250624130631-fd0c2f8fd85c h1:Lc6JZNufAA1gKTXfhJiEZ6BLPC9mHa89dKw0m6FmPpo= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250624130631-fd0c2f8fd85c/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250702065121-52f00968ef48 h1:BFnPuug11fEeANLCHBUz4uVtZMjQv7mMvrif4u96DSs= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250702065121-52f00968ef48/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250702065121-52f00968ef48 h1:grCVxkCkQLAsmHQNXMi81LwTuOVrnxU+luQyM9pJ9lw= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250702065121-52f00968ef48/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= @@ -284,6 +284,8 @@ github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2T github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= @@ -293,6 +295,16 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fluxcd/helm-controller/api v1.2.0 h1:cjpHBpJQv+8WyYQNwoujoNMFOQx2llllv4peLIiWyxU= +github.com/fluxcd/helm-controller/api v1.2.0/go.mod h1:3NZts/4n6PpD4sONSDJWXPQzfPpBk3YpknIFA6rLW3I= +github.com/fluxcd/pkg/apis/acl v0.6.0 h1:rllf5uQLzTow81ZCslkQ6LPpDNqVQr6/fWaNksdUEtc= +github.com/fluxcd/pkg/apis/acl v0.6.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs= +github.com/fluxcd/pkg/apis/kustomize v1.9.0 h1:SJpT1CK58AnTvCpDKeGfMNA0Xud/4VReZNvPe8XkTxo= +github.com/fluxcd/pkg/apis/kustomize v1.9.0/go.mod h1:AZl2GU03oPVue6SUivdiIYd/3mvF94j7t1G2JO26d4s= +github.com/fluxcd/pkg/apis/meta v1.10.0 h1:rqbAuyl5ug7A5jjRf/rNwBXmNl6tJ9wG2iIsriwnQUk= +github.com/fluxcd/pkg/apis/meta v1.10.0/go.mod h1:n7NstXHDaleAUMajcXTVkhz0MYkvEXy1C/eLI/t1xoI= +github.com/fluxcd/source-controller/api v1.5.0 h1:caSR+u/r2Vh0jq/0pNR0r1zLxyvgatWuGSV2mxgTB/I= +github.com/fluxcd/source-controller/api v1.5.0/go.mod h1:OZPuHMlLH2E2mnj6Q5DLkWfUOmJ20zA1LIvUVfNsYl8= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -337,6 +349,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= @@ -1233,6 +1247,8 @@ mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0= mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY= oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= +sigs.k8s.io/controller-runtime v0.20.1 h1:JbGMAG/X94NeM3xvjenVUaBjy6Ui4Ogd/J5ZtjZnHaE= +sigs.k8s.io/controller-runtime v0.20.1/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ= diff --git a/internal/sql/repository/chartConfig/PipelineOverrideRepository.go b/internal/sql/repository/chartConfig/PipelineOverrideRepository.go index db8476d913..0cac9230f5 100644 --- a/internal/sql/repository/chartConfig/PipelineOverrideRepository.go +++ b/internal/sql/repository/chartConfig/PipelineOverrideRepository.go @@ -23,6 +23,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/sql" + util2 "github.com/devtron-labs/devtron/util" "github.com/go-pg/pg" "github.com/go-pg/pg/orm" "github.com/juju/errors" @@ -68,6 +69,7 @@ type PipelineOverrideRepository interface { GetByPipelineIdAndReleaseNo(pipelineId, releaseNo int) (pipelineOverrides []*PipelineOverride, err error) GetAllRelease(appId, environmentId int) (pipelineOverrides []*PipelineOverride, err error) FindByPipelineTriggerGitHash(gitHash string) (pipelineOverride *PipelineOverride, err error) + FindByPipelineLikeTriggerGitHash(gitHash string) (pipelineOverride *PipelineOverride, err error) GetLatestRelease(appId, environmentId int) (pipelineOverrides *PipelineOverride, err error) GetLatestReleaseForAppIds(appIds []int, envId int) (pipelineOverrides []*PipelineConfigOverrideMetadata, err error) FindById(id int) (*PipelineOverride, error) @@ -288,6 +290,16 @@ func (impl PipelineOverrideRepositoryImpl) FindByPipelineTriggerGitHash(gitHash return pipelineOverride, err } +func (impl PipelineOverrideRepositoryImpl) FindByPipelineLikeTriggerGitHash(gitHash string) (pipelineOverride *PipelineOverride, err error) { + pipelineOverride = &PipelineOverride{} + err = impl.dbConnection.Model(pipelineOverride). + Column("pipeline_override.*", "Pipeline", "CiArtifact"). + Where("pipeline_override.git_hash LIKE ?", util2.GetLIKEClauseQueryParamEnd(gitHash)). + Order("id DESC").Limit(1). + Select() + return pipelineOverride, err +} + func (impl PipelineOverrideRepositoryImpl) FindById(id int) (*PipelineOverride, error) { var pipelineOverride PipelineOverride err := impl.dbConnection.Model(&pipelineOverride). diff --git a/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go b/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go index 4df9b57ab0..6b6001a8dd 100644 --- a/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go +++ b/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go @@ -23,7 +23,6 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" - "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/constants" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" @@ -75,7 +74,7 @@ type CdWorkflowRepository interface { ExistsByStatus(status string) (bool, error) FetchEnvAllCdStagesLatestEntityStatus(wfrIds []int, envID int) ([]*CdWorkflowRunner, error) FetchArtifactsByCdPipelineId(pipelineId int, runnerType apiBean.WorkflowType, offset, limit int, searchString string) ([]CdWorkflowRunner, error) - GetLatestTriggersOfHelmPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours int) ([]*CdWorkflowRunner, error) + GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours int, deploymentAppType string) ([]*CdWorkflowRunner, error) FindLatestRunnerByPipelineIdsAndRunnerType(ctx context.Context, pipelineIds []int, runnerType apiBean.WorkflowType) ([]CdWorkflowRunner, error) MigrateIsArtifactUploaded(wfrId int, isArtifactUploaded bool) @@ -675,7 +674,7 @@ func (impl *CdWorkflowRepositoryImpl) FetchArtifactsByCdPipelineIdV2(listingFilt return wfrList, totalCount, nil } -func (impl *CdWorkflowRepositoryImpl) GetLatestTriggersOfHelmPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours int) ([]*CdWorkflowRunner, error) { +func (impl *CdWorkflowRepositoryImpl) GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours int, deploymentAppType string) ([]*CdWorkflowRunner, error) { var wfrList []*CdWorkflowRunner excludedStatusList := cdWorkflow.WfrTerminalStatusList excludedStatusList = append(excludedStatusList, cdWorkflow.WorkflowInitiated, cdWorkflow.WorkflowInQueue, cdWorkflow.WorkflowStarting) @@ -692,13 +691,13 @@ func (impl *CdWorkflowRepositoryImpl) GetLatestTriggersOfHelmPipelinesStuckInNon " AND cd_workflow_runner.status != ?"+ " GROUP BY cd_workflow.pipeline_id"+ " ORDER BY cd_workflow.pipeline_id desc)", apiBean.CD_WORKFLOW_TYPE_DEPLOY, cdWorkflow.WorkflowInQueue). - Where("(cd_workflow__pipeline.deployment_app_type=? or dc.deployment_app_type=?)", util.PIPELINE_DEPLOYMENT_TYPE_HELM, util.PIPELINE_DEPLOYMENT_TYPE_HELM). + Where("(cd_workflow__pipeline.deployment_app_type=? or dc.deployment_app_type=?)", deploymentAppType, deploymentAppType). Where("cd_workflow_runner.started_on > NOW() - INTERVAL '? hours'", getPipelineDeployedWithinHours). Where("cd_workflow__pipeline.deleted=?", false). Order("cd_workflow_runner.id DESC"). Select() if err != nil { - impl.logger.Errorw("error,GetLatestTriggersOfHelmPipelinesStuckInNonTerminalStatuses ", "err", err) + impl.logger.Errorw("error,GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses ", "err", err) return nil, err } return wfrList, err diff --git a/internal/sql/repository/pipelineConfig/mocks/CdWorkflowRepository.go b/internal/sql/repository/pipelineConfig/mocks/CdWorkflowRepository.go index 23822b7d20..e94e2cddbd 100644 --- a/internal/sql/repository/pipelineConfig/mocks/CdWorkflowRepository.go +++ b/internal/sql/repository/pipelineConfig/mocks/CdWorkflowRepository.go @@ -806,7 +806,7 @@ func (_m *CdWorkflowRepository) GetLatestTriggersOfHelmPipelinesStuckInNonTermin ret := _m.Called(getPipelineDeployedWithinHours) if len(ret) == 0 { - panic("no return value specified for GetLatestTriggersOfHelmPipelinesStuckInNonTerminalStatuses") + panic("no return value specified for GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses") } var r0 []*pipelineConfig.CdWorkflowRunner diff --git a/internal/util/ChartTemplateService.go b/internal/util/ChartTemplateService.go index 0f72eb550f..b03c86dfa5 100644 --- a/internal/util/ChartTemplateService.go +++ b/internal/util/ChartTemplateService.go @@ -40,6 +40,7 @@ import ( const ( PIPELINE_DEPLOYMENT_TYPE_ACD = "argo_cd" + PIPELINE_DEPLOYMENT_TYPE_FLUX = "flux_cd" PIPELINE_DEPLOYMENT_TYPE_HELM = "helm" PIPELINE_DEPLOYMENT_TYPE_MANIFEST_DOWNLOAD = "manifest_download" PIPELINE_DEPLOYMENT_TYPE_MANIFEST_PUSH = "manifest_push" @@ -450,6 +451,10 @@ func IsAcdApp(deploymentAppType string) bool { return deploymentAppType == PIPELINE_DEPLOYMENT_TYPE_ACD } +func IsFluxApp(deploymentAppType string) bool { + return deploymentAppType == PIPELINE_DEPLOYMENT_TYPE_FLUX +} + // TODO refactoring: This feature belongs to enterprise only func IsManifestDownload(deploymentAppType string) bool { return deploymentAppType == PIPELINE_DEPLOYMENT_TYPE_MANIFEST_DOWNLOAD diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go index 51969779f6..e44f0db22f 100644 --- a/pkg/app/AppService.go +++ b/pkg/app/AppService.go @@ -74,14 +74,16 @@ import ( type AppServiceConfig struct { CdPipelineStatusCronTime string `env:"CD_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *" description:"Cron time for CD pipeline status"` CdHelmPipelineStatusCronTime string `env:"CD_HELM_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *" description:"Cron time to check the pipeline status "` + CdFluxPipelineStatusCronTime string `env:"CD_FLUX_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *" description:"Cron time to check the pipeline status for flux cd pipeline"` CdPipelineStatusTimeoutDuration string `env:"CD_PIPELINE_STATUS_TIMEOUT_DURATION" envDefault:"20" description:"Timeout for CD pipeline to get healthy" ` // in minutes PipelineDegradedTime string `env:"PIPELINE_DEGRADED_TIME" envDefault:"10" description:"Time to mark a pipeline degraded if not healthy in defined time"` // in minutes GetPipelineDeployedWithinHours int `env:"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS" envDefault:"12" description:"This flag is used to fetch the deployment status of the application. It retrieves the status of deployments that occurred between 12 hours and 10 minutes prior to the current time. It fetches non-terminal statuses."` // in hours HelmPipelineStatusCheckEligibleTime string `env:"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME" envDefault:"120" description:"eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle."` // in seconds ExposeCDMetrics bool `env:"EXPOSE_CD_METRICS" envDefault:"false"` - DevtronChartHelmInstallRequestTimeout int `env:"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT" envDefault:"6" description:"Context timeout for no gitops concurrent async deployments"` // in minutes - DevtronChartArgoCdInstallRequestTimeout int `env:"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT" envDefault:"1" description:"Context timeout for gitops concurrent async deployments"` // in minutes - ArgoCdManualSyncCronPipelineDeployedBefore int `env:"ARGO_APP_MANUAL_SYNC_TIME" envDefault:"3" description:"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)"` // in minutes + DevtronChartHelmInstallRequestTimeout int `env:"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT" envDefault:"6" description:"Context timeout for no gitops concurrent async deployments"` // in minutes + DevtronChartArgoCdInstallRequestTimeout int `env:"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT" envDefault:"1" description:"Context timeout for gitops concurrent async deployments"` // in minutes + ArgoCdManualSyncCronPipelineDeployedBefore int `env:"ARGO_APP_MANUAL_SYNC_TIME" envDefault:"3" description:"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)"` // in minutes + FluxCDPipelineStatusCheckEligibleTime string `env:"FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME" envDefault:"120" description:"eligible time for checking flux app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. FLUX_CD_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle."` // in seconds } func GetAppServiceConfig() (*AppServiceConfig, error) { diff --git a/pkg/app/bean/ManifestPushTemplate.go b/pkg/app/bean/ManifestPushTemplate.go index 3439adafb1..11faaf477a 100644 --- a/pkg/app/bean/ManifestPushTemplate.go +++ b/pkg/app/bean/ManifestPushTemplate.go @@ -43,7 +43,7 @@ type ManifestPushTemplate struct { BuiltChartPath string BuiltChartBytes *[]byte MergedValues string - IsArgoSyncSupported bool + ArgoSyncNeeded bool } type ManifestPushResponse struct { diff --git a/pkg/app/status/PipelineStatusTimelineService.go b/pkg/app/status/PipelineStatusTimelineService.go index 35e4c99f81..0d30b59f51 100644 --- a/pkg/app/status/PipelineStatusTimelineService.go +++ b/pkg/app/status/PipelineStatusTimelineService.go @@ -84,6 +84,7 @@ func NewPipelineStatusTimelineServiceImpl(logger *zap.SugaredLogger, } type PipelineTimelineDetailDto struct { + DeploymentAppType string `json:"deploymentAppType"` DeploymentStartedOn time.Time `json:"deploymentStartedOn"` DeploymentFinishedOn time.Time `json:"deploymentFinishedOn"` TriggeredBy string `json:"triggeredBy"` @@ -102,6 +103,7 @@ type PipelineStatusTimelineDto struct { StatusDetail string `json:"statusDetail"` StatusTime time.Time `json:"statusTime"` ResourceDetails []*SyncStageResourceDetailDto `json:"resourceDetails,omitempty"` + DeploymentAppType string `json:"deploymentAppType"` } func (impl *PipelineStatusTimelineServiceImpl) SaveTimeline(timeline *pipelineConfig.PipelineStatusTimeline, tx *pg.Tx) error { @@ -240,7 +242,7 @@ func (impl *PipelineStatusTimelineServiceImpl) FetchTimelines(appId, envId, wfrI var timelineDtos []*PipelineStatusTimelineDto var statusLastFetchedAt time.Time var statusFetchCount int - if util.IsAcdApp(deploymentAppType) && showTimeline { + if (util.IsAcdApp(deploymentAppType) || util.IsFluxApp(deploymentAppType)) && showTimeline { timelines, err := impl.pipelineStatusTimelineRepository.FetchTimelinesByWfrId(wfrId) if err != nil { impl.logger.Errorw("error in getting timelines by wfrId", "err", err, "wfrId", wfrId) @@ -253,10 +255,13 @@ func (impl *PipelineStatusTimelineServiceImpl) FetchTimelines(appId, envId, wfrI if len(cdWorkflowRunnerIds) == 0 { return nil, err } - timelineResourceMap, err := impl.pipelineStatusTimelineResourcesService.GetTimelineResourcesForATimeline(cdWorkflowRunnerIds) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in getting timeline resources details", "err", err) - return nil, err + timelineResourceMap := make(map[int][]*SyncStageResourceDetailDto) + if util.IsAcdApp(deploymentAppType) { + timelineResourceMap, err = impl.pipelineStatusTimelineResourcesService.GetTimelineResourcesForATimeline(cdWorkflowRunnerIds) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in getting timeline resources details", "err", err) + return nil, err + } } for _, timeline := range timelines { timelineResourceDetails := make([]*SyncStageResourceDetailDto, 0) @@ -279,6 +284,7 @@ func (impl *PipelineStatusTimelineServiceImpl) FetchTimelines(appId, envId, wfrI } } timelineDetail := &PipelineTimelineDetailDto{ + DeploymentAppType: deploymentAppType, TriggeredBy: triggeredByUserEmailId, DeploymentStartedOn: deploymentStartedOn, DeploymentFinishedOn: deploymentFinishedOn, @@ -380,6 +386,7 @@ func (impl *PipelineStatusTimelineServiceImpl) FetchTimelinesForAppStore(install StatusFetchCount: statusFetchCount, WfrStatus: installedAppVersionHistoryStatus, DeploymentAppDeleteRequest: false, + DeploymentAppType: deploymentAppType, } return timelineDetail, nil } diff --git a/pkg/appStore/adapter/Adapter.go b/pkg/appStore/adapter/Adapter.go index 9808d43a72..83ed138e79 100644 --- a/pkg/appStore/adapter/Adapter.go +++ b/pkg/appStore/adapter/Adapter.go @@ -102,14 +102,22 @@ func NewInstalledAppDeploymentAction(deploymentAppType string) *appStoreBean.Ins installedAppDeploymentAction.PerformGitOps = true installedAppDeploymentAction.PerformACDDeployment = true installedAppDeploymentAction.PerformHelmDeployment = false + installedAppDeploymentAction.PerformFluxDeployment = false + case util.PIPELINE_DEPLOYMENT_TYPE_FLUX: + installedAppDeploymentAction.PerformGitOps = true + installedAppDeploymentAction.PerformFluxDeployment = true + installedAppDeploymentAction.PerformACDDeployment = false + installedAppDeploymentAction.PerformHelmDeployment = false case util.PIPELINE_DEPLOYMENT_TYPE_HELM: installedAppDeploymentAction.PerformGitOps = false installedAppDeploymentAction.PerformACDDeployment = false installedAppDeploymentAction.PerformHelmDeployment = true + installedAppDeploymentAction.PerformFluxDeployment = false case util.PIPELINE_DEPLOYMENT_TYPE_MANIFEST_DOWNLOAD: installedAppDeploymentAction.PerformGitOps = false installedAppDeploymentAction.PerformHelmDeployment = false installedAppDeploymentAction.PerformACDDeployment = false + installedAppDeploymentAction.PerformFluxDeployment = false } return installedAppDeploymentAction } @@ -273,7 +281,7 @@ func UpdateInstallAppDetails(request *appStoreBean.InstallAppVersionDTO, install request.EnvironmentId = installedApp.EnvironmentId request.Status = installedApp.Status request.DeploymentAppType = config.DeploymentAppType - if util.IsAcdApp(config.DeploymentAppType) { + if util.IsAcdApp(config.DeploymentAppType) || util.IsFluxApp(config.DeploymentAppType) { request.GitOpsRepoURL = config.GetRepoURL() request.TargetRevision = config.GetTargetRevision() } diff --git a/pkg/appStore/bean/bean.go b/pkg/appStore/bean/bean.go index d5967d892c..1dfe17b5c6 100644 --- a/pkg/appStore/bean/bean.go +++ b/pkg/appStore/bean/bean.go @@ -18,6 +18,7 @@ package appStoreBean import ( "encoding/json" + "fmt" "github.com/argoproj/gitops-engine/pkg/health" "github.com/devtron-labs/common-lib/utils/k8s/commonBean" apiBean "github.com/devtron-labs/devtron/api/bean/gitOps" @@ -127,6 +128,7 @@ type InstallAppVersionDTO struct { AppStoreApplicationVersionId int DisplayName string `json:"-"` // used only for external apps IsChartLinkRequest bool + GitOpsId int } func (chart *InstallAppVersionDTO) GetTargetRevision() string { @@ -195,6 +197,7 @@ type InstalledAppDeploymentAction struct { PerformGitOps bool PerformACDDeployment bool PerformHelmDeployment bool + PerformFluxDeployment bool } type InstalledAppDeleteResponseDTO struct { @@ -218,6 +221,9 @@ type InstallAppVersionChartRepoDTO struct { } func (chart *InstallAppVersionDTO) GetDeploymentConfig() *bean2.DeploymentConfig { + if util2.IsFluxApp(chart.DeploymentAppType) { + return chart.GetFluxDeploymentConfig() + } var configType string if chart.IsCustomRepository { configType = bean2.CUSTOM.String() @@ -258,6 +264,40 @@ func (chart *InstallAppVersionDTO) GetDeploymentConfig() *bean2.DeploymentConfig } } +func (chart *InstallAppVersionDTO) GetFluxDeploymentConfig() *bean2.DeploymentConfig { + var configType string + if chart.IsCustomRepository { + configType = bean2.CUSTOM.String() + } else { + configType = bean2.SYSTEM_GENERATED.String() + } + chartLocation := util.BuildDeployedAppName(chart.AppName, chart.EnvironmentName) + return &bean2.DeploymentConfig{ + AppId: chart.AppId, + EnvironmentId: chart.EnvironmentId, + ConfigType: configType, + DeploymentAppType: chart.DeploymentAppType, + ReleaseMode: util2.PIPELINE_RELEASE_MODE_CREATE, + ReleaseConfiguration: &bean2.ReleaseConfiguration{ + Version: bean2.Version, + FluxCDSpec: bean2.FluxCDSpec{ + ClusterId: chart.ClusterId, + HelmReleaseNamespace: chart.Namespace, + GitRepositoryNamespace: chart.Namespace, + GitRepositoryName: util.BuildDeployedAppName(chart.AppName, chart.EnvironmentName), + HelmReleaseName: util.BuildDeployedAppName(chart.AppName, chart.EnvironmentName), + GitOpsSecretName: fmt.Sprintf("devtron-flux-secret-%d", chart.GitOpsId), + ChartLocation: chartLocation, + //ChartVersion: chart.InstallAppVersionChartDTO.ChartVersion, + RevisionTarget: util.GetDefaultTargetRevision(), + RepoUrl: chart.GitOpsRepoURL, + DevtronValueFile: "values.yaml", + }, + }, + Active: true, + } +} + // / type RefChartProxyDir string diff --git a/pkg/appStore/installedApp/service/AppStoreDeploymentDBService.go b/pkg/appStore/installedApp/service/AppStoreDeploymentDBService.go index 24ed4d3c5d..fe80c962eb 100644 --- a/pkg/appStore/installedApp/service/AppStoreDeploymentDBService.go +++ b/pkg/appStore/installedApp/service/AppStoreDeploymentDBService.go @@ -169,7 +169,7 @@ func (impl *AppStoreDeploymentDBServiceImpl) AppStoreDeployOperationDB(installRe // Stage 2: ends // Stage 3: save installed_apps model - if globalUtil.IsFullStack() && util.IsAcdApp(installRequest.DeploymentAppType) { + if globalUtil.IsFullStack() && (util.IsAcdApp(installRequest.DeploymentAppType) || util.IsFluxApp(installRequest.DeploymentAppType)) { installRequest.UpdateCustomGitOpsRepoUrl(gitOpsConfigStatus.AllowCustomRepository, requestType) // validate GitOps request validationErr := impl.validateGitOpsRequest(gitOpsConfigStatus.AllowCustomRepository, installRequest.GitOpsRepoURL) @@ -208,6 +208,14 @@ func (impl *AppStoreDeploymentDBServiceImpl) AppStoreDeployOperationDB(installRe installRequest.InstalledAppId = installedApp.Id // Stage 3: ends + if len(installRequest.GitOpsRepoURL) > 0 { + gitOpsConfig, err := impl.gitOpsConfigReadService.GetGitOpsProviderByRepoURL(installRequest.GitOpsRepoURL) + if err != nil { + impl.logger.Errorw("error fetching gitops config by repo url", "repoUrl", installRequest.GitOpsRepoURL, "err", err) + return nil, err + } + installRequest.GitOpsId = gitOpsConfig.Id + } deploymentConfig := installRequest.GetDeploymentConfig() deploymentConfig, err = impl.deploymentConfigService.CreateOrUpdateConfig(tx, deploymentConfig, installRequest.UserId) if err != nil { diff --git a/pkg/appStore/installedApp/service/AppStoreDeploymentService.go b/pkg/appStore/installedApp/service/AppStoreDeploymentService.go index 7a9fd2e40b..d1096d4060 100644 --- a/pkg/appStore/installedApp/service/AppStoreDeploymentService.go +++ b/pkg/appStore/installedApp/service/AppStoreDeploymentService.go @@ -82,6 +82,7 @@ type AppStoreDeploymentServiceImpl struct { appRepository app.AppRepository eaModeDeploymentService deployment2.EAModeDeploymentService fullModeDeploymentService deployment.FullModeDeploymentService + fullModeFluxDeploymentService deployment.FullModeFluxDeploymentService environmentService environment.EnvironmentService helmAppService service.HelmAppService installedAppRepositoryHistory repository.InstalledAppVersionHistoryRepository @@ -103,6 +104,7 @@ func NewAppStoreDeploymentServiceImpl(logger *zap.SugaredLogger, appRepository app.AppRepository, eaModeDeploymentService deployment2.EAModeDeploymentService, fullModeDeploymentService deployment.FullModeDeploymentService, + fullModeFluxDeploymentService deployment.FullModeFluxDeploymentService, environmentService environment.EnvironmentService, helmAppService service.HelmAppService, installedAppRepositoryHistory repository.InstalledAppVersionHistoryRepository, @@ -123,6 +125,7 @@ func NewAppStoreDeploymentServiceImpl(logger *zap.SugaredLogger, appRepository: appRepository, eaModeDeploymentService: eaModeDeploymentService, fullModeDeploymentService: fullModeDeploymentService, + fullModeFluxDeploymentService: fullModeFluxDeploymentService, environmentService: environmentService, helmAppService: helmAppService, installedAppRepositoryHistory: installedAppRepositoryHistory, @@ -200,6 +203,8 @@ func (impl *AppStoreDeploymentServiceImpl) InstallApp(installAppVersionRequest * if impl.aCDConfig.IsManualSyncEnabled() { _ = impl.fullModeDeploymentService.SaveTimelineForHelmApps(installAppVersionRequest, timelineStatus.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_SYNC_INITIATED, time.Now(), tx) } + } else if util.IsFluxApp(installAppVersionRequest.DeploymentAppType) { + _ = impl.fullModeDeploymentService.SaveTimelineForHelmApps(installAppVersionRequest, timelineStatus.TIMELINE_STATUS_GIT_COMMIT, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_GIT_COMMIT, time.Now(), tx) } installAppVersionRequest.GitHash = gitOpsResponse.GitHash if len(installAppVersionRequest.GitHash) > 0 { @@ -218,6 +223,11 @@ func (impl *AppStoreDeploymentServiceImpl) InstallApp(installAppVersionRequest * return nil, errors.New("service err, Error in git operations") } installAppVersionRequest, err = impl.fullModeDeploymentService.InstallApp(installAppVersionRequest, gitOpsResponse.ChartGitAttribute, ctx, tx) + } else if util.IsFluxApp(installAppVersionRequest.DeploymentAppType) { + if gitOpsResponse == nil && gitOpsResponse.ChartGitAttribute != nil { + return nil, errors.New("service err, Error in git operations") + } + installAppVersionRequest, err = impl.fullModeFluxDeploymentService.InstallApp(installAppVersionRequest, gitOpsResponse.ChartGitAttribute, ctx, tx) } if err != nil { return nil, err @@ -594,7 +604,7 @@ func (impl *AppStoreDeploymentServiceImpl) updateInstalledApp(ctx context.Contex installedAppDeploymentAction := adapter.NewInstalledAppDeploymentAction(deploymentConfig.DeploymentAppType) // migrate installedApp.GitOpsRepoName to installedApp.GitOpsRepoUrl - if util.IsAcdApp(deploymentConfig.DeploymentAppType) && + if (util.IsAcdApp(deploymentConfig.DeploymentAppType) || util.IsFluxApp(deploymentConfig.DeploymentAppType)) && len(deploymentConfig.GetRepoURL()) == 0 { gitRepoUrl, err := impl.fullModeDeploymentService.GetAcdAppGitOpsRepoURL(installedApp.App.AppName, installedApp.Environment.Name) if err != nil { @@ -725,7 +735,7 @@ func (impl *AppStoreDeploymentServiceImpl) updateInstalledApp(ctx context.Contex upgradeAppRequest.GitHash = gitOpsResponse.GitHash _ = impl.fullModeDeploymentService.SaveTimelineForHelmApps(upgradeAppRequest, timelineStatus.TIMELINE_STATUS_GIT_COMMIT, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_GIT_COMMIT, time.Now(), tx) - if impl.aCDConfig.IsManualSyncEnabled() { + if installedAppDeploymentAction.PerformACDDeployment && impl.aCDConfig.IsManualSyncEnabled() { //if acd then only save manifest timeline, filtering flux through this check _ = impl.fullModeDeploymentService.SaveTimelineForHelmApps(upgradeAppRequest, timelineStatus.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_SYNC_INITIATED, time.Now(), tx) } installedAppVersionHistory.GitHash = gitOpsResponse.GitHash @@ -751,6 +761,12 @@ func (impl *AppStoreDeploymentServiceImpl) updateInstalledApp(ctx context.Contex return nil, err } } + } else if installedAppDeploymentAction.PerformFluxDeployment { + err = impl.fullModeFluxDeploymentService.UpgradeDeployment(upgradeAppRequest, gitOpsResponse.ChartGitAttribute, upgradeAppRequest.InstalledAppVersionHistoryId, ctx) + if err != nil { + impl.logger.Errorw("error in flux app patch request", "err", err) + return nil, err + } } installedApp.UpdateStatus(appStoreBean.DEPLOY_SUCCESS) installedApp.UpdateAuditLog(upgradeAppRequest.UserId) @@ -849,7 +865,7 @@ func (impl *AppStoreDeploymentServiceImpl) InstallAppByHelm(installAppVersionReq func (impl *AppStoreDeploymentServiceImpl) UpdatePreviousDeploymentStatusForAppStore(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, triggeredAt time.Time, err error) error { //creating pipeline status timeline for deployment failed - if !util.IsAcdApp(installAppVersionRequest.DeploymentAppType) { + if !util.IsAcdApp(installAppVersionRequest.DeploymentAppType) && !util.IsFluxApp(installAppVersionRequest.DeploymentAppType) { return nil } err1 := impl.fullModeDeploymentService.UpdateInstalledAppAndPipelineStatusForFailedDeploymentStatus(installAppVersionRequest, triggeredAt, err) diff --git a/pkg/appStore/installedApp/service/FullMode/InstalledAppDBExtendedService.go b/pkg/appStore/installedApp/service/FullMode/InstalledAppDBExtendedService.go index 49a3a5c2a2..708e13e126 100644 --- a/pkg/appStore/installedApp/service/FullMode/InstalledAppDBExtendedService.go +++ b/pkg/appStore/installedApp/service/FullMode/InstalledAppDBExtendedService.go @@ -28,7 +28,7 @@ import ( type InstalledAppDBExtendedService interface { EAMode.InstalledAppDBService UpdateInstalledAppVersionStatus(application *v1alpha1.Application) (bool, error) - IsGitOpsRepoAlreadyRegistered(repoUrl string) (bool, error) + IsGitOpsRepoAlreadyRegistered(repoUrl string, appId int) (bool, error) } type InstalledAppDBExtendedServiceImpl struct { @@ -91,9 +91,9 @@ func (impl *InstalledAppDBExtendedServiceImpl) UpdateInstalledAppVersionStatus(a return true, nil } -func (impl *InstalledAppDBExtendedServiceImpl) IsGitOpsRepoAlreadyRegistered(repoUrl string) (bool, error) { +func (impl *InstalledAppDBExtendedServiceImpl) IsGitOpsRepoAlreadyRegistered(repoUrl string, appId int) (bool, error) { - urlPresent, err := impl.InstalledAppDBServiceImpl.DeploymentConfigService.CheckIfURLAlreadyPresent(repoUrl) + urlPresent, err := impl.InstalledAppDBServiceImpl.DeploymentConfigService.CheckIfURLAlreadyPresent(repoUrl, appId) if err != nil && !util.IsErrNoRows(err) { impl.Logger.Errorw("error in checking url in deployment configs", "repoUrl", repoUrl, "err", err) return false, err @@ -111,6 +111,9 @@ func (impl *InstalledAppDBExtendedServiceImpl) IsGitOpsRepoAlreadyRegistered(rep if util.IsErrNoRows(err) { return false, nil } + if installedAppModel != nil && installedAppModel.AppId == appId { + return false, nil + } impl.Logger.Warnw("repository is already in use for helm app", "repoUrl", repoUrl, "appId", installedAppModel.AppId) return true, nil } diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/DeploymentStatusService.go b/pkg/appStore/installedApp/service/FullMode/deployment/DeploymentStatusService.go index 342d5f6b4b..2826b73182 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/DeploymentStatusService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/DeploymentStatusService.go @@ -38,7 +38,8 @@ type DeploymentStatusService interface { func (impl *FullModeDeploymentServiceImpl) SaveTimelineForHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status timelineStatus.TimelineStatus, statusDetail string, statusTime time.Time, tx *pg.Tx) error { - if !util.IsAcdApp(installAppVersionRequest.DeploymentAppType) && !util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) { + if !util.IsAcdApp(installAppVersionRequest.DeploymentAppType) && !util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) && + !util.IsFluxApp(installAppVersionRequest.DeploymentAppType) { return nil } diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/FullModeFluxDeploymentService.go b/pkg/appStore/installedApp/service/FullMode/deployment/FullModeFluxDeploymentService.go new file mode 100644 index 0000000000..f7a1277be3 --- /dev/null +++ b/pkg/appStore/installedApp/service/FullMode/deployment/FullModeFluxDeploymentService.go @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package deployment + +import ( + "context" + "errors" + "github.com/devtron-labs/devtron/client/fluxcd" + appStoreBean "github.com/devtron-labs/devtron/pkg/appStore/bean" + "github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository" + appStoreDeploymentCommon "github.com/devtron-labs/devtron/pkg/appStore/installedApp/service/common" + "github.com/devtron-labs/devtron/pkg/cluster" + commonBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/common/bean" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +// FullModeDeploymentService TODO refactoring: Use extended binding over EAMode.EAModeDeploymentService +// Currently creating duplicate methods in EAMode.EAModeDeploymentService +type FullModeFluxDeploymentService interface { + // FluxCd Services + + // InstallApp will create git repo and helm release crd objects + InstallApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *commonBean.ChartGitAttribute, ctx context.Context, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) + // UpgradeDeployment will update git repo and helm release crd objects + UpgradeDeployment(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *commonBean.ChartGitAttribute, installedAppVersionHistoryId int, ctx context.Context) error + + // DeleteInstalledApp will delete entry from appStatus.AppStatusDto table, from repository.ChartGroupDeployment table (if exists) and delete crd objects + DeleteInstalledApp(ctx context.Context, appName string, environmentName string, installAppVersionRequest *appStoreBean.InstallAppVersionDTO, installedApps *repository.InstalledApps, dbTransaction *pg.Tx) error + // RollbackRelease will rollback to a previous deployment for the given installedAppVersionHistoryId; returns - valuesYamlStr, success, error + RollbackRelease(ctx context.Context, installedApp *appStoreBean.InstallAppVersionDTO, deploymentVersion int32) (*appStoreBean.InstallAppVersionDTO, bool, error) +} + +type FullModeFluxDeploymentServiceImpl struct { + logger *zap.SugaredLogger + appStoreDeploymentCommonService appStoreDeploymentCommon.AppStoreDeploymentCommonService + fluxCdDeploymentService fluxcd.DeploymentService + clusterService cluster.ClusterService +} + +func NewFullModeFluxDeploymentServiceImpl(logger *zap.SugaredLogger, + appStoreDeploymentCommonService appStoreDeploymentCommon.AppStoreDeploymentCommonService, + fluxCdDeploymentService fluxcd.DeploymentService, clusterService cluster.ClusterService) *FullModeFluxDeploymentServiceImpl { + return &FullModeFluxDeploymentServiceImpl{ + logger: logger, + appStoreDeploymentCommonService: appStoreDeploymentCommonService, + fluxCdDeploymentService: fluxCdDeploymentService, + clusterService: clusterService, + } +} + +func (impl *FullModeFluxDeploymentServiceImpl) InstallApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *commonBean.ChartGitAttribute, + ctx context.Context, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) { + clusterConfig, err := impl.clusterService.GetClusterConfigByClusterId(installAppVersionRequest.ClusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", installAppVersionRequest.ClusterId, "error", err) + return nil, err + } + //deploy app + err = impl.fluxCdDeploymentService.DeployFluxCdApp(ctx, &fluxcd.DeploymentRequest{ + ClusterConfig: clusterConfig, + DeploymentConfig: installAppVersionRequest.GetDeploymentConfig(), + IsAppCreated: false, + }) + if err != nil { + impl.logger.Errorw("error in deploy Flux Cd App", "error", err) + return nil, err + } + return installAppVersionRequest, nil +} + +func (impl *FullModeFluxDeploymentServiceImpl) UpgradeDeployment(upgradeAppRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *commonBean.ChartGitAttribute, installedAppVersionHistoryId int, ctx context.Context) error { + clusterConfig, err := impl.clusterService.GetClusterConfigByClusterId(upgradeAppRequest.ClusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", upgradeAppRequest.ClusterId, "error", err) + return err + } + //deploy app + err = impl.fluxCdDeploymentService.DeployFluxCdApp(ctx, &fluxcd.DeploymentRequest{ + ClusterConfig: clusterConfig, + DeploymentConfig: upgradeAppRequest.GetDeploymentConfig(), + IsAppCreated: true, + }) + if err != nil { + impl.logger.Errorw("error in deploy Flux Cd App", "error", err) + return err + } + return nil +} + +func (impl *FullModeFluxDeploymentServiceImpl) DeleteInstalledApp(ctx context.Context, appName, environmentName string, + installAppVersionRequest *appStoreBean.InstallAppVersionDTO, installedApps *repository.InstalledApps, tx *pg.Tx) error { + clusterConfig, err := impl.clusterService.GetClusterConfigByClusterId(installAppVersionRequest.ClusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", installAppVersionRequest.ClusterId, "error", err) + return err + } + err = impl.fluxCdDeploymentService.DeleteFluxDeploymentApp(ctx, &fluxcd.DeploymentAppDeleteRequest{ + ClusterConfig: clusterConfig, + }) + if err != nil { + impl.logger.Errorw("error in deploy Flux Cd App", "error", err) + return err + } + return nil +} + +func (impl *FullModeFluxDeploymentServiceImpl) RollbackRelease(ctx context.Context, installedApp *appStoreBean.InstallAppVersionDTO, deploymentVersion int32) (*appStoreBean.InstallAppVersionDTO, bool, error) { + return nil, false, errors.New("this is not implemented") +} diff --git a/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go b/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go index 5a4cd57313..955877e3e8 100644 --- a/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go +++ b/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go @@ -32,6 +32,7 @@ import ( "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/constants" repository2 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" + cdWorkflow2 "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/appStatus" "github.com/devtron-labs/devtron/pkg/appStore/bean" @@ -39,8 +40,11 @@ import ( "github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository" "github.com/devtron-labs/devtron/pkg/argoApplication" bean3 "github.com/devtron-labs/devtron/pkg/argoApplication/bean" + bean4 "github.com/devtron-labs/devtron/pkg/auth/user/bean" "github.com/devtron-labs/devtron/pkg/deployment/common" bean2 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" + "github.com/devtron-labs/devtron/pkg/fluxApplication" + bean5 "github.com/devtron-labs/devtron/pkg/fluxApplication/bean" "github.com/devtron-labs/devtron/pkg/k8s" application3 "github.com/devtron-labs/devtron/pkg/k8s/application" util3 "github.com/devtron-labs/devtron/pkg/util" @@ -77,6 +81,7 @@ type InstalledAppResourceServiceImpl struct { deploymentConfigurationService common.DeploymentConfigService OCIRegistryConfigRepository repository2.OCIRegistryConfigRepository argoApplicationService argoApplication.ArgoApplicationService + fluxApplicationService fluxApplication.FluxApplicationService } func NewInstalledAppResourceServiceImpl(logger *zap.SugaredLogger, @@ -91,7 +96,8 @@ func NewInstalledAppResourceServiceImpl(logger *zap.SugaredLogger, k8sCommonService k8s.K8sCommonService, k8sApplicationService application3.K8sApplicationService, K8sUtil k8s2.K8sService, deploymentConfigurationService common.DeploymentConfigService, OCIRegistryConfigRepository repository2.OCIRegistryConfigRepository, - argoApplicationService argoApplication.ArgoApplicationService) *InstalledAppResourceServiceImpl { + argoApplicationService argoApplication.ArgoApplicationService, + fluxApplicationService fluxApplication.FluxApplicationService) *InstalledAppResourceServiceImpl { return &InstalledAppResourceServiceImpl{ logger: logger, installedAppRepository: installedAppRepository, @@ -108,6 +114,7 @@ func NewInstalledAppResourceServiceImpl(logger *zap.SugaredLogger, deploymentConfigurationService: deploymentConfigurationService, OCIRegistryConfigRepository: OCIRegistryConfigRepository, argoApplicationService: argoApplicationService, + fluxApplicationService: fluxApplicationService, } } @@ -171,6 +178,49 @@ func (impl *InstalledAppResourceServiceImpl) FetchResourceTree(rctx context.Cont releaseStatusMap := util2.InterfaceToMapAdapter(releaseStatus) appDetailsContainer.ReleaseStatus = releaseStatusMap } + } else if util.IsFluxApp(deploymentConfig.DeploymentAppType) { + req := &bean5.FluxAppIdentifier{ + ClusterId: installedApp.Environment.ClusterId, + Namespace: installedApp.Environment.Namespace, + Name: deploymentAppName, + IsKustomizeApp: false, + } + detail, err := impl.fluxApplicationService.GetFluxAppDetail(rctx, req) + if err != nil { + impl.logger.Errorw("error in fetching app detail", "payload", req, "err", err) + } + if detail != nil { + iaVersion, err := impl.installedAppRepositoryHistory.GetLatestInstalledAppVersionHistoryByInstalledAppId(installedApp.Id) + if err != nil { + impl.logger.Errorw("error in fetching latest installed app version history", "err", err) + } else if iaVersion != nil { + switch detail.FluxAppStatusDetail.Reason { + case bean5.InstallSucceededReason, bean5.UpgradeSucceededReason, bean5.TestSucceededReason, bean5.RollbackSucceededReason: + if detail.AppHealthStatus == commonBean.HealthStatusHealthy { + iaVersion.Status = cdWorkflow2.WorkflowSucceeded + } + case bean5.UpgradeFailedReason, + bean5.TestFailedReason, + bean5.RollbackFailedReason, + bean5.UninstallFailedReason, + bean5.ArtifactFailedReason, + bean5.InstallFailedReason: + iaVersion.Status = cdWorkflow2.WorkflowFailed + } + iaVersion.UpdateAuditLog(bean4.SYSTEM_USER_ID) + _, err = impl.installedAppRepositoryHistory.UpdateInstalledAppVersionHistory(iaVersion, nil) + if err != nil { + impl.logger.Errorw("error in updating app version history", "err", err) + } + } + resourceTree = util2.InterfaceToMapAdapter(detail.ResourceTreeResponse) + applicationStatus := detail.AppHealthStatus + if detail.ResourceTreeResponse != nil && len(detail.ResourceTreeResponse.Nodes) == 0 { + resourceTree["status"] = commonBean.HealthStatusUnknown + } else { + resourceTree["status"] = applicationStatus + } + } } if resourceTree != nil { version, err := impl.k8sCommonService.GetK8sServerVersion(installedApp.Environment.ClusterId) diff --git a/pkg/bean/app.go b/pkg/bean/app.go index d43c370ea5..d198f849c2 100644 --- a/pkg/bean/app.go +++ b/pkg/bean/app.go @@ -657,6 +657,14 @@ type CDPipelineConfigObject struct { ReleaseMode string `json:"releaseMode" validate:"omitempty,oneof=link create"` } +func (cdPipelineConfig *CDPipelineConfigObject) IsFluxDeploymentAppType() bool { + return cdPipelineConfig.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX +} + +func (cdPipelineConfig *CDPipelineConfigObject) IsAcdDeploymentAppType() bool { + return cdPipelineConfig.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD +} + func (cdPipelineConfig *CDPipelineConfigObject) IsLinkedRelease() bool { return cdPipelineConfig.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_LINK } @@ -706,6 +714,11 @@ func (cdPipelineConfig *CDPipelineConfigObject) IsExternalArgoAppLinkRequest() b cdPipelineConfig.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_LINK } +func (cdPipelineConfig *CDPipelineConfigObject) IsExternalFluxAppLinkRequest() bool { + return cdPipelineConfig.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX && + cdPipelineConfig.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_LINK +} + func (cdPipelineConfig *CDPipelineConfigObject) IsExternalHelmAppLinkRequest() bool { return cdPipelineConfig.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_HELM && cdPipelineConfig.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_LINK diff --git a/pkg/chart/ChartService.go b/pkg/chart/ChartService.go index 419aac1720..fb2307542d 100644 --- a/pkg/chart/ChartService.go +++ b/pkg/chart/ChartService.go @@ -72,7 +72,7 @@ type ChartService interface { ConfigureGitOpsRepoUrlForApp(appId int, repoUrl, chartLocation string, isCustomRepo bool, userId int32) (*bean2.DeploymentConfig, error) IsGitOpsRepoConfiguredForDevtronApp(appId int) (bool, error) - IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string) (bool, error) + IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string, appId int) (bool, error) GetDeploymentTemplateDataByAppIdAndCharRefId(appId, chartRefId int) (map[string]interface{}, error) @@ -1047,9 +1047,9 @@ func (impl *ChartServiceImpl) ConfigureGitOpsRepoUrlForApp(appId int, repoUrl, c // return nil //} -func (impl *ChartServiceImpl) IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string) (bool, error) { +func (impl *ChartServiceImpl) IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string, appId int) (bool, error) { - isURLPresent, err := impl.deploymentConfigService.CheckIfURLAlreadyPresent(gitOpsRepoUrl) + isURLPresent, err := impl.deploymentConfigService.CheckIfURLAlreadyPresent(gitOpsRepoUrl, appId) if err != nil { impl.logger.Errorw("error in checking if gitOps repo url is already present", "error", err) return false, err @@ -1065,6 +1065,9 @@ func (impl *ChartServiceImpl) IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string } else if util.IsErrNoRows(err) { return false, nil } + if chartModel != nil && chartModel.AppId == appId { + return false, nil + } impl.logger.Errorw("repository is already in use for devtron app", "repoUrl", gitOpsRepoUrl, "appId", chartModel.AppId) return true, nil } diff --git a/pkg/cluster/environment/EnvironmentService.go b/pkg/cluster/environment/EnvironmentService.go index c143a53135..8ad9077537 100644 --- a/pkg/cluster/environment/EnvironmentService.go +++ b/pkg/cluster/environment/EnvironmentService.go @@ -351,7 +351,7 @@ func (impl EnvironmentServiceImpl) FindClusterByEnvId(id int) (*bean4.ClusterBea return clusterBean, nil } -var permittedDeploymentConfigString = []string{bean2.PIPELINE_DEPLOYMENT_TYPE_HELM, bean2.PIPELINE_DEPLOYMENT_TYPE_ACD} +var permittedDeploymentConfigString = []string{bean2.PIPELINE_DEPLOYMENT_TYPE_HELM, bean2.PIPELINE_DEPLOYMENT_TYPE_ACD, bean2.PIPELINE_DEPLOYMENT_TYPE_FLUX} func (impl EnvironmentServiceImpl) GetEnvironmentListForAutocomplete(isDeploymentTypeParam bool) ([]bean2.EnvironmentBean, error) { models, err := impl.environmentRepository.FindAllActive() diff --git a/pkg/cluster/environment/bean/bean.go b/pkg/cluster/environment/bean/bean.go index 760ef70eeb..2584fcb3b0 100644 --- a/pkg/cluster/environment/bean/bean.go +++ b/pkg/cluster/environment/bean/bean.go @@ -66,6 +66,7 @@ type ResourceGroupingResponse struct { const ( PIPELINE_DEPLOYMENT_TYPE_HELM = "helm" PIPELINE_DEPLOYMENT_TYPE_ACD = "argo_cd" + PIPELINE_DEPLOYMENT_TYPE_FLUX = "flux_cd" ) type DataSourceMetaData struct { diff --git a/pkg/cluster/read/ClusterReadService.go b/pkg/cluster/read/ClusterReadService.go index e8ab539baa..22c1209498 100644 --- a/pkg/cluster/read/ClusterReadService.go +++ b/pkg/cluster/read/ClusterReadService.go @@ -1,6 +1,7 @@ package read import ( + "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/pkg/cluster/adapter" "github.com/devtron-labs/devtron/pkg/cluster/bean" "github.com/devtron-labs/devtron/pkg/cluster/repository" @@ -12,6 +13,7 @@ type ClusterReadService interface { FindById(id int) (*bean.ClusterBean, error) FindOne(clusterName string) (*bean.ClusterBean, error) FindByClusterURL(clusterURL string) (*bean.ClusterBean, error) + GetClusterConfigByClusterId(clusterId int) (*k8s.ClusterConfig, error) } type ClusterReadServiceImpl struct { @@ -27,6 +29,17 @@ func NewClusterReadServiceImpl(logger *zap.SugaredLogger, } } +func (impl *ClusterReadServiceImpl) GetClusterConfigByClusterId(clusterId int) (*k8s.ClusterConfig, error) { + clusterBean, err := impl.FindById(clusterId) + if err != nil { + impl.logger.Errorw("error in getting clusterBean by cluster id", "err", err, "clusterId", clusterId) + return nil, err + } + rq := *clusterBean + clusterConfig := rq.GetClusterConfig() + return clusterConfig, nil +} + func (impl *ClusterReadServiceImpl) IsClusterReachable(clusterId int) (bool, error) { cluster, err := impl.clusterRepository.FindById(clusterId) if err != nil { diff --git a/pkg/commonService/CommonBaseService.go b/pkg/commonService/CommonBaseService.go index 664bb4eb61..5e2847922b 100644 --- a/pkg/commonService/CommonBaseService.go +++ b/pkg/commonService/CommonBaseService.go @@ -46,6 +46,10 @@ func (impl *CommonBaseServiceImpl) isGitOpsEnable() (*FeatureGitOpsVariables, er featureGitOpsFlags := &FeatureGitOpsVariables{ IsFeatureArgoCdMigrationEnabled: impl.globalEnvVariables.DeploymentServiceTypeConfig.IsFeatureMigrateArgoCdApplicationEnable(), } + if impl.globalEnvVariables.DeploymentServiceTypeConfig.FeatureMigrateFluxApplicationEnable { + featureGitOpsFlags.IsFeatureGitOpsEnabled = true + featureGitOpsFlags.IsFeatureUserDefinedGitOpsEnabled = true + } argoModule, err := impl.moduleReadService.GetModuleInfoByName(bean.ModuleNameArgoCd) if err != nil && !errors.Is(err, moduleErr.ModuleNotFoundError) { impl.logger.Errorw("error in getting argo module", "error", err) diff --git a/pkg/deployment/common/adapter/adapter.go b/pkg/deployment/common/adapter/adapter.go index eab0d11bf0..31f8cc1e73 100644 --- a/pkg/deployment/common/adapter/adapter.go +++ b/pkg/deployment/common/adapter/adapter.go @@ -73,6 +73,26 @@ func NewAppLevelReleaseConfigFromChart(gitRepoURL, chartLocation string) *bean.R }} } +func NewFluxSpecReleaseConfig(clusterId int, helmReleaseNamespace, gitRepositoryName, gitRepositoryNamespace, helmReleaseName, gitOpsSecretName, ChartLocation, ChartVersion, RevisionTarget, RepoUrl, DevtronValueFileName string, HelmReleaseValuesFiles []string, extValues string) *bean.ReleaseConfiguration { + return &bean.ReleaseConfiguration{ + Version: bean.Version, + FluxCDSpec: bean.FluxCDSpec{ + ClusterId: clusterId, + HelmReleaseNamespace: helmReleaseNamespace, + GitRepositoryName: gitRepositoryName, + GitRepositoryNamespace: gitRepositoryNamespace, + HelmReleaseName: helmReleaseName, + GitOpsSecretName: gitOpsSecretName, + ChartLocation: ChartLocation, + ChartVersion: ChartVersion, + RevisionTarget: RevisionTarget, + RepoUrl: RepoUrl, + DevtronValueFile: DevtronValueFileName, + HelmReleaseValuesFiles: HelmReleaseValuesFiles, + ExtFluxValues: extValues, + }} +} + func GetDeploymentConfigType(isCustomGitOpsRepo bool) string { if isCustomGitOpsRepo { return string(bean.CUSTOM) diff --git a/pkg/deployment/common/bean/bean.go b/pkg/deployment/common/bean/bean.go index e2dfdbebc7..60174e3b17 100644 --- a/pkg/deployment/common/bean/bean.go +++ b/pkg/deployment/common/bean/bean.go @@ -5,6 +5,7 @@ import ( apiGitOpsBean "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/internal/util" globalUtil "github.com/devtron-labs/devtron/util" + "path" "strconv" "strings" ) @@ -18,6 +19,30 @@ const ( type ReleaseConfiguration struct { Version ReleaseConfigVersion `json:"version"` ArgoCDSpec ArgoCDSpec `json:"argoCDSpec"` + FluxCDSpec FluxCDSpec `json:"fluxCDSpec"` +} + +type FluxCDSpec struct { + ClusterId int `json:"clusterId"` + HelmReleaseNamespace string `json:"helmReleaseNamespace"` + GitRepositoryName string `json:"gitRepositoryName"` + GitRepositoryNamespace string `json:"gitRepositoryNamespace"` + HelmReleaseName string `json:"helmReleaseName"` + GitOpsSecretName string `json:"gitOpsSecretName"` //fmt.Sprintf("devtron-flux-secret-%d", gitOpsConfig.Id) + + ChartLocation string `json:"chartLocation"` + ChartVersion string `json:"chartVersion"` + RevisionTarget string `json:"revisionTarget"` + RepoUrl string `json:"repoUrl"` + DevtronValueFile string `json:"devtronValueFile"` + HelmReleaseValuesFiles []string `json:"helmReleaseValuesFiles"` //getValuesFileArr + ExtFluxValues string `json:"extFluxValues"` +} + +func (f *FluxCDSpec) GetFinalValuesFilePathArray() []string { + //here our understanding is that devtron will always commit at chartLocation/devtronValueFile path + //and apart from this there might be some other value files too, that are required for the chart to function + return append(f.HelmReleaseValuesFiles, path.Join(f.ChartLocation, f.DevtronValueFile)) } type ArgoCDSpec struct { @@ -172,6 +197,14 @@ func (d *DeploymentConfig) IsAcdRelease() bool { return d.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD } +func (d *DeploymentConfig) IsFluxCDRelease() bool { + return d.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX +} + +func (d *DeploymentConfig) IsFluxRelease() bool { + return d.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX +} + func (d *DeploymentConfig) IsLinkedRelease() bool { return d.ReleaseMode == util.PIPELINE_RELEASE_MODE_LINK } @@ -181,7 +214,7 @@ func (d *DeploymentConfig) IsArgoCdClientSupported() bool { } func (d *DeploymentConfig) IsArgoAppSyncAndRefreshSupported() bool { - return d.IsAcdRelease() && !d.IsLinkedRelease() + return d.IsAcdRelease() && d.IsFluxCDRelease() && !d.IsLinkedRelease() } func (d *DeploymentConfig) IsArgoAppPatchSupported() bool { @@ -210,6 +243,11 @@ func (d *DeploymentConfig) IsPipelineGitOpsRepoConfigured(isAppLevelGitOpsConfig } func (d *DeploymentConfig) GetRepoURL() string { + + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + return d.ReleaseConfiguration.FluxCDSpec.RepoUrl + } + if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { return d.RepoURL } @@ -217,6 +255,9 @@ func (d *DeploymentConfig) GetRepoURL() string { } func (d *DeploymentConfig) GetTargetRevision() string { + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + return d.ReleaseConfiguration.FluxCDSpec.RevisionTarget + } if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil || len(d.ReleaseConfiguration.ArgoCDSpec.Spec.Source.TargetRevision) == 0 { @@ -225,7 +266,11 @@ func (d *DeploymentConfig) GetTargetRevision() string { return d.ReleaseConfiguration.ArgoCDSpec.Spec.Source.TargetRevision } -func (d *DeploymentConfig) GetValuesFilePath() string { +func (d *DeploymentConfig) GetValuesFilePathForCommit() string { + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + // We will commit values in last file of array + return d.ReleaseConfiguration.FluxCDSpec.DevtronValueFile + } if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { return "" } @@ -238,6 +283,9 @@ func (d *DeploymentConfig) GetValuesFilePath() string { } func (d *DeploymentConfig) GetChartLocation() string { + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + return d.ReleaseConfiguration.FluxCDSpec.ChartLocation + } if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { return "" } @@ -246,6 +294,10 @@ func (d *DeploymentConfig) GetChartLocation() string { func (d *DeploymentConfig) SetRepoURL(repoURL string) *DeploymentConfig { d.RepoURL = repoURL // maintain for backward compatibility + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + d.ReleaseConfiguration.FluxCDSpec.RepoUrl = repoURL + return d + } if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { return d } @@ -254,17 +306,32 @@ func (d *DeploymentConfig) SetRepoURL(repoURL string) *DeploymentConfig { } func (d *DeploymentConfig) SetChartLocation(chartLocation string) { - if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + d.ReleaseConfiguration.FluxCDSpec.ChartLocation = chartLocation + return + } + if d.ReleaseConfiguration == nil || + (d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil && + len(d.ReleaseConfiguration.FluxCDSpec.ChartLocation) == 0) { return } d.ReleaseConfiguration.ArgoCDSpec.Spec.Source.Path = chartLocation } func (d *DeploymentConfig) GetRevision() string { + if d.IsFluxRelease() && d.ReleaseConfiguration != nil { + return d.ReleaseConfiguration.FluxCDSpec.RevisionTarget + } + if d.ReleaseConfiguration == nil || d.ReleaseConfiguration.ArgoCDSpec.Spec.Source == nil { return "" } - return d.ReleaseConfiguration.ArgoCDSpec.Spec.Source.TargetRevision + if d.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD { + return d.ReleaseConfiguration.ArgoCDSpec.Spec.Source.TargetRevision + } else if d.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX { + return d.ReleaseConfiguration.FluxCDSpec.RevisionTarget + } + return "" } func (d *DeploymentConfig) GetAcdAppName() string { diff --git a/pkg/deployment/common/deploymentConfigService.go b/pkg/deployment/common/deploymentConfigService.go index a35150498d..87cd063144 100644 --- a/pkg/deployment/common/deploymentConfigService.go +++ b/pkg/deployment/common/deploymentConfigService.go @@ -57,7 +57,7 @@ type DeploymentConfigService interface { UpdateChartLocationInDeploymentConfig(appId, envId, chartRefId int, userId int32, chartVersion string) error GetAllArgoAppInfosByDeploymentAppNames(deploymentAppNames []string) ([]*bean.DevtronArgoCdAppInfo, error) GetExternalReleaseType(appId, environmentId int) (bean.ExternalReleaseType, error) - CheckIfURLAlreadyPresent(repoURL string) (bool, error) + CheckIfURLAlreadyPresent(repoURL string, appId int) (bool, error) FilterPipelinesByApplicationClusterIdAndNamespace(pipelines []pipelineConfig.Pipeline, applicationObjectClusterId int, applicationObjectNamespace string) (pipelineConfig.Pipeline, error) } @@ -336,7 +336,7 @@ func (impl *DeploymentConfigServiceImpl) UpdateChartLocationInDeploymentConfig(a impl.logger.Errorw("error, GetConfigForDevtronApps", "appId", appId, "envId", envId, "err", err) return err } - if config.ReleaseMode == util2.PIPELINE_RELEASE_MODE_CREATE && config.DeploymentAppType == bean4.PIPELINE_DEPLOYMENT_TYPE_ACD { + if config.ReleaseMode == util2.PIPELINE_RELEASE_MODE_CREATE && (config.IsAcdRelease() || config.IsFluxRelease()) { chartRef, err := impl.chartRefRepository.FindById(chartRefId) if err != nil { impl.logger.Errorw("error in chartRefRepository.FindById", "chartRefId", chartRefId, "err", err) @@ -408,7 +408,7 @@ func (impl *DeploymentConfigServiceImpl) GetExternalReleaseType(appId, environme return externalHelmReleaseType, nil } -func (impl *DeploymentConfigServiceImpl) CheckIfURLAlreadyPresent(repoURL string) (bool, error) { +func (impl *DeploymentConfigServiceImpl) CheckIfURLAlreadyPresent(repoURL string, appId int) (bool, error) { //TODO: optimisation configs, err := impl.getAllAppLevelConfigsWithCustomGitOpsURL() if err != nil { @@ -416,7 +416,7 @@ func (impl *DeploymentConfigServiceImpl) CheckIfURLAlreadyPresent(repoURL string return false, err } for _, dc := range configs { - if dc.GetRepoURL() == repoURL { + if dc.GetRepoURL() == repoURL && dc.AppId != appId { impl.logger.Warnw("repository is already in use for helm app", "repoUrl", repoURL) return true, nil } diff --git a/pkg/deployment/deployedApp/status/resourceTree/ResourceTreeService.go b/pkg/deployment/deployedApp/status/resourceTree/ResourceTreeService.go index 66a6756574..f00d39be9b 100644 --- a/pkg/deployment/deployedApp/status/resourceTree/ResourceTreeService.go +++ b/pkg/deployment/deployedApp/status/resourceTree/ResourceTreeService.go @@ -20,6 +20,8 @@ import ( "context" "fmt" "github.com/devtron-labs/common-lib/async" + "github.com/devtron-labs/devtron/pkg/fluxApplication" + bean3 "github.com/devtron-labs/devtron/pkg/fluxApplication/bean" "strconv" "time" @@ -69,6 +71,7 @@ type ServiceImpl struct { k8sCommonService k8s.K8sCommonService environmentReadService read2.EnvironmentReadService asyncRunnable *async.Runnable + fluxApplicationService fluxApplication.FluxApplicationService } func NewServiceImpl(logger *zap.SugaredLogger, @@ -82,6 +85,7 @@ func NewServiceImpl(logger *zap.SugaredLogger, k8sCommonService k8s.K8sCommonService, environmentReadService read2.EnvironmentReadService, asyncRunnable *async.Runnable, + fluxApplicationService fluxApplication.FluxApplicationService, ) *ServiceImpl { serviceImpl := &ServiceImpl{ logger: logger, @@ -95,6 +99,7 @@ func NewServiceImpl(logger *zap.SugaredLogger, k8sCommonService: k8sCommonService, environmentReadService: environmentReadService, asyncRunnable: asyncRunnable, + fluxApplicationService: fluxApplicationService, } return serviceImpl } @@ -228,6 +233,32 @@ func (impl *ServiceImpl) FetchResourceTree(ctx context.Context, appId int, envId } impl.logger.Warnw("appName and envName not found - avoiding resource tree call", "app", cdPipeline.DeploymentAppName, "env", cdPipeline.Environment.Name) } + } else if len(cdPipeline.DeploymentAppName) > 0 && cdPipeline.EnvironmentId > 0 && util.IsFluxApp(deploymentConfig.DeploymentAppType) { + req := &bean3.FluxAppIdentifier{ + ClusterId: cdPipeline.Environment.ClusterId, + Namespace: cdPipeline.Environment.Namespace, + Name: cdPipeline.DeploymentAppName, + IsKustomizeApp: false, + } + detail, err := impl.fluxApplicationService.GetFluxAppDetail(ctx, req) + if err != nil { + impl.logger.Errorw("error in fetching app detail", "payload", req, "err", err) + } + resourceTree = util2.InterfaceToMapAdapter(detail.ResourceTreeResponse) + applicationStatus := detail.AppHealthStatus + if detail != nil && detail.ResourceTreeResponse != nil && len(detail.ResourceTreeResponse.Nodes) == 0 { + resourceTree["status"] = k8sCommonBean.HealthStatusUnknown + } else { + resourceTree["status"] = applicationStatus + } + if applicationStatus == argoApplication.Healthy { + status, err := impl.appListingService.ISLastReleaseStopType(appId, envId) + if err != nil { + impl.logger.Errorw("service err, FetchAppDetailsV2", "err", err, "app", appId, "env", envId) + } else if status { + resourceTree["status"] = argoApplication.HIBERNATING + } + } } else { impl.logger.Warnw("appName and envName not found - avoiding resource tree call", "app", cdPipeline.DeploymentAppName, "env", cdPipeline.Environment.Name) } diff --git a/pkg/deployment/gitOps/config/GitOpsConfigReadService.go b/pkg/deployment/gitOps/config/GitOpsConfigReadService.go index d60c085879..489ca824e4 100644 --- a/pkg/deployment/gitOps/config/GitOpsConfigReadService.go +++ b/pkg/deployment/gitOps/config/GitOpsConfigReadService.go @@ -19,6 +19,7 @@ package config import ( "errors" "fmt" + bean3 "github.com/devtron-labs/devtron/api/bean" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -47,6 +48,7 @@ type GitOpsConfigReadService interface { GetGitOpsRepoNameFromUrl(gitRepoUrl string) string GetBitbucketMetadata() (*bean.BitbucketProviderMetadata, error) GetGitOpsConfigActive() (*bean2.GitOpsConfigDto, error) + GetAllGitOpsConfig() ([]*bean2.GitOpsConfigDto, error) GetConfiguredGitOpsCount() (int, error) GetGitOpsProviderByRepoURL(gitRepoUrl string) (*bean2.GitOpsConfigDto, error) GetGitOpsById(id int) (*bean2.GitOpsConfigDto, error) @@ -161,6 +163,39 @@ func (impl *GitOpsConfigReadServiceImpl) GetGitOpsConfigActive() (*bean2.GitOpsC return adapter.GetGitOpsConfigBean(model), err } +func (impl *GitOpsConfigReadServiceImpl) GetAllGitOpsConfig() ([]*bean2.GitOpsConfigDto, error) { + models, err := impl.gitOpsRepository.GetAllGitOpsConfig() + if err != nil { + impl.logger.Errorw("error, GetGitOpsConfigActive", "err", err) + return nil, err + } + configs := make([]*bean2.GitOpsConfigDto, 0, len(models)) + for _, model := range models { + configs = append(configs, &bean2.GitOpsConfigDto{ + Id: model.Id, + Provider: model.Provider, + GitHubOrgId: model.GitHubOrgId, + GitLabGroupId: model.GitLabGroupId, + Active: model.Active, + Token: model.Token, + Host: model.Host, + Username: model.Username, + UserId: model.CreatedBy, + AzureProjectName: model.AzureProject, + BitBucketWorkspaceId: model.BitBucketWorkspaceId, + BitBucketProjectKey: model.BitBucketProjectKey, + AllowCustomRepository: model.AllowCustomRepository, + TLSConfig: &bean3.TLSConfig{ + CaData: model.CaCert, + TLSCertData: model.TlsCert, + TLSKeyData: model.TlsKey, + }, + EnableTLSVerification: model.EnableTLSVerification, + }) + } + return configs, err +} + func (impl *GitOpsConfigReadServiceImpl) GetConfiguredGitOpsCount() (int, error) { count, err := impl.gitOpsRepository.GetAllGitOpsConfigCount() return count, err diff --git a/pkg/deployment/gitOps/git/GitFactory.go b/pkg/deployment/gitOps/git/GitFactory.go index 301a93682f..6cf677c489 100644 --- a/pkg/deployment/gitOps/git/GitFactory.go +++ b/pkg/deployment/gitOps/git/GitFactory.go @@ -23,6 +23,7 @@ import ( "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/adapter" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" "github.com/devtron-labs/devtron/util" "github.com/go-pg/pg" "github.com/xanzy/go-gitlab" @@ -31,9 +32,14 @@ import ( ) type GitFactory struct { - Client GitOpsClient - GitOpsHelper *GitOpsHelper - logger *zap.SugaredLogger + Client GitOpsClient + GitOpsHelper *GitOpsHelper + logger *zap.SugaredLogger + ClientHelperMap map[string]*ClientHelperObject +} + +type ClientHelperObject struct { + Config *bean.GitConfig } func (factory *GitFactory) Reload(gitOpsConfigReadService config.GitOpsConfigReadService) (err error) { @@ -42,21 +48,31 @@ func (factory *GitFactory) Reload(gitOpsConfigReadService config.GitOpsConfigRea util.TriggerGitOpsMetrics("Reload", "GitService", start, err) }() factory.logger.Infow("reloading gitops details") - gitConfig, err := gitOpsConfigReadService.GetGitConfig() + cfgs, err := GetGitConfigAll(gitOpsConfigReadService) if err != nil && !errors.Is(err, pg.ErrNoRows) { - factory.logger.Errorw("error in getting gitops config", "err", err) return err - } else if errors.Is(err, pg.ErrNoRows) || gitConfig == nil { + } else if errors.Is(err, pg.ErrNoRows) || len(cfgs) == 0 { factory.logger.Warn("no gitops config found, gitops will not work") return nil } - factory.GitOpsHelper.SetAuth(gitConfig.GetAuth()) - client, err := NewGitOpsClient(gitConfig, factory.logger, factory.GitOpsHelper) - if err != nil { - return err + clientHelperMap := make(map[string]*ClientHelperObject, len(cfgs)) + for _, cfg := range cfgs { + gitOpsHelper, _ := NewGitOpsHelperImpl(cfg.GetAuth(), factory.logger, cfg.GetTLSConfig(), cfg.EnableTLSVerification) + client, clientCreationError := NewGitOpsClient(cfg, factory.logger, gitOpsHelper) + if clientCreationError != nil && cfg.IsActiveConfig { // only passing error in case of active config + return err + } + host := cfg.GitHost + clientHelperMap[host] = &ClientHelperObject{ + Config: cfg, + } + if cfg.IsActiveConfig { //also setting in old client and gitOps helper with active config + factory.Client = client + factory.GitOpsHelper = gitOpsHelper + } } - factory.Client = client - factory.logger.Infow("gitops details reload success") + factory.ClientHelperMap = clientHelperMap + factory.logger.Infow(" gitops details reload success") return nil } @@ -69,7 +85,7 @@ func (factory *GitFactory) GetGitLabGroupPath(gitOpsConfig *gitOps.GitOpsConfigD var tlsConfig *tls.Config if gitOpsConfig.TLSConfig != nil { - tlsConfig, err = util.GetTlsConfig(gitOpsConfig.TLSConfig.TLSKeyData, gitOpsConfig.TLSConfig.TLSCertData, gitOpsConfig.TLSConfig.CaData, GIT_TLS_DIR) + tlsConfig, err = util.GetTlsConfig(gitOpsConfig.TLSConfig.TLSKeyData, gitOpsConfig.TLSConfig.TLSCertData, gitOpsConfig.TLSConfig.CaData, bean.GIT_TLS_DIR) if err != nil { factory.logger.Errorw("error in getting tls config", "err", err) return "", err @@ -118,31 +134,16 @@ func (factory *GitFactory) NewClientForValidation(gitOpsConfig *gitOps.GitOpsCon } func NewGitFactory(logger *zap.SugaredLogger, gitOpsConfigReadService config.GitOpsConfigReadService) (*GitFactory, error) { - gitFactory := &GitFactory{ + factory := &GitFactory{ logger: logger, } - gitConfig, err := gitOpsConfigReadService.GetGitConfig() - if err != nil && !errors.Is(err, pg.ErrNoRows) { - logger.Errorw("error in getting gitops config", "err", err) - return gitFactory, err - } else if errors.Is(err, pg.ErrNoRows) || gitConfig == nil { - logger.Warn("no gitops config found, gitops will not work") - return gitFactory, nil - } - gitOpsHelper, err := NewGitOpsHelperImpl(gitConfig.GetAuth(), logger, gitConfig.GetTLSConfig(), gitConfig.EnableTLSVerification) - if err != nil { - logger.Errorw("error in creating gitOps helper", "gitProvider", gitConfig.GitProvider, "err", err) - // error handling is skipped intentionally here, otherwise orchestration will not work - } - gitFactory.GitOpsHelper = gitOpsHelper - client, err := NewGitOpsClient(gitConfig, logger, gitOpsHelper) + err := factory.Reload(gitOpsConfigReadService) if err != nil { - logger.Errorw("error in creating gitOps client", "gitProvider", gitConfig.GitProvider, "err", err) + logger.Errorw("error NewGitFactory", "err", err) // error handling is skipped intentionally here, otherwise orchestration will not work } - if client == nil { - client = &UnimplementedGitOpsClient{} + if factory.Client == nil { + factory.Client = &UnimplementedGitOpsClient{} } - gitFactory.Client = client - return gitFactory, nil + return factory, nil } diff --git a/pkg/deployment/gitOps/git/GitOperationService.go b/pkg/deployment/gitOps/git/GitOperationService.go index 480d29abab..af3812d316 100644 --- a/pkg/deployment/gitOps/git/GitOperationService.go +++ b/pkg/deployment/gitOps/git/GitOperationService.go @@ -114,7 +114,7 @@ func (impl *GitOperationServiceImpl) CreateGitRepositoryForDevtronApp(ctx contex } func getChartDirPathFromCloneDir(cloneDirPath string) (string, error) { - return filepath.Rel(GIT_WORKING_DIR, cloneDirPath) + return filepath.Rel(bean.GIT_WORKING_DIR, cloneDirPath) } func (impl *GitOperationServiceImpl) PushChartToGitRepo(ctx context.Context, gitOpsRepoName, chartLocation, tempReferenceTemplateDir, repoUrl, targetRevision string, userId int32) (err error) { @@ -403,14 +403,14 @@ func (impl *GitOperationServiceImpl) ReloadGitOpsProvider() error { func (impl *GitOperationServiceImpl) UpdateGitHostUrlByProvider(request *apiBean.GitOpsConfigDto) error { switch strings.ToUpper(request.Provider) { - case GITHUB_PROVIDER: + case bean.GITHUB_PROVIDER: orgUrl, err := buildGithubOrgUrl(request.Host, request.GitHubOrgId) if err != nil { return err } request.Host = orgUrl - case GITLAB_PROVIDER: + case bean.GITLAB_PROVIDER: if request.EnableTLSVerification && (request.TLSConfig == nil || @@ -437,7 +437,7 @@ func (impl *GitOperationServiceImpl) UpdateGitHostUrlByProvider(request *apiBean } else { request.Host = fmt.Sprintf(request.Host+"/%s", groupName) } - case BITBUCKET_PROVIDER: + case bean.BITBUCKET_PROVIDER: request.Host = BITBUCKET_CLONE_BASE_URL + request.BitBucketWorkspaceId } return nil diff --git a/pkg/deployment/gitOps/git/GitOpsClient.go b/pkg/deployment/gitOps/git/GitOpsClient.go index 5b80136515..5df2e02c0f 100644 --- a/pkg/deployment/gitOps/git/GitOpsClient.go +++ b/pkg/deployment/gitOps/git/GitOpsClient.go @@ -20,8 +20,10 @@ import ( "context" "crypto/tls" "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" "github.com/devtron-labs/devtron/util" + "github.com/go-pg/pg" "go.uber.org/zap" "time" ) @@ -37,28 +39,58 @@ type GitOpsClient interface { CreateFirstCommitOnHead(ctx context.Context, config *gitOps.GitOpsConfigDto) (string, error) } +func GetGitConfigAll(gitOpsConfigReadService config.GitOpsConfigReadService) ([]*bean.GitConfig, error) { + gitOpsConfigs, err := gitOpsConfigReadService.GetAllGitOpsConfig() + if err != nil && err != pg.ErrNoRows { + return nil, err + } else if err == pg.ErrNoRows { + return nil, nil + } + cfgs := make([]*bean.GitConfig, 0, len(gitOpsConfigs)) + for _, gitOpsConfig := range gitOpsConfigs { + cfgs = append(cfgs, &bean.GitConfig{ + GitlabGroupId: gitOpsConfig.GitLabGroupId, + GitToken: gitOpsConfig.Token, + GitUserName: gitOpsConfig.Username, + GithubOrganization: gitOpsConfig.GitHubOrgId, + GitProvider: gitOpsConfig.Provider, + GitHost: gitOpsConfig.Host, + AzureToken: gitOpsConfig.Token, + AzureProject: gitOpsConfig.AzureProjectName, + BitbucketWorkspaceId: gitOpsConfig.BitBucketWorkspaceId, + BitbucketProjectKey: gitOpsConfig.BitBucketProjectKey, + IsActiveConfig: gitOpsConfig.Active, + CaCert: gitOpsConfig.TLSConfig.CaData, + TLSCert: gitOpsConfig.TLSConfig.TLSCertData, + TLSKey: gitOpsConfig.TLSConfig.TLSKeyData, + EnableTLSVerification: gitOpsConfig.EnableTLSVerification, + }) + } + return cfgs, nil +} + func NewGitOpsClient(config *bean.GitConfig, logger *zap.SugaredLogger, gitOpsHelper *GitOpsHelper) (GitOpsClient, error) { var tlsConfig *tls.Config var err error if config.EnableTLSVerification { - tlsConfig, err = util.GetTlsConfig(config.TLSKey, config.TLSCert, config.CaCert, GIT_TLS_DIR) + tlsConfig, err = util.GetTlsConfig(config.TLSKey, config.TLSCert, config.CaCert, bean.GIT_TLS_DIR) if err != nil { logger.Errorw("error in getting tls config", "err", err) return nil, err } } - if config.GitProvider == GITLAB_PROVIDER { + if config.GitProvider == bean.GITLAB_PROVIDER { gitLabClient, err := NewGitLabClient(config, logger, gitOpsHelper, tlsConfig) return gitLabClient, err - } else if config.GitProvider == GITHUB_PROVIDER { + } else if config.GitProvider == bean.GITHUB_PROVIDER { gitHubClient, err := NewGithubClient(config.GitHost, config.GitToken, config.GithubOrganization, logger, gitOpsHelper, tlsConfig) return gitHubClient, err - } else if config.GitProvider == AZURE_DEVOPS_PROVIDER { + } else if config.GitProvider == bean.AZURE_DEVOPS_PROVIDER { gitAzureClient, err := NewGitAzureClient(config.AzureToken, config.GitHost, config.AzureProject, logger, gitOpsHelper, tlsConfig) return gitAzureClient, err - } else if config.GitProvider == BITBUCKET_PROVIDER { + } else if config.GitProvider == bean.BITBUCKET_PROVIDER { gitBitbucketClient := NewGitBitbucketClient(config.GitUserName, config.GitToken, config.GitHost, logger, gitOpsHelper, tlsConfig) return gitBitbucketClient, nil } else { diff --git a/pkg/deployment/gitOps/git/GitOpsHelper.go b/pkg/deployment/gitOps/git/GitOpsHelper.go index 390b527664..aeab26ff7e 100644 --- a/pkg/deployment/gitOps/git/GitOpsHelper.go +++ b/pkg/deployment/gitOps/git/GitOpsHelper.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/devtron-labs/devtron/api/bean" apiGitOpsBean "github.com/devtron-labs/devtron/api/bean/gitOps" + bean2 "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" git "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/commandManager" "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/sliceUtil" @@ -63,7 +64,7 @@ func (impl *GitOpsHelper) GetCloneDirectory(targetDir string) (clonedDir string) defer func() { util.TriggerGitOpsMetrics("GetCloneDirectory", "GitService", start, nil) }() - clonedDir = filepath.Join(GIT_WORKING_DIR, targetDir) + clonedDir = filepath.Join(bean2.GIT_WORKING_DIR, targetDir) return clonedDir } @@ -88,7 +89,7 @@ func (impl *GitOpsHelper) Clone(url, targetDir, targetRevision string) (clonedDi func (impl *GitOpsHelper) cloneAndFetch(url, targetDir string) (ctx git.GitContext, clonedDir string, err error) { impl.logger.Debugw("git checkout ", "url", url, "dir", targetDir) - clonedDir = filepath.Join(GIT_WORKING_DIR, targetDir) + clonedDir = filepath.Join(bean2.GIT_WORKING_DIR, targetDir) ctx = git.BuildGitContext(context.Background()).WithCredentials(impl.Auth). WithTLSData(impl.tlsConfig.CaData, impl.tlsConfig.TLSKeyData, impl.tlsConfig.TLSCertData, impl.isTlsEnabled) err = impl.init(ctx, clonedDir, url, false) @@ -281,10 +282,10 @@ Case AZURE_DEVOPS_PROVIDER: */ func SanitiseCustomGitRepoURL(activeGitOpsConfig *apiGitOpsBean.GitOpsConfigDto, gitRepoURL string) (sanitisedGitRepoURL string) { sanitisedGitRepoURL = gitRepoURL - if activeGitOpsConfig.Provider == BITBUCKET_PROVIDER && strings.Contains(gitRepoURL, fmt.Sprintf("://%s@%s", activeGitOpsConfig.Username, "bitbucket.org/")) { + if activeGitOpsConfig.Provider == bean2.BITBUCKET_PROVIDER && strings.Contains(gitRepoURL, fmt.Sprintf("://%s@%s", activeGitOpsConfig.Username, "bitbucket.org/")) { sanitisedGitRepoURL = strings.ReplaceAll(gitRepoURL, fmt.Sprintf("://%s@%s", activeGitOpsConfig.Username, "bitbucket.org/"), "://bitbucket.org/") } - if activeGitOpsConfig.Provider == AZURE_DEVOPS_PROVIDER { + if activeGitOpsConfig.Provider == bean2.AZURE_DEVOPS_PROVIDER { azureDevopsOrgName := activeGitOpsConfig.Host[strings.LastIndex(activeGitOpsConfig.Host, "/")+1:] invalidBaseUrlFormat := fmt.Sprintf("://%s@%s", azureDevopsOrgName, "dev.azure.com/") if invalidBaseUrlFormat != "" && strings.Contains(gitRepoURL, invalidBaseUrlFormat) { diff --git a/pkg/deployment/gitOps/git/GitServiceAzure.go b/pkg/deployment/gitOps/git/GitServiceAzure.go index 6d042609aa..ed0b4ce76c 100644 --- a/pkg/deployment/gitOps/git/GitServiceAzure.go +++ b/pkg/deployment/gitOps/git/GitServiceAzure.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" globalUtil "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/gitUtil" "github.com/devtron-labs/devtron/util/retryFunc" @@ -112,12 +113,12 @@ func (impl GitAzureClient) CreateRepository(ctx context.Context, config *bean2.G url, repoExists, isEmpty, err = impl.repoExists(config.GitRepoName, impl.project) if err != nil { impl.logger.Errorw("error in communication with azure", "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[GetRepoUrlStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.GetRepoUrlStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) return "", false, isEmpty, detailedErrorGitOpsConfigActions } if repoExists { - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, GetRepoUrlStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.GetRepoUrlStage) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, nil) return url, false, isEmpty, detailedErrorGitOpsConfigActions } @@ -131,7 +132,7 @@ func (impl GitAzureClient) CreateRepository(ctx context.Context, config *bean2.G }) if err != nil { impl.logger.Errorw("error in creating repo azure", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateRepoStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateRepoStage] = err url, repoExists, isEmpty, err = impl.repoExists(config.GitRepoName, impl.project) if err != nil { impl.logger.Errorw("error in communication with azure", "err", err) @@ -142,45 +143,45 @@ func (impl GitAzureClient) CreateRepository(ctx context.Context, config *bean2.G } } impl.logger.Infow("repo created ", "r", operationReference.WebUrl) - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateRepoStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateRepoStage) validated, err := impl.ensureProjectAvailabilityOnHttp(config.GitRepoName) if err != nil { impl.logger.Errorw("error in ensuring project availability azure", "project", config.GitRepoName, "err", err) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err return *operationReference.WebUrl, true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneHttpStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneHttpStage) _, err = impl.CreateReadme(ctx, config) if err != nil { impl.logger.Errorw("error in creating readme azure", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateReadmeStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateReadmeStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) return *operationReference.WebUrl, true, isEmpty, detailedErrorGitOpsConfigActions } isEmpty = false //As we have created readme, repo is no longer empty - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateReadmeStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateReadmeStage) validated, err = impl.ensureProjectAvailabilityOnSsh(impl.project, *operationReference.WebUrl, config.TargetRevision) if err != nil { impl.logger.Errorw("error in ensuring project availability azure", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) return *operationReference.WebUrl, true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneSshStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneSshStage) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitAzureClient", start, nil) return *operationReference.WebUrl, true, isEmpty, detailedErrorGitOpsConfigActions } diff --git a/pkg/deployment/gitOps/git/GitServiceBitbucket.go b/pkg/deployment/gitOps/git/GitServiceBitbucket.go index bd8a4ace17..1a08db3ed5 100644 --- a/pkg/deployment/gitOps/git/GitServiceBitbucket.go +++ b/pkg/deployment/gitOps/git/GitServiceBitbucket.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/retryFunc" "github.com/devtron-labs/go-bitbucket" @@ -122,19 +123,19 @@ func (impl GitBitbucketClient) CreateRepository(ctx context.Context, config *bea repoUrl, repoExists, err := impl.repoExists(repoOptions) if err != nil { impl.logger.Errorw("error in communication with bitbucket", "repoOptions", repoOptions, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[GetRepoUrlStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.GetRepoUrlStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", false, isEmpty, detailedErrorGitOpsConfigActions } if repoExists { - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, GetRepoUrlStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.GetRepoUrlStage) util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, nil) return repoUrl, false, isEmpty, detailedErrorGitOpsConfigActions } _, err = impl.client.Repositories.Repository.Create(repoOptions) if err != nil { impl.logger.Errorw("error in creating repo bitbucket", "repoOptions", repoOptions, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateRepoStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateRepoStage] = err repoUrl, repoExists, err = impl.repoExists(repoOptions) if err != nil { impl.logger.Errorw("error in creating repo bitbucket", "repoOptions", repoOptions, "err", err) @@ -146,46 +147,46 @@ func (impl GitBitbucketClient) CreateRepository(ctx context.Context, config *bea } repoUrl = fmt.Sprintf(BITBUCKET_CLONE_BASE_URL+"%s/%s.git", repoOptions.Owner, repoOptions.RepoSlug) impl.logger.Infow("repo created ", "repoUrl", repoUrl) - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateRepoStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateRepoStage) validated, err := impl.ensureProjectAvailabilityOnHttp(repoOptions) if err != nil { impl.logger.Errorw("error in ensuring project availability bitbucket", "repoName", repoOptions.RepoSlug, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneHttpStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneHttpStage) _, err = impl.CreateReadme(ctx, config) if err != nil { impl.logger.Errorw("error in creating readme bitbucket", "repoName", repoOptions.RepoSlug, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateReadmeStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateReadmeStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateReadmeStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateReadmeStage) validated, err = impl.ensureProjectAvailabilityOnSsh(repoOptions, config.TargetRevision) if err != nil { impl.logger.Errorw("error in ensuring project availability bitbucket", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneSshStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneSshStage) util.TriggerGitOpsMetrics("CreateRepository", "GitBitbucketClient", start, nil) return repoUrl, true, isEmpty, detailedErrorGitOpsConfigActions } diff --git a/pkg/deployment/gitOps/git/GitServiceGithub.go b/pkg/deployment/gitOps/git/GitServiceGithub.go index c5831146ed..da916003fd 100644 --- a/pkg/deployment/gitOps/git/GitServiceGithub.go +++ b/pkg/deployment/gitOps/git/GitServiceGithub.go @@ -23,6 +23,7 @@ import ( "fmt" "github.com/devtron-labs/common-lib/utils/runTime" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" globalUtil "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/retryFunc" "github.com/google/go-github/github" @@ -62,11 +63,11 @@ func NewGithubClient(host string, token string, org string, logger *zap.SugaredL logger.Errorw("error in creating git client ", "host", hostUrl, "err", err) return GitHubClient{}, err } - if hostUrl.Host == GITHUB_HOST { + if hostUrl.Host == bean.GITHUB_HOST { client = github.NewClient(tc) } else { logger.Infow("creating github EnterpriseClient with org", "host", host, "org", org) - hostUrl.Path = path.Join(hostUrl.Path, GITHUB_API_V3) + hostUrl.Path = path.Join(hostUrl.Path, bean.GITHUB_API_V3) client, err = github.NewEnterpriseClient(hostUrl.String(), hostUrl.String(), tc) } @@ -120,13 +121,13 @@ func (impl GitHubClient) CreateRepository(ctx context.Context, config *bean2.Git repoExists = false } else { impl.logger.Errorw("error in creating github repo", "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[GetRepoUrlStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.GetRepoUrlStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return "", false, isEmpty, detailedErrorGitOpsConfigActions } } if repoExists { - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, GetRepoUrlStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.GetRepoUrlStage) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, nil) return url, false, isEmpty, detailedErrorGitOpsConfigActions } @@ -143,56 +144,56 @@ func (impl GitHubClient) CreateRepository(ctx context.Context, config *bean2.Git url, isEmpty, err = impl.GetRepoUrl(config) if err != nil { impl.logger.Errorw("error in getting github repo", "repo", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateRepoStage] = err1 + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateRepoStage] = err1 globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err1) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, GetRepoUrlStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.GetRepoUrlStage) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, nil) return url, false, isEmpty, detailedErrorGitOpsConfigActions } impl.logger.Infow("github repo created ", "r", r.CloneURL) - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateRepoStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateRepoStage) validated, err := impl.ensureProjectAvailabilityOnHttp(config) if err != nil { impl.logger.Errorw("error in ensuring project availability github", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return *r.CloneURL, true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneHttpStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneHttpStage) _, err = impl.CreateReadme(ctx, config) if err != nil { impl.logger.Errorw("error in creating readme github", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateReadmeStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateReadmeStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return *r.CloneURL, true, isEmpty, detailedErrorGitOpsConfigActions } isEmpty = false //As we have created readme, repo is no longer empty - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateReadmeStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateReadmeStage) validated, err = impl.ensureProjectAvailabilityOnSsh(config.GitRepoName, *r.CloneURL, config.TargetRevision) if err != nil { impl.logger.Errorw("error in ensuring project availability github", "project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return *r.CloneURL, true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneSshStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneSshStage) //_, err = impl.createReadme(name) globalUtil.TriggerGitOpsMetrics("CreateRepository", "GitHubClient", start, nil) return *r.CloneURL, true, isEmpty, detailedErrorGitOpsConfigActions diff --git a/pkg/deployment/gitOps/git/GitServiceGitlab.go b/pkg/deployment/gitOps/git/GitServiceGitlab.go index 75b1c0a0a8..89ae44a53b 100644 --- a/pkg/deployment/gitOps/git/GitServiceGitlab.go +++ b/pkg/deployment/gitOps/git/GitServiceGitlab.go @@ -141,18 +141,18 @@ func (impl GitLabClient) CreateRepository(ctx context.Context, config *bean2.Git repoUrl, isEmpty, err = impl.GetRepoUrl(config) if err != nil { impl.logger.Errorw("error in getting repo url ", "gitlab project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[GetRepoUrlStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.GetRepoUrlStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", false, isEmpty, detailedErrorGitOpsConfigActions } if len(repoUrl) > 0 { - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, GetRepoUrlStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.GetRepoUrlStage) util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, nil) return repoUrl, false, isEmpty, detailedErrorGitOpsConfigActions } else { url, err = impl.createProject(config.GitRepoName, config.Description) if err != nil { - detailedErrorGitOpsConfigActions.StageErrorMap[CreateRepoStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateRepoStage] = err repoUrl, isEmpty, err = impl.GetRepoUrl(config) if err != nil { impl.logger.Errorw("error in getting repo url ", "gitlab project", config.GitRepoName, "err", err) @@ -162,46 +162,46 @@ func (impl GitLabClient) CreateRepository(ctx context.Context, config *bean2.Git return "", true, isEmpty, detailedErrorGitOpsConfigActions } } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateRepoStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateRepoStage) } repoUrl = url validated, err := impl.ensureProjectAvailability(config.GitRepoName) if err != nil { impl.logger.Errorw("error in ensuring project availability ", "gitlab project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneHttpStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneHttpStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneHttpStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneHttpStage) _, err = impl.CreateReadme(ctx, config) if err != nil { impl.logger.Errorw("error in creating readme ", "gitlab project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CreateReadmeStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CreateReadmeStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } isEmpty = false //As we have created readme, repo is no longer empty - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CreateReadmeStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CreateReadmeStage) validated, err = impl.ensureProjectAvailabilityOnSsh(config.GitRepoName, repoUrl, config.TargetRevision) if err != nil { impl.logger.Errorw("error in ensuring project availability ", "gitlab project", config.GitRepoName, "err", err) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } if !validated { err = fmt.Errorf("unable to validate project:%s in given time", config.GitRepoName) - detailedErrorGitOpsConfigActions.StageErrorMap[CloneSshStage] = err + detailedErrorGitOpsConfigActions.StageErrorMap[bean.CloneSshStage] = err util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, err) return "", true, isEmpty, detailedErrorGitOpsConfigActions } - detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, CloneSshStage) + detailedErrorGitOpsConfigActions.SuccessfulStages = append(detailedErrorGitOpsConfigActions.SuccessfulStages, bean.CloneSshStage) util.TriggerGitOpsMetrics("CreateRepository", "GitLabClient", start, nil) return url, true, isEmpty, detailedErrorGitOpsConfigActions } diff --git a/pkg/deployment/gitOps/git/bean/bean.go b/pkg/deployment/gitOps/git/bean/bean.go index 2eacaeb8d1..acfcb5f176 100644 --- a/pkg/deployment/gitOps/git/bean/bean.go +++ b/pkg/deployment/gitOps/git/bean/bean.go @@ -34,6 +34,8 @@ type GitConfig struct { BitbucketWorkspaceId string BitbucketProjectKey string + IsActiveConfig bool //flag to check if the gitOps config is active + EnableTLSVerification bool CaCert string TLSCert string diff --git a/pkg/deployment/gitOps/git/constants.go b/pkg/deployment/gitOps/git/bean/constants.go similarity index 94% rename from pkg/deployment/gitOps/git/constants.go rename to pkg/deployment/gitOps/git/bean/constants.go index 2851d9e4ed..911e8be75c 100644 --- a/pkg/deployment/gitOps/git/constants.go +++ b/pkg/deployment/gitOps/git/bean/constants.go @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package git +package bean const ( GIT_WORKING_DIR = "/tmp/gitops/" diff --git a/pkg/deployment/gitOps/validation/bean/bean.go b/pkg/deployment/gitOps/validation/bean/bean.go index af8baa2e22..784d20aa51 100644 --- a/pkg/deployment/gitOps/validation/bean/bean.go +++ b/pkg/deployment/gitOps/validation/bean/bean.go @@ -22,6 +22,7 @@ type ValidateGitOpsRepoUrlRequest struct { RequestedGitUrl string DesiredGitUrl string UseActiveGitOps bool + AppId int } type ValidateGitOpsRepoRequest struct { diff --git a/pkg/deployment/gitOps/validation/gitOpsValidationService.go b/pkg/deployment/gitOps/validation/gitOpsValidationService.go index 77d903488a..39bfa91c28 100644 --- a/pkg/deployment/gitOps/validation/gitOpsValidationService.go +++ b/pkg/deployment/gitOps/validation/gitOpsValidationService.go @@ -28,6 +28,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config/bean" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git" + bean2 "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" gitOpsBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/validation/bean" globalUtil "github.com/devtron-labs/devtron/util" "github.com/microsoft/azure-devops-go-api/azuredevops" @@ -180,7 +181,7 @@ func (impl *GitOpsValidationServiceImpl) ValidateGitOpsRepoUrl(request *gitOpsBe // Validate: Organisational URL ends // Validate: Unique GitOps repository URL starts - isValid := impl.validateUniqueGitOpsRepo(sanitiseGitRepoUrl) + isValid := impl.validateUniqueGitOpsRepo(sanitiseGitRepoUrl, request.AppId) if !isValid { impl.logger.Errorw("git repo url already exists", "repo url", request.RequestedGitUrl) errMsg := fmt.Sprintf("invalid git repository! '%s' is already in use by another application! Use a different repository", request.RequestedGitUrl) @@ -290,14 +291,14 @@ func (impl *GitOpsValidationServiceImpl) validateForGitOpsOrg(request *gitOpsBea func (impl *GitOpsValidationServiceImpl) extractErrorMessageByProvider(err error, provider string) error { switch provider { - case git.GITLAB_PROVIDER: + case bean2.GITLAB_PROVIDER: errorResponse, ok := err.(*gitlab.ErrorResponse) if ok { errorMessage := fmt.Errorf("gitlab client error: %s", errorResponse.Message) return errorMessage } return fmt.Errorf("gitlab client error: %s", err.Error()) - case git.AZURE_DEVOPS_PROVIDER: + case bean2.AZURE_DEVOPS_PROVIDER: if errorResponse, ok := err.(azuredevops.WrappedError); ok { errorMessage := fmt.Errorf("azure devops client error: %s", *errorResponse.Message) return errorMessage @@ -306,9 +307,9 @@ func (impl *GitOpsValidationServiceImpl) extractErrorMessageByProvider(err error return errorMessage } return fmt.Errorf("azure devops client error: %s", err.Error()) - case git.BITBUCKET_PROVIDER: + case bean2.BITBUCKET_PROVIDER: return fmt.Errorf("bitbucket client error: %s", err.Error()) - case git.GITHUB_PROVIDER: + case bean2.GITHUB_PROVIDER: return fmt.Errorf("github client error: %s", err.Error()) } return err @@ -328,19 +329,19 @@ func (impl *GitOpsValidationServiceImpl) convertDetailedErrorToResponse(detailed func (impl *GitOpsValidationServiceImpl) getValidationErrorForNonOrganisationalURL(activeGitOpsConfig *apiBean.GitOpsConfigDto) error { var errorMessageKey, errorMessage string switch strings.ToUpper(activeGitOpsConfig.Provider) { - case git.GITHUB_PROVIDER: + case bean2.GITHUB_PROVIDER: errorMessageKey = "The repository must belong to GitHub organization" errorMessage = fmt.Sprintf("%s as configured in global configurations > GitOps", activeGitOpsConfig.GitHubOrgId) - case git.GITLAB_PROVIDER: + case bean2.GITLAB_PROVIDER: errorMessageKey = "The repository must belong to gitLab Group ID" errorMessage = fmt.Sprintf("%s as configured in global configurations > GitOps", activeGitOpsConfig.GitHubOrgId) - case git.BITBUCKET_PROVIDER: + case bean2.BITBUCKET_PROVIDER: errorMessageKey = "The repository must belong to BitBucket Workspace" errorMessage = fmt.Sprintf("%s as configured in global configurations > GitOps", activeGitOpsConfig.BitBucketWorkspaceId) - case git.AZURE_DEVOPS_PROVIDER: + case bean2.AZURE_DEVOPS_PROVIDER: errorMessageKey = "The repository must belong to Azure DevOps Project" errorMessage = fmt.Sprintf("%s as configured in global configurations > GitOps", activeGitOpsConfig.AzureProjectName) } @@ -349,12 +350,12 @@ func (impl *GitOpsValidationServiceImpl) getValidationErrorForNonOrganisationalU WithCode(constants.GitOpsOrganisationMismatch) } -func (impl *GitOpsValidationServiceImpl) validateUniqueGitOpsRepo(repoUrl string) (isValid bool) { - isDevtronAppRegistered, err := impl.chartService.IsGitOpsRepoAlreadyRegistered(repoUrl) +func (impl *GitOpsValidationServiceImpl) validateUniqueGitOpsRepo(repoUrl string, appId int) (isValid bool) { + isDevtronAppRegistered, err := impl.chartService.IsGitOpsRepoAlreadyRegistered(repoUrl, appId) if err != nil || isDevtronAppRegistered { return isValid } - isHelmAppRegistered, err := impl.installedAppService.IsGitOpsRepoAlreadyRegistered(repoUrl) + isHelmAppRegistered, err := impl.installedAppService.IsGitOpsRepoAlreadyRegistered(repoUrl, appId) if err != nil || isHelmAppRegistered { return isValid } diff --git a/pkg/deployment/manifest/publish/ManifestPushService.go b/pkg/deployment/manifest/publish/ManifestPushService.go index 6bdb30687a..bfb896f7a7 100644 --- a/pkg/deployment/manifest/publish/ManifestPushService.go +++ b/pkg/deployment/manifest/publish/ManifestPushService.go @@ -216,7 +216,7 @@ func (impl *GitOpsManifestPushServiceImpl) PushChart(ctx context.Context, manife } gitCommitTimeline := impl.pipelineStatusTimelineService.NewDevtronAppPipelineStatusTimelineDbObject(manifestPushTemplate.WorkflowRunnerId, timelineStatus.TIMELINE_STATUS_GIT_COMMIT, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_GIT_COMMIT, manifestPushTemplate.UserId) timelines := []*pipelineConfig.PipelineStatusTimeline{gitCommitTimeline} - if impl.acdConfig.IsManualSyncEnabled() && manifestPushTemplate.IsArgoSyncSupported { + if impl.acdConfig.IsManualSyncEnabled() && manifestPushTemplate.ArgoSyncNeeded { // if manual sync is enabled, add ARGOCD_SYNC_INITIATED_TIMELINE argoCDSyncInitiatedTimeline := impl.pipelineStatusTimelineService.NewDevtronAppPipelineStatusTimelineDbObject(manifestPushTemplate.WorkflowRunnerId, timelineStatus.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, timelineStatus.TIMELINE_DESCRIPTION_ARGOCD_SYNC_INITIATED, manifestPushTemplate.UserId) timelines = append(timelines, argoCDSyncInitiatedTimeline) diff --git a/pkg/deployment/providerConfig/DeploymentTypeOverrideService.go b/pkg/deployment/providerConfig/DeploymentTypeOverrideService.go index 62309ffb5a..b82dc998a6 100644 --- a/pkg/deployment/providerConfig/DeploymentTypeOverrideService.go +++ b/pkg/deployment/providerConfig/DeploymentTypeOverrideService.go @@ -62,6 +62,7 @@ func (impl *DeploymentTypeOverrideServiceImpl) ValidateAndOverrideDeploymentAppT AllowedDeploymentAppTypes := map[string]bool{ util2.PIPELINE_DEPLOYMENT_TYPE_ACD: true, util2.PIPELINE_DEPLOYMENT_TYPE_HELM: true, + util2.PIPELINE_DEPLOYMENT_TYPE_FLUX: true, } for k, v := range deploymentTypeValidationConfig { // rewriting allowed deployment types based on config provided by user @@ -72,11 +73,15 @@ func (impl *DeploymentTypeOverrideServiceImpl) ValidateAndOverrideDeploymentAppT overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_ACD } else if AllowedDeploymentAppTypes[util2.PIPELINE_DEPLOYMENT_TYPE_HELM] { overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_HELM + } else if AllowedDeploymentAppTypes[util2.PIPELINE_DEPLOYMENT_TYPE_FLUX] { + overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_FLUX } } if deploymentType == "" { if isGitOpsConfigured && AllowedDeploymentAppTypes[util2.PIPELINE_DEPLOYMENT_TYPE_ACD] { overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_ACD + } else if isGitOpsConfigured && AllowedDeploymentAppTypes[util2.PIPELINE_DEPLOYMENT_TYPE_FLUX] { + overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_FLUX } else if AllowedDeploymentAppTypes[util2.PIPELINE_DEPLOYMENT_TYPE_HELM] { overrideDeploymentType = util2.PIPELINE_DEPLOYMENT_TYPE_HELM } @@ -85,7 +90,7 @@ func (impl *DeploymentTypeOverrideServiceImpl) ValidateAndOverrideDeploymentAppT impl.logger.Errorw("validation error for the given deployment type", "deploymentType", deploymentType, "err", err) return overrideDeploymentType, err } - if !isGitOpsConfigured && util2.IsAcdApp(overrideDeploymentType) { + if !isGitOpsConfigured && util2.IsAcdApp(overrideDeploymentType) && util2.IsFluxApp(overrideDeploymentType) { impl.logger.Errorw("GitOps not configured but selected as a deployment app type") err = &util2.ApiError{ HttpStatusCode: http.StatusBadRequest, diff --git a/pkg/deployment/trigger/devtronApps/HandlerService.go b/pkg/deployment/trigger/devtronApps/HandlerService.go index 460e3e1295..28ff4ca715 100644 --- a/pkg/deployment/trigger/devtronApps/HandlerService.go +++ b/pkg/deployment/trigger/devtronApps/HandlerService.go @@ -21,6 +21,7 @@ import ( "context" "github.com/devtron-labs/common-lib/async" service2 "github.com/devtron-labs/devtron/pkg/workflow/trigger/audit/service" + "github.com/devtron-labs/devtron/client/fluxcd" "os" "time" @@ -172,6 +173,7 @@ type HandlerServiceImpl struct { deploymentEventHandler app.DeploymentEventHandler asyncRunnable *async.Runnable workflowTriggerAuditService service2.WorkflowTriggerAuditService + fluxCdDeploymentService fluxcd.DeploymentService } func NewHandlerServiceImpl(logger *zap.SugaredLogger, @@ -236,7 +238,7 @@ func NewHandlerServiceImpl(logger *zap.SugaredLogger, deploymentEventHandler app.DeploymentEventHandler, asyncRunnable *async.Runnable, workflowTriggerAuditService service2.WorkflowTriggerAuditService, -) (*HandlerServiceImpl, error) { + fluxCdDeploymentService fluxcd.DeploymentService) (*HandlerServiceImpl, error) { impl := &HandlerServiceImpl{ logger: logger, cdWorkflowCommonService: cdWorkflowCommonService, @@ -305,6 +307,7 @@ func NewHandlerServiceImpl(logger *zap.SugaredLogger, deploymentEventHandler: deploymentEventHandler, asyncRunnable: asyncRunnable, workflowTriggerAuditService: workflowTriggerAuditService, + fluxCdDeploymentService: fluxCdDeploymentService, } config, err := types.GetCdConfig() if err != nil { diff --git a/pkg/deployment/trigger/devtronApps/bean/bean.go b/pkg/deployment/trigger/devtronApps/bean/bean.go index cbf2e2e80a..7d67c8a4ae 100644 --- a/pkg/deployment/trigger/devtronApps/bean/bean.go +++ b/pkg/deployment/trigger/devtronApps/bean/bean.go @@ -79,6 +79,7 @@ type DeploymentType = string const ( Helm DeploymentType = "helm" ArgoCd DeploymentType = "argo_cd" + FluxCd DeploymentType = "flux_cd" ManifestDownload DeploymentType = "manifest_download" GitOpsWithoutDeployment DeploymentType = "git_ops_without_deployment" ) diff --git a/pkg/deployment/trigger/devtronApps/deployStageHandlerCode.go b/pkg/deployment/trigger/devtronApps/deployStageHandlerCode.go index 1b9cfbb136..8be669ae92 100644 --- a/pkg/deployment/trigger/devtronApps/deployStageHandlerCode.go +++ b/pkg/deployment/trigger/devtronApps/deployStageHandlerCode.go @@ -800,16 +800,17 @@ func (impl *HandlerServiceImpl) buildManifestPushTemplate(overrideRequest *bean3 } } } else { + manifestPushTemplate.ChartReferenceTemplate = valuesOverrideResponse.EnvOverride.Chart.ReferenceTemplate manifestPushTemplate.ChartName = valuesOverrideResponse.EnvOverride.Chart.ChartName manifestPushTemplate.ChartVersion = valuesOverrideResponse.EnvOverride.Chart.ChartVersion manifestPushTemplate.ChartLocation = valuesOverrideResponse.DeploymentConfig.GetChartLocation() manifestPushTemplate.RepoUrl = valuesOverrideResponse.DeploymentConfig.GetRepoURL() manifestPushTemplate.TargetRevision = valuesOverrideResponse.DeploymentConfig.GetTargetRevision() - manifestPushTemplate.ValuesFilePath = valuesOverrideResponse.DeploymentConfig.GetValuesFilePath() + manifestPushTemplate.ValuesFilePath = valuesOverrideResponse.DeploymentConfig.GetValuesFilePathForCommit() manifestPushTemplate.ReleaseMode = valuesOverrideResponse.DeploymentConfig.ReleaseMode manifestPushTemplate.IsCustomGitRepository = common.IsCustomGitOpsRepo(valuesOverrideResponse.DeploymentConfig.ConfigType) - manifestPushTemplate.IsArgoSyncSupported = valuesOverrideResponse.DeploymentConfig.IsArgoAppSyncAndRefreshSupported() + manifestPushTemplate.ArgoSyncNeeded = valuesOverrideResponse.DeploymentConfig.IsArgoAppSyncAndRefreshSupported() } return manifestPushTemplate, nil } @@ -826,6 +827,12 @@ func (impl *HandlerServiceImpl) deployApp(ctx context.Context, overrideRequest * impl.logger.Errorw("error in deploying app on ArgoCd", "err", err) return err } + } else if util.IsFluxApp(overrideRequest.DeploymentAppType) { + err = impl.deployFluxCdApp(newCtx, overrideRequest, valuesOverrideResponse) + if err != nil { + impl.logger.Errorw("error in deploying app on Flux", "err", err) + return err + } } else if util.IsHelmApp(overrideRequest.DeploymentAppType) { _, referenceChartByte, err = impl.createHelmAppForCdPipeline(newCtx, overrideRequest, valuesOverrideResponse) if err != nil { @@ -1261,6 +1268,9 @@ func (impl *HandlerServiceImpl) isDevtronAsyncInstallModeEnabled(overrideRequest } else if util.IsAcdApp(overrideRequest.DeploymentAppType) { return impl.isDevtronAsyncArgoCdInstallModeEnabledForApp(overrideRequest.AppId, overrideRequest.EnvId, overrideRequest.ForceSyncDeployment) + } else if util.IsFluxApp(overrideRequest.DeploymentAppType) { + // will need sanity and testing around flux cd + return false, nil } return false, nil } diff --git a/pkg/deployment/trigger/devtronApps/deployStageHandlerCodeFlux.go b/pkg/deployment/trigger/devtronApps/deployStageHandlerCodeFlux.go new file mode 100644 index 0000000000..83c1488991 --- /dev/null +++ b/pkg/deployment/trigger/devtronApps/deployStageHandlerCodeFlux.go @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package devtronApps + +import ( + "context" + bean3 "github.com/devtron-labs/devtron/api/bean" + "github.com/devtron-labs/devtron/client/fluxcd" + "github.com/devtron-labs/devtron/pkg/app" + "go.opentelemetry.io/otel" + "time" +) + +const ( + gitRepositoryReconcileInterval = 1 * time.Minute + helmReleaseReconcileInterval = 1 * time.Minute +) + +func (impl *HandlerServiceImpl) deployFluxCdApp(ctx context.Context, overrideRequest *bean3.ValuesOverrideRequest, + valuesOverrideResponse *app.ValuesOverrideResponse) error { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "HandlerServiceImpl.deployFluxCdApp") + defer span.End() + clusterConfig, err := impl.clusterService.GetClusterConfigByClusterId(overrideRequest.ClusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", overrideRequest.ClusterId, "error", err) + return err + } + req := &fluxcd.DeploymentRequest{ + ClusterConfig: clusterConfig, + DeploymentConfig: valuesOverrideResponse.DeploymentConfig, + IsAppCreated: valuesOverrideResponse.Pipeline != nil && valuesOverrideResponse.Pipeline.DeploymentAppCreated, + } + err = impl.fluxCdDeploymentService.DeployFluxCdApp(newCtx, req) + if err != nil { + impl.logger.Errorw("error in deploying FluxCdApp", "err", err) + return err + } + if !req.IsAppCreated { + //setting deploymentAppCreated = true + _, err = impl.updatePipeline(valuesOverrideResponse.Pipeline, overrideRequest.UserId) + if err != nil { + impl.logger.Errorw("error in update cd pipeline for deployment app created or not", "err", err) + return err + } + } + return nil +} diff --git a/pkg/deployment/trigger/devtronApps/helper/helper.go b/pkg/deployment/trigger/devtronApps/helper/helper.go index 4fa14195cf..5358678716 100644 --- a/pkg/deployment/trigger/devtronApps/helper/helper.go +++ b/pkg/deployment/trigger/devtronApps/helper/helper.go @@ -34,12 +34,14 @@ func NewTriggerEvent(deploymentAppType string, triggeredAt time.Time, deployedBy TriggeredAt: triggeredAt, } switch deploymentAppType { - case bean.ArgoCd: + case bean.ArgoCd, bean.FluxCd: triggerEvent.PerformChartPush = true triggerEvent.PerformDeploymentOnCluster = true - triggerEvent.DeployArgoCdApp = true - triggerEvent.DeploymentAppType = bean.ArgoCd + triggerEvent.DeploymentAppType = deploymentAppType triggerEvent.ManifestStorageType = bean2.ManifestStorageGit + if deploymentAppType == bean.ArgoCd { + triggerEvent.DeployArgoCdApp = true + } case bean.Helm: triggerEvent.PerformChartPush = false triggerEvent.PerformDeploymentOnCluster = true diff --git a/pkg/fluxApplication/FluxApplicationService.go b/pkg/fluxApplication/FluxApplicationService.go index edb6d0264c..779b5b2c63 100644 --- a/pkg/fluxApplication/FluxApplicationService.go +++ b/pkg/fluxApplication/FluxApplicationService.go @@ -9,39 +9,51 @@ import ( openapi "github.com/devtron-labs/devtron/api/helm-app/openapiClient" "github.com/devtron-labs/devtron/api/helm-app/service" "github.com/devtron-labs/devtron/api/helm-app/service/read" + "github.com/devtron-labs/devtron/api/restHandler/common" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository" "github.com/devtron-labs/devtron/pkg/cluster" "github.com/devtron-labs/devtron/pkg/fluxApplication/bean" + "github.com/devtron-labs/devtron/util/sliceUtil" "github.com/gogo/protobuf/proto" "go.opentelemetry.io/otel" "go.uber.org/zap" + "io" "net/http" ) type FluxApplicationService interface { - ListFluxApplications(ctx context.Context, clusterIds []int, w http.ResponseWriter) + ListFluxApplications(ctx context.Context, clusterIds []int, noStream bool, w http.ResponseWriter) GetFluxAppDetail(ctx context.Context, app *bean.FluxAppIdentifier) (*bean.FluxApplicationDetailDto, error) HibernateFluxApplication(ctx context.Context, app *bean.FluxAppIdentifier, hibernateRequest *openapi.HibernateRequest) ([]*openapi.HibernateStatus, error) UnHibernateFluxApplication(ctx context.Context, app *bean.FluxAppIdentifier, hibernateRequest *openapi.HibernateRequest) ([]*openapi.HibernateStatus, error) } type FluxApplicationServiceImpl struct { - logger *zap.SugaredLogger - helmAppReadService read.HelmAppReadService - clusterService cluster.ClusterService - helmAppClient gRPC.HelmAppClient - pump connector.Pump + logger *zap.SugaredLogger + helmAppReadService read.HelmAppReadService + clusterService cluster.ClusterService + helmAppClient gRPC.HelmAppClient + pump connector.Pump + pipelineRepository pipelineConfig.PipelineRepository + installedAppRepository repository.InstalledAppRepository } func NewFluxApplicationServiceImpl(logger *zap.SugaredLogger, helmAppReadService read.HelmAppReadService, clusterService cluster.ClusterService, - helmAppClient gRPC.HelmAppClient, pump connector.Pump) *FluxApplicationServiceImpl { + helmAppClient gRPC.HelmAppClient, pump connector.Pump, + pipelineRepository pipelineConfig.PipelineRepository, + installedAppRepository repository.InstalledAppRepository) *FluxApplicationServiceImpl { return &FluxApplicationServiceImpl{ - logger: logger, - helmAppReadService: helmAppReadService, - clusterService: clusterService, - helmAppClient: helmAppClient, - pump: pump, + logger: logger, + helmAppReadService: helmAppReadService, + clusterService: clusterService, + helmAppClient: helmAppClient, + pump: pump, + pipelineRepository: pipelineRepository, + installedAppRepository: installedAppRepository, } } @@ -80,15 +92,98 @@ func (impl *FluxApplicationServiceImpl) UnHibernateFluxApplication(ctx context.C return response, nil } -func (impl *FluxApplicationServiceImpl) ListFluxApplications(ctx context.Context, clusterIds []int, w http.ResponseWriter) { +func (impl *FluxApplicationServiceImpl) ListFluxApplications(ctx context.Context, clusterIds []int, noStream bool, w http.ResponseWriter) { appStream, err := impl.listApplications(ctx, clusterIds) + if err != nil { + impl.logger.Errorw("error in listing flux applications", "clusterIds", clusterIds, "err", err) + return + } + + fluxCdPipelines, err := impl.pipelineRepository.GetAppAndEnvDetailsForDeploymentAppTypePipeline(util.PIPELINE_DEPLOYMENT_TYPE_FLUX, clusterIds) + if err != nil { + impl.logger.Errorw("error in fetching helm app list from DB created using cd_pipelines", "clusters", clusterIds, "err", err) + return + } + + installedHelmApps, err := impl.installedAppRepository.GetAppAndEnvDetailsForDeploymentAppTypeInstalledApps(util.PIPELINE_DEPLOYMENT_TYPE_FLUX, clusterIds) + if err != nil { + impl.logger.Errorw("error in fetching helm app list from DB created from app store", "clusters", clusterIds, "err", err) + return + } + + cdPipelineMap := make(map[string]map[string]bool) // map of clusterId-namespace, deploymentAppName + for _, p := range fluxCdPipelines { + key := fmt.Sprintf("%v-%s", p.Environment.ClusterId, p.Environment.Namespace) + if _, ok := cdPipelineMap[key]; !ok { + cdPipelineMap[key] = make(map[string]bool) + } + cdPipelineMap[key][p.DeploymentAppName] = true + } - impl.pump.StartStreamWithTransformer(w, func() (proto.Message, error) { - return appStream.Recv() - }, err, - func(message interface{}) interface{} { - return impl.appListRespProtoTransformer(message.(*gRPC.FluxApplicationList)) + installedAppMap := make(map[string]map[string]bool) + for _, i := range installedHelmApps { + key := fmt.Sprintf("%v-%s", i.Environment.ClusterId, i.Environment.Namespace) + if _, ok := installedAppMap[key]; !ok { + installedAppMap[key] = make(map[string]bool) + } + deploymentAppName := fmt.Sprintf("%s-%s", i.App.AppName, i.Environment.Namespace) + installedAppMap[key][deploymentAppName] = true + } + if !noStream { + impl.pump.StartStreamWithTransformer(w, func() (proto.Message, error) { + return appStream.Recv() + }, err, + func(message interface{}) interface{} { + return impl.appListRespProtoTransformer(message.(*gRPC.FluxApplicationList), cdPipelineMap, installedAppMap) + }) + } else { + fluxApps := make([]bean.FluxApplication, 0) + for { + appDetail, err := appStream.Recv() + if err == io.EOF { + break + } + if err != nil { + return + } + if appDetail.Errored { + appList := bean.FluxAppList{ + Errored: &appDetail.Errored, + ErrorMsg: &appDetail.ErrorMsg, + } + common.WriteJsonResp(w, nil, appList, http.StatusOK) + return + } else { + for _, deployedApp := range appDetail.FluxApplication { + key := fmt.Sprintf("%v-%s", deployedApp.EnvironmentDetail.ClusterId, deployedApp.EnvironmentDetail.Namespace) + if _, ok := cdPipelineMap[key][deployedApp.Name]; ok { + continue + } + if _, ok := installedAppMap[key][deployedApp.Name]; ok { + continue + } + fluxApp := bean.FluxApplication{ + Name: deployedApp.Name, + HealthStatus: deployedApp.HealthStatus, + SyncStatus: deployedApp.SyncStatus, + ClusterId: int(deployedApp.EnvironmentDetail.ClusterId), + ClusterName: deployedApp.EnvironmentDetail.ClusterName, + Namespace: deployedApp.EnvironmentDetail.Namespace, + FluxAppDeploymentType: deployedApp.FluxAppDeploymentType, + } + fluxApps = append(fluxApps, fluxApp) + } + } + } + clusterIdsInt32 := sliceUtil.NewSliceFromFuncExec(clusterIds, func(clusterId int) int32 { + return int32(clusterId) }) + appList := bean.FluxAppList{ + ClusterId: &clusterIdsInt32, + FluxApps: &fluxApps, + } + common.WriteJsonResp(w, nil, appList, http.StatusOK) + } } func (impl *FluxApplicationServiceImpl) GetFluxAppDetail(ctx context.Context, app *bean.FluxAppIdentifier) (*bean.FluxApplicationDetailDto, error) { config, err := impl.helmAppReadService.GetClusterConf(app.ClusterId) @@ -118,6 +213,8 @@ func (impl *FluxApplicationServiceImpl) GetFluxAppDetail(ctx context.Context, ap Message: fluxDetailResponse.FluxAppStatusDetail.GetMessage(), }, ResourceTreeResponse: fluxDetailResponse.ResourceTreeResponse, + AppHealthStatus: fluxDetailResponse.ApplicationStatus, + LastObservedVersion: fluxDetailResponse.GetLastObservedGeneration(), } return appDetail, nil @@ -155,22 +252,30 @@ func (impl *FluxApplicationServiceImpl) listApplications(ctx context.Context, cl return applicationStream, err } -func (impl *FluxApplicationServiceImpl) appListRespProtoTransformer(deployedApps *gRPC.FluxApplicationList) bean.FluxAppList { +func (impl *FluxApplicationServiceImpl) appListRespProtoTransformer(deployedApps *gRPC.FluxApplicationList, fluxCdPipelines map[string]map[string]bool, fluxInstalledApps map[string]map[string]bool) bean.FluxAppList { + appList := bean.FluxAppList{ClusterId: &[]int32{deployedApps.ClusterId}} if deployedApps.Errored { appList.Errored = &deployedApps.Errored appList.ErrorMsg = &deployedApps.ErrorMsg } else { fluxApps := make([]bean.FluxApplication, 0, len(deployedApps.FluxApplication)) - for _, deployedapp := range deployedApps.FluxApplication { + for _, deployedApp := range deployedApps.FluxApplication { + key := fmt.Sprintf("%v-%s", deployedApp.EnvironmentDetail.ClusterId, deployedApp.EnvironmentDetail.Namespace) + if _, ok := fluxCdPipelines[key][deployedApp.Name]; ok { + continue + } + if _, ok := fluxInstalledApps[key][deployedApp.Name]; ok { + continue + } fluxApp := bean.FluxApplication{ - Name: deployedapp.Name, - HealthStatus: deployedapp.HealthStatus, - SyncStatus: deployedapp.SyncStatus, - ClusterId: int(deployedapp.EnvironmentDetail.ClusterId), - ClusterName: deployedapp.EnvironmentDetail.ClusterName, - Namespace: deployedapp.EnvironmentDetail.Namespace, - FluxAppDeploymentType: deployedapp.FluxAppDeploymentType, + Name: deployedApp.Name, + HealthStatus: deployedApp.HealthStatus, + SyncStatus: deployedApp.SyncStatus, + ClusterId: int(deployedApp.EnvironmentDetail.ClusterId), + ClusterName: deployedApp.EnvironmentDetail.ClusterName, + Namespace: deployedApp.EnvironmentDetail.Namespace, + FluxAppDeploymentType: deployedApp.FluxAppDeploymentType, } fluxApps = append(fluxApps, fluxApp) } diff --git a/pkg/fluxApplication/bean/bean.go b/pkg/fluxApplication/bean/bean.go index 1d3c74dbc3..d9b06a6322 100644 --- a/pkg/fluxApplication/bean/bean.go +++ b/pkg/fluxApplication/bean/bean.go @@ -34,6 +34,8 @@ type FluxApplicationDetailDto struct { *FluxApplication FluxAppStatusDetail *FluxAppStatusDetail ResourceTreeResponse *gRPC.ResourceTreeResponse `json:"resourceTree"` + AppHealthStatus string `json:"appHealthStatus"` + LastObservedVersion string `json:"lastObservedVersion"` } type FluxAppStatusDetail struct { diff --git a/pkg/fluxApplication/bean/enums.go b/pkg/fluxApplication/bean/enums.go new file mode 100644 index 0000000000..17e452296c --- /dev/null +++ b/pkg/fluxApplication/bean/enums.go @@ -0,0 +1,51 @@ +package bean + +const ( + // InstallSucceededReason represents the fact that the Helm install for the + // HelmRelease succeeded. + InstallSucceededReason string = "InstallSucceeded" + + // InstallFailedReason represents the fact that the Helm install for the + // HelmRelease failed. + InstallFailedReason string = "InstallFailed" + + // UpgradeSucceededReason represents the fact that the Helm upgrade for the + // HelmRelease succeeded. + UpgradeSucceededReason string = "UpgradeSucceeded" + + // UpgradeFailedReason represents the fact that the Helm upgrade for the + // HelmRelease failed. + UpgradeFailedReason string = "UpgradeFailed" + + // TestSucceededReason represents the fact that the Helm tests for the + // HelmRelease succeeded. + TestSucceededReason string = "TestSucceeded" + + // TestFailedReason represents the fact that the Helm tests for the HelmRelease + // failed. + TestFailedReason string = "TestFailed" + + // RollbackSucceededReason represents the fact that the Helm rollback for the + // HelmRelease succeeded. + RollbackSucceededReason string = "RollbackSucceeded" + + // RollbackFailedReason represents the fact that the Helm test for the + // HelmRelease failed. + RollbackFailedReason string = "RollbackFailed" + + // UninstallSucceededReason represents the fact that the Helm uninstall for the + // HelmRelease succeeded. + UninstallSucceededReason string = "UninstallSucceeded" + + // UninstallFailedReason represents the fact that the Helm uninstall for the + // HelmRelease failed. + UninstallFailedReason string = "UninstallFailed" + + // ArtifactFailedReason represents the fact that the artifact download for the + // HelmRelease failed. + ArtifactFailedReason string = "ArtifactFailed" + + // DependencyNotReadyReason represents the fact that + // one of the dependencies is not ready. + DependencyNotReadyReason string = "DependencyNotReady" +) diff --git a/pkg/pipeline/CdHandler.go b/pkg/pipeline/CdHandler.go index 8d468eed6c..40e2ba41f4 100644 --- a/pkg/pipeline/CdHandler.go +++ b/pkg/pipeline/CdHandler.go @@ -56,6 +56,7 @@ import ( const ( DEVTRON_APP_HELM_PIPELINE_STATUS_UPDATE_CRON = "DTAppHelmPipelineStatusUpdateCron" DEVTRON_APP_ARGO_PIPELINE_STATUS_UPDATE_CRON = "DTAppArgoPipelineStatusUpdateCron" + DEVTRON_APP_FLUX_PIPELINE_STATUS_UPDATE_CRON = "DTAppFluxPipelineStatusUpdateCron" HELM_APP_ARGO_PIPELINE_STATUS_UPDATE_CRON = "HelmAppArgoPipelineStatusUpdateCron" ) diff --git a/pkg/pipeline/DeploymentPipelineConfigService.go b/pkg/pipeline/DeploymentPipelineConfigService.go index b0443eddc8..5e0a881f09 100644 --- a/pkg/pipeline/DeploymentPipelineConfigService.go +++ b/pkg/pipeline/DeploymentPipelineConfigService.go @@ -22,6 +22,7 @@ import ( errors3 "errors" "fmt" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/devtron-labs/common-lib/utils/k8s" commonBean2 "github.com/devtron-labs/common-lib/utils/k8s/commonBean" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/api/bean/gitOps" @@ -30,6 +31,7 @@ import ( helmBean "github.com/devtron-labs/devtron/api/helm-app/service/bean" read4 "github.com/devtron-labs/devtron/api/helm-app/service/read" "github.com/devtron-labs/devtron/client/argocdServer" + "github.com/devtron-labs/devtron/client/fluxcd" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/sql/models" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -53,6 +55,7 @@ import ( read2 "github.com/devtron-labs/devtron/pkg/cluster/read" repository2 "github.com/devtron-labs/devtron/pkg/cluster/repository" "github.com/devtron-labs/devtron/pkg/deployment/common" + adapter2 "github.com/devtron-labs/devtron/pkg/deployment/common/adapter" bean4 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" errors4 "github.com/devtron-labs/devtron/pkg/deployment/common/errors" commonBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/common/bean" @@ -82,15 +85,23 @@ import ( globalUtil "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/beHelper" "github.com/devtron-labs/devtron/util/rbac" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" "github.com/go-pg/pg" errors2 "github.com/juju/errors" "go.opentelemetry.io/otel" "go.uber.org/zap" chart2 "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" + v1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" "net/http" + "path" "path/filepath" + controllerClient "sigs.k8s.io/controller-runtime/pkg/client" "strconv" "strings" "time" @@ -107,6 +118,7 @@ type CdPipelineConfigService interface { CreateCdPipelines(cdPipelines *bean.CdPipelines, ctx context.Context) (*bean.CdPipelines, error) ValidateLinkExternalArgoCDRequest(request *pipelineConfigBean.MigrateReleaseValidationRequest) pipelineConfigBean.ExternalAppLinkValidationResponse ValidateLinkHelmAppRequest(ctx context.Context, request *pipelineConfigBean.MigrateReleaseValidationRequest) pipelineConfigBean.ExternalAppLinkValidationResponse + ValidateLinkFluxAppRequest(ctx context.Context, request *pipelineConfigBean.MigrateReleaseValidationRequest) pipelineConfigBean.ExternalAppLinkValidationResponse // PatchCdPipelines : Handle CD pipeline patch requests, making necessary changes to the configuration and returning the updated version. // Performs Create ,Update and Delete operation. PatchCdPipelines(cdPipelines *bean.CDPatchRequest, ctx context.Context) (*bean.CdPipelines, error) @@ -194,6 +206,8 @@ type CdPipelineConfigServiceImpl struct { installedAppReadService installedAppReader.InstalledAppReadService chartReadService read3.ChartReadService helmAppReadService read4.HelmAppReadService + K8sUtil *k8s.K8sServiceImpl + fluxCDDeploymentService fluxcd.DeploymentService } func NewCdPipelineConfigServiceImpl(logger *zap.SugaredLogger, pipelineRepository pipelineConfig.PipelineRepository, @@ -227,7 +241,9 @@ func NewCdPipelineConfigServiceImpl(logger *zap.SugaredLogger, pipelineRepositor clusterReadService read2.ClusterReadService, installedAppReadService installedAppReader.InstalledAppReadService, chartReadService read3.ChartReadService, - helmAppReadService read4.HelmAppReadService) *CdPipelineConfigServiceImpl { + helmAppReadService read4.HelmAppReadService, + K8sUtil *k8s.K8sServiceImpl, + fluxCDDeploymentService fluxcd.DeploymentService) *CdPipelineConfigServiceImpl { return &CdPipelineConfigServiceImpl{ logger: logger, pipelineRepository: pipelineRepository, @@ -273,6 +289,8 @@ func NewCdPipelineConfigServiceImpl(logger *zap.SugaredLogger, pipelineRepositor installedAppReadService: installedAppReadService, chartReadService: chartReadService, helmAppReadService: helmAppReadService, + K8sUtil: K8sUtil, + fluxCDDeploymentService: fluxCDDeploymentService, } } @@ -520,6 +538,14 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest linkCDValidationResponse.ErrorDetail.ValidationFailedMessage, string(linkCDValidationResponse.ErrorDetail.ValidationFailedReason)) } + } else if pipeline.IsExternalFluxAppLinkRequest() { + linkCDValidationResponse := impl.ValidateLinkFluxAppRequest(context.Background(), migrationReq) + if !linkCDValidationResponse.IsLinkable { + return nil, + util.NewApiError(http.StatusPreconditionFailed, + linkCDValidationResponse.ErrorDetail.ValidationFailedMessage, + string(linkCDValidationResponse.ErrorDetail.ValidationFailedReason)) + } } } @@ -529,8 +555,9 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest return nil, err } + isGitopsConfiguredAndFluxCDRequest := gitOpsConfigurationStatus.IsGitOpsConfigured && pipelineCreateRequest.Pipelines[0].DeploymentAppType == clutserBean.PIPELINE_DEPLOYMENT_TYPE_FLUX // TODO: creating git repo for all apps irrespective of acd or helm - if gitOpsConfigurationStatus.IsGitOpsConfiguredAndArgoCdInstalled() && + if (gitOpsConfigurationStatus.IsGitOpsConfiguredAndArgoCdInstalled() || isGitopsConfiguredAndFluxCDRequest) && impl.IsGitOpsRequiredForCD(pipelineCreateRequest) { //TODO: ayush revisit if gitOps.IsGitOpsRepoNotConfigured(appDeploymentConfig.GetRepoURL()) { @@ -548,10 +575,12 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest impl.logger.Errorw("error in creating git repo", "err", err) return nil, fmt.Errorf("Create GitOps repository error: %s", err.Error()) } - err = impl.RegisterInACD(ctx, chartGitAttr, pipelineCreateRequest.UserId) - if err != nil { - impl.logger.Errorw("error in registering app in acd", "err", err) - return nil, err + if pipelineCreateRequest.Pipelines[0].IsAcdDeploymentAppType() { + err = impl.RegisterInACD(ctx, chartGitAttr, pipelineCreateRequest.UserId) + if err != nil { + impl.logger.Errorw("error in registering app in acd", "err", err) + return nil, err + } } // below function will update gitRepoUrl for charts if user has not already provided gitOps repoURL appDeploymentConfig, err = impl.chartService.ConfigureGitOpsRepoUrlForApp(pipelineCreateRequest.AppId, chartGitAttr.RepoUrl, chartGitAttr.ChartLocation, false, pipelineCreateRequest.UserId) @@ -580,6 +609,7 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest Active: true, } var releaseConfig *bean4.ReleaseConfiguration + //TODO: abstract below code into function for getting release config if pipeline.IsExternalArgoAppLinkRequest() { releaseConfig, err = impl.parseReleaseConfigForExternalAcdApp(pipeline.ApplicationObjectClusterId, pipeline.ApplicationObjectNamespace, pipeline.DeploymentAppName) if err != nil { @@ -587,13 +617,27 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest return nil, err } envDeploymentConfig.ConfigType = bean4.CUSTOM.String() - } else if pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD { + } else if pipeline.IsExternalFluxAppLinkRequest() { + releaseConfig, err = impl.ParseReleaseConfigForExternalFluxCDApp(ctx, env.ClusterId, env.Namespace, pipeline.DeploymentAppName, env) + if err != nil { + impl.logger.Errorw("error in parsing deployment config for external flux app", "appId", pipeline.AppId, "envId", pipeline.EnvironmentId, "err", err) + return nil, err + } + envDeploymentConfig.ConfigType = bean4.CUSTOM.String() + } else if pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD && pipeline.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_CREATE { releaseConfig, err = impl.parseReleaseConfigForACDApp(app, appDeploymentConfig, env) if err != nil { impl.logger.Errorw("error in parsing deployment config for acd app", "appId", pipeline.AppId, "envId", pipeline.EnvironmentId, "err", err) return nil, err } envDeploymentConfig.ConfigType = appDeploymentConfig.ConfigType + } else if pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX && pipeline.GetReleaseMode() == util.PIPELINE_RELEASE_MODE_CREATE { + releaseConfig, err = impl.parseReleaseConfigForFluxApp(app, appDeploymentConfig, env) + if err != nil { + impl.logger.Errorw("error in parsing deployment config for helm app", "appId", pipeline.AppId, "envId", pipeline.EnvironmentId, "err", err) + return nil, err + } + envDeploymentConfig.ConfigType = appDeploymentConfig.ConfigType } envDeploymentConfig.ReleaseConfiguration = releaseConfig if releaseConfig != nil && releaseConfig.ArgoCDSpec.Spec.Source != nil { @@ -685,6 +729,137 @@ func (impl *CdPipelineConfigServiceImpl) parseReleaseConfigForACDApp(app *app2.A }, nil } +func (impl *CdPipelineConfigServiceImpl) parseReleaseConfigForFluxApp(app *app2.App, appDeploymentConfig *bean4.DeploymentConfig, env *repository6.Environment) (*bean4.ReleaseConfiguration, error) { + + envOverride, err := impl.envConfigOverrideService.FindLatestChartForAppByAppIdAndEnvId(app.Id, env.Id) + if err != nil && !errors2.IsNotFound(err) { + impl.logger.Errorw("error in fetch") + return nil, err + } + var latestChart *chartRepoRepository.Chart + if !envOverride.IsOverridden() { + latestChart, err = impl.chartRepository.FindLatestChartForAppByAppId(app.Id) + if err != nil { + return nil, err + } + } else { + //if chart is overrides in env, it means it may have different version than app level. + latestChart = envOverride.Chart + } + chartRefId := latestChart.ChartRefId + + chartRef, err := impl.chartRefReadService.FindById(chartRefId) + if err != nil { + impl.logger.Errorw("error in fetching chart", "chartRefId", chartRefId, "err", err) + return nil, err + } + + activeGitOpsConfig, err := impl.gitOpsConfigReadService.GetGitOpsConfigActive() + if err != nil { + impl.logger.Errorw("error in fetching active gitops config", "err", err) + return nil, err + } + + chartLocation := filepath.Join(chartRef.Location, latestChart.ChartVersion) + deploymentAppName := fmt.Sprintf("%s-%s", app.AppName, env.Name) + secretName := fmt.Sprintf("devtron-flux-secret-%d", activeGitOpsConfig.Id) + valueFileNameEnv := fmt.Sprintf("_%d-values.yaml", env.Id) + return adapter2.NewFluxSpecReleaseConfig(env.ClusterId, env.Namespace, deploymentAppName, env.Namespace, deploymentAppName, secretName, chartLocation, latestChart.ChartVersion, globalUtil.GetDefaultTargetRevision(), appDeploymentConfig.GetRepoURL(), valueFileNameEnv, getValuesFileArrForDevtronInlineApps(chartLocation), ""), nil +} + +func getValuesFileArrForDevtronInlineApps(chartLocation string) []string { + //order matters here, last file will override previous file + //for external flux apps this array might have some other data and we will add our devtronValueFileName (format: _{envId}-values.yaml) along with this array + return []string{path.Join(chartLocation, "values.yaml")} +} + +func (impl *CdPipelineConfigServiceImpl) ParseReleaseConfigForExternalFluxCDApp(ctx context.Context, clusterId int, namespace, fluxHelmReleaseName string, env *repository6.Environment) (*bean4.ReleaseConfiguration, error) { + + existingHelmRelease, existingGitRepository, err := impl.getExtFluxHelmReleaseAndGitRepository(ctx, clusterId, namespace, fluxHelmReleaseName) + if err != nil { + impl.logger.Errorw("error in fetching flux helm release", "clusterId", clusterId, "namespace", namespace, "err", err) + return nil, err + } + var gitRepositoryName, gitRepositoryNamespace, secretName, chartLocation, chartVersion, revision, repoURL, extValueFile string + var valuesFile []string + if existingHelmRelease != nil && existingHelmRelease.Spec.Chart != nil { + gitRepositoryName = existingHelmRelease.Spec.Chart.Spec.SourceRef.Name + gitRepositoryNamespace = existingHelmRelease.Spec.Chart.Spec.SourceRef.Namespace + chartLocation = existingHelmRelease.Spec.Chart.Spec.Chart + chartVersion = existingHelmRelease.Spec.Chart.Spec.Version + valuesFile = existingHelmRelease.Spec.Chart.Spec.ValuesFiles + extValueFile = existingHelmRelease.Spec.Values.String() + // assuming helm repo and git repository are in same namespace + } + if existingGitRepository != nil && existingGitRepository.Spec.SecretRef != nil { + secretName = existingGitRepository.Spec.SecretRef.Name + repoURL = existingGitRepository.Spec.URL + if existingGitRepository.Spec.Reference != nil { + revision = existingGitRepository.Spec.Reference.Branch + } + } + valueFileNameEnv := fmt.Sprintf("_%d-values.yaml", env.Id) + releaseConfig := adapter2.NewFluxSpecReleaseConfig(env.ClusterId, env.Namespace, gitRepositoryName, gitRepositoryNamespace, existingHelmRelease.Name, secretName, chartLocation, chartVersion, revision, repoURL, valueFileNameEnv, valuesFile, extValueFile) + return releaseConfig, nil +} + +func (impl *CdPipelineConfigServiceImpl) getExtFluxHelmReleaseAndGitRepository(ctx context.Context, clusterId int, namespace string, fluxHelmReleaseName string) (*helmv2.HelmRelease, *sourcev1.GitRepository, error) { + clusterConfig, err := impl.clusterReadService.GetClusterConfigByClusterId(clusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", clusterId, "error", err) + return nil, nil, err + } + + restConfig, err := impl.K8sUtil.GetRestConfigByCluster(clusterConfig) + if err != nil { + impl.logger.Errorw("error in getting rest config", "clusterId", clusterId, "err", err) + return nil, nil, err + } + + apiClient, err := getClient(restConfig) + if err != nil { + impl.logger.Errorw("error in creating k8s client", "clusterId", clusterId, "err", err) + return nil, nil, err + } + + key := types.NamespacedName{Name: fluxHelmReleaseName, Namespace: namespace} + existingHelmRelease := &helmv2.HelmRelease{} + err = apiClient.Get(ctx, key, existingHelmRelease) + if err != nil { + impl.logger.Errorw("error in getting helm release", "key", key, "err", err) + return nil, nil, err + } + + if existingHelmRelease != nil && existingHelmRelease.Spec.Chart != nil && existingHelmRelease.Spec.Chart.Spec.SourceRef.Kind != "GitRepository" { + return nil, nil, pipelineConfigBean.LinkFailedError{ + Reason: pipelineConfigBean.UnsupportedFluxHelmReleaseSpec, + UserMessage: fmt.Sprintf("invalid source repository kind %s", existingHelmRelease.Spec.Chart.Spec.SourceRef.Kind), + } + } + + var existingGitRepository *sourcev1.GitRepository + if existingHelmRelease != nil && existingHelmRelease.Spec.Chart != nil { + key := types.NamespacedName{Name: existingHelmRelease.Spec.Chart.Spec.SourceRef.Name, Namespace: existingHelmRelease.Spec.Chart.Spec.SourceRef.Namespace} + existingGitRepository = &sourcev1.GitRepository{} + err := apiClient.Get(ctx, key, existingGitRepository) + if err != nil { + impl.logger.Errorw("error in getting git repository", "key", key, "err", err) + return nil, nil, err + } + } + return existingHelmRelease, existingGitRepository, nil +} + +func getClient(config *rest.Config) (controllerClient.Client, error) { + scheme := runtime.NewScheme() + // Register core Kubernetes types + _ = v1.AddToScheme(scheme) + // Register Flux types + _ = sourcev1.AddToScheme(scheme) + _ = helmv2.AddToScheme(scheme) + return controllerClient.New(config, controllerClient.Options{Scheme: scheme}) +} + func (impl *CdPipelineConfigServiceImpl) ValidateLinkExternalArgoCDRequest(request *pipelineConfigBean.MigrateReleaseValidationRequest) pipelineConfigBean.ExternalAppLinkValidationResponse { appId := request.AppId @@ -720,7 +895,12 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkExternalArgoCDRequest(reque } response.ApplicationMetadata.UpdateEnvironmentData(targetEnv) - sanitisedRepoUrl, err := impl.validateGitOpsForExternalAcd(argoApplicationSpec) + var requestedGitUrl string + if argoApplicationSpec.Spec.Source != nil { + requestedGitUrl = argoApplicationSpec.Spec.Source.RepoURL + } + + sanitisedRepoUrl, err := impl.validateGitOpsForExternalApp(requestedGitUrl, appId) if err != nil { return response.SetErrorDetail(err) } @@ -730,7 +910,7 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkExternalArgoCDRequest(reque chartPath = argoApplicationSpec.Spec.Source.Path targetRevision = argoApplicationSpec.Spec.Source.TargetRevision } - helmChart, err := impl.extractHelmChartForExternalArgoApp(sanitisedRepoUrl, targetRevision, chartPath) + helmChart, err := impl.extractHelmChartForExternalArgoOrFluxApp(sanitisedRepoUrl, targetRevision, chartPath) if err != nil { impl.logger.Errorw("error in extracting helm chart from application spec", "acdAppName", acdAppName, "err", err) return response.SetUnknownErrorDetail(err) @@ -763,7 +943,7 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkExternalArgoCDRequest(reque } func (impl *CdPipelineConfigServiceImpl) ValidateDeploymentAppTypeForLinkRequest(targetEnvId int, expectedDeploymentAppType string, isGitOpsConfigured bool) error { - overrideDeploymentType, err := impl.deploymentTypeOverrideService.ValidateAndOverrideDeploymentAppType(util.PIPELINE_DEPLOYMENT_TYPE_ACD, isGitOpsConfigured, targetEnvId) + overrideDeploymentType, err := impl.deploymentTypeOverrideService.ValidateAndOverrideDeploymentAppType(expectedDeploymentAppType, isGitOpsConfigured, targetEnvId) if err != nil { impl.logger.Errorw("validation error for the used deployment type", "targetEnvId", targetEnvId, "deploymentAppType", expectedDeploymentAppType, "err", err) if apiError, ok := err.(*util.ApiError); ok && apiError.Code == constants.InvalidDeploymentAppTypeForPipeline { @@ -777,8 +957,8 @@ func (impl *CdPipelineConfigServiceImpl) ValidateDeploymentAppTypeForLinkRequest UserMessage: err.Error(), } } - if overrideDeploymentType != util.PIPELINE_DEPLOYMENT_TYPE_ACD { - errMsg := fmt.Sprintf("Cannot migrate Argo CD Application. Deployment via %q is enforced on the target environment.", overrideDeploymentType) + if overrideDeploymentType != expectedDeploymentAppType { + errMsg := fmt.Sprintf("Cannot migrate Externalgit. Deployment via %q is enforced on the target environment.", overrideDeploymentType) return pipelineConfigBean.LinkFailedError{ Reason: pipelineConfigBean.EnforcedPolicyViolation, UserMessage: errMsg, @@ -804,14 +984,12 @@ func (impl *CdPipelineConfigServiceImpl) validateIfChartVersionAvailableForChart return nil } -func (impl *CdPipelineConfigServiceImpl) validateGitOpsForExternalAcd(argoApplicationSpec *v1alpha1.Application) (string, error) { - var requestedGitUrl string - if argoApplicationSpec.Spec.Source != nil { - requestedGitUrl = argoApplicationSpec.Spec.Source.RepoURL - } +func (impl *CdPipelineConfigServiceImpl) validateGitOpsForExternalApp(requestedGitUrl string, appId int) (string, error) { + validateRequest := &validationBean.ValidateGitOpsRepoUrlRequest{ RequestedGitUrl: requestedGitUrl, UseActiveGitOps: true, // oss only supports active gitops + AppId: appId, } sanitisedRepoUrl, err := impl.gitOpsValidationService.ValidateGitOpsRepoUrl(validateRequest) if err != nil { @@ -868,7 +1046,7 @@ func (impl *CdPipelineConfigServiceImpl) ValidateAppChartTypeForLinkedApp(appId UserMessage: err.Error(), } } - if chartRef.Name != requiredChartName { + if impl.deploymentConfig.ValidateExtAppChart && chartRef.Name != requiredChartName { return chartRef, pipelineConfigBean.LinkFailedError{ Reason: pipelineConfigBean.ChartTypeMismatch, UserMessage: fmt.Sprintf(pipelineConfigBean.ChartTypeMismatchErrorMsg, requiredChartName, chartRef.Name), @@ -1033,8 +1211,8 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkHelmAppRequest(ctx context. appId := request.AppId - releaseClusterId := request.GetReleaseClusterId() - releaseNamespace := request.GetReleaseNamespace() + releaseClusterId := request.GetHelmReleaseClusterId() + releaseNamespace := request.GetHelmReleaseNamespace() release, err := impl.helmAppService.GetReleaseDetails(ctx, releaseClusterId, request.DeploymentAppName, releaseNamespace) if err != nil { @@ -1048,13 +1226,13 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkHelmAppRequest(ctx context. impl.logger.Errorw("error in getting cluster by id", "clusterId", releaseClusterId, "err", err) return response.SetUnknownErrorDetail(err) } - response.HelmReleaseMetadata.UpdateClusterData(cluster) + response.HelmReleaseMetadata.Destination.UpdateClusterData(cluster) targetEnv, err := impl.validateIfTargetEnvironmentAdded(releaseClusterId, releaseNamespace) if err != nil { return response.SetErrorDetail(err) } - response.HelmReleaseMetadata.UpdateEnvironmentMetadata(targetEnv) + response.HelmReleaseMetadata.Destination.UpdateEnvironmentMetadata(targetEnv) chartRef, err := impl.ValidateAppChartTypeForLinkedApp(appId, release.ChartName) if err != nil { @@ -1081,6 +1259,84 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkHelmAppRequest(ctx context. return response } +func (impl *CdPipelineConfigServiceImpl) ValidateLinkFluxAppRequest(ctx context.Context, request *pipelineConfigBean.MigrateReleaseValidationRequest) pipelineConfigBean.ExternalAppLinkValidationResponse { + + response := pipelineConfigBean.ExternalAppLinkValidationResponse{} + + appId := request.AppId + releaseClusterId := request.GetFluxReleaseClusterId() + releaseNamespace := request.GetFluxReleaseNamespace() + deploymentAppName := request.DeploymentAppName + + helmRelease, gitRepository, err := impl.getExtFluxHelmReleaseAndGitRepository(ctx, releaseClusterId, releaseNamespace, deploymentAppName) + if err != nil { + impl.logger.Errorw("error in fetching flux helm release", "clusterId", releaseClusterId, "namespace", releaseNamespace, "err", err) + return response.SetUnknownErrorDetail(err) + } + + var requestedGitUrl, branch, chartLocation string + + if helmRelease != nil { + chartLocation = helmRelease.Spec.Chart.Spec.Chart + } + if gitRepository != nil { + requestedGitUrl = gitRepository.Spec.URL + branch = gitRepository.Spec.Reference.Branch + } + + sanitisedRepoUrl, err := impl.validateGitOpsForExternalApp(requestedGitUrl, appId) + if err != nil { + return response.SetErrorDetail(err) + } + + helmChart, err := impl.extractHelmChartForExternalArgoOrFluxApp(sanitisedRepoUrl, branch, chartLocation) + if err != nil { + impl.logger.Errorw("error in extracting helm chart from external flux app", "fluxAppName", request.DeploymentAppName, "err", err) + return response.SetUnknownErrorDetail(err) + } + response.FluxReleaseMetadata.RequiredChartName = helmChart.Name() + response.FluxReleaseMetadata.RequiredChartVersion = helmChart.Metadata.Version + + chartRef, err := impl.ValidateAppChartTypeForLinkedApp(appId, response.FluxReleaseMetadata.RequiredChartName) + if err != nil { + if chartRef != nil { + response.FluxReleaseMetadata.SavedChartName = chartRef.Name + } + impl.logger.Errorw("error in finding chart configured for app ", "appId", appId, "err", err) + return response.SetErrorDetail(err) + } + response.FluxReleaseMetadata.SavedChartName = chartRef.Name + + if impl.deploymentConfig.ValidateExtAppChart { + err = impl.validateIfChartVersionAvailableForChart(chartRef, response.FluxReleaseMetadata.RequiredChartVersion) + if err != nil { + return response.SetErrorDetail(err) + } + } + + cluster, err := impl.clusterReadService.FindById(releaseClusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster by id", "clusterId", releaseClusterId, "err", err) + return response.SetUnknownErrorDetail(err) + } + response.FluxReleaseMetadata.Destination.UpdateClusterData(cluster) + + targetEnv, err := impl.validateIfTargetEnvironmentAdded(releaseClusterId, releaseNamespace) + if err != nil { + return response.SetErrorDetail(err) + } + response.FluxReleaseMetadata.Destination.UpdateEnvironmentMetadata(targetEnv) + + err = impl.ValidateDeploymentAppTypeForLinkRequest(targetEnv.Id, util.PIPELINE_DEPLOYMENT_TYPE_FLUX, true) + if err != nil { + return response.SetErrorDetail(err) + } + + response.IsLinkable = true + + return response +} + func (impl *CdPipelineConfigServiceImpl) CDPipelineCustomTagDBOperations(pipeline *bean.CDPipelineConfigObject) error { if pipeline.EnableCustomTag && (pipeline.CustomTagObject != nil && len(pipeline.CustomTagObject.TagPattern) == 0) { @@ -1474,6 +1730,22 @@ func (impl *CdPipelineConfigServiceImpl) DeleteCdPipeline(pipeline *pipelineConf } impl.logger.Infow("app deleted from argocd", "id", pipeline.Id, "pipelineName", pipeline.Name, "app", deploymentAppName) } + } else if util.IsFluxApp(envDeploymentConfig.DeploymentAppType) { + clusterConfig, err := impl.clusterReadService.GetClusterConfigByClusterId(clusterBean.Id) + if err != nil { + impl.logger.Errorw("error, GetClusterConfigByClusterId", "clusterId", clusterBean.Id, "err", err) + return nil, err + } + err = impl.fluxCDDeploymentService.DeleteFluxDeploymentApp(ctx, &fluxcd.DeploymentAppDeleteRequest{ + ClusterConfig: clusterConfig, + DeploymentConfig: envDeploymentConfig, + }) + if err != nil { + impl.logger.Errorw("error, DeleteFluxTypePipelineDeploymentApp", "err", err, "pipelineId", pipeline.Id) + if !forceDelete { + return deleteResponse, err + } + } } else if util.IsHelmApp(envDeploymentConfig.DeploymentAppType) { err = impl.DeleteHelmTypePipelineDeploymentApp(ctx, forceDelete, pipeline) if err != nil { @@ -1493,6 +1765,55 @@ func (impl *CdPipelineConfigServiceImpl) DeleteCdPipeline(pipeline *pipelineConf return deleteResponse, nil } +func (impl *CdPipelineConfigServiceImpl) DeleteFluxTypePipelineDeploymentApp(ctx context.Context, envDeploymentConfig *bean4.DeploymentConfig) error { + fluxCdSpec := envDeploymentConfig.ReleaseConfiguration.FluxCDSpec + clusterId := fluxCdSpec.ClusterId + clusterConfig, err := impl.clusterReadService.GetClusterConfigByClusterId(clusterId) + if err != nil { + impl.logger.Errorw("error in getting cluster", "clusterId", clusterId, "error", err) + return err + } + restConfig, err := impl.K8sUtil.GetRestConfigByCluster(clusterConfig) + if err != nil { + impl.logger.Errorw("error in getting rest config", "clusterId", clusterId, "err", err) + return err + } + + apiClient, err := getClient(restConfig) + if err != nil { + impl.logger.Errorw("error in creating k8s client", "clusterId", clusterId, "err", err) + return err + } + name, namespace := fluxCdSpec.HelmReleaseName, fluxCdSpec.HelmReleaseNamespace + key := types.NamespacedName{Name: name, Namespace: namespace} + + existingHelmRelease := &helmv2.HelmRelease{} + err = apiClient.Get(ctx, key, existingHelmRelease) + if err != nil { + impl.logger.Errorw("error in getting helm release", "key", key, "err", err) + return err + } + err = apiClient.Delete(ctx, existingHelmRelease) + if err != nil { + impl.logger.Errorw("error in deleting helm release", "key", key, "err", err) + return err + } + + key = types.NamespacedName{Name: fluxCdSpec.GitRepositoryName, Namespace: fluxCdSpec.GitRepositoryNamespace} + existingGitRepository := &sourcev1.GitRepository{} + err = apiClient.Get(ctx, key, existingGitRepository) + if err != nil { + impl.logger.Errorw("error in getting git repository", "key", key, "err", err) + return err + } + err = apiClient.Delete(ctx, existingGitRepository) + if err != nil { + impl.logger.Errorw("error in deleting git repository", "name", name, "namespace", namespace, "err", err) + return err + } + return nil +} + func (impl *CdPipelineConfigServiceImpl) DeleteHelmTypePipelineDeploymentApp(ctx context.Context, forceDelete bool, pipeline *pipelineConfig.Pipeline) error { deploymentAppName := pipeline.DeploymentAppName appIdentifier := &helmBean.AppIdentifier{ @@ -2059,8 +2380,9 @@ func (impl *CdPipelineConfigServiceImpl) IsGitOpsRequiredForCD(pipelineCreateReq haveAtLeastOneGitOps := false for _, pipeline := range pipelineCreateRequest.Pipelines { if pipeline.EnvironmentId > 0 && - pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD && - !pipeline.IsExternalArgoAppLinkRequest() { + (pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD && + !pipeline.IsExternalArgoAppLinkRequest()) || (pipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_FLUX && + !pipeline.IsExternalFluxAppLinkRequest()) { haveAtLeastOneGitOps = true } } @@ -2320,6 +2642,17 @@ func (impl *CdPipelineConfigServiceImpl) createCdPipeline(ctx context.Context, a impl.logger.Errorw("error in creating env override", "appId", app.Id, "envId", envOverride.TargetEnvironment, "err", err) return 0, err } + } else if pipeline.IsExternalFluxAppLinkRequest() { + overrideCreateRequest, err := impl.parseEnvOverrideCreateRequestForExternalFluxApp(deploymentConfig, latestChart, app, userId, pipeline, appLevelAppMetricsEnabled) + if err != nil { + impl.logger.Errorw("error in parsing override request for external acd app", "appId", app.Id, "err", err) + return 0, err + } + envOverride, updatedAppMetrics, err = impl.propertiesConfigService.CreateIfRequired(overrideCreateRequest, tx) + if err != nil { + impl.logger.Errorw("error in creating env override", "appId", app.Id, "envId", envOverride.TargetEnvironment, "err", err) + return 0, err + } } else { overrideCreateRequest := &pipelineConfigBean.EnvironmentOverrideCreateInternalDTO{ Chart: latestChart, @@ -2523,13 +2856,36 @@ func (impl *CdPipelineConfigServiceImpl) parseEnvOverrideCreateRequestForExterna return overrideCreateRequest, err } +func (impl *CdPipelineConfigServiceImpl) parseEnvOverrideCreateRequestForExternalFluxApp(deploymentConfig *bean4.DeploymentConfig, latestChart *chartRepoRepository.Chart, app *app2.App, userId int32, pipeline *bean.CDPipelineConfigObject, appLevelAppMetricsEnabled bool) (*pipelineConfigBean.EnvironmentOverrideCreateInternalDTO, error) { + values, _, err := impl.GetValuesAndChartMetadataForExternalFluxCDApp(deploymentConfig.ReleaseConfiguration.FluxCDSpec) + if err != nil { + impl.logger.Errorw("error in reading values for external argocd app", "acdAppName", deploymentConfig.ReleaseConfiguration.ArgoCDSpec.Metadata.Name, "err", err) + return nil, err + } + latestChart.GlobalOverride = string(values) + overrideCreateRequest := &pipelineConfigBean.EnvironmentOverrideCreateInternalDTO{ + Chart: latestChart, + EnvironmentId: pipeline.EnvironmentId, + UserId: userId, + ManualReviewed: false, + ChartStatus: models.CHARTSTATUS_NEW, + IsOverride: true, + IsAppMetricsEnabled: appLevelAppMetricsEnabled, + IsBasicViewLocked: false, + Namespace: pipeline.Namespace, + CurrentViewEditor: latestChart.CurrentViewEditor, + MergeStrategy: models.MERGE_STRATEGY_REPLACE, + } + return overrideCreateRequest, err +} + func (impl *CdPipelineConfigServiceImpl) GetValuesAndChartMetadataForExternalArgoCDApp(spec bean4.ArgoCDSpec) (json.RawMessage, *chart2.Metadata, error) { repoURL := spec.Spec.Source.RepoURL chartPath := spec.Spec.Source.Path targetRevision := spec.Spec.Source.TargetRevision //validation is performed before this step, so assuming ValueFiles array has one and only one entry valuesFileName := spec.Spec.Source.Helm.ValueFiles[0] - helmChart, err := impl.extractHelmChartForExternalArgoApp(repoURL, targetRevision, chartPath) + helmChart, err := impl.extractHelmChartForExternalArgoOrFluxApp(repoURL, targetRevision, chartPath) if err != nil { impl.logger.Errorw("error in extracting helm ") return nil, nil, err @@ -2550,7 +2906,42 @@ func (impl *CdPipelineConfigServiceImpl) GetValuesAndChartMetadataForExternalArg return nil, nil, errors2.New(fmt.Sprintf("values file with name %s not found in chart", valuesFileName)) } -func (impl *CdPipelineConfigServiceImpl) extractHelmChartForExternalArgoApp(repoURL, targetRevision, chartPath string) (*chart2.Chart, error) { +func (impl *CdPipelineConfigServiceImpl) GetValuesAndChartMetadataForExternalFluxCDApp(spec bean4.FluxCDSpec) (json.RawMessage, *chart2.Metadata, error) { + repoURL := spec.RepoUrl + chartPath := spec.ChartLocation + targetRevision := spec.RevisionTarget + //TODO: validation is performed before this step, so assuming ValueFiles array is not empty + + helmChart, err := impl.extractHelmChartForExternalArgoOrFluxApp(repoURL, targetRevision, chartPath) + if err != nil { + impl.logger.Errorw("error in extracting helm ") + return nil, nil, err + } + + var valuesFilePath string + if len(spec.HelmReleaseValuesFiles) == 0 { + return []byte(spec.ExtFluxValues), helmChart.Metadata, nil + } else { + valuesFilePath = spec.HelmReleaseValuesFiles[len(spec.HelmReleaseValuesFiles)-1] + valuesFileName := filepath.Base(valuesFilePath) + for _, file := range helmChart.Files { + if file.Name == valuesFileName { + return file.Data, helmChart.Metadata, nil + } + } + if valuesFileName == "values.yaml" && helmChart.Values != nil { + byteValues, err := json.Marshal(helmChart.Values) + if err != nil { + impl.logger.Errorw("error in json Marshal values", "values", helmChart.Values, "err", err) + return nil, nil, err + } + return byteValues, helmChart.Metadata, nil + } + } + return nil, nil, errors2.New("unable to parse values") +} + +func (impl *CdPipelineConfigServiceImpl) extractHelmChartForExternalArgoOrFluxApp(repoURL, targetRevision, chartPath string) (*chart2.Chart, error) { repoName := impl.gitOpsConfigReadService.GetGitOpsRepoNameFromUrl(repoURL) chartDir := fmt.Sprintf("%s-%s", repoName, impl.chartTemplateService.GetDir()) clonedDir, err := impl.gitOperationService.GetClonedDir(context.Background(), chartDir, repoURL, targetRevision) diff --git a/pkg/pipeline/adapter/adapter.go b/pkg/pipeline/adapter/adapter.go index d480731a2a..3ac8b35f7a 100644 --- a/pkg/pipeline/adapter/adapter.go +++ b/pkg/pipeline/adapter/adapter.go @@ -398,6 +398,11 @@ func NewMigrateExternalAppValidationRequest(pipeline *bean.CDPipelineConfigObjec ReleaseClusterId: env.ClusterId, ReleaseNamespace: env.Namespace, } + } else if pipeline.DeploymentAppType == bean3.PIPELINE_DEPLOYMENT_TYPE_FLUX { + request.FluxReleaseMetadataRequest = pipelineConfigBean.FluxReleaseMetadataRequest{ + ReleaseClusterId: env.ClusterId, + ReleaseNamespace: env.Namespace, + } } return request } diff --git a/pkg/pipeline/bean/ExternalArgoAppLink.go b/pkg/pipeline/bean/ExternalArgoAppLink.go index 2585135f9e..2570ee7b61 100644 --- a/pkg/pipeline/bean/ExternalArgoAppLink.go +++ b/pkg/pipeline/bean/ExternalArgoAppLink.go @@ -17,6 +17,7 @@ type MigrateReleaseValidationRequest struct { DeploymentAppType string `json:"deploymentAppType"` ApplicationMetadataRequest ApplicationMetadataRequest `json:"applicationMetadata"` HelmReleaseMetadataRequest HelmReleaseMetadataRequest `json:"helmReleaseMetadata"` + FluxReleaseMetadataRequest FluxReleaseMetadataRequest `json:"fluxReleaseMetadata"` } type ApplicationMetadataRequest struct { @@ -29,19 +30,33 @@ type HelmReleaseMetadataRequest struct { ReleaseNamespace string `json:"releaseNamespace"` } -func (h MigrateReleaseValidationRequest) GetReleaseClusterId() int { +type FluxReleaseMetadataRequest struct { + ReleaseClusterId int `json:"releaseClusterId"` + ReleaseNamespace string `json:"releaseNamespace"` +} + +func (h MigrateReleaseValidationRequest) GetHelmReleaseClusterId() int { return h.HelmReleaseMetadataRequest.ReleaseClusterId } -func (h MigrateReleaseValidationRequest) GetReleaseNamespace() string { +func (h MigrateReleaseValidationRequest) GetHelmReleaseNamespace() string { return h.HelmReleaseMetadataRequest.ReleaseNamespace } +func (h MigrateReleaseValidationRequest) GetFluxReleaseClusterId() int { + return h.FluxReleaseMetadataRequest.ReleaseClusterId +} + +func (h MigrateReleaseValidationRequest) GetFluxReleaseNamespace() string { + return h.FluxReleaseMetadataRequest.ReleaseNamespace +} + type ExternalAppLinkValidationResponse struct { IsLinkable bool `json:"isLinkable"` ErrorDetail *ErrorDetail `json:"errorDetail"` ApplicationMetadata ApplicationMetadata `json:"applicationMetadata"` HelmReleaseMetadata HelmReleaseMetadata `json:"helmReleaseMetadata"` + FluxReleaseMetadata FluxReleaseMetadata `json:"fluxReleaseMetadata"` } func (a *ApplicationMetadata) UpdateApplicationSpecData(argoApplicationSpec *v1alpha1.Application) { @@ -127,14 +142,15 @@ func (r *HelmReleaseMetadata) UpdateReleaseData(release *gRPC.DeployedAppDetail) } } -func (r *HelmReleaseMetadata) UpdateClusterData(cluster *bean.ClusterBean) { - r.Destination.ClusterName = cluster.ClusterName - r.Destination.ClusterServerUrl = cluster.ServerUrl +func (r *Destination) UpdateClusterData(cluster *bean.ClusterBean) { + r.ClusterName = cluster.ClusterName + r.ClusterServerUrl = cluster.ServerUrl } -func (r *HelmReleaseMetadata) UpdateEnvironmentMetadata(environment *repository.Environment) { - r.Destination.EnvironmentName = environment.Name - r.Destination.EnvironmentId = environment.Id +func (r *Destination) UpdateEnvironmentMetadata(environment *repository.Environment) { + r.EnvironmentName = environment.Name + r.EnvironmentId = environment.Id + r.Namespace = environment.Namespace } func (r *HelmReleaseMetadata) UpdateChartRefData(chartRef *bean2.ChartRefDto) { @@ -179,6 +195,14 @@ type HelmReleaseMetadata struct { Destination Destination `json:"destination"` } +type FluxReleaseMetadata struct { + RepoUrl string `json:"repoUrl"` + RequiredChartName string `json:"requiredChartName"` + SavedChartName string `json:"savedChartName"` + RequiredChartVersion string `json:"requiredChartVersion"` + Destination Destination `json:"destination"` +} + type HelmReleaseChart struct { HelmReleaseChartMetadata HelmReleaseChartMetadata `json:"metadata"` } @@ -245,10 +269,11 @@ const ( InternalServerError LinkFailedReason = "InternalServerError" EnvironmentAlreadyPresent LinkFailedReason = "EnvironmentAlreadyPresent" EnforcedPolicyViolation LinkFailedReason = "EnforcedPolicyViolation" + UnsupportedFluxHelmReleaseSpec LinkFailedReason = "UnsupportedFluxHelmReleaseSpec" ) const ( - ChartTypeMismatchErrorMsg string = "Argo CD application uses '%s' chart where as this application uses '%s' chart. You can upload your own charts in Global Configuration > Deployment Charts." + ChartTypeMismatchErrorMsg string = "External application uses '%s' chart where as this application uses '%s' chart. You can upload your own charts in Global Configuration > Deployment Charts." ChartVersionNotFoundErrorMsg string = "Chart version %s not found for %s chart" PipelineAlreadyPresentMsg string = "A pipeline already exist for this environment." HelmAppAlreadyPresentMsg string = "A helm app already exist for this environment." diff --git a/pkg/workflow/dag/WorkflowDagExecutor.go b/pkg/workflow/dag/WorkflowDagExecutor.go index b33769c41b..18335dd4fa 100644 --- a/pkg/workflow/dag/WorkflowDagExecutor.go +++ b/pkg/workflow/dag/WorkflowDagExecutor.go @@ -25,6 +25,7 @@ import ( "github.com/devtron-labs/common-lib/async" "github.com/devtron-labs/common-lib/utils" "github.com/devtron-labs/common-lib/utils/k8s" + "github.com/devtron-labs/common-lib/utils/k8s/commonBean" "github.com/devtron-labs/common-lib/utils/workFlow" bean6 "github.com/devtron-labs/devtron/api/helm-app/bean" client2 "github.com/devtron-labs/devtron/api/helm-app/service" @@ -51,6 +52,8 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/service" eventProcessorBean "github.com/devtron-labs/devtron/pkg/eventProcessor/bean" "github.com/devtron-labs/devtron/pkg/executor" + "github.com/devtron-labs/devtron/pkg/fluxApplication" + bean8 "github.com/devtron-labs/devtron/pkg/fluxApplication/bean" k8sPkg "github.com/devtron-labs/devtron/pkg/k8s" "github.com/devtron-labs/devtron/pkg/pipeline" constants2 "github.com/devtron-labs/devtron/pkg/pipeline/constants" @@ -110,11 +113,13 @@ type WorkflowDagExecutor interface { UpdateWorkflowRunnerStatusForDeployment(appIdentifier *helmBean.AppIdentifier, wfr *pipelineConfig.CdWorkflowRunner, skipReleaseNotFound bool) bool BuildCiArtifactRequestForWebhook(event pipeline.ExternalCiWebhookDto) (*bean2.CiArtifactWebhookRequest, error) + UpdateWorkflowRunnerStatusForFluxDeployment(appIdentifier *bean8.FluxAppIdentifier, wfr *pipelineConfig.CdWorkflowRunner, pipelineOverride *chartConfig.PipelineOverride) bool } type WorkflowDagExecutorImpl struct { logger *zap.SugaredLogger pipelineRepository pipelineConfig.PipelineRepository + pipelineOverrideRepository chartConfig.PipelineOverrideRepository cdWorkflowRepository pipelineConfig.CdWorkflowRepository ciArtifactRepository repository.CiArtifactRepository enforcerUtil rbac.EnforcerUtil @@ -153,9 +158,11 @@ type WorkflowDagExecutorImpl struct { workflowService executor.WorkflowService ciHandlerService trigger.HandlerService workflowTriggerAuditService auditService.WorkflowTriggerAuditService + fluxApplicationService fluxApplication.FluxApplicationService } func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pipelineConfig.PipelineRepository, + pipelineOverrideRepository chartConfig.PipelineOverrideRepository, cdWorkflowRepository pipelineConfig.CdWorkflowRepository, ciArtifactRepository repository.CiArtifactRepository, enforcerUtil rbac.EnforcerUtil, @@ -187,9 +194,11 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi workflowService executor.WorkflowService, ciHandlerService trigger.HandlerService, workflowTriggerAuditService auditService.WorkflowTriggerAuditService, + fluxApplicationService fluxApplication.FluxApplicationService, ) *WorkflowDagExecutorImpl { wde := &WorkflowDagExecutorImpl{logger: Logger, pipelineRepository: pipelineRepository, + pipelineOverrideRepository: pipelineOverrideRepository, cdWorkflowRepository: cdWorkflowRepository, ciArtifactRepository: ciArtifactRepository, enforcerUtil: enforcerUtil, @@ -221,6 +230,7 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi workflowService: workflowService, ciHandlerService: ciHandlerService, workflowTriggerAuditService: workflowTriggerAuditService, + fluxApplicationService: fluxApplicationService, } config, err := types.GetCdConfig() if err != nil { @@ -1309,3 +1319,73 @@ func (impl *WorkflowDagExecutorImpl) BuildCiArtifactRequestForWebhook(event pipe } return request, nil } + +func (impl *WorkflowDagExecutorImpl) UpdateWorkflowRunnerStatusForFluxDeployment(appIdentifier *bean8.FluxAppIdentifier, wfr *pipelineConfig.CdWorkflowRunner, + pipelineOverride *chartConfig.PipelineOverride) bool { + fluxAppDetail, err := impl.fluxApplicationService.GetFluxAppDetail(context.Background(), appIdentifier) + if err != nil { + impl.logger.Errorw("error in getting helm app release status", "appIdentifier", appIdentifier, "err", err) + // Handle release not found errors + // If release not found, mark the deployment as failure + wfr.Status = cdWorkflow2.WorkflowUnableToFetchState + wfr.Message = fmt.Sprintf("error in fetching app detail; err: %s", err.Error()) + wfr.FinishedOn = time.Now() + return true + } + if !impl.checkIfFluxPipelineEventIsValid(fluxAppDetail.LastObservedVersion, pipelineOverride) { + return false + } + wfr.FinishedOn = time.Now() + wfr.Message = fluxAppDetail.FluxAppStatusDetail.Message + switch fluxAppDetail.FluxAppStatusDetail.Reason { + case bean8.InstallSucceededReason, bean8.UpgradeSucceededReason, bean8.TestSucceededReason, bean8.RollbackSucceededReason: + if fluxAppDetail.AppHealthStatus == commonBean.HealthStatusHealthy { + wfr.Status = cdWorkflow2.WorkflowSucceeded + } + case bean8.UpgradeFailedReason, + bean8.TestFailedReason, + bean8.RollbackFailedReason, + bean8.UninstallFailedReason, + bean8.ArtifactFailedReason, + bean8.InstallFailedReason: + wfr.Status = cdWorkflow2.WorkflowFailed + } + return true +} + +func (impl *WorkflowDagExecutorImpl) checkIfFluxPipelineEventIsValid(lastObservedVersion string, pipelineOverride *chartConfig.PipelineOverride) bool { + gitHash := getShortHash(lastObservedVersion) + if !strings.HasPrefix(pipelineOverride.GitHash, gitHash) { + pipelineOverrideByHash, err := impl.pipelineOverrideRepository.FindByPipelineLikeTriggerGitHash(gitHash) + if err != nil { + impl.logger.Errorw("error on update application status", "gitHash", gitHash, "err", err) + return false + } + if pipelineOverrideByHash == nil || pipelineOverrideByHash.CommitTime.Before(pipelineOverride.CommitTime) { + // we have received trigger hash which is committed before this apps actual gitHash stored by us + // this means that the hash stored by us will be synced later, so we will drop this event + return false + } + } + return true +} + +// getShortHash gets the short Git hash embedded in the version string +// with the beginning of the full Git commit hash. +// +// version: expected format like "4.22.1+." +// fullHash: expected to be a full 40-character Git commit SHA +func getShortHash(version string) string { + // Split version string at '+' to extract metadata + parts := strings.Split(version, "+") + if len(parts) < 2 { + return "" // No metadata found + } + + // Metadata might look like "2b6c6b2.2" → short hash + build number + metaParts := strings.Split(parts[1], ".") + shortHash := metaParts[0] // Take only the short hash before the dot + + // Compare short hash with prefix of full hash + return shortHash +} diff --git a/pkg/workflow/status/WorkflowStatusService.go b/pkg/workflow/status/WorkflowStatusService.go index 56d9918747..48d0368cbd 100644 --- a/pkg/workflow/status/WorkflowStatusService.go +++ b/pkg/workflow/status/WorkflowStatusService.go @@ -19,6 +19,8 @@ package status import ( "context" "fmt" + util2 "github.com/devtron-labs/devtron/internal/util" + bean4 "github.com/devtron-labs/devtron/pkg/fluxApplication/bean" util "github.com/devtron-labs/devtron/util/event" "time" @@ -63,6 +65,8 @@ type WorkflowStatusService interface { CheckArgoPipelineTimelineStatusPeriodicallyAndUpdateInDb(pendingSinceSeconds int, timeForDegradation int) error CheckArgoAppStatusPeriodicallyAndUpdateInDb(getPipelineDeployedBeforeMinutes int, getPipelineDeployedWithinHours int) error + + CheckFluxAppStatusPeriodicallyAndUpdateInDb(fluxPipelineStatusCheckEligibleTime int, getPipelineDeployedWithinHours int, cdPipelineTimeoutDuration int) error } type WorkflowStatusServiceImpl struct { @@ -149,7 +153,7 @@ func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, func (impl *WorkflowStatusServiceImpl) CheckHelmAppStatusPeriodicallyAndUpdateInDb(helmPipelineStatusCheckEligibleTime int, getPipelineDeployedWithinHours int) error { - wfrList, err := impl.cdWorkflowRepository.GetLatestTriggersOfHelmPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours) + wfrList, err := impl.cdWorkflowRepository.GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours, util2.PIPELINE_DEPLOYMENT_TYPE_HELM) if err != nil { impl.logger.Errorw("error in getting latest triggers of helm pipelines which are stuck in non terminal statuses", "err", err) return err @@ -596,3 +600,83 @@ func (impl *WorkflowStatusServiceImpl) syncACDHelmApps(deployedBeforeMinutes int } return nil } + +func (impl *WorkflowStatusServiceImpl) CheckFluxAppStatusPeriodicallyAndUpdateInDb(fluxPipelineStatusCheckEligibleTime int, getPipelineDeployedWithinHours int, cdPipelineTimeoutDuration int) error { + wfrList, err := impl.cdWorkflowRepository.GetLatestTriggersOfPipelinesStuckInNonTerminalStatuses(getPipelineDeployedWithinHours, util2.PIPELINE_DEPLOYMENT_TYPE_FLUX) + if err != nil { + impl.logger.Errorw("error in getting latest triggers of helm pipelines which are stuck in non terminal statuses", "err", err) + return err + } + impl.logger.Debugw("checking helm app status for non terminal deployment triggers", "wfrList", wfrList, "number of wfr", len(wfrList)) + for _, wfr := range wfrList { + if time.Now().Sub(wfr.StartedOn) <= time.Duration(fluxPipelineStatusCheckEligibleTime)*time.Second { + // if wfr is updated within configured time then do not include for this cron cycle + continue + } + + appIdentifier := &bean4.FluxAppIdentifier{ + ClusterId: wfr.CdWorkflow.Pipeline.Environment.ClusterId, + Namespace: wfr.CdWorkflow.Pipeline.Environment.Namespace, + Name: wfr.CdWorkflow.Pipeline.DeploymentAppName, + IsKustomizeApp: false, + } + pipeline := wfr.CdWorkflow.Pipeline + + // getting latest pipelineOverride for app (by appId and envId) + pipelineOverride, err := impl.pipelineOverrideRepository.FindLatestByAppIdAndEnvId(pipeline.AppId, pipeline.EnvironmentId, bean3.FluxCd) + if err != nil { + impl.logger.Errorw("error in getting latest pipelineOverride by appId and envId", "err", err, "appId", pipeline.AppId, "envId", pipeline.EnvironmentId) + return err + } + + if isWfrUpdated := impl.workflowDagExecutor.UpdateWorkflowRunnerStatusForFluxDeployment(appIdentifier, wfr, pipelineOverride); !isWfrUpdated { + continue + } + + wfr.UpdateAuditLog(1) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(wfr) + if err != nil { + impl.logger.Errorw("error on update cd workflow runner", "wfr", wfr, "err", err) + return err + } + + if wfr.Status == cdWorkflow2.WorkflowFailed { + err = impl.pipelineStatusTimelineService.MarkPipelineStatusTimelineFailed(wfr.RefCdWorkflowRunnerId, "Deployment failed") + if err != nil { + impl.logger.Errorw("error updating CdPipelineStatusTimeline", "err", err) + return err + } + impl.deploymentEventHandler.WriteCDNotificationEventAsync(pipelineOverride.Pipeline.AppId, pipelineOverride.Pipeline.EnvironmentId, pipelineOverride, util.Fail) + } + + appId := wfr.CdWorkflow.Pipeline.AppId + envId := wfr.CdWorkflow.Pipeline.EnvironmentId + envDeploymentConfig, err := impl.deploymentConfigService.GetConfigForDevtronApps(appId, envId) + if err != nil { + impl.logger.Errorw("error in fetching environment deployment config by appId and envId", "appId", appId, "envId", envId, "err", err) + return err + } + if slices.Contains(cdWorkflow2.WfrTerminalStatusList, wfr.Status) { + util3.TriggerCDMetrics(cdWorkflow.GetTriggerMetricsFromRunnerObj(wfr, envDeploymentConfig), impl.config.ExposeCDMetrics) + } + + impl.logger.Infow("updated workflow runner status for helm app", "wfr", wfr) + if wfr.Status == cdWorkflow2.WorkflowSucceeded { + timeline := impl.pipelineStatusTimelineService.NewDevtronAppPipelineStatusTimelineDbObject(wfr.Id, timelineStatus.TIMELINE_STATUS_APP_HEALTHY, "App status is Healthy.", 1) + _, err = impl.pipelineStatusTimelineService.SaveTimelineIfNotAlreadyPresent(timeline, nil) + if err != nil { + impl.logger.Errorw("error in saving timeline status for helm app", "wfr.Id", wfr.Id, "err", err) + return err + } + impl.deploymentEventHandler.WriteCDNotificationEventAsync(pipelineOverride.Pipeline.AppId, pipelineOverride.Pipeline.EnvironmentId, pipelineOverride, util.Success) + err = impl.workflowDagExecutor.HandleDeploymentSuccessEvent(bean3.TriggerContext{}, pipelineOverride) + if err != nil { + impl.logger.Errorw("error on handling deployment success event", "wfr", wfr, "err", err) + return err + } + } else if wfr.Status == cdWorkflow2.WorkflowTimedOut { + impl.deploymentEventHandler.WriteCDNotificationEventAsync(pipelineOverride.Pipeline.AppId, pipelineOverride.Pipeline.EnvironmentId, pipelineOverride, util.Fail) + } + } + return nil +} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.helmignore b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.helmignore new file mode 100644 index 0000000000..50af031725 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.image_descriptor_template.json b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.image_descriptor_template.json new file mode 100644 index 0000000000..8a99a95664 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/.image_descriptor_template.json @@ -0,0 +1 @@ +{"server":{"deployment":{"image_tag":"{{.Tag}}","image":"{{.Name}}"}},"pipelineName": "{{.PipelineName}}","releaseVersion":"{{.ReleaseVersion}}","deploymentType": "{{.DeploymentType}}", "app": "{{.App}}", "env": "{{.Env}}", "appMetrics": {{.AppMetrics}}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/Chart.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/Chart.yaml new file mode 100644 index 0000000000..d6447056e4 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: deployment-chart_4-22-0 +version: 4.22.0 diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/README.md b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/README.md new file mode 100644 index 0000000000..07f18f2885 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/README.md @@ -0,0 +1,991 @@ + +# Deployment Chart - v4.21.0 + +## 1. Yaml File - + +### Container Ports + +This defines ports on which application services will be exposed to other services + +```yaml +ContainerPort: + - envoyPort: 8799 + idleTimeout: + name: app + port: 8080 + servicePort: 80 + nodePort: 32056 + supportStreaming: true + useHTTP2: true + protocol: TCP +``` + +| Key | Description | +| :--- | :--- | +| `envoyPort` | envoy port for the container. | +| `idleTimeout` | the duration of time that a connection is idle before the connection is terminated. | +| `name` | name of the port. | +| `port` | port for the container. | +| `servicePort` | port of the corresponding kubernetes service. | +| `nodePort` | nodeport of the corresponding kubernetes service. | +| `supportStreaming` | Used for high performance protocols like grpc where timeout needs to be disabled. | +| `useHTTP2` | Envoy container can accept HTTP2 requests. | +| `protocol` | Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP"| + +### EnvVariables +```yaml +EnvVariables: [] +``` +To set environment variables for the containers that run in the Pod. +### EnvVariablesFromSecretKeys +```yaml +EnvVariablesFromSecretKeys: + - name: ENV_NAME + secretName: SECRET_NAME + keyName: SECRET_KEY + +``` + It is use to get the name of Environment Variable name, Secret name and the Key name from which we are using the value in that corresponding Environment Variable. + + ### EnvVariablesFromConfigMapKeys +```yaml +EnvVariablesFromConfigMapKeys: + - name: ENV_NAME + configMapName: CONFIG_MAP_NAME + keyName: CONFIG_MAP_KEY + +``` + It is use to get the name of Environment Variable name, Config Map name and the Key name from which we are using the value in that corresponding Environment Variable. + +### Liveness Probe + +If this check fails, kubernetes restarts the pod. This should return error code in case of non-recoverable error. + +```yaml +LivenessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + scheme: "" + tcp: true + grpc: + port: 8080 + service: "" +``` + +| Key | Description | +| :--- | :--- | +| `Path` | It define the path where the liveness needs to be checked. | +| `initialDelaySeconds` | It defines the time to wait before a given container is checked for liveliness. | +| `periodSeconds` | It defines the time to check a given container for liveness. | +| `successThreshold` | It defines the number of successes required before a given container is said to fulfil the liveness probe. | +| `timeoutSeconds` | It defines the time for checking timeout. | +| `failureThreshold` | It defines the maximum number of failures that are acceptable before a given container is not considered as live. | +| `httpHeaders` | Custom headers to set in the request. HTTP allows repeated headers,You can override the default headers by defining .httpHeaders for the probe. | +| `scheme` | Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP. +| `tcp` | The kubelet will attempt to open a socket to your container on the specified port. If it can establish a connection, the container is considered healthy. | +| `grpc` | GRPC specifies an action involving a GRPC port. Port is a required field if using gRPC service for health probes. Number must be in the range 1 to 65535. Service (optional) is the name of the service to place in the gRPC HealthCheckRequest. | + + + +### MaxUnavailable + +```yaml + MaxUnavailable: 0 +``` +The maximum number of pods that can be unavailable during the update process. The value of "MaxUnavailable: " can be an absolute number or percentage of the replicas count. The default value of "MaxUnavailable: " is 25%. + +### MaxSurge + +```yaml +MaxSurge: 1 +``` +The maximum number of pods that can be created over the desired number of pods. For "MaxSurge: " also, the value can be an absolute number or percentage of the replicas count. +The default value of "MaxSurge: " is 25%. + +### Min Ready Seconds + +```yaml +MinReadySeconds: 60 +``` +This specifies the minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available. This defaults to 0 (the Pod will be considered available as soon as it is ready). + +### Readiness Probe + +If this check fails, kubernetes stops sending traffic to the application. This should return error code in case of errors which can be recovered from if traffic is stopped. + +```yaml +ReadinessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + scheme: "" + tcp: true + grpc: + port: 8080 + service: "" +``` + +| Key | Description | +| :--- | :--- | +| `Path` | It define the path where the readiness needs to be checked. | +| `initialDelaySeconds` | It defines the time to wait before a given container is checked for readiness. | +| `periodSeconds` | It defines the time to check a given container for readiness. | +| `successThreshold` | It defines the number of successes required before a given container is said to fulfill the readiness probe. | +| `timeoutSeconds` | It defines the time for checking timeout. | +| `failureThreshold` | It defines the maximum number of failures that are acceptable before a given container is not considered as ready. | +| `httpHeaders` | Custom headers to set in the request. HTTP allows repeated headers,You can override the default headers by defining .httpHeaders for the probe. | +| `scheme` | Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP. +| `tcp` | The kubelet will attempt to open a socket to your container on the specified port. If it can establish a connection, the container is considered healthy. | +| `grpc` | GRPC specifies an action involving a GRPC port. Port is a required field if using gRPC service for health probes. Number must be in the range 1 to 65535. Service (optional) is the name of the service to place in the gRPC HealthCheckRequest. | + + +### Pod Disruption Budget + +You can create `PodDisruptionBudget` for each application. A PDB limits the number of pods of a replicated application that are down simultaneously from voluntary disruptions. For example, an application would like to ensure the number of replicas running is never brought below the certain number. + +```yaml +podDisruptionBudget: + minAvailable: 1 +``` + +or + +```yaml +podDisruptionBudget: + maxUnavailable: 50% +``` + +You can specify either `maxUnavailable` or `minAvailable` in a PodDisruptionBudget and it can be expressed as integers or as a percentage + +| Key | Description | +| :--- | :--- | +| `minAvailable` | Evictions are allowed as long as they leave behind 1 or more healthy pods of the total number of desired replicas. | +| `maxUnavailable` | Evictions are allowed as long as at most 1 unhealthy replica among the total number of desired replicas. | + +### Ambassador Mappings + +You can create ambassador mappings to access your applications from outside the cluster. At its core a Mapping resource maps a resource to a service. + +```yaml +ambassadorMapping: + ambassadorId: "prod-emissary" + cors: {} + enabled: true + hostname: devtron.example.com + labels: {} + prefix: / + retryPolicy: {} + rewrite: "" + tls: + context: "devtron-tls-context" + create: false + hosts: [] + secretName: "" +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Set true to enable ambassador mapping else set false.| +| `ambassadorId` | used to specify id for specific ambassador mappings controller. | +| `cors` | used to specify cors policy to access host for this mapping. | +| `weight` | used to specify weight for canary ambassador mappings. | +| `hostname` | used to specify hostname for ambassador mapping. | +| `prefix` | used to specify path for ambassador mapping. | +| `labels` | used to provide custom labels for ambassador mapping. | +| `retryPolicy` | used to specify retry policy for ambassador mapping. | +| `corsPolicy` | Provide cors headers on flagger resource. | +| `rewrite` | used to specify whether to redirect the path of this mapping and where. | +| `tls` | used to create or define ambassador TLSContext resource. | +| `extraSpec` | used to provide extra spec values which not present in deployment template for ambassador resource. | + +### Autoscaling + +This is connected to HPA and controls scaling up and down in response to request load. + +```yaml +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + containerResource: + enabled: true + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + + extraMetrics: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Set true to enable autoscaling else set false.| +| `MinReplicas` | Minimum number of replicas allowed for scaling. | +| `MaxReplicas` | Maximum number of replicas allowed for scaling. | +| `TargetCPUUtilizationPercentage` | The target CPU utilization that is expected for a container. | +| `TargetMemoryUtilizationPercentage` | The target memory utilization that is expected for a container. | +| `extraMetrics` | Used to give external metrics for autoscaling. | +| `containerResource` | Used to scale resource as per container resource. | + +### Flagger + +You can use flagger for canary releases with deployment objects. It supports flexible traffic routing with istio service mesh as well. + +```yaml +flaggerCanary: + addOtherGateways: [] + addOtherHosts: [] + analysis: + interval: 15s + maxWeight: 50 + stepWeight: 5 + threshold: 5 + annotations: {} + appProtocol: http + corsPolicy: + allowCredentials: false + allowHeaders: + - x-some-header + allowMethods: + - GET + allowOrigin: + - example.com + maxAge: 24h + createIstioGateway: + annotations: {} + enabled: false + host: example.com + labels: {} + tls: + enabled: false + secretName: example-tls-secret + enabled: false + gatewayRefs: null + headers: + request: + add: + x-some-header: value + labels: {} + loadtest: + enabled: true + url: http://flagger-loadtester.istio-system/ + match: + - uri: + prefix: / + port: 8080 + portDiscovery: true + retries: null + rewriteUri: / + targetPort: 8080 + thresholds: + latency: 500 + successRate: 90 + timeout: null +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Set true to enable canary releases using flagger else set false.| +| `addOtherGateways` | To provide multiple istio gateways for flagger. | +| `addOtherHosts` | Add multiple hosts for istio service mesh with flagger. | +| `analysis` | Define how the canary release should progresss and at what interval. | +| `annotations` | Annotation to add on flagger resource. | +| `labels` | Labels to add on flagger resource. | +| `appProtocol` | Protocol to use for canary. | +| `corsPolicy` | Provide cors headers on flagger resource. | +| `createIstioGateway` | Set to true if you want to create istio gateway as well with flagger. | +| `headers` | Add headers if any. | +| `loadtest` | Enable load testing for your canary release. | + + + +### Fullname Override + +```yaml +fullnameOverride: app-name +``` +`fullnameOverride` replaces the release fullname created by default by devtron, which is used to construct Kubernetes object names. By default, devtron uses {app-name}-{environment-name} as release fullname. + +### Image + +```yaml +image: + pullPolicy: IfNotPresent +``` + +Image is used to access images in kubernetes, pullpolicy is used to define the instances calling the image, here the image is pulled when the image is not present,it can also be set as "Always". + +### imagePullSecrets + +`imagePullSecrets` contains the docker credentials that are used for accessing a registry. + +```yaml +imagePullSecrets: + - regcred +``` +regcred is the secret that contains the docker credentials that are used for accessing a registry. Devtron will not create this secret automatically, you'll have to create this secret using dt-secrets helm chart in the App store or create one using kubectl. You can follow this documentation Pull an Image from a Private Registry [https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) . + +### Ingress + +This allows public access to the url, please ensure you are using right nginx annotation for nginx class, its default value is nginx + +```yaml +ingress: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + className: nginx + annotations: {} + hosts: + - host: example1.com + paths: + - /example + - host: example2.com + paths: + - /example2 + - /example2/healthz + tls: [] +``` +Legacy deployment-template ingress format + +```yaml +ingress: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + ingressClassName: nginx-internal + annotations: {} + path: "" + host: "" + tls: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Enable or disable ingress | +| `annotations` | To configure some options depending on the Ingress controller | +| `path` | Path name | +| `host` | Host name | +| `tls` | It contains security details | + +### Ingress Internal + +This allows private access to the url, please ensure you are using right nginx annotation for nginx class, its default value is nginx + +```yaml +ingressInternal: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + ingressClassName: nginx-internal + annotations: {} + hosts: + - host: example1.com + paths: + - /example + - host: example2.com + paths: + - /example2 + - /example2/healthz + tls: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Enable or disable ingress | +| `annotations` | To configure some options depending on the Ingress controller | +| `path` | Path name | +| `host` | Host name | +| `tls` | It contains security details | + +### additionalBackends + +This defines additional backend path in the ingress . + +```yaml + hosts: + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + additionalBackends: + - path: /example1 + pathType: "ImplementationSpecific" + backend: + service: + name: test-service + port: + number: 80 +``` + +### Init Containers +```yaml +initContainers: + - reuseContainerImage: true + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + volumeMounts: + - mountPath: /etc/ls-oms + name: ls-oms-cm-vol + args: + - sleep 300 + command: + - flyway + - -configFiles=/etc/ls-oms/flyway.conf + - migrate + + - name: nginx + image: nginx:1.14.2 + securityContext: + privileged: true + ports: + - containerPort: 80 + command: ["/usr/local/bin/nginx"] + args: ["-g", "daemon off;"] +``` +Specialized containers that run before app containers in a Pod. Init containers can contain utilities or setup scripts not present in an app image. One can use base image inside initContainer by setting the reuseContainerImage flag to `true`. + +### Istio + +Istio is a service mesh which simplifies observability, traffic management, security and much more with it's virtual services and gateways. + +```yaml +istio: + enable: true + gateway: + annotations: {} + enabled: false + host: example.com + labels: {} + tls: + enabled: false + secretName: example-tls-secret + virtualService: + annotations: {} + enabled: false + gateways: [] + hosts: [] + http: + - corsPolicy: + allowCredentials: false + allowHeaders: + - x-some-header + allowMethods: + - GET + allowOrigin: + - example.com + maxAge: 24h + headers: + request: + add: + x-some-header: value + match: + - uri: + prefix: /v1 + - uri: + prefix: /v2 + retries: + attempts: 2 + perTryTimeout: 3s + rewriteUri: / + route: + - destination: + host: service1 + port: 80 + timeout: 12s + - route: + - destination: + host: service2 + labels: {} +``` + +### Pause For Seconds Before Switch Active +```yaml +pauseForSecondsBeforeSwitchActive: 30 +``` +To wait for given period of time before switch active the container. + +### Resources + +These define minimum and maximum RAM and CPU available to the application. + +```yaml +resources: + limits: + cpu: "1" + memory: "200Mi" + requests: + cpu: "0.10" + memory: "100Mi" +``` + +Resources are required to set CPU and memory usage. + +#### Limits + +Limits make sure a container never goes above a certain value. The container is only allowed to go up to the limit, and then it is restricted. + +#### Requests + +Requests are what the container is guaranteed to get. + +### Service + +This defines annotations and the type of service, optionally can define name also. + +Supports "ClientIP" and "None". Used to maintain session affinity. Enable + client IP based session affinity. + +```yaml + service: + type: ClusterIP + annotations: {} + sessionAffinity: + enabled: true + sessionAffinityConfig: {} +``` + +### Volumes + +```yaml +volumes: + - name: log-volume + emptyDir: {} + - name: logpv + persistentVolumeClaim: + claimName: logpvc +``` + +It is required when some values need to be read from or written to an external disk. + +### Volume Mounts + +```yaml +volumeMounts: + - mountPath: /var/log/nginx/ + name: log-volume + - mountPath: /mnt/logs + name: logpvc + subPath: employee +``` + +It is used to provide mounts to the volume. + +### Affinity and anti-affinity + +```yaml +Spec: + Affinity: + Key: + Values: +``` + +Spec is used to define the desire state of the given container. + +Node Affinity allows you to constrain which nodes your pod is eligible to schedule on, based on labels of the node. + +Inter-pod affinity allow you to constrain which nodes your pod is eligible to be scheduled based on labels on pods. + +#### Key + +Key part of the label for node selection, this should be same as that on node. Please confirm with devops team. + +#### Values + +Value part of the label for node selection, this should be same as that on node. Please confirm with devops team. + +### Tolerations + +```yaml +tolerations: + - key: "key" + operator: "Equal" + value: "value" + effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" +``` + +Taints are the opposite, they allow a node to repel a set of pods. + +A given pod can access the given node and avoid the given taint only if the given pod satisfies a given taint. + +Taints and tolerations are a mechanism which work together that allows you to ensure that pods are not placed on inappropriate nodes. Taints are added to nodes, while tolerations are defined in the pod specification. When you taint a node, it will repel all the pods except those that have a toleration for that taint. A node can have one or many taints associated with it. + +### Arguments + +```yaml +args: + enabled: false + value: [] +``` + +This is used to give arguments to command. + +### Command + +```yaml +command: + enabled: false + value: [] +``` + +It contains the commands for the server. + +| Key | Description | +| :--- | :--- | +| `enabled` | To enable or disable the command. | +| `value` | It contains the commands. | + + +### Containers +Containers section can be used to run side-car containers along with your main container within same pod. Containers running within same pod can share volumes and IP Address and can address each other @localhost. We can use base image inside container by setting the reuseContainerImage flag to `true`. + +```yaml + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + command: ["/usr/local/bin/nginx"] + args: ["-g", "daemon off;"] + - reuseContainerImage: true + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + volumeMounts: + - mountPath: /etc/ls-oms + name: ls-oms-cm-vol + command: + - flyway + - -configFiles=/etc/ls-oms/flyway.conf + - migrate +``` + +### Prometheus + +```yaml + prometheus: + release: monitoring +``` + +It is a kubernetes monitoring tool and the name of the file to be monitored as monitoring in the given case.It describes the state of the prometheus. + +### rawYaml + +```yaml +rawYaml: + - apiVersion: v1 + kind: Service + metadata: + name: my-service + spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 + type: ClusterIP +``` +Accepts an array of Kubernetes objects. You can specify any kubernetes yaml here and it will be applied when your app gets deployed. + +### Grace Period + +```yaml +GracePeriod: 30 +``` +Kubernetes waits for the specified time called the termination grace period before terminating the pods. By default, this is 30 seconds. If your pod usually takes longer than 30 seconds to shut down gracefully, make sure you increase the `GracePeriod`. + +A Graceful termination in practice means that your application needs to handle the SIGTERM message and begin shutting down when it receives it. This means saving all data that needs to be saved, closing down network connections, finishing any work that is left, and other similar tasks. + +There are many reasons why Kubernetes might terminate a perfectly healthy container. If you update your deployment with a rolling update, Kubernetes slowly terminates old pods while spinning up new ones. If you drain a node, Kubernetes terminates all pods on that node. If a node runs out of resources, Kubernetes terminates pods to free those resources. It’s important that your application handle termination gracefully so that there is minimal impact on the end user and the time-to-recovery is as fast as possible. + + +### Server + +```yaml +server: + deployment: + image_tag: 1-95a53 + image: "" +``` + +It is used for providing server configurations. + +#### Deployment + +It gives the details for deployment. + +| Key | Description | +| :--- | :--- | +| `image_tag` | It is the image tag | +| `image` | It is the URL of the image | + +### Service Monitor + +```yaml +servicemonitor: + enabled: true + path: /abc + scheme: 'http' + interval: 30s + scrapeTimeout: 20s + metricRelabelings: + - sourceLabels: [namespace] + regex: '(.*)' + replacement: myapp + targetLabel: target_namespace +``` + +It gives the set of targets to be monitored. + +### Db Migration Config + +```yaml +dbMigrationConfig: + enabled: false +``` + +It is used to configure database migration. + + +### KEDA Autoscaling +[KEDA](https://keda.sh) is a Kubernetes-based Event Driven Autoscaler. With KEDA, you can drive the scaling of any container in Kubernetes based on the number of events needing to be processed. KEDA can be installed into any Kubernetes cluster and can work alongside standard Kubernetes components like the Horizontal Pod Autoscaler(HPA). + +Example for autosccaling with KEDA using Prometheus metrics is given below: +```yaml +kedaAutoscaling: + enabled: true + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 + pollingInterval: 30 + advanced: + restoreToOriginalReplicaCount: true + horizontalPodAutoscalerConfig: + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + triggers: + - type: prometheus + metadata: + serverAddress: http://:9090 + metricName: http_request_total + query: envoy_cluster_upstream_rq{appId="300", cluster_name="300-0", container="envoy",} + threshold: "50" + triggerAuthentication: + enabled: false + name: + spec: {} + authenticationRef: {} +``` +Example for autosccaling with KEDA based on kafka is given below : +```yaml +kedaAutoscaling: + enabled: true + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 + pollingInterval: 30 + advanced: {} + triggers: + - type: kafka + metadata: + bootstrapServers: b-2.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092,b-3.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092,b-1.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092 + topic: Orders-Service-ESP.info + lagThreshold: "100" + consumerGroup: oders-remove-delivered-packages + allowIdleConsumers: "true" + triggerAuthentication: + enabled: true + name: keda-trigger-auth-kafka-credential + spec: + secretTargetRef: + - parameter: sasl + name: keda-kafka-secrets + key: sasl + - parameter: username + name: keda-kafka-secrets + key: username + authenticationRef: + name: keda-trigger-auth-kafka-credential +``` + +### Winter-Soldier +Winter Soldier can be used to +- cleans up (delete) Kubernetes resources +- reduce workload pods to 0 + +**_NOTE:_** After deploying this we can create the Hibernator object and provide the custom configuration by which workloads going to delete, sleep and many more. for more information check [the main repo](https://github.com/devtron-labs/winter-soldier) + +Given below is template values you can give in winter-soldier: +```yaml +winterSoldier: + enabled: false + apiVersion: pincher.devtron.ai/v1alpha1 + action: sleep + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: [] + targetReplicas: [] + fieldSelector: [] +``` +Here, +| Key | values | Description | +| :--- | :--- | :--- | +| `enabled` | `fasle`,`true` | decide the enabling factor | +| `apiVersion` | `pincher.devtron.ai/v1beta1`, `pincher.devtron.ai/v1alpha1` | specific api version | +| `action` | `sleep`,`delete`, `scale` | This specify the action need to perform. | +| `timeRangesWithZone`:`timeZone` | eg:- `"Asia/Kolkata"`,`"US/Pacific"` | It use to specify the timeZone used. (It uses standard format. please refer [this](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) | +| `timeRangesWithZone`:`timeRanges` | array of [ `timeFrom`, `timeTo`, `weekdayFrom`, `weekdayTo`] | It use to define time period/range on which the user need to perform the specified action. you can have multiple timeRanges.
These settings will take `action` on Sat and Sun from 00:00 to 23:59:59, | +| `targetReplicas` | `[n]` : n - number of replicas to scale. | These is mandatory field when the `action` is `scale`
Defalut value is `[]`. | +| `fieldSelector` | `- AfterTime(AddTime( ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) ` | These value will take a list of methods to select the resources on which we perform specified `action` . | + + +here is an example, +```yaml +winterSoldier: + apiVersion: pincher.devtron.ai/v1alpha1 + enabled: true + annotations: {} + labels: {} + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: + - timeFrom: 00:00 + timeTo: 23:59:59 + weekdayFrom: Sat + weekdayTo: Sun + - timeFrom: 00:00 + timeTo: 08:00 + weekdayFrom: Mon + weekdayTo: Fri + - timeFrom: 20:00 + timeTo: 23:59:59 + weekdayFrom: Mon + weekdayTo: Fri + action: scale + targetReplicas: [1,1,1] + fieldSelector: + - AfterTime(AddTime( ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '10h'), Now()) +``` +Above settings will take action on `Sat` and `Sun` from 00:00 to 23:59:59, and on `Mon`-`Fri` from 00:00 to 08:00 and 20:00 to 23:59:59. If `action:sleep` then runs hibernate at timeFrom and unhibernate at `timeTo`. If `action: delete` then it will delete workloads at `timeFrom` and `timeTo`. Here the `action:scale` thus it scale the number of resource replicas to `targetReplicas: [1,1,1]`. Here each element of `targetReplicas` array is mapped with the corresponding elments of array `timeRangesWithZone/timeRanges`. Thus make sure the length of both array is equal, otherwise the cnages cannot be observed. + +The above example will select the application objects which have been created 10 hours ago across all namespaces excluding application's namespace. Winter soldier exposes following functions to handle time, cpu and memory. + +- ParseTime - This function can be used to parse time. For eg to parse creationTimestamp use ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z') +- AddTime - This can be used to add time. For eg AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '-10h') ll add 10h to the time. Use d for day, h for hour, m for minutes and s for seconds. Use negative number to get earlier time. +- Now - This can be used to get current time. +- CpuToNumber - This can be used to compare CPU. For eg any({{spec.containers.#.resources.requests}}, { MemoryToNumber(.memory) < MemoryToNumber('60Mi')}) will check if any resource.requests is less than 60Mi. + + +### Security Context +A security context defines privilege and access control settings for a Pod or Container. + +To add a security context for main container: +```yaml +containerSecurityContext: + allowPrivilegeEscalation: false +``` + +To add a security context on pod level: +```yaml +podSecurityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 +``` + +### Topology Spread Constraints +You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. This can help to achieve high availability as well as efficient resource utilization. + +```yaml +topologySpreadConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: DoNotSchedule + autoLabelSelector: true + customLabelSelector: {} + minDomains: 1 + nodeAffinityPolicy: Ignore +``` + +### Persistent Volume Claim +You can use persistent volume claim to mount volume as per your usecase. + +```yaml +persistentVolumeClaim: + name: my-pvc + storageClassName: default + accessMode: + - ReadWriteOnce + mountPath: /tmp +``` + +### Vertical Pod Autoscaling +This is connected to VPA and controls scaling up and down in response to request load. +```yaml +verticalPodScaling: + enabled: true + resourcePolicy: {} + updatePolicy: {} + ``` + +### Scheduler Name + +You can provide you own custom scheduler to schedule your application + +```yaml +schedulerName: "" +``` + +### Deployment Metrics + +It gives the realtime metrics of the deployed applications + +| Key | Description | +| :--- | :--- | +| `Deployment Frequency` | It shows how often this app is deployed to production | +| `Change Failure Rate` | It shows how often the respective pipeline fails. | +| `Mean Lead Time` | It shows the average time taken to deliver a change to production. | +| `Mean Time to Recovery` | It shows the average time taken to fix a failed pipeline. | + +## 2. Show application metrics + +If you want to see application metrics like different HTTP status codes metrics, application throughput, latency, response time. Enable the Application metrics from below the deployment template Save button. After enabling it, you should be able to see all metrics on App detail page. By default it remains disabled. +![](../../../.gitbook/assets/deployment_application_metrics%20%282%29.png) + +Once all the Deployment template configurations are done, click on `Save` to save your deployment configuration. Now you are ready to create [Workflow](workflow/) to do CI/CD. + +### Helm Chart Json Schema + +Helm Chart [json schema](../../../scripts/devtron-reference-helm-charts/reference-chart_4-11-0/schema.json) is used to validate the deployment template values. + +### Other Validations in Json Schema + +The values of CPU and Memory in limits must be greater than or equal to in requests respectively. Similarly, In case of envoyproxy, the values of limits are greater than or equal to requests as mentioned below. +``` +resources.limits.cpu >= resources.requests.cpu +resources.limits.memory >= resources.requests.memory +envoyproxy.resources.limits.cpu >= envoyproxy.resources.requests.cpu +envoyproxy.resources.limits.memory >= envoyproxy.resources.requests.memory +``` diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/app-values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/app-values.yaml new file mode 100644 index 0000000000..5f8216c0a7 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/app-values.yaml @@ -0,0 +1,530 @@ +# Mandatory configs + +podDisruptionBudget: {} +deploymentLabels: {} +deploymentAnnotations: {} + +containerSpec: + lifecycle: + enabled: false + preStop: + exec: + command: ["sleep","10"] + postStart: + httpGet: + host: example.com + path: /example + port: 90 + +replicaCount: 1 +MinReadySeconds: 60 +GracePeriod: 30 +image: + pullPolicy: IfNotPresent +restartPolicy: Always +service: + type: ClusterIP + # enabled: true + #name: "service-1234567890" + loadBalancerSourceRanges: [] + # loadBalancerSourceRanges: + # - 1.2.3.4/32 + # - 1.2.5.6/23 + annotations: {} + # test1: test2 + # test3: test4 +ContainerPort: + - name: app + port: 8080 + servicePort: 80 + envoyPort: 8799 + useHTTP2: false + supportStreaming: false + idleTimeout: 1800s + protocol: TCP +# servicemonitor: +# enabled: true +# path: /abc +# scheme: 'http' +# interval: 30s +# scrapeTimeout: 20s +# metricRelabelings: +# - sourceLabels: [namespace] +# regex: '(.*)' +# replacement: myapp +# targetLabel: target_namespace +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 1 + memory: 200Mi + requests: + cpu: 0.10 + memory: 100Mi + +# Optional configs +LivenessProbe: + Path: "" + port: 8080 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + tcp: false + command: [] + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + grpc: {} + + +ReadinessProbe: + Path: "" + port: 8080 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + tcp: false + command: [] + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + grpc: {} + + +StartupProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: [] + command: [] + tcp: false + grpc: {} + + +ingress: + enabled: false + className: "" + labels: {} + annotations: {} +# nginx.ingress.kubernetes.io/force-ssl-redirect: 'false' +# nginx.ingress.kubernetes.io/ssl-redirect: 'false' +# kubernetes.io/ingress.class: nginx +# nginx.ingress.kubernetes.io/rewrite-target: /$2 +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +istio: + enable: false + gateway: + enabled: false + labels: {} + annotations: {} + host: example.com + tls: + enabled: false + secretName: example-secret + virtualService: + enabled: false + labels: {} + annotations: {} + gateways: [] + hosts: [] + http: [] + # - match: + # - uri: + # prefix: /v1 + # - uri: + # prefix: /v2 + # timeout: 12 + # headers: + # request: + # add: + # x-some-header: "value" + # retries: + # attempts: 2 + # perTryTimeout: 3s + destinationRule: + enabled: false + labels: {} + annotations: {} + subsets: [] + trafficPolicy: {} + peerAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + mtls: + mode: "" + portLevelMtls: {} + requestAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + jwtRules: [] + authorizationPolicy: + enabled: false + labels: {} + annotations: {} + action: + provider: {} + rules: [] + +winterSoldier: + enabled: false + apiVersion: pincher.devtron.ai/v1alpha1 + annotation: {} + labels: {} + type: Deployment + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: [] + action: sleep + targetReplicas: [] + fieldSelector: + - AfterTime(AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) + +networkPolicy: + enabled: false + annotations: {} + labels: {} + podSelector: + matchExpressions: [] + matchLabels: {} + policyTypes: [] + ingress: [] + egress: [] + +flaggerCanary: + enabled: false + labels: {} + annotations: {} + createIstioGateway: + enabled: false + labels: {} + annotations: {} + host: + tls: + enabled: false + secretName: + # Istio gateways (optional) + addOtherGateways: [] + # Istio virtual service host names (optional) + addOtherHosts: [] + # Istio gateway refs (optional) + gatewayRefs: + # - name: istio-gateway + # namespace: istio-system + #service port + serviceport: 8080 + #containerPort + targetPort: 8080 + # discover all port open in container + portDiscovery: true + # application protocol (optional) + appProtocol: http + # Istio retry policy (optional) + retries: + # attempts: 3 + # perTryTimeout: 1s + # retryOn: "gateway-error,connect-failure,refused-stream" + # HTTP match conditions (optional) + match: + - uri: + prefix: / + # HTTP rewrite (optional) + rewriteUri: / + # timeout (optional) + timeout: + # Add headers (optional) + headers: + # request: + # add: + # x-some-header: "value" + # cross-origin resource sharing policy (optional) + corsPolicy: + # allowOrigin: + # - example.com + # allowMethods: + # - GET + # allowCredentials: false + # allowHeaders: + # - x-some-header + # maxAge: 24h + analysis: + # schedule interval (default 60s) + interval: 15s + # max number of failed metric checks before rollback + threshold: 5 + # max traffic percentage routed to canary + # percentage (0-100) + maxWeight: 50 + # canary increment step + # percentage (0-100) + stepWeight: 5 + thresholds: + # minimum req success rate (non 5xx responses) + # percentage (0-100) + successRate: 90 + # maximum req duration P99 + # milliseconds + latency: 500 + loadtest: + enabled: true + # load tester address + url: http://flagger-loadtester.istio-system/ + +ingressInternal: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +command: + workingDir: {} + enabled: false + value: [] + +args: + enabled: false + value: + - /bin/sh + - -c + - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 + +#For adding custom labels to pods + +podLabels: {} +# customKey: customValue +podAnnotations: {} +# customKey: customValue + +rawYaml: [] + +topologySpreadConstraints: [] + +initContainers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + +containers: [] + ## Additional containers to run along with application pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + +dbMigrationConfig: + enabled: false + +tolerations: [] + +podSecurityContext: {} + +containerSecurityContext: {} + +Spec: + Affinity: + Key: "" + # Key: kops.k8s.io/instancegroup + Values: "" + +affinity: + enabled: false + values: {} + +ambassadorMapping: + enabled: false + labels: {} + prefix: / + ambassadorId: "" + hostname: devtron.example.com + rewrite: "" + retryPolicy: {} + cors: {} + tls: + context: "" + create: false + secretName: "" + hosts: [] + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 70 + TargetMemoryUtilizationPercentage: 80 + annotations: {} + labels: {} + behavior: {} + containerResource: + enabled: false + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +kedaAutoscaling: + enabled: false + envSourceContainerName: "" # Optional. Default: .spec.template.spec.containers[0] + minReplicaCount: 1 + maxReplicaCount: 2 + advanced: {} + triggers: [] + triggerAuthentication: + enabled: false + name: "" + spec: {} + authenticationRef: {} + +# kedaHttpScaledObject: +# enabled: false +# minReplicaCount: 1 +# maxReplicaCount: 2 +# targetPendingRequests: +# scaledownPeriod: +# servicePort: 80 # port of the service (required) + +prometheus: + release: monitoring + +server: + deployment: + image_tag: 1-95af053 + image: "" + +servicemonitor: + additionalLabels: {} + +envoyproxy: + image: quay.io/devtron/envoy:v1.16.0 + configMapName: "" + lifecycle: {} + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: {} + +imagePullSecrets: [] + # - test1 + # - test2 +hostAliases: [] +# - ip: "127.0.0.1" +# hostnames: +# - "foo.local" +# - "bar.local" +# - ip: "10.1.2.3" +# hostnames: +# - "foo.remote" +# - "bar.remote" + +verticalPodScaling: + enabled: false \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/env-values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/env-values.yaml new file mode 100644 index 0000000000..48b794e8f2 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/env-values.yaml @@ -0,0 +1,66 @@ +replicaCount: 1 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 + +Spec: + Affinity: + Key: "" + Values: "" + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + behavior: {} +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# +secret: + enabled: false + data: {} +# my_own_secret: S3ViZXJuZXRlcyBXb3Jrcw== + +EnvVariables: [] +# - name: FLASK_ENV +# value: qa + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: "0.05" + memory: 50Mi + requests: + cpu: "0.01" + memory: 10Mi + + diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/pipeline-values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/pipeline-values.yaml new file mode 100644 index 0000000000..dbe4db3e8e --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/pipeline-values.yaml @@ -0,0 +1,6 @@ +deployment: + strategy: + recreate: {} + rolling: + maxSurge: "25%" + maxUnavailable: 1 diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/release-values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/release-values.yaml new file mode 100644 index 0000000000..48eb3f482c --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/release-values.yaml @@ -0,0 +1,14 @@ +server: + deployment: + image_tag: IMAGE_TAG + image: IMAGE_REPO + enabled: false +dbMigrationConfig: + enabled: false + +pauseForSecondsBeforeSwitchActive: 0 +waitForSecondsBeforeScalingDown: 0 +autoPromotionSeconds: 30 + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/schema.json b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/schema.json new file mode 100644 index 0000000000..6a332631a9 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/schema.json @@ -0,0 +1,1368 @@ + +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "containerExtraSpecs":{ + "type": "object", + "title": "containerExtraSpecs", + "description": "Define container extra specs here" + }, + "ContainerPort": { + "type": "array", + "description": "defines ports on which application services will be exposed to other services", + "title": "Container Port", + "items": { + "type": "object", + "properties": { + "envoyPort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "envoy port for the container", + "title": "Envoy Port" + }, + "idleTimeout": { + "type": "string", + "description": "duration of time for which a connection is idle before the connection is terminated", + "title": "Idle Timeout" + }, + "name": { + "type": "string", + "description": "name of the port", + "title": "Name" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Port", + "title": "port for the container" + }, + "servicePort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port of the corresponding kubernetes service", + "title": "Service Port" + }, + "nodePort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "nodeport of the corresponding kubernetes service", + "title": "Node Port" + }, + "supportStreaming": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "field to enable/disable timeout for high performance protocols like grpc", + "title": "Support Streaming" + }, + "useHTTP2": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": " field for setting if envoy container can accept(or not) HTTP2 requests", + "title": "Use HTTP2" + } + } + } + }, + "EnvVariables": { + "type": "array", + "items": {}, + "description": "contains environment variables needed by the containers", + "title": "Environment Variables" + }, + "EnvVariablesFromFieldPath":{ + "type": "array", + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs", + "title": "EnvVariablesFromFieldPath", + "items": [ + { + "type": "object", + "properties": { + "name":{ + "type": "string", + "title": "name", + "description": "Env variable name to be" + }, + "fieldPath":{ + "type": "string", + "title": "fieldPath", + "description": "Path of the field to select in the specified API version" + } + } + } + ] + }, + "EnvVariablesFromSecretKeys": { + "type": "array", + "description": "Selects a field of the deployment: It is use to get the name of Environment Variable name, Secret name and the Key name from which we are using the value in that corresponding Environment Variable.", + "title": "EnvVariablesFromSecretKeys", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name", + "description": "Env variable name to be used." + }, + "secretName": { + "type": "string", + "title": "secretName", + "description": "Name of Secret from which we are taking the value." + }, + "keyName": { + "type": "string", + "title": "keyName", + "description": "Name of The Key Where the value is mapped with." + } + } + } + ] + }, + "EnvVariablesFromConfigMapKeys": { + "type": "array", + "description": "Selects a field of the deployment: It is use to get the name of Environment Variable name, Config Map name and the Key name from which we are using the value in that corresponding Environment Variable.", + "title": "EnvVariablesFromConfigMapKeys", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name", + "description": "Env variable name to be used." + }, + "configMapName": { + "type": "string", + "title": "configMapName", + "description": "Name of configMap from which we are taking the value." + }, + "keyName": { + "type": "string", + "title": "keyName", + "description": "Name of The Key Where the value is mapped with." + } + } + } + ] + }, + "GracePeriod": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "time for which Kubernetes waits before terminating the pods", + "title": "Grace Period" + }, + "LivenessProbe": { + "type": "object", + "description": "used by the kubelet to know when to restart a container", + "title": "Liveness Probe", + "properties": { + "Path": { + "type": "string", + "description": "defines the path where the liveness needs to be checked", + "title": "Path" + }, + "command": { + "type": "array", + "items": {}, + "description": "commands executed to perform a probe", + "title": "Command" + }, + "failureThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the maximum number of failures that are acceptable before a given container is not considered as live", + "title": "Failure Threshold" + }, + "httpHeaders": { + "type": "array", + "items": {}, + "description": "used to override the default headers by defining .httpHeaders for the probe", + "title": "HTTP headers" + }, + "initialDelaySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to wait before a given container is checked for liveness", + "title": "Initial Delay Seconds" + }, + "periodSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to check a given container for liveness", + "title": "Period Seconds" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port to access on the container", + "title": "Port" + }, + "scheme": { + "type": "string", + "description": "Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.", + "title": "Scheme" + }, + "successThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the number of successes required before a given container is said to fulfil the liveness probe", + "title": "Success Threshold" + }, + "tcp": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "If enabled, the kubelet will attempt to open a socket to container. If connection is established, the container is considered healthy", + "title": "TCP" + }, + "timeoutSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time for checking timeout", + "title": "Timeout Seconds" + } + } + }, + "MaxSurge": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "maximum number of pods that can be created over the desired number of pods", + "title": "Maximum Surge" + }, + "MaxUnavailable": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "maximum number of pods that can be unavailable during the update process", + "title": "Maximum Unavailable" + }, + "MinReadySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available", + "title": "Minimum Ready Seconds" + }, + "ReadinessProbe": { + "type": "object", + "description": "kubelet uses readiness probes to know when a container is ready to start accepting traffic", + "title": "Readiness Probe", + "properties": { + "Path": { + "type": "string", + "description": "defines the path where the readiness needs to be checked", + "title": "Path" + }, + "command": { + "type": "array", + "items": {}, + "description": "commands executed to perform a probe", + "title": "Command" + }, + "failureThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the maximum number of failures that are acceptable before a given container is not considered as ready", + "title": "Failure Threshold" + }, + "httpHeader": { + "type": "array", + "items": {}, + "description": "used to override the default headers by defining .httpHeaders for the probe", + "title": "HTTP headers" + }, + "initialDelaySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to wait before a given container is checked for readiness", + "title": "Initial Delay Seconds" + }, + "periodSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to check a given container for readiness", + "title": "Period Seconds" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port to access on the container", + "title": "Port" + }, + "scheme": { + "type": "string", + "description": "Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.", + "title": "Scheme" + }, + "successThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the number of successes required before a given container is said to fulfil the readiness probe", + "title": "Success Threshold" + }, + "tcp": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "If enabled, the kubelet will attempt to open a socket to container. If connection is established, the container is considered healthy", + "title": "TCP" + }, + "timeoutSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time for checking timeout", + "title": "Timeout Seconds" + } + } + }, + "networkPolicy": { + "type": "object", + "description": "NetworkPolicy describes what network traffic is allowed for a set of Pods", + "title": "Network Policy", + "properties": { + "enabled":{ + "type":"boolean", + "description": "used to enable or disable NetworkPolicy" + }, + "annotations":{ + "type": "object", + "description": "Annotations for NetworkPolicy" + }, + "labels":{ + "type":"object", + "description": "Labels for NetworkPolicy" + }, + "podSelector":{ + "type": "object", + "description": "Selects the pods to which this NetworkPolicy object applies", + "properties": { + "matchExpressions":{ + "type":"array", + "description": "list of label selector" + }, + "matchLabels":{ + "type":"object", + "description": "map of {key,value} pairs" + } + } + }, + "policyTypes":{ + "type":"array", + "description": "List of rule types that the NetworkPolicy relates to. Valid options are Ingress,Egress." + }, + "ingress":{ + "type":"array", + "description": "List of ingress rules to be applied to the selected pods" + }, + "egress":{ + "type":"array", + "description": "List of egress rules to be applied to the selected pods" + } + } + }, + "istio": { + "type": "object", + "description": "Istio Service mesh", + "title": "Istio" + }, + "flaggerCanary":{ + "type": "object", + "description": "Flagger for canary release with istio service mesh", + "title": "Flagger Canary Release" + }, + "Spec": { + "type": "object", + "description": "used to define the desire state of the given container", + "title": "Spec", + "properties": { + "Affinity": { + "type": "object", + "description": "Node/Inter-pod Affinity allows you to constrain which nodes your pod is eligible to schedule on, based on labels of the node/pods", + "title": "Affinity", + "properties": { + "Key": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "description": "Key part of the label for node/pod selection", + "title": "Key" + } + ] + }, + "Values": { + "type": "string", + "description": "Value part of the label for node/pod selection", + "title": "Values" + }, + "key": { + "type": "string" + } + } + } + } + }, + "ambassadorMapping": { + "type": "object", + "description": "used to create ambassador mapping resource", + "title": "Mapping", + "properties": { + "ambassadorId": { + "type": "string", + "description": "used to specify id for specific ambassador mappings controller", + "title": "Ambassador ID" + }, + "cors": { + "type": "object", + "description": "used to specify cors policy to access host for this mapping", + "title": "CORS" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to specify whether to create an ambassador mapping or not", + "title": "Enabled" + }, + "weight": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to specify weight for canary ambassador mappings" + }, + "hostname": { + "type": "string", + "description": "used to specify hostname for ambassador mapping", + "title": "Hostname" + }, + "labels": { + "type": "object", + "description": "used to provide custom labels for ambassador mapping", + "title": "Labels" + }, + "prefix": { + "type": "string", + "description": "used to specify path for ambassador mapping", + "title": "Prefix" + }, + "retryPolicy": { + "type": "object", + "description": "used to specify retry policy for ambassador mapping", + "title": "Retry Policy" + }, + "rewrite": { + "type": "string", + "description": "used to specify whether to redirect the path of this mapping and where", + "title": "Rewrite" + }, + "tls": { + "type": "object", + "description": "used to create or define ambassador TLSContext resource", + "title": "TLS Context" + }, + "extraSpec": { + "type": "object", + "description": "used to provide extra spec values which not present in deployment template for ambassador resource", + "title": "Extra Spec" + } + } + }, + "args": { + "type": "object", + "description": " used to give arguments to command", + "title": "Arguments", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling aruguments", + "title": "Enabled" + }, + "value": { + "type": "array", + "description": "values of the arguments", + "title": "Value", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "autoscaling": { + "type": "object", + "description": "connected to HPA and controls scaling up and down in response to request load", + "title": "Autoscaling", + "properties": { + "MaxReplicas": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Maximum number of replicas allowed for scaling", + "title": "Maximum Replicas" + }, + "MinReplicas": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Minimum number of replicas allowed for scaling", + "title": "Minimum Replicas" + }, + "TargetCPUUtilizationPercentage": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "The target CPU utilization that is expected for a container", + "title": "TargetCPUUtilizationPercentage" + }, + "TargetMemoryUtilizationPercentage": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "The target memory utilization that is expected for a container", + "title": "TargetMemoryUtilizationPercentage" + }, + "behavior": { + "type": "object", + "description": "describes behavior and scaling policies for that behavior", + "title": "Behavior" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling autoscaling", + "title": "Enabled" + }, + "labels": { + "type": "object", + "description": "labels for HPA", + "title": "labels" + }, + "annotations": { + "type": "object", + "description": "used to configure some options for HPA", + "title": "annotations" + }, + "extraMetrics": { + "type": "array", + "items": {}, + "description": "used to give external metrics for autoscaling", + "title": "Extra Metrics" + } + } + }, + "command": { + "type": "object", + "description": "contains the commands for the server", + "title": "Command", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling commands" + }, + "value": { + "type": "array", + "items": {}, + "description": "contains the commands", + "title": "Value" + }, + "workingDir": { + "type": "object", + "items": {}, + "description": "contains the working directory", + "title": "Working directory" + } + } + }, + "containerSecurityContext": { + "type": "object", + "description": " defines privilege and access control settings for a Container", + "title": "Container Security Context" + }, + "containers": { + "type": "array", + "items": {}, + "description": " used to run side-car containers along with the main container within same pod" + }, + "dbMigrationConfig": { + "type": "object", + "description": "used to configure database migration", + "title": "Db Migration Config", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling the config", + "title": "Enabled" + } + } + }, + "envoyproxy": { + "type": "object", + "description": "envoy is attached as a sidecar to the application container to collect metrics like 4XX, 5XX, throughput and latency", + "title": "Envoy Proxy", + "properties": { + "configMapName": { + "type": "string", + "description": "configMap containing configuration for Envoy", + "title": "ConfigMap" + }, + "lifecycle":{ + "type": "object", + "description": "Actions that the management system should take in response to container lifecycle events", + "title": "lifecycle", + "properties": { + "enabled":{ + "type": "boolean" + }, + "postStart":{ + "type": "object", + "title": "postStart", + "description": "PostStart is called immediately after a container is created" + }, + "preStop":{ + "type": "object", + "title": "preStop", + "description": "PreStop is called immediately before a container is terminated" + } + } + }, + "image": { + "type": "string", + "description": "image of envoy to be used" + }, + "resources": { + "type": "object", + "description": "minimum and maximum RAM and CPU available to the application", + "title": "Resources", + "properties": { + "limits": { + "type": "object", + "description": "the maximum values a container can reach", + "title": "Limits", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "limit of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "limit of memory", + "title": "Memory" + } + } + }, + "requests": { + "type": "object", + "description": "request is what the container is guaranteed to get", + "title": "Requests", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "request value of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "request value of memory", + "title": "Memory" + } + } + } + } + } + } + }, + "hostAliases":{ + "type": "array", + "title": "hostAliases", + "description": "HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file", + "items": [ + { + "type": "object", + "properties": { + "ip":{ + "type": "string", + "title": "IP", + "description": "IP address of the host file entry" + }, + "hostnames":{ + "type": "array", + "description": "Hostnames for the above IP address", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "image": { + "type": "object", + "description": "used to access images in kubernetes", + "title": "Image", + "properties": { + "pullPolicy": { + "type": "string", + "description": "used to define the instances calling the image", + "title": "Pull Policy", + "enum": ["IfNotPresent", "Always"] + } + } + }, + "restartPolicy": { + "type": "string", + "description": "It restarts the docker container based on defined conditions.", + "title": "Restart Policy", + "enum": [ + "Always", + "OnFailure", + "Never" + ] + }, + "imagePullSecrets": { + "type": "array", + "items": {}, + "description": "contains the docker credentials that are used for accessing a registry", + "title": "Image PullSecrets" + }, + "winterSoldier": { + "type": "object", + "description": "allows to scale, sleep or delete the resource based on time.", + "title": "winterSoldier", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the winterSoldier controller", + "title": "Annotations" + }, + "labels": { + "type": "object", + "description": "labels for winterSoldier", + "title": "winterSoldier labels", + "default": "" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "apiVersion": { + "type": "string", + "description": "Api version for winterSoldier", + "title": "winterSoldier apiVersion", + "default": "pincher.devtron.ai/v1alpha1" + }, + "timeRangesWithZone": { + "type": "object", + "description": "describe time zone and time ranges to input in the winterSoldier", + "title": "Time Ranges With Zone", + "timeZone": { + "type": "string", + "description": "describe time zone, and follow standard format", + "title": "Time Zone" + }, + "timeRanges": { + "type": "array", + "items": {}, + "description": "used to take array of time ranges in which each element contains timeFrom, timeTo, weekdayFrom and weekdayTo.", + "title": "Time Ranges" + } + }, + "type": { + "type": "string", + "description": "describe the type of application Rollout/deployment.", + "title": "Type" + }, + "action": { + "type": "string", + "description": "describe the action to be performed by winterSoldier.", + "title": "Action" + }, + "targetReplicas": { + "type": "array", + "description": "describe the number of replicas to which the resource should scale up or down.", + "title": "Target Replicas" + }, + "fieldSelector": { + "type": "array", + "description": "it takes arrays of methods to select specific fields.", + "title": "Field Selector" + } + } + }, + "ingress": { + "type": "object", + "description": "allows public access to URLs", + "title": "Ingress", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the Ingress controller", + "title": "Annotations" + }, + "className": { + "type": "string", + "description": "name of ingress class, a reference to an IngressClass resource that contains additional configuration including the name of the controller", + "title": "Ingress class name", + "default": "nginx" + }, + "labels": { + "type": "object", + "description": "labels for ingress", + "title": "Ingress labels", + "default": "" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "hosts": { + "type": "array", + "description": "list of hosts in ingress", + "title": "Hosts", + "items": [ + { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "host URL", + "title": "Host" + }, + "pathType": { + "type": "string", + "description": "type of path", + "title": "PathType" + }, + "paths": { + "type": "array", + "description": "list of paths for a given host", + "title": "Paths", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "tls": { + "type": "array", + "items": {}, + "description": "contains security details - private key and certificate", + "title": "TLS" + } + } + }, + "ingressInternal": { + "type": "object", + "description": "allows private access to the URLs", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the Ingress controller", + "title": "Annotations" + }, + "className": { + "type": "string", + "description": "name of ingress class, a reference to an IngressClass resource that contains additional configuration including the name of the controller", + "title": "Ingress class name", + "default": "nginx-internal" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "hosts": { + "type": "array", + "description": "list of hosts in ingress", + "title": "Hosts", + "items": [ + { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "host URL", + "title": "Host" + }, + "pathType": { + "type": "string", + "description": "type of path", + "title": "PathType" + }, + "paths": { + "type": "array", + "description": "list of paths for a given host", + "title": "Paths", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "tls": { + "type": "array", + "items": {}, + "description": "contains security details - private key and certificate", + "title": "TLS" + } + } + }, + "initContainers": { + "type": "array", + "items": {}, + "description": "specialized containers that run before app containers in a Pod, can contain utilities or setup scripts not present in an app image", + "title": "Init Containers" + }, + "kedaAutoscaling": { + "type": "object", + "description": "Kubernetes-based event driven autoscaler. With KEDA, one can drive the scaling of any container in Kubernetes based on the no. of events needing to be processed", + "title": "KEDA Autoscaling", + "properties": { + "advanced": { + "type": "object" + }, + "authenticationRef": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "envSourceContainerName": { + "type": "string" + }, + "maxReplicaCount": { + "type": "integer" + }, + "minReplicaCount": { + "type": "integer" + }, + "triggerAuthentication": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "spec": { + "type": "object" + } + } + }, + "triggers": { + "type": "array", + "items": {} + } + } + }, + "containerSpec": { + "type":"object", + "description": "define the container specic configuration", + "title": "containerSpec", + "properties": { + "lifecycle": { + "type": "object", + "description": "Actions that the management system should take in response to container lifecycle events", + "title": "lifecycle", + "properties": { + "enabled":{ + "type": "boolean" + }, + "postStart":{ + "type": "object", + "title": "postStart", + "description": "PostStart is called immediately after a container is created.You could use this event to check that a required API is available before the container’s main work begins" + }, + "preStop":{ + "type": "object", + "title": "preStop", + "description": "PreStop is called immediately before a container is terminated" + } + } + } + } + }, + "pauseForSecondsBeforeSwitchActive": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "tell how much to wait for given period of time before switch active the container", + "title": "Pause For Seconds Before SwitchActive" + }, + "podAnnotations": { + "type":"object", + "description": "used to attach metadata and configs in Kubernetes", + "title": "Pod Annotations" + }, + "podDisruptionBudget": { + "type": "object", + "description": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", + "properties": { + "minAvailable":{ + "type": "string", + "title": "minAvailable", + "description": "An eviction is allowed if at least \"minAvailable\" pods selected by \"selector\" will still be available after the eviction, i.e. even in the absence of the evicted pod" + }, + "maxUnavailable":{ + "type": "string", + "title": "maxUnavailable", + "description": "An eviction is allowed if at most \"maxUnavailable\" pods selected by \"selector\" are unavailable after the eviction, i.e. even in absence of the evicted pod." + } + } + }, + "deploymentLabels": { + "type": "object", + "description": "deploymentLabels is an object to define the label on deployment.", + "title": "DeploymentLabels" + }, + "deploymentAnnotations": { + "type": "object", + "description": "deploymentAnnotations is an object to define the annotations on deployment.", + "title": "DeploymentAnnotations" + }, + "podExtraSpecs":{ + "type": "object", + "description": "ExtraSpec for the pods to be configured", + "title": "podExtraSpecs" + }, + "podLabels": { + "type":"object", + "description": "key/value pairs that are attached to pods, are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users, but do not directly imply semantics to the core system", + "title": "Pod Labels" + }, + "podSecurityContext": { + "type":"object", + "description": "defines privilege and access control settings for a Pod or Container", + "title": "Pod Security Context" + }, + "prometheus": { + "type": "object", + "description": "a kubernetes monitoring tool", + "title": "Prometheus", + "properties": { + "release": { + "type": "string", + "description": "name of the file to be monitored, describes the state of prometheus" + } + } + }, + "rawYaml": { + "type": "array", + "items": {}, + "description": "Accepts an array of Kubernetes objects. One can specify any kubernetes yaml here & it will be applied when a app gets deployed.", + "title": "Raw YAML" + }, + "replicaCount": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "count of Replicas of pod", + "title": "REplica Count" + }, + "resources": { + "type": "object", + "description": "minimum and maximum RAM and CPU available to the application", + "title": "Resources", + "properties": { + "limits": { + "type": "object", + "description": "the maximum values a container can reach", + "title": "Limits", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "limit of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "limit of memory", + "title": "Memory" + } + } + }, + "requests": { + "type": "object", + "description": "request is what the container is guaranteed to get", + "title": "Requests", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "request value of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "request value of memory", + "title": "Memory" + } + } + } + } + }, + "secret": { + "type": "object", + "properties": { + "data": { + "type": "object" + }, + "enabled": { + "type": "boolean" + } + } + }, + "server": { + "type": "object", + "description": "used for providing server configurations.", + "title": "Server", + "properties": { + "deployment": { + "type": "object", + "description": "gives the details for deployment", + "title": "Deployment", + "properties": { + "image": { + "type": "string", + "description": "URL of the image", + "title": "Image" + }, + "image_tag": { + "type": "string", + "description": "tag of the image", + "title": "Image Tag" + } + } + } + } + }, + "service": { + "type": "object", + "description": "defines annotations and the type of service", + "title": "Service", + "properties": { + "annotations": { + "type": "object", + "title": "Annotations", + "description": "annotations of service" + }, + "type": { + "type": "string", + "description": "type of service", + "title": "Type", + "enum": [ + "ClusterIP", + "LoadBalancer", + "NodePort", + "ExternalName" + ] + } + } + }, + "serviceAccount": { + "type": "object", + "description": "defines service account for pods", + "title": "Service Account", + "properties": { + "annotations": { + "type": "object", + "title": "Annotations", + "description": "annotations of service account" + }, + "name": { + "type": "string", + "description": "name of service account", + "title": "Name" + }, + "create": { + "type": "boolean" + } + } + }, + "servicemonitor": { + "type": "object", + "description": "gives the set of targets to be monitored", + "title": "Service Monitor", + "properties": { + "additionalLabels": { + "type": "object" + } + } + }, + "tolerations": { + "type": "array", + "items": {}, + "description": "a mechanism which work together with Taints which ensures that pods are not placed on inappropriate nodes", + "title": "Tolerations" + }, + "topologySpreadConstraints": { + "type": "array", + "items": {}, + "description": "used to control how Pods are spread across a cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains", + "title": "Topology Spread Constraints" + }, + "volumeMounts": { + "type": "array", + "items": {}, + "description": "used to provide mounts to the volume", + "title": "Volume Mounts" + }, + "volumes": { + "type": "array", + "items": {}, + "description": "required when some values need to be read from or written to an external disk", + "title": "Volumes" + }, + "waitForSecondsBeforeScalingDown": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Wait for given period of time before scaling down the container", + "title": "Wait For Seconds Before Scaling Down" + } + } +} + diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/secrets-test-values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/secrets-test-values.yaml new file mode 100644 index 0000000000..4a20404db8 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/secrets-test-values.yaml @@ -0,0 +1 @@ +{"ConfigSecrets":{"enabled":true,"secrets":[{"data":{"standard_key":"c3RhbmRhcmQtdmFsdWU="},"external":false,"externalType":"","mountPath":"/test","name":"normal-secret","type":"volume"},{"data":{"secret_key":"U0VDUkVUIERBVEE="},"external":true,"externalType":"AWSSecretsManager","mountPath":"","name":"external-secret-3","type":"environment"}]}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/NOTES.txt b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/NOTES.txt new file mode 100644 index 0000000000..2b14478168 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range $.Values.ingress.paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include ".Chart.Name .fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ include ".Chart.Name .fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include ".Chart.Name .fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include ".Chart.Name .name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/_helpers.tpl b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/_helpers.tpl new file mode 100644 index 0000000000..10de322e2a --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/_helpers.tpl @@ -0,0 +1,167 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define ".Chart.Name .name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create service name +*/}} +{{- define ".servicename" -}} +{{- if .Values.service.name -}} +{{- .Values.service.name | trunc 63 | trimSuffix "-" -}} +{{- else if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 55 | trimSuffix "-" -}}-service +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 55 | trimSuffix "-" -}}-service +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 55 | trimSuffix "-" -}}-service +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create preview service name +*/}} +{{- define ".previewservicename" -}} +{{- if .Values.service.name -}} +{{- .Values.service.name | trunc 55 | trimSuffix "-" -}}-preview +{{- else if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 47 | trimSuffix "-" -}}-preview-service +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 47 | trimSuffix "-" -}}-preview-service +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 47 | trimSuffix "-" -}}-preview-service +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define ".Chart.Name .fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define ".Chart.Name .chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define ".Chart.Name .color" -}} +{{- $active0 := (index .Values.server.deployment 0).enabled -}} +{{/* +{{- $active1 := (index .Values.server.deployment 1).enabled -}} +*/}} +{{- $active1 := include "safeenabledcheck" . -}} +{{- $active := and $active0 $active1 -}} +{{- $active -}} +{{- end -}} + +{{- define "safeenabledcheck" -}} +{{- if (eq (len .Values.server.deployment) 2) -}} + {{- if (index .Values.server.deployment 1).enabled -}} + {{- $active := true -}} + {{- $active -}} + {{- else -}} + {{- $active := false -}} + {{- $active -}} + {{- end -}} +{{- else -}} + {{- $active := false -}} + {{- $active -}} +{{- end -}} +{{- end -}} + + +{{- define "isCMVolumeExists" -}} + {{- $isCMVolumeExists := false -}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $isCMVolumeExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{- $isCMVolumeExists -}} +{{- end -}} + +{{- define "isSecretVolumeExists" -}} + {{- $isSecretVolumeExists := false -}} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $isSecretVolumeExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{- $isSecretVolumeExists -}} +{{- end -}} + + + + +{{- define "serviceMonitorEnabled" -}} + {{- $SMenabled := false -}} + {{- range .Values.ContainerPort }} + {{- if .servicemonitor }} + {{- if and .servicemonitor.enabled }} + {{- $SMenabled = true -}} + {{- end }} + {{- end }} + {{- end }} + {{- $SMenabled -}} +{{- end -}} + +{{- define "VerticalPodAutoScalingEnabled" -}} + {{- $SMenabled := false -}} + {{- if and .Values.verticalPodScaling.enabled }} + {{- $SMenabled = true -}} + {{- end }} + {{- $SMenabled -}} +{{- end -}} + +{{/* Create the name of the service account to use */}} +{{- define "serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include ".Chart.Name .fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Check for app/release labels in customPodLabels and replace accordingly */}} +{{- define "customPodLabelsContainsApp" -}} + {{- $LabelsContain := false -}} + {{- if hasKey .Values.customPodLabels "app" }} + {{- $LabelsContain = true -}} + {{- end }} + {{- $LabelsContain -}} +{{- end -}} + +{{- define "customPodLabelsContainsRelease" -}} + {{- $LabelsContain := false -}} + {{- if hasKey .Values.customPodLabels "release" }} + {{- $LabelsContain = true -}} + {{- end }} + {{- $LabelsContain -}} +{{- end -}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ambassador.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ambassador.yaml new file mode 100644 index 0000000000..9d4a431c26 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ambassador.yaml @@ -0,0 +1,94 @@ +{{ $svcName := include ".servicename" . }} +{{ $svcPort := (index .Values.ContainerPort 0).servicePort }} +{{- if $.Values.ambassadorMapping.enabled }} +{{- with $.Values.ambassadorMapping }} +apiVersion: getambassador.io/v3alpha1 +kind: Mapping +metadata: + {{- if .name }} + name: {{ .name }} + {{- else }} + name: {{ include ".Chart.Name .fullname" $ }}-mapping + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ $.Values.pipelineName }} + {{- if .labels }} +{{ toYaml .labels | nindent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .ambassadorId }} + ambassador_id: {{ .ambassadorId }} + {{- end }} + {{- if .hostname }} + hostname: {{ .hostname | quote }} + {{- end }} + prefix: {{ .prefix }} + {{- if .rewrite }} + rewrite: {{ .rewrite }} + {{- end }} + service: {{ $svcName }}.{{ $.Release.Namespace }}:{{ $svcPort }} + {{- if .retryPolicy }} + retry_policy: +{{ toYaml .retryPolicy | indent 4 }} + {{- end }} + {{- if .cors }} + cors: +{{ toYaml .cors | indent 4 }} + {{- end }} + {{- if .weight }} + weight: {{ .weight }} + {{- end }} + {{- if .method }} + method: {{ .method }} + {{- end }} + {{- if .extraSpec }} +{{ toYaml .extraSpec | indent 2 }} + {{- end }} + {{- if .tls }} + {{- if .tls.context }} + tls: {{ .tls.context }} +{{- if .tls.create }} +--- +apiVersion: getambassador.io/v3alpha1 +kind: TLSContext +metadata: + name: {{ .tls.context }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ $.Values.pipelineName }} + {{- if .tls.labels }} +{{ toYaml .tls.labels | nindent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .tls.secretName }} + secret: {{ .tls.secretName }} + {{- end }} + {{- if .tls.hosts }} + hosts: +{{ toYaml .tls.hosts | nindent 4 }} + {{- end }} + {{- if .tls.extraSpec }} +{{ toYaml .tls.extraSpec | indent 2 }} + {{- end }} +{{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/configmap.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/configmap.yaml new file mode 100644 index 0000000000..4e7879665e --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/configmap.yaml @@ -0,0 +1,22 @@ +{{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{if eq .external false}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .name}}-{{ $.Values.app }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +data: +{{ toYaml .data | trim | indent 2 }} + {{- end}} + {{- end}} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/deployment.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/deployment.yaml new file mode 100644 index 0000000000..1ac0dd96a4 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/deployment.yaml @@ -0,0 +1,1264 @@ + {{- $hasCMEnvExists := false -}} + {{- $hasCMVolumeExists := false -}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $hasCMVolumeExists = true}} + {{- end }} + {{- if eq .type "environment"}} + {{- $hasCMEnvExists = true}} + {{- end }} + {{- end }} + {{- end }} + + {{- $hasPVCExists := false -}} + {{- if .Values.persistentVolumeClaim.name }} + {{- $hasPVCExists = true }} + {{- end }} + + {{- $hasSecretEnvExists := false -}} + {{- $hasSecretVolumeExists := false -}} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $hasSecretVolumeExists = true}} + {{- end }} + {{- if eq .type "environment"}} + {{- $hasSecretEnvExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{ $CustomLabelsApp:= include "customPodLabelsContainsApp" . }} + {{ $CustomLabelsRelease:= include "customPodLabelsContainsRelease" . }} + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include ".Chart.Name .fullname" $ }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ .Values.pipelineName }} +{{- if .Values.deploymentLabels }} +{{ toYaml .Values.deploymentLabels | indent 4 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + +{{- if .Values.deploymentAnnotations }} + annotations: +{{ toYaml .Values.deploymentAnnotations | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: +{{- if .Values.customMatchLabels }} +{{ toYaml .Values.customMatchLabels | indent 6 }} +{{- else }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + release: {{ .Values.customPodLabels.release | default $.Release.Name }} +{{- end }} + replicas: {{ $.Values.replicaCount }} + minReadySeconds: {{ $.Values.MinReadySeconds }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: + {{- range $key, $value := .Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + labels: + {{- if not (eq "true" $CustomLabelsApp) }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + {{- end }} + {{- if not (eq "true" $CustomLabelsRelease) }} + release: {{ .Values.customPodLabels.release |default $.Release.Name }} + {{- end }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} +{{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 8 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 8 }} +{{- end }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + spec: +{{- if $.Values.podExtraSpecs }} +{{ toYaml .Values.podExtraSpecs | indent 6 }} +{{- end }} + terminationGracePeriodSeconds: {{ $.Values.GracePeriod }} +{{- if $.Values.hostAliases }} + hostAliases: +{{ toYaml .Values.hostAliases | indent 8 }} +{{- end }} +{{- if and $.Values.Spec.Affinity.Key $.Values.Spec.Affinity.Values }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ $.Values.Spec.Affinity.Key }} + operator: In + values: + - {{ $.Values.Spec.Affinity.Values | default "nodes" }} +{{- else if $.Values.affinity.enabled }} + affinity: +{{ toYaml .Values.affinity.values | indent 8 }} +{{- end }} +{{- if $.Values.serviceAccountName }} + serviceAccountName: {{ $.Values.serviceAccountName }} +{{- else }} + serviceAccountName: {{ template "serviceAccountName" . }} +{{- end }} +{{- if $.Values.schedulerName }} + schedulerName: {{ .Values.schedulerName }} +{{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} +{{- if $.Values.imagePullSecrets}} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end }} +{{- end}} +{{- if $.Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range $.Values.topologySpreadConstraints }} + - maxSkew: {{ .maxSkew }} + topologyKey: {{ .topologyKey }} + whenUnsatisfiable: {{ .whenUnsatisfiable }} + {{- if semverCompare "<=1.30-0" $.Capabilities.KubeVersion.GitVersion }} + {{- if .minDomains }} + minDomains: {{ .minDomains }} + {{- end }} + {{- end }} + {{- if .nodeAffinityPolicy }} + nodeAffinityPolicy: {{ .nodeAffinityPolicy }} + {{- end }} + {{- if .nodeTaintsPolicy }} + nodeTaintsPolicy: {{ .nodeTaintsPolicy }} + {{- end }} + labelSelector: + matchLabels: + {{- if and .autoLabelSelector .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- else if .autoLabelSelector }} + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} + {{- else if .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- end }} +{{- end }} +{{- end }} +{{- if $.Values.topologySpreadConstraint }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraint }} +{{- end }} +{{- if $.Values.podSecurityContext }} + securityContext: +{{ toYaml .Values.podSecurityContext | indent 8 }} +{{- end }} +{{- if $.Values.restartPolicy }} + restartPolicy: {{ $.Values.restartPolicy }} +{{- else }} + restartPolicy: Always +{{- end }} +{{- if $.Values.initContainers}} + initContainers: +{{- range $i, $c := .Values.initContainers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-init-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .args}} + args: +{{ toYaml .args | indent 12 -}} +{{- end}} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + containers: + - name: {{ $.Chart.Name }} + image: "{{ .Values.server.deployment.image }}:{{ .Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} + {{- if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- if $.Values.containerSpec.lifecycle.postStart }} + postStart: +{{ toYaml $.Values.containerSpec.lifecycle.postStart | indent 12 -}} + {{- end }} + {{- end }} +{{- if and $.Values.containerSecurityContext $.Values.privileged }} + securityContext: + privileged: true +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- else if $.Values.privileged }} + securityContext: + privileged: true +{{- else if $.Values.containerSecurityContext }} + securityContext: +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- end }} +{{- if $.Values.containerExtraSpecs }} +{{ toYaml .Values.containerExtraSpecs | indent 10 }} +{{- end }} +{{- if $.Values.resizePolicy }} + resizePolicy: +{{ toYaml .Values.resizePolicy | indent 12 }} +{{- end }} + ports: + {{- range $.Values.ContainerPort }} + - name: {{ .name}} + containerPort: {{ .port }} + protocol: {{ .protocol | default "TCP" }} + {{- end}} +{{- if and $.Values.command.enabled $.Values.command.workingDir }} + workingDir: {{ $.Values.command.workingDir }} +{{- end}} +{{- if and $.Values.command.value $.Values.command.enabled}} + command: +{{ toYaml $.Values.command.value | indent 12 -}} +{{- end}} +{{- if and $.Values.args.value $.Values.args.enabled}} + args: +{{ toYaml $.Values.args.value | indent 12 -}} +{{- end }} + env: + - name: CONFIG_HASH + value: {{ include (print $.Chart.Name "/templates/configmap.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.ConfigHash) }}{{ .Values.devtronInternal.containerSpecs.ConfigHash }}{{ end }} + - name: SECRET_HASH + value: {{ include (print $.Chart.Name "/templates/secret.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.SecretHash) }}{{ .Values.devtronInternal.containerSpecs.SecretHash }}{{ end }} + - name: DEVTRON_APP_NAME + value: {{ template ".Chart.Name .name" $ }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DEVTRON_CONTAINER_REPO + value: "{{ .Values.server.deployment.image }}" + - name: DEVTRON_CONTAINER_TAG + value: "{{ .Values.server.deployment.image_tag }}" + {{- range $.Values.EnvVariablesFromFieldPath }} + - name: {{ .name }} + valueFrom: + fieldRef: + fieldPath: {{ .fieldPath }} + {{- end}} + {{- range $.Values.EnvVariables }} + {{- if and .name .value }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromSecretKeys }} + {{- if and .name .secretName .keyName }} + - name: {{ .name }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromConfigMapKeys }} + {{- if and .name .configMapName .keyName }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ .configMapName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- if or (and ($hasCMEnvExists) (.Values.ConfigMaps.enabled)) (and ($hasSecretEnvExists) (.Values.ConfigSecrets.enabled)) }} + envFrom: + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "environment" }} + - configMapRef: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "environment" }} + - secretRef: + {{if eq .external true}} + name: {{ .name }} + {{else if eq .external false}} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + +{{- if or $.Values.LivenessProbe.Path $.Values.LivenessProbe.command $.Values.LivenessProbe.tcp $.Values.LivenessProbe.grpc }} + livenessProbe: +{{- if $.Values.LivenessProbe.Path }} + httpGet: + path: {{ $.Values.LivenessProbe.Path }} + port: {{ $.Values.LivenessProbe.port }} + scheme: {{ $.Values.LivenessProbe.scheme }} + {{- if $.Values.LivenessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.LivenessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.LivenessProbe.command }} + exec: + command: +{{ toYaml .Values.LivenessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.LivenessProbe.tcp }} + tcpSocket: + port: {{ $.Values.LivenessProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.LivenessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.LivenessProbe.periodSeconds }} + successThreshold: {{ $.Values.LivenessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.LivenessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.LivenessProbe.failureThreshold }} + {{- if $.Values.LivenessProbe.grpc }} + grpc: +{{ toYaml .Values.LivenessProbe.grpc | indent 14 }} + {{- end }} +{{- end }} +{{- if or $.Values.ReadinessProbe.Path $.Values.ReadinessProbe.command $.Values.ReadinessProbe.tcp $.Values.ReadinessProbe.grpc }} + readinessProbe: +{{- if $.Values.ReadinessProbe.Path }} + httpGet: + path: {{ $.Values.ReadinessProbe.Path }} + port: {{ $.Values.ReadinessProbe.port }} + scheme: {{ $.Values.ReadinessProbe.scheme }} + {{- if $.Values.ReadinessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.ReadinessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.ReadinessProbe.command }} + exec: + command: +{{ toYaml .Values.ReadinessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.ReadinessProbe.tcp }} + tcpSocket: + port: {{ $.Values.ReadinessProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.ReadinessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.ReadinessProbe.periodSeconds }} + successThreshold: {{ $.Values.ReadinessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.ReadinessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.ReadinessProbe.failureThreshold }} + {{- if $.Values.ReadinessProbe.grpc }} + grpc: +{{ toYaml .Values.ReadinessProbe.grpc | indent 14 }} + {{- end}} +{{- end }} + resources: +{{ toYaml $.Values.resources | trim | indent 12 }} +{{- if or $.Values.StartupProbe.Path $.Values.StartupProbe.command $.Values.StartupProbe.tcp $.Values.StartupProbe.grpc }} + startupProbe: +{{- if $.Values.StartupProbe.Path }} + httpGet: + path: {{ $.Values.StartupProbe.Path }} + port: {{ $.Values.StartupProbe.port }} + {{- if $.Values.StartupProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.StartupProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.StartupProbe.command }} + exec: + command: +{{ toYaml .Values.StartupProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.StartupProbe.tcp }} + tcpSocket: + port: {{ $.Values.StartupProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.StartupProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.StartupProbe.periodSeconds }} + successThreshold: {{ $.Values.StartupProbe.successThreshold }} + timeoutSeconds: {{ $.Values.StartupProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.StartupProbe.failureThreshold }} + {{- if $.Values.StartupProbe.grpc }} + grpc: +{{ toYaml .Values.StartupProbe.grpc | indent 14 }} + {{- end}} +{{- end }} + volumeMounts: +{{- with .Values.volumeMounts }} +{{ toYaml . | trim | indent 12 }} +{{- end }} +{{- if $.Values.persistentVolumeClaim.name }} + - name: {{ .Values.persistentVolumeClaim.name }}-vol + mountPath: {{ .Values.persistentVolumeClaim.mountPath | default "/tmp" }} +{{- end}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{- range $k, $v := .data }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{if (or (eq .externalType "ESO_GoogleSecretsManager") (eq .externalType "ESO_AWSSecretsManager") (eq .externalType "ESO_HashiCorpVault") (eq .externalType "ESO_AzureSecretsManager"))}} + {{- if and (.esoSubPath) (ne (len .esoSubPath) 0) }} + {{- range .esoSubPath }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ . }} + subPath: {{ . }} + {{- end }} + {{- else }} + {{- range .esoSecretData.esoData }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ .secretKey }} + subPath: {{ .secretKey }} + {{- end }} + {{- end }} + {{- else }} + {{- range $k, $v := .data }} # for others secrets the mount path will be .data[i].secretKey + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) }} []{{- end }} + {{- if and (eq (len .Values.volumeMounts) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) }} [] {{- end }} +{{- if $.Values.appMetrics }} + - name: envoy + image: {{ $.Values.envoyproxy.image | default "quay.io/devtron/envoy:v1.16.0"}} + {{- if $.Values.envoyproxy.lifecycle }} + lifecycle: +{{ toYaml .Values.envoyproxy.lifecycle | indent 12 -}} + {{- else if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- end }} + resources: +{{ toYaml $.Values.envoyproxy.resources | trim | indent 12 }} + ports: + - containerPort: 9901 + protocol: TCP + name: envoy-admin + {{- range $index, $element := .Values.ContainerPort }} + - name: envoy-{{ $element.name}} + containerPort: {{ $element.envoyPort | default (add 8790 $index) }} + protocol: TCP + {{- end }} + command: ["/usr/local/bin/envoy"] + args: ["-c", "/etc/envoy-config/envoy-config.json", "-l", "info", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"] + volumeMounts: + - name: {{ $.Values.envoyproxy.configMapName | default "envoy-config-volume" }} + mountPath: /etc/envoy-config/ +{{- if $.Values.envoyproxy.readinessProbe}} + readinessProbe: +{{ toYaml $.Values.envoyproxy.readinessProbe | indent 12}} +{{- end }} +{{- if $.Values.envoyproxy.livenessProbe}} + livenessProbe: +{{ toYaml $.Values.envoyproxy.livenessProbe | indent 12}} +{{- end }} +{{- end}} +{{- if $.Values.containers }} +{{- range $i, $c := .Values.containers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-sidecontainer-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .env }} + env: +{{ toYaml .env | indent 12 }} +{{- end }} + {{- if .envFrom }} + envFrom: +{{ toYaml .env | indent 12 }} +{{- end }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .resizePolicy }} + resizePolicy: +{{ toYaml .resziePolicy | indent 12}} +{{- end }} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + + + volumes: + {{- if $.Values.appMetrics }} + - name: envoy-config-volume + configMap: + name: sidecar-config-{{ template ".Chart.Name .name" $ }} + {{- end }} +{{- with .Values.volumes }} +{{ toYaml . | trim | indent 8 }} +{{- end }} +{{- if .Values.persistentVolumeClaim.name }} + - name: {{.Values.persistentVolumeClaim.name}}-vol + persistentVolumeClaim: + claimName: {{.Values.persistentVolumeClaim.name }} +{{- end}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + configMap: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + secret: + {{- if eq .external true }} + secretName: {{ .name }} + {{- else if eq .external false }} + secretName: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) (eq (.Values.appMetrics) false) }} []{{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) (eq (.Values.appMetrics) false) }} [] {{- end }} + + revisionHistoryLimit: 3 +## pauseForSecondsBeforeSwitchActive: {{ $.Values.pauseForSecondsBeforeSwitchActive }} +# waitForSecondsBeforeScalingDown: {{ $.Values.waitForSecondsBeforeScalingDown }} + strategy: + {{- if eq .Values.deploymentType "ROLLING" }} + type: "RollingUpdate" + rollingUpdate: + maxSurge: {{ $.Values.deployment.strategy.rolling.maxSurge }} + maxUnavailable: {{ $.Values.deployment.strategy.rolling.maxUnavailable }} + {{- end }} + {{- if eq .Values.deploymentType "RECREATE" }} + type: "Recreate" + {{- end }} +{{- if $.Values.secondaryWorkload.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include ".Chart.Name .fullname" $ }}-{{ $.Values.secondaryWorkload.postfix | default "sec" }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ .Values.pipelineName }} +{{- if .Values.deploymentLabels }} +{{ toYaml .Values.deploymentLabels | indent 4 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + +{{- if .Values.deploymentAnnotations }} + annotations: +{{ toYaml .Values.deploymentAnnotations | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: +{{- if .Values.customMatchLabels }} +{{ toYaml .Values.customMatchLabels | indent 6 }} +{{- else }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + release: {{ .Values.customPodLabels.release | default $.Release.Name }} +{{- end }} + replicas: {{ $.Values.secondaryWorkload.replicaCount | default 1 }} + minReadySeconds: {{ $.Values.MinReadySeconds }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: + {{- range $key, $value := .Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + labels: + {{- if not (eq "true" $CustomLabelsApp) }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + {{- end }} + {{- if not (eq "true" $CustomLabelsRelease) }} + release: {{ .Values.customPodLabels.release |default $.Release.Name }} + {{- end }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} +{{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 8 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 8 }} +{{- end }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + spec: +{{- if $.Values.podExtraSpecs }} +{{ toYaml .Values.podExtraSpecs | indent 6 }} +{{- end }} + terminationGracePeriodSeconds: {{ $.Values.GracePeriod }} +{{- if $.Values.hostAliases }} + hostAliases: +{{ toYaml .Values.hostAliases | indent 8 }} +{{- end }} +{{- with $.Values.secondaryWorkload }} +{{- if and .Spec.Affinity.Key .Spec.Affinity.Values }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .Spec.Affinity.Key }} + operator: In + values: + - {{ .Spec.Affinity.Values | default "nodes" }} +{{- else if .affinity.enabled }} + affinity: +{{ toYaml .affinity.values | indent 8 }} +{{- end }} +{{- end }} +{{- if $.Values.serviceAccountName }} + serviceAccountName: {{ $.Values.serviceAccountName }} +{{- else }} + serviceAccountName: {{ template "serviceAccountName" . }} +{{- end }} +{{- if $.Values.schedulerName }} + schedulerName: {{ .Values.schedulerName }} +{{- end }} + {{- if $.Values.secondaryWorkload.tolerations }} + tolerations: +{{ toYaml $.Values.secondaryWorkload.tolerations | indent 8 }} + {{- end }} +{{- if $.Values.imagePullSecrets}} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end }} +{{- end}} +{{- if $.Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range $.Values.topologySpreadConstraints }} + - maxSkew: {{ .maxSkew }} + topologyKey: {{ .topologyKey }} + whenUnsatisfiable: {{ .whenUnsatisfiable }} + {{- if semverCompare "<=1.30-0" $.Capabilities.KubeVersion.GitVersion }} + {{- if .minDomains }} + minDomains: {{ .minDomains }} + {{- end }} + {{- end }} + {{- if .nodeAffinityPolicy }} + nodeAffinityPolicy: {{ .nodeAffinityPolicy }} + {{- end }} + {{- if .nodeTaintsPolicy }} + nodeTaintsPolicy: {{ .nodeTaintsPolicy }} + {{- end }} + labelSelector: + matchLabels: + {{- if and .autoLabelSelector .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- else if .autoLabelSelector }} + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} + {{- else if .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- end }} +{{- end }} +{{- end }} +{{- if $.Values.topologySpreadConstraint }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraint }} +{{- end }} +{{- if $.Values.podSecurityContext }} + securityContext: +{{ toYaml .Values.podSecurityContext | indent 8 }} +{{- end }} +{{- if $.Values.restartPolicy }} + restartPolicy: {{ $.Values.restartPolicy }} +{{- else }} + restartPolicy: Always +{{- end }} +{{- if $.Values.initContainers}} + initContainers: +{{- range $i, $c := .Values.initContainers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-init-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .args}} + args: +{{ toYaml .args | indent 12 -}} +{{- end}} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + containers: + - name: {{ $.Chart.Name }} + image: "{{ .Values.server.deployment.image }}:{{ .Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} + {{- if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- if $.Values.containerSpec.lifecycle.postStart }} + postStart: +{{ toYaml $.Values.containerSpec.lifecycle.postStart | indent 12 -}} + {{- end }} + {{- end }} +{{- if and $.Values.containerSecurityContext $.Values.privileged }} + securityContext: + privileged: true +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- else if $.Values.privileged }} + securityContext: + privileged: true +{{- else if $.Values.containerSecurityContext }} + securityContext: +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- end }} +{{- if $.Values.containerExtraSpecs }} +{{ toYaml .Values.containerExtraSpecs | indent 10 }} +{{- end }} +{{- if $.Values.resizePolicy }} + resizePolicy: +{{ toYaml .Values.resizePolicy | indent 12 }} +{{- end }} + ports: + {{- range $.Values.ContainerPort }} + - name: {{ .name}} + containerPort: {{ .port }} + protocol: {{ .protocol | default "TCP" }} + {{- end}} +{{- if and $.Values.command.enabled $.Values.command.workingDir }} + workingDir: {{ $.Values.command.workingDir }} +{{- end}} +{{- if and $.Values.command.value $.Values.command.enabled}} + command: +{{ toYaml $.Values.command.value | indent 12 -}} +{{- end}} +{{- if and $.Values.args.value $.Values.args.enabled}} + args: +{{ toYaml $.Values.args.value | indent 12 -}} +{{- end }} + env: + - name: CONFIG_HASH + value: {{ include (print $.Chart.Name "/templates/configmap.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.ConfigHash) }}{{ .Values.devtronInternal.containerSpecs.ConfigHash }}{{ end }} + - name: SECRET_HASH + value: {{ include (print $.Chart.Name "/templates/secret.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.SecretHash) }}{{ .Values.devtronInternal.containerSpecs.SecretHash }}{{ end }} + - name: DEVTRON_APP_NAME + value: {{ template ".Chart.Name .name" $ }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DEVTRON_CONTAINER_REPO + value: "{{ .Values.server.deployment.image }}" + - name: DEVTRON_CONTAINER_TAG + value: "{{ .Values.server.deployment.image_tag }}" + {{- range $.Values.EnvVariablesFromFieldPath }} + - name: {{ .name }} + valueFrom: + fieldRef: + fieldPath: {{ .fieldPath }} + {{- end}} + {{- range $.Values.EnvVariables }} + {{- if and .name .value }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromSecretKeys }} + {{- if and .name .secretName .keyName }} + - name: {{ .name }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromConfigMapKeys }} + {{- if and .name .configMapName .keyName }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ .configMapName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- if or (and ($hasCMEnvExists) (.Values.ConfigMaps.enabled)) (and ($hasSecretEnvExists) (.Values.ConfigSecrets.enabled)) }} + envFrom: + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "environment" }} + - configMapRef: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "environment" }} + - secretRef: + {{if eq .external true}} + name: {{ .name }} + {{else if eq .external false}} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + +{{- if or $.Values.LivenessProbe.Path $.Values.LivenessProbe.command $.Values.LivenessProbe.tcp $.Values.LivenessProbe.grpc }} + livenessProbe: +{{- if $.Values.LivenessProbe.Path }} + httpGet: + path: {{ $.Values.LivenessProbe.Path }} + port: {{ $.Values.LivenessProbe.port }} + scheme: {{ $.Values.LivenessProbe.scheme }} + {{- if $.Values.LivenessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.LivenessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.LivenessProbe.command }} + exec: + command: +{{ toYaml .Values.LivenessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.LivenessProbe.tcp }} + tcpSocket: + port: {{ $.Values.LivenessProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.LivenessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.LivenessProbe.periodSeconds }} + successThreshold: {{ $.Values.LivenessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.LivenessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.LivenessProbe.failureThreshold }} + {{- if $.Values.LivenessProbe.grpc }} + grpc: +{{ toYaml .Values.LivenessProbe.grpc | indent 14 }} + {{- end }} +{{- end }} +{{- if or $.Values.ReadinessProbe.Path $.Values.ReadinessProbe.command $.Values.ReadinessProbe.tcp $.Values.ReadinessProbe.grpc }} + readinessProbe: +{{- if $.Values.ReadinessProbe.Path }} + httpGet: + path: {{ $.Values.ReadinessProbe.Path }} + port: {{ $.Values.ReadinessProbe.port }} + scheme: {{ $.Values.ReadinessProbe.scheme }} + {{- if $.Values.ReadinessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.ReadinessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.ReadinessProbe.command }} + exec: + command: +{{ toYaml .Values.ReadinessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.ReadinessProbe.tcp }} + tcpSocket: + port: {{ $.Values.ReadinessProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.ReadinessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.ReadinessProbe.periodSeconds }} + successThreshold: {{ $.Values.ReadinessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.ReadinessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.ReadinessProbe.failureThreshold }} + {{- if $.Values.ReadinessProbe.grpc }} + grpc: +{{ toYaml .Values.ReadinessProbe.grpc | indent 14 }} + {{- end}} +{{- end }} + resources: +{{ toYaml $.Values.resources | trim | indent 12 }} +{{- if or $.Values.StartupProbe.Path $.Values.StartupProbe.command $.Values.StartupProbe.tcp $.Values.StartupProbe.grpc }} + startupProbe: +{{- if $.Values.StartupProbe.Path }} + httpGet: + path: {{ $.Values.StartupProbe.Path }} + port: {{ $.Values.StartupProbe.port }} + {{- if $.Values.StartupProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.StartupProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.StartupProbe.command }} + exec: + command: +{{ toYaml .Values.StartupProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.StartupProbe.tcp }} + tcpSocket: + port: {{ $.Values.StartupProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.StartupProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.StartupProbe.periodSeconds }} + successThreshold: {{ $.Values.StartupProbe.successThreshold }} + timeoutSeconds: {{ $.Values.StartupProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.StartupProbe.failureThreshold }} + {{- if $.Values.StartupProbe.grpc }} + grpc: +{{ toYaml .Values.StartupProbe.grpc | indent 14 }} + {{- end}} +{{- end }} + volumeMounts: +{{- with .Values.volumeMounts }} +{{ toYaml . | trim | indent 12 }} +{{- end }} +{{- if $.Values.persistentVolumeClaim.name }} + - name: {{ .Values.persistentVolumeClaim.name }}-vol + mountPath: {{ .Values.persistentVolumeClaim.mountPath | default "/tmp" }} +{{- end}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{- range $k, $v := .data }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{if (or (eq .externalType "ESO_GoogleSecretsManager") (eq .externalType "ESO_AWSSecretsManager") (eq .externalType "ESO_HashiCorpVault") (eq .externalType "ESO_AzureSecretsManager"))}} + {{- if and (.esoSubPath) (ne (len .esoSubPath) 0) }} + {{- range .esoSubPath }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ . }} + subPath: {{ . }} + {{- end }} + {{- else }} + {{- range .esoSecretData.esoData }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ .secretKey }} + subPath: {{ .secretKey }} + {{- end }} + {{- end }} + {{- else }} + {{- range $k, $v := .data }} # for others secrets the mount path will be .data[i].secretKey + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) }} []{{- end }} + {{- if and (eq (len .Values.volumeMounts) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) }} [] {{- end }} +{{- if $.Values.appMetrics }} + - name: envoy + image: {{ $.Values.envoyproxy.image | default "quay.io/devtron/envoy:v1.16.0"}} + {{- if $.Values.envoyproxy.lifecycle }} + lifecycle: +{{ toYaml .Values.envoyproxy.lifecycle | indent 12 -}} + {{- else if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- end }} + resources: +{{ toYaml $.Values.envoyproxy.resources | trim | indent 12 }} + ports: + - containerPort: 9901 + protocol: TCP + name: envoy-admin + {{- range $index, $element := .Values.ContainerPort }} + - name: envoy-{{ $element.name}} + containerPort: {{ $element.envoyPort | default (add 8790 $index) }} + protocol: TCP + {{- end }} + command: ["/usr/local/bin/envoy"] + args: ["-c", "/etc/envoy-config/envoy-config.json", "-l", "info", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"] + volumeMounts: + - name: {{ $.Values.envoyproxy.configMapName | default "envoy-config-volume" }} + mountPath: /etc/envoy-config/ +{{- if $.Values.envoyproxy.readinessProbe}} + readinessProbe: +{{ toYaml $.Values.envoyproxy.readinessProbe | indent 12}} +{{- end }} +{{- if $.Values.envoyproxy.livenessProbe}} + livenessProbe: +{{ toYaml $.Values.envoyproxy.livenessProbe | indent 12}} +{{- end }} +{{- end}} +{{- if $.Values.containers }} +{{- range $i, $c := .Values.containers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-sidecontainer-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .env }} + env: +{{ toYaml .env | indent 12 }} +{{- end }} + {{- if .envFrom }} + envFrom: +{{ toYaml .env | indent 12 }} +{{- end }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .resizePolicy }} + resizePolicy: +{{ toYaml .resziePolicy | indent 12}} +{{- end }} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + + + volumes: + {{- if $.Values.appMetrics }} + - name: envoy-config-volume + configMap: + name: sidecar-config-{{ template ".Chart.Name .name" $ }} + {{- end }} +{{- with .Values.volumes }} +{{ toYaml . | trim | indent 8 }} +{{- end }} +{{- if .Values.persistentVolumeClaim.name }} + - name: {{.Values.persistentVolumeClaim.name}}-vol + persistentVolumeClaim: + claimName: {{.Values.persistentVolumeClaim.name }} +{{- end}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + configMap: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + secret: + {{- if eq .external true }} + secretName: {{ .name }} + {{- else if eq .external false }} + secretName: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) (eq (.Values.appMetrics) false) }} []{{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) (eq (.Values.appMetrics) false) }} [] {{- end }} + + revisionHistoryLimit: 3 +## pauseForSecondsBeforeSwitchActive: {{ $.Values.pauseForSecondsBeforeSwitchActive }} +# waitForSecondsBeforeScalingDown: {{ $.Values.waitForSecondsBeforeScalingDown }} + strategy: + {{- if eq .Values.deploymentType "ROLLING" }} + type: "RollingUpdate" + rollingUpdate: + maxSurge: {{ $.Values.deployment.strategy.rolling.maxSurge }} + maxUnavailable: {{ $.Values.deployment.strategy.rolling.maxUnavailable }} + {{- end }} + {{- if eq .Values.deploymentType "RECREATE" }} + type: "Recreate" + {{- end }} +{{- end }} + diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/externalsecrets.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/externalsecrets.yaml new file mode 100644 index 0000000000..efd291af5d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/externalsecrets.yaml @@ -0,0 +1,76 @@ +{{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{if eq .external true }} + {{if (or (eq .externalType "ESO_GoogleSecretsManager") (eq .externalType "ESO_AWSSecretsManager") (eq .externalType "ESO_HashiCorpVault") (eq .externalType "ESO_AzureSecretsManager"))}} +{{- if .esoSecretData.secretStore }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: {{ .name}} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + provider: + {{- toYaml .esoSecretData.secretStore | nindent 4 }} +{{- end }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ .name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .esoSecretData.refreshInterval }} + refreshInterval: {{ .esoSecretData.refreshInterval }} + {{- else }} + refreshInterval: 1h + {{- end}} + {{- if and .esoSecretData.secretStoreRef (not .esoSecretData.secretStore) }} + secretStoreRef: +{{ toYaml .esoSecretData.secretStoreRef | indent 4 }} + {{- else }} + secretStoreRef: + name: {{ .name}} + kind: SecretStore + {{- end }} + target: + name: {{ .name}} + {{- if .esoSecretData.template }} + template: + {{- toYaml .esoSecretData.template | nindent 6 }} + {{- end }} + creationPolicy: Owner + {{- if .esoSecretData.esoDataFrom }} + dataFrom: + {{- toYaml .esoSecretData.esoDataFrom | nindent 4 }} + {{- else }} + data: + {{- range .esoSecretData.esoData }} + - secretKey: {{ .secretKey }} + remoteRef: + key: {{ .key }} + {{- if .property }} + property: {{ .property }} + {{- end }} + {{- end}} +{{- end}} +{{- end}} +{{- end}} +{{- end}} +{{- end}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/flagger.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/flagger.yaml new file mode 100644 index 0000000000..766098fb61 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/flagger.yaml @@ -0,0 +1,164 @@ +{{- if .Values.flaggerCanary.enabled }} +{{ if .Values.flaggerCanary.createIstioGateway.enabled -}} +{{- with .Values.flaggerCanary.createIstioGateway }} +apiVersion: networking.istio.io/v1beta1 +kind: Gateway +metadata: + name: {{ template ".Chart.Name .fullname" $ }}-istio-gateway + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .labels }} +{{ toYaml .labels | indent 4 }} + {{- end }} +{{- if .annotations }} + annotations: +{{ toYaml .annotations | indent 4 }} +{{- end }} +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - {{ .host | quote -}} +{{- if .tls.enabled }} + tls: + httpsRedirect: true + - port: + number: 443 + name: https + protocol: HTTPS + hosts: + - {{ .host | quote }} + tls: + mode: SIMPLE + credentialName: {{ .tls.secretName }} +{{ end }} +{{ end }} +{{ end }} +{{ end }} +--- +{{- if .Values.flaggerCanary.enabled }} +{{- with .Values.flaggerCanary }} +apiVersion: flagger.app/v1beta1 +kind: Canary +metadata: + name: {{ template ".Chart.Name .fullname" $ }}-canary + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .labels }} +{{ toYaml .labels | indent 4 }} + {{- end }} +{{- if .annotations }} + annotations: +{{ toYaml .annotations | indent 4 }} +{{- end }} +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Chart.Name .fullname" $ }} +{{- if $.Values.autoscaling.enabled }} + autoscalerRef: + apiVersion: autoscaling/v1 + kind: HorizontalPodAutoscaler + name: {{ template ".Chart.Name .fullname" $ }}-hpa +{{- end }} + service: + portDiscovery: {{ .portDiscovery }} + port: {{ .serviceport }} + targetPort: {{ .targetPort }} + {{- if .appProtocol }} + appProtocol: {{ .appProtocol }} + {{- end }} +{{- if $.Values.flaggerCanary.gatewayRefs }} + gatewayRefs: +{{ toYaml $.Values.flaggerCanary.gatewayRefs | indent 6 }} +{{- end }} + {{- if or .createIstioGateway.enabled .addOtherGateways }} + gateways: + {{- if .createIstioGateway.enabled }} + - {{ template ".Chart.Name .fullname" $ }}-istio-gateway + {{- end }} + {{- if .addOtherGateways }} + {{- range .addOtherGateways }} + - {{ . }} + {{- end }} + {{- end }} + {{- end }} + {{- if or .createIstioGateway.enabled .addOtherHosts }} + hosts: + {{- if .createIstioGateway.enabled }} + - {{ .createIstioGateway.host | quote }} + {{- end }} + {{- if .addOtherHosts }} + {{- range .addOtherHosts }} + - {{ . | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- if .retries }} + retries: +{{ toYaml .retries | indent 6 }} + {{- end }} + {{- if .match }} + match: + {{- range .match }} + - uri: + prefix: {{ .uri.prefix }} + {{- end }} + {{- end }} + {{- if .rewriteUri }} + rewrite: + uri: {{ .rewriteUri }} + {{- end }} + {{- if .timeout }} + timeout: {{ .timeout }} + {{- end }} +{{- if $.Values.flaggerCanary.headers }} + headers: +{{ toYaml $.Values.flaggerCanary.headers | indent 6 }} +{{- end }} +{{- if $.Values.flaggerCanary.corsPolicy }} + corsPolicy: +{{ toYaml $.Values.flaggerCanary.corsPolicy | indent 6 }} +{{- end }} + analysis: + interval: {{ .analysis.interval }} + threshold: {{ .analysis.threshold }} + maxWeight: {{ .analysis.maxWeight }} + stepWeight: {{ .analysis.stepWeight }} + metrics: + - name: request-success-rate + threshold: {{ .thresholds.successRate }} + interval: 1m + - name: request-duration + threshold: {{ .thresholds.latency }} + interval: 1m + webhooks: + {{- if .loadtest.enabled }} + - name: load-test + url: {{ .loadtest.url }} + timeout: 5s + metadata: + cmd: "hey -z 1m -q 10 -c 2 http://{{ include ".Chart.Name .fullname" $ }}-canary.{{ $.Release.Namespace }}:{{ $.Values.flaggerCanary.targetPort }}/" + {{- end }} +{{- end }} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/generic.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/generic.yaml new file mode 100644 index 0000000000..db95e84267 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/generic.yaml @@ -0,0 +1,4 @@ +{{- range .Values.rawYaml }} +--- +{{ toYaml . }} + {{- end -}} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/hpa.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/hpa.yaml new file mode 100644 index 0000000000..fd7c7e3f60 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/hpa.yaml @@ -0,0 +1,177 @@ +{{- if $.Values.autoscaling.enabled }} +{{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2 +{{- else if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2beta2 +{{- else }} +apiVersion: autoscaling/v2beta1 +{{- end }} +kind: HorizontalPodAutoscaler +metadata: + {{- if $.Values.autoscaling.name }} + name: {{ $.Values.autoscaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-hpa + {{- end }} + {{- if .Values.autoscaling.annotations }} + annotations: +{{ toYaml .Values.autoscaling.annotations | indent 4 }} + {{- end }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + {{- if .Values.autoscaling.labels }} +{{ toYaml .Values.autoscaling.labels | indent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Chart.Name .fullname" $ }} + minReplicas: {{ $.Values.autoscaling.MinReplicas }} + maxReplicas: {{ $.Values.autoscaling.MaxReplicas }} + metrics: + {{- if $.Values.autoscaling.containerResource.enabled }} + {{- with $.Values.autoscaling.containerResource }} + {{- if .TargetCPUUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: cpu + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetCPUUtilizationPercentage }} + {{- end}} + {{- if .TargetMemoryUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: memory + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetMemoryUtilizationPercentage }} + {{- end}} + {{- end }} + {{- end }} + {{- if $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if $.Values.autoscaling.TargetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ $.Values.autoscaling.TargetCPUUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ $.Values.autoscaling.TargetCPUUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if and $.Values.autoscaling.extraMetrics (semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion) }} + {{- toYaml $.Values.autoscaling.extraMetrics | nindent 2 }} + {{- end}} + {{- if and $.Values.autoscaling.behavior (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + behavior: + {{- toYaml $.Values.autoscaling.behavior | nindent 4 }} + {{- end }} + {{- end }} +{{- if and $.Values.secondaryWorkload.enabled $.Values.secondaryWorkload.autoscaling.enabled }} +--- +{{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2 +{{- else if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2beta2 +{{- else }} +apiVersion: autoscaling/v2beta1 +{{- end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ template ".Chart.Name .fullname" $ }}-{{ $.Values.secondaryWorkload.postfix | default "sec" }}-hpa + {{- if .Values.autoscaling.annotations }} + annotations: +{{ toYaml .Values.autoscaling.annotations | indent 4 }} + {{- end }} + {{- if .Values.autoscaling.labels }} + labels: +{{ toYaml .Values.autoscaling.labels | indent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Chart.Name .fullname" $ }}-{{ $.Values.secondaryWorkload.postfix | default "sec" }} + {{- with $.Values.secondaryWorkload }} + minReplicas: {{ .autoscaling.MinReplicas }} + maxReplicas: {{ .autoscaling.MaxReplicas }} + metrics: + {{- if .autoscaling.containerResource.enabled }} + {{- with .autoscaling.containerResource }} + {{- if .TargetCPUUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: cpu + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetCPUUtilizationPercentage }} + {{- end}} + {{- if .TargetMemoryUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: memory + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetMemoryUtilizationPercentage }} + {{- end}} + {{- end }} + {{- end }} + {{- if .autoscaling.TargetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + {{- if semverCompare ">=1.16-0" $.Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ .autoscaling.TargetMemoryUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ .autoscaling.TargetMemoryUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if .autoscaling.TargetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + {{- if semverCompare ">=1.16-0" $.Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ .autoscaling.TargetCPUUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ .autoscaling.TargetCPUUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if and .autoscaling.extraMetrics (semverCompare ">=1.16-0" $.Capabilities.KubeVersion.GitVersion) }} + {{- toYaml .autoscaling.extraMetrics | nindent 2 }} + {{- end}} + {{- if and .autoscaling.behavior (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + behavior: + {{- toYaml .autoscaling.behavior | nindent 4 }} + {{- end }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ingress.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ingress.yaml new file mode 100644 index 0000000000..d9a2543e98 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/ingress.yaml @@ -0,0 +1,188 @@ +{{ $svcName := include ".servicename" . }} +{{ $svcPort := (index .Values.ContainerPort 0).servicePort }} +{{- if $.Values.ingress.enabled -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- if and .Values.ingressInternal.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingressInternal.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingressInternal.annotations "kubernetes.io/ingress.class" .Values.ingressInternal.className}} + {{- end }} +{{- end }} +{{- end }} +--- +{{ if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + {{- if $.Values.ingress.name }} + name: {{ $.Values.ingress.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-ingress + {{- end }} + namespace: {{ $.Values.NameSpace }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + {{- if .Values.ingress.labels }} +{{ toYaml .Values.ingress.labels | indent 4 }} + {{- end }} +{{- if .Values.ingress.annotations }} + annotations: +{{ toYaml .Values.ingress.annotations | indent 4 }} +{{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- if or .Values.ingress.host .Values.ingress.path }} + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.path }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $.Values.ingress.pathType | default "ImplementationSpecific" }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if and ($.Values.ingress.hosts) (not ($.Values.ingress.host )) }} + {{- range .Values.ingress.hosts }} + {{ $outer := . -}} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $outer.pathType | default "ImplementationSpecific" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if .additionalBackends }} +{{ toYaml .additionalBackends | indent 10 }} + {{- end }} + + {{- end }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end }} +{{- if $.Values.ingressInternal.enabled }} +--- +{{ if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{ else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{ else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + {{- if $.Values.ingressInternal.name }} + name: {{ $.Values.ingressInternal.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-ingress-internal + {{- end }} + namespace: {{ $.Values.NameSpace }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- if .Values.ingressInternal.annotations }} + annotations: +{{ toYaml .Values.ingressInternal.annotations | indent 4 }} +{{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingressInternal.className }} + {{- end }} + rules: + {{- if or .Values.ingressInternal.host .Values.ingressInternal.path }} + - host: {{ .Values.ingressInternal.host }} + http: + paths: + - path: {{ .Values.ingressInternal.path }} + {{- if and .Values.ingressInternal.pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $.Values.ingressInternal.pathType | default "Prefix" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if and ($.Values.ingressInternal.hosts) (not ($.Values.ingressInternal.host )) }} + {{- range .Values.ingressInternal.hosts }} + {{ $outer := . -}} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $outer.pathType | default "ImplementationSpecific" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if .additionalBackends }} +{{ toYaml .additionalBackends | indent 10 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ingressInternal.tls }} + tls: +{{ toYaml .Values.ingressInternal.tls | indent 4 }} + {{- end -}} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-authorizationpolicy.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-authorizationpolicy.yaml new file mode 100644 index 0000000000..8340555ff3 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-authorizationpolicy.yaml @@ -0,0 +1,41 @@ +{{- with .Values.istio }} +{{- if and .enable .authorizationPolicy.enabled }} +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + {{- if .authorizationPolicy.name }} + name: {{ .authorizationPolicy.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .authorizationPolicy.labels }} +{{ toYaml .authorizationPolicy.labels | indent 4 }} + {{- end }} +{{- if .authorizationPolicy.annotations }} + annotations: +{{ toYaml .authorizationPolicy.annotations | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} + action: {{ .authorizationPolicy.action }} +{{- if $.Values.istio.authorizationPolicy.provider }} + provider: +{{ toYaml $.Values.istio.authorizationPolicy.provider | indent 4 }} +{{- end }} +{{- if $.Values.istio.authorizationPolicy.rules }} + rules: +{{ toYaml $.Values.istio.authorizationPolicy.rules | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-destinationrule.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-destinationrule.yaml new file mode 100644 index 0000000000..4d06deb0b8 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-destinationrule.yaml @@ -0,0 +1,38 @@ +{{- with .Values.istio }} +{{- if and .enable .destinationRule.enabled }} +apiVersion: networking.istio.io/v1beta1 +kind: DestinationRule +metadata: + {{- if .destinationRule.name }} + name: {{ .destinationRule.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-destinationrule + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .destinationRule.labels }} +{{ toYaml .destinationRule.labels | indent 4 }} + {{- end }} +{{- if .destinationRule.annotations }} + annotations: +{{ toYaml .destinationRule.annotations | indent 4 }} +{{- end }} +spec: + host: "{{ include ".servicename" $ }}.{{ $.Release.Namespace }}.svc.cluster.local" +{{- if $.Values.istio.destinationRule.subsets }} + subsets: +{{ toYaml $.Values.istio.destinationRule.subsets | indent 4 }} +{{- end }} +{{- if $.Values.istio.destinationRule.trafficPolicy }} + trafficPolicy: +{{ toYaml $.Values.istio.destinationRule.trafficPolicy | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-gateway.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-gateway.yaml new file mode 100644 index 0000000000..b145d6c569 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-gateway.yaml @@ -0,0 +1,71 @@ +{{- if and .Values.istio.enable .Values.istio.gateway.enabled -}} +apiVersion: networking.istio.io/v1beta1 +kind: Gateway +metadata: + {{- if .Values.istio.gateway.name }} + name: {{ .Values.istio.gateway.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-istio-gateway + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if $.Values.istio.gateway.labels }} +{{ toYaml $.Values.istio.gateway.labels | indent 4 }} + {{- end }} +{{- if $.Values.istio.gateway.annotations }} + annotations: +{{ toYaml $.Values.istio.gateway.annotations | indent 4 }} +{{- end }} +spec: +{{ with $.Values.istio.gateway }} + selector: + {{- if .selector }} + {{- toYaml .selector | nindent 4 }} + {{- else }} + istio: ingressgateway + {{- end }} + servers: + {{- if .servers }} + {{- toYaml .servers | nindent 2 }} + {{- else }} + - port: + number: 80 + name: http + protocol: HTTP + hosts: +{{- if .host }} + - {{ .host | quote -}} +{{- else if .hosts }} +{{- range .hosts }} + - {{ . | quote }} +{{- end }} +{{- end }} +{{- if .tls.enabled }} + tls: + httpsRedirect: true + - port: + number: 443 + name: https + protocol: HTTPS + hosts: +{{- if .host }} + - {{ .host | quote }} +{{- else if .hosts }} +{{- range .hosts }} + - {{ . | quote }} +{{- end }} +{{- end }} + tls: + mode: SIMPLE + credentialName: {{ .tls.secretName }} +{{ end }} +{{ end }} +{{ end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-peerauthentication.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-peerauthentication.yaml new file mode 100644 index 0000000000..dedd971c6d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-peerauthentication.yaml @@ -0,0 +1,40 @@ +{{- with .Values.istio }} +{{- if and .enable .peerAuthentication.enabled }} +apiVersion: security.istio.io/v1beta1 +kind: PeerAuthentication +metadata: + {{- if .peerAuthentication.name }} + name: {{ .peerAuthentication.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .peerAuthentication.labels }} +{{ toYaml .peerAuthentication.labels | indent 4 }} + {{- end }} +{{- if .peerAuthentication.annotations }} + annotations: +{{ toYaml .peerAuthentication.annotations | indent 4 }} +{{- end }} +spec: +{{- if .peerAuthentication.selector.enabled }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} +{{- end }} + mtls: + mode: {{ .peerAuthentication.mtls.mode }} +{{- if $.Values.istio.peerAuthentication.portLevelMtls }} + portLevelMtls: +{{ toYaml $.Values.istio.peerAuthentication.portLevelMtls | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-requestauthentication.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-requestauthentication.yaml new file mode 100644 index 0000000000..49bb89552d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-requestauthentication.yaml @@ -0,0 +1,38 @@ +{{- with .Values.istio }} +{{- if and .enable .requestAuthentication.enabled }} +apiVersion: security.istio.io/v1beta1 +kind: RequestAuthentication +metadata: + {{- if .requestAuthentication.name }} + name: {{.requestAuthentication.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .requestAuthentication.labels }} +{{ toYaml .requestAuthentication.labels | indent 4 }} + {{- end }} +{{- if .requestAuthentication.annotations }} + annotations: +{{ toYaml .requestAuthentication.annotations | indent 4 }} +{{- end }} +spec: +{{- if .requestAuthentication.selector.enabled }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} +{{- end }} +{{- if $.Values.istio.requestAuthentication.jwtRules }} + jwtRules: +{{ toYaml $.Values.istio.requestAuthentication.jwtRules | indent 2 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-virtualservice.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-virtualservice.yaml new file mode 100644 index 0000000000..32a3380228 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/istio-virtualservice.yaml @@ -0,0 +1,68 @@ +{{- with .Values.istio }} +{{- if and .enable .virtualService.enabled }} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + {{- if .virtualService.name }} + name: {{ .virtualService.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-virtualservice + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .virtualService.labels }} +{{ toYaml .virtualService.labels | indent 4 }} + {{- end }} +{{- if .virtualService.annotations }} + annotations: +{{ toYaml .virtualService.annotations | indent 4 }} +{{- end }} +spec: +{{- if or .gateway.enabled .virtualService.gateways }} + gateways: + {{- if .gateway.enabled }} + {{- if .gateway.name }} + - {{ .gateway.name }} + {{- else }} + - {{ template ".Chart.Name .fullname" $ }}-istio-gateway + {{- end }} + {{- end }} + {{- range .virtualService.gateways }} + - {{ . | quote }} + {{- end }} +{{- end }} +{{- if or .gateway.enabled .virtualService.hosts }} + hosts: + {{- if .gateway.enabled }} + {{- if .gateway.host }} + - {{ .gateway.host | quote }} + {{- else if .gateway.hosts }} +{{- range .gateway.hosts }} + - {{ . | quote }} +{{- end }} + {{- end }} + {{- end }} + {{- range .virtualService.hosts }} + - {{ . | quote }} + {{- end }} +{{- else }} + hosts: + {{- if $.Values.service.name }} + - {{ $.Values.service.name }}.{{ $.Release.Namespace }}.svc.cluster.local + {{- else }} + - "{{ include ".servicename" $ }}.{{ $.Release.Namespace }}.svc.cluster.local" + {{- end }} +{{- end }} +{{- if $.Values.istio.virtualService.http }} + http: +{{ toYaml $.Values.istio.virtualService.http | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/keda-autoscaling.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/keda-autoscaling.yaml new file mode 100644 index 0000000000..780afa73b1 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/keda-autoscaling.yaml @@ -0,0 +1,78 @@ +{{- if $.Values.kedaAutoscaling.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + {{- if $.Values.kedaAutoscaling.name }} + name: {{ $.Values.kedaAutoscaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-keda + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ .Release.Name }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} + {{- if .Values.kedaAutoscaling.labels }} +{{ toYaml .Values.kedaAutoscaling.labels | indent 4 }} + {{- end }} + {{- if .Values.kedaAutoscaling.annotations }} + annotations: +{{ toYaml .Values.kedaAutoscaling.annotations | indent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Chart.Name .fullname" $ }} +{{- if $.Values.kedaAutoscaling.envSourceContainerName }} + envSourceContainerName: {{ $.Values.kedaAutoscaling.envSourceContainerName }} +{{- end }} +{{- if $.Values.kedaAutoscaling.pollingInterval }} + pollingInterval: {{ $.Values.kedaAutoscaling.pollingInterval }} +{{- end }} +{{- if $.Values.kedaAutoscaling.cooldownPeriod }} + cooldownPeriod: {{ $.Values.kedaAutoscaling.cooldownPeriod }} +{{- end }} +{{- if $.Values.kedaAutoscaling.idleReplicaCount }} + idleReplicaCount: {{ $.Values.kedaAutoscaling.idleReplicaCount }} +{{- end }} + minReplicaCount: {{ $.Values.kedaAutoscaling.minReplicaCount }} + maxReplicaCount: {{ $.Values.kedaAutoscaling.maxReplicaCount }} +{{- if $.Values.kedaAutoscaling.fallback }} + fallback: +{{ toYaml $.Values.kedaAutoscaling.fallback | indent 4 }} +{{- end }} +{{- if $.Values.kedaAutoscaling.advanced }} + advanced: +{{ toYaml $.Values.kedaAutoscaling.advanced | indent 4 }} +{{- end }} + triggers: +{{ toYaml .Values.kedaAutoscaling.triggers | indent 2}} +{{- if $.Values.kedaAutoscaling.authenticationRef }} + authenticationRef: +{{ toYaml $.Values.kedaAutoscaling.authenticationRef | indent 6 }} +{{- end }} +--- +{{- if $.Values.kedaAutoscaling.triggerAuthentication.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{ $.Values.kedaAutoscaling.triggerAuthentication.name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: +{{ toYaml $.Values.kedaAutoscaling.triggerAuthentication.spec | indent 2 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/metrics-service-monitor.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/metrics-service-monitor.yaml new file mode 100644 index 0000000000..fa5321d303 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/metrics-service-monitor.yaml @@ -0,0 +1,35 @@ +{{- if $.Values.appMetrics -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template ".Chart.Name .fullname" $ }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} +spec: + jobLabel: {{ template ".Chart.Name .name" $ }} + endpoints: + - port: envoy-admin + interval: 30s + path: /stats/prometheus + relabelings: + - action: replace + sourceLabels: + - __meta_kubernetes_pod_label_pod_template_hash + targetLabel: devtron_app_hash + selector: + matchLabels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + namespaceSelector: + matchNames: + - {{.Release.Namespace}} + podTargetLabels: + - appId + - envId + - devtron_app_hash +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/networkpolicy.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/networkpolicy.yaml new file mode 100644 index 0000000000..ee8bdaf8be --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/networkpolicy.yaml @@ -0,0 +1,52 @@ +{{- if .Values.networkPolicy.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + {{- if .Values.networkPolicy.name }} + name: {{ .Values.networkPolicy.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-networkpolicy + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if $.Values.networkPolicy.labels }} +{{ toYaml $.Values.networkPolicy.labels | indent 4 }} + {{- end }} +{{- if $.Values.networkPolicy.annotations }} + annotations: +{{ toYaml $.Values.networkPolicy.annotations | indent 4 }} +{{- end }} +spec: + podSelector: +{{- if .podSelector.matchExpressions }} + matchExpressions: +{{ toYaml $.Values.networkPolicy.podSelector.matchExpressions | indent 6 }} +{{- end }} +{{- if .podSelector.matchLabels }} + matchLabels: +{{ toYaml $.Values.networkPolicy.podSelector.matchLabels | indent 6 }} +{{- else }} + matchLabels: + app: {{ template ".Chart.Name .name" $ }} + release: {{ $.Release.Name }} +{{- end }} +{{- if .policyTypes }} + policyTypes: +{{ toYaml $.Values.networkPolicy.policyTypes | indent 4 }} +{{- end }} +{{- if .ingress }} + ingress: +{{ toYaml $.Values.networkPolicy.ingress | indent 4 }} +{{- end }} +{{- if .egress }} + egress: +{{ toYaml $.Values.networkPolicy.ingress | indent 4}} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/persistent-volume-claim.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/persistent-volume-claim.yaml new file mode 100644 index 0000000000..bf4e6dfb71 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/persistent-volume-claim.yaml @@ -0,0 +1,24 @@ +{{- if .Values.persistentVolumeClaim.name }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{.Values.persistentVolumeClaim.name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- with .Values.persistentVolumeClaim }} +spec: + accessModes: +{{- range .accessMode }} + - {{ . }} +{{- end }} + resources: + requests: + storage: {{ .storage | default "5Gi" }} + storageClassName: {{ .storageClassName | default "default" }} + volumeMode: {{ .volumeMode | default "Filesystem" }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/poddisruptionbudget.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000..9094fd82e6 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/poddisruptionbudget.yaml @@ -0,0 +1,38 @@ +{{- if .Values.podDisruptionBudget }} +{{- if semverCompare ">=1.21-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: policy/v1 +{{- else -}} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + {{- if .Values.podDisruptionBudget.name }} + name: {{ .Values.podDisruptionBudget.name }} + {{- else }} + name: {{ include ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 6 }} + {{- else }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/pre-sync-job.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/pre-sync-job.yaml new file mode 100644 index 0000000000..54c9f636ee --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/pre-sync-job.yaml @@ -0,0 +1,29 @@ +{{- if $.Values.dbMigrationConfig.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template ".Chart.Name .fullname" $ }}-migrator + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + annotations: + argocd.argoproj.io/hook: PreSync +# argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + template: + spec: + containers: + - name: migrator + image: 686244538589.dkr.ecr.us-east-2.amazonaws.com/migrator:0.0.1-rc14 + env: + {{- range $.Values.dbMigrationConfig.envValues }} + - name: {{ .key}} + value: {{ .value | quote }} + {{- end}} + restartPolicy: Never + backoffLimit: 0 +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/prometheusrules.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/prometheusrules.yaml new file mode 100644 index 0000000000..c285de1388 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/prometheusrules.yaml @@ -0,0 +1,33 @@ +{{- if .Values.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + {{- if .Values.prometheusRule.name }} + name: {{ .Values.prometheusRule.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }} + {{- end }} + {{- if .Values.prometheusRule.namespace }} + namespace: {{ .Values.prometheusRule.namespace }} + {{- end }} + labels: + kind: Prometheus + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ .Values.prometheus.release }} + {{- if .Values.prometheusRule.additionalLabels }} +{{ toYaml .Values.prometheusRule.additionalLabels | indent 4 }} + {{- end }} +spec: + {{- with .Values.prometheusRule.rules }} + groups: + {{- if $.Values.prometheusRule.name }} + - name: {{ $.Values.prometheusRule.name }} + {{- else }} + - name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + rules: {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/secret.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/secret.yaml new file mode 100644 index 0000000000..5ac3ae1410 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/secret.yaml @@ -0,0 +1,84 @@ +{{- if $.Values.secret.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: app-secret + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +type: Opaque +data: +{{ toYaml $.Values.secret.data | indent 2 }} +{{- end }} + + +{{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{if eq .external false}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name}}-{{ $.Values.app }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + release: {{ $.Release.Name }} + chart: {{ template ".Chart.Name .chart" $ }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +type: Opaque +data: +{{ toYaml .data | trim | indent 2 }} +{{- end}} + {{if eq .external true }} + {{if (or (eq .externalType "AWSSecretsManager") (eq .externalType "AWSSystemManager") (eq .externalType "HashiCorpVault"))}} +--- +apiVersion: kubernetes-client.io/v1 +kind: ExternalSecret +metadata: + name: {{ .name}} +{{- if $.Values.appLabels }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .roleARN }} + roleArn: .roleARN + {{- end}} + {{- if eq .externalType "AWSSecretsManager"}} + backendType: secretsManager + {{- end}} + {{- if eq .externalType "AWSSystemManager"}} + backendType: systemManager + {{- end}} + {{- if eq .externalType "HashiCorpVault"}} + backendType: vault + {{- end}} + data: + {{- range .secretData }} + - key: {{.key}} + name: {{.name}} + {{- if .property }} + property: {{.property}} + {{- end}} + isBinary: {{.isBinary}} + {{- end}} + {{- end}} + {{- end}} + {{- end}} + {{- end}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/service.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/service.yaml new file mode 100644 index 0000000000..14e1a7c37a --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/service.yaml @@ -0,0 +1,106 @@ +{{- if .Values.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template ".servicename" . }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end}} +spec: + type: {{ .Values.service.type | default "ClusterIP" }} +{{- if (and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerSourceRanges )}} + loadBalancerSourceRanges: + {{- range .Values.service.loadBalancerSourceRanges }} + - {{ . }} + {{- end }} +{{- end }} + ports: + {{- range .Values.ContainerPort }} + {{- if .servicePort }} + - port: {{ .servicePort }} + {{- else }} + - port: {{ .port }} + {{- end }} + {{- if .targetPort }} + targetPort: {{ .targetPort }} + {{- else if $.Values.appMetrics }} + targetPort: envoy-{{ .name }} + {{- else }} + targetPort: {{ .name }} + {{- end }} + protocol: {{ .protocol | default "TCP" }} + {{- if (and (eq $.Values.service.type "NodePort") .nodePort ) }} + nodePort: {{ .nodePort }} + {{- end }} + name: {{ .name }} + {{- end }} + {{- if $.Values.appMetrics }} + - port: 9901 + name: envoy-admin + {{- end }} + selector: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 4 }} + {{- else }} + app: {{ template ".Chart.Name .name" . }} + {{- end }} +{{- if .Values.service.sessionAffinity.enabled }} + sessionAffinity: ClientIP +{{- end }} +{{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: +{{ toYaml .Values.service.sessionAffinityConfig | indent 4 }} +{{- end }} +{{- if eq .Values.deploymentType "BLUE-GREEN" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template ".previewservicename" . }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +spec: + type: ClusterIP + ports: + {{- range .Values.ContainerPort }} + {{- if .servicePort }} + - port: {{ .servicePort }} + {{- else }} + - port: {{ .port }} + {{- end }} + {{- if .targetPort }} + targetPort: {{ .targetPort }} + {{- else if $.Values.appMetrics }} + targetPort: envoy-{{ .name }} + {{- else }} + targetPort: {{ .name }} + {{- end }} + protocol: TCP + name: {{ .name }} + {{- end }} + {{- if $.Values.appMetrics }} + - port: 9901 + name: envoy-admin + {{- end }} + selector: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 4 }} + {{- else }} + app: {{ template ".Chart.Name .name" . }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/serviceaccount.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/serviceaccount.yaml new file mode 100644 index 0000000000..f337548e94 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if $.Values.serviceAccount }} +{{- if $.Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "serviceAccountName" . }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 4 }} + {{- end }} + {{- if .Values.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.serviceAccount.annotations | indent 4 }} + {{- end }} +{{- end -}} +{{- end -}} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/servicemonitor.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/servicemonitor.yaml new file mode 100644 index 0000000000..9b920388d2 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/servicemonitor.yaml @@ -0,0 +1,117 @@ +{{ $serviceMonitorEnabled := include "serviceMonitorEnabled" . }} +{{- if eq "true" $serviceMonitorEnabled -}} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + {{- if .Values.servicemonitor.name }} + name: {{ .Values.servicemonitor.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-sm + {{- end }} + labels: + kind: Prometheus + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} + {{- if .Values.servicemonitor.additionalLabels }} +{{ toYaml .Values.servicemonitor.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: + endpoints: + {{- range .Values.ContainerPort }} + {{- if .servicemonitor }} + {{- if .servicemonitor.enabled}} + {{- if .servicemonitor.targetPort }} + - targetPort: {{ .servicemonitor.targetPort }} + {{- else if .servicePort }} + - port: {{ .name }} + {{- end }} + {{- if .servicemonitor.path }} + path: {{ .servicemonitor.path}} + {{- end }} + {{- if .servicemonitor.scheme }} + scheme: {{ .servicemonitor.scheme}} + {{- end }} + {{- if .servicemonitor.interval }} + interval: {{ .servicemonitor.interval}} + {{- end }} + {{- if .servicemonitor.scrapeTimeout }} + scrapeTimeout: {{ .servicemonitor.scrapeTimeout | quote }} + {{- end }} + {{- if .servicemonitor.basicAuth }} + basicAuth: + {{- toYaml .servicemonitor.basicAuth | nindent 8 }} + {{- end }} + {{- if .servicemonitor.insecureTLS }} + tlsConfig: + insecureSkipVerify: true + {{- else if .servicemonitor.tlsConfig }} + tlsConfig: + {{- toYaml .servicemonitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .servicemonitor.metricRelabelings}} + metricRelabelings: +{{toYaml .servicemonitor.metricRelabelings | indent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- range .Values.containers }} + {{- range .ports }} + {{- if .servicemonitor }} + {{- if .servicemonitor.enabled}} + {{- if .servicemonitor.targetPort }} + - targetPort: {{ .servicemonitor.targetPort }} + {{- else if .servicePort }} + - port: {{ .name }} + {{- end }} + {{- if .servicemonitor.path }} + path: {{ .servicemonitor.path}} + {{- end }} + {{- if .servicemonitor.scheme }} + scheme: {{ .servicemonitor.scheme}} + {{- end }} + {{- if .servicemonitor.interval }} + interval: {{ .servicemonitor.interval}} + {{- end }} + {{- if .servicemonitor.scrapeTimeout }} + scrapeTimeout: {{ .servicemonitor.scrapeTimeout}} + {{- end }} + {{- if .servicemonitor.basicAuth }} + basicAuth: + {{- toYaml .servicemonitor.basicAuth | nindent 8 }} + {{- end }} + {{- if .servicemonitor.insecureTLS }} + tlsConfig: + insecureSkipVerify: true + {{- else if .servicemonitor.tlsConfig }} + tlsConfig: + {{- toYaml .servicemonitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .servicemonitor.metricRelabelings}} + metricRelabelings: +{{toYaml .servicemonitor.metricRelabelings | indent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.servicemonitor.namespaceSelector }} + namespaceSelector: + matchNames: + {{- toYaml .Values.servicemonitor.namespaceSelector | nindent 6 }} + {{- end }} + selector: + matchLabels: + {{- if .Values.servicemonitor.matchLabels }} + {{- toYaml .Values.servicemonitor.matchLabels | nindent 6 }} + {{- else }} + app: {{ template ".Chart.Name .name" $ }} +{{- end }} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/sidecar-configmap.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/sidecar-configmap.yaml new file mode 100644 index 0000000000..cf32679409 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/sidecar-configmap.yaml @@ -0,0 +1,169 @@ +{{- if .Values.appMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: 2019-08-12T18:38:34Z + name: sidecar-config-{{ template ".Chart.Name .name" $ }} +data: + envoy-config.json: | + { + "stats_config": { + "use_all_default_tags": false, + "stats_tags": [ + { + "tag_name": "cluster_name", + "regex": "^cluster\\.((.+?(\\..+?\\.svc\\.cluster\\.local)?)\\.)" + }, + { + "tag_name": "tcp_prefix", + "regex": "^tcp\\.((.*?)\\.)\\w+?$" + }, + { + "tag_name": "response_code", + "regex": "_rq(_(\\d{3}))$" + }, + { + "tag_name": "response_code_class", + "regex": ".*_rq(_(\\dxx))$" + }, + { + "tag_name": "http_conn_manager_listener_prefix", + "regex": "^listener(?=\\.).*?\\.http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "http_conn_manager_prefix", + "regex": "^http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "listener_address", + "regex": "^listener\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "mongo_prefix", + "regex": "^mongo\\.(.+?)\\.(collection|cmd|cx_|op_|delays_|decoding_)(.*?)$" + } + ], + "stats_matcher": { + "inclusion_list": { + "patterns": [ + { + "regex": ".*_rq_\\dxx$" + }, + { + "regex": ".*_rq_time$" + }, + { + "regex": "cluster.*" + }, + ] + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "0.0.0.0", + "port_value": 9901 + } + } + }, + "static_resources": { + "clusters": [ + {{- range $index, $element := .Values.ContainerPort }} + { + "name": "{{ $.Values.app }}-{{ $index }}", + "type": "STATIC", + "connect_timeout": "0.250s", + "lb_policy": "ROUND_ROBIN", +{{- if $element.idleTimeout }} + "common_http_protocol_options": { + "idle_timeout": {{ $element.idleTimeout | quote }} + }, +{{- end }} +{{- if or $element.useHTTP2 $element.useGRPC }} + "http2_protocol_options": {}, +{{- end }} +{{- if and (not $element.useGRPC) (not $element.supportStreaming) }} + "max_requests_per_connection": "1", +{{- end }} + "load_assignment": { + "cluster_name": "9", + "endpoints": { + "lb_endpoints": [ + { + "endpoint": { + "address": { + "socket_address": { + "protocol": "TCP", + "address": "127.0.0.1", + "port_value": {{ $element.port }} + } + } + } + } + ] + } + } + }, + {{- end }} + ], + "listeners":[ + {{- range $index, $element := .Values.ContainerPort }} + { + "address": { + "socket_address": { + "protocol": "TCP", + "address": "0.0.0.0", + "port_value": {{ $element.envoyPort | default (add 8790 $index) }} + } + }, + "filter_chains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "config": { + "codec_type": "AUTO", + "stat_prefix": "stats", + "route_config": { + "virtual_hosts": [ + { + "name": "backend", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { +{{- if $element.supportStreaming }} + "timeout": "0s", +{{- end }} +{{- if and ($element.envoyTimeout) (not $element.supportStreaming) }} + "timeout": "{{ $element.envoyTimeout }}", +{{- end }} + "cluster": "{{ $.Values.app }}-{{ $index }}" + } + } + ] + } + ] + }, + "http_filters": { + "name": "envoy.filters.http.router" + } + } + } + ] + } + ] + }, + {{- end }} + ] + } + } +--- +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/vertical-pod-autoscaler.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/vertical-pod-autoscaler.yaml new file mode 100644 index 0000000000..ffbf24d823 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/vertical-pod-autoscaler.yaml @@ -0,0 +1,34 @@ +{{ $VerticalPodAutoScalingEnabled := include "VerticalPodAutoScalingEnabled" . }} +{{- if eq "true" $VerticalPodAutoScalingEnabled -}} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + {{- if .Values.verticalPodScaling.name }} + name: {{ .Values.verticalPodScaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-vpa + {{- end }} + labels: + kind: Prometheus + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: +{{- if .Values.verticalPodScaling.resourcePolicy }} + resourcePolicy: +{{ toYaml .Values.verticalPodScaling.resourcePolicy}} +{{- end }} +{{- if .Values.verticalPodScaling.updatePolicy }} + updatePolicy: +{{ toYaml .Values.verticalPodScaling.updatePolicy}} +{{- end }} + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Chart.Name .fullname" $ }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/winter-soldier.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/winter-soldier.yaml new file mode 100644 index 0000000000..314f0c6db0 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/templates/winter-soldier.yaml @@ -0,0 +1,45 @@ +{{- if .Values.winterSoldier.enabled }} +apiVersion: {{ $.Values.winterSoldier.apiVersion }} +kind: Hibernator +metadata: + {{- if .Values.winterSoldier.name }} + name: {{ .Values.winterSoldier.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-hibernator + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + {{- if .Values.winterSoldier.labels }} +{{ toYaml .Values.winterSoldier.labels | indent 4 }} + {{- end }} +{{- if .Values.winterSoldier.annotations }} + annotations: +{{ toYaml .Values.winterSoldier.annotations | indent 4 }} +{{- end }} +spec: + timeRangesWithZone: +{{ toYaml $.Values.winterSoldier.timeRangesWithZone | indent 4}} + selectors: + - inclusions: + - objectSelector: + name: {{ include ".Chart.Name .fullname" $ }} + type: {{ .Values.winterSoldier.type | quote }} + fieldSelector: +{{toYaml $.Values.winterSoldier.fieldSelector | indent 14 }} + namespaceSelector: + name: {{ $.Release.Namespace }} + exclusions: [] + action: {{ $.Values.winterSoldier.action }} + {{- if eq .Values.winterSoldier.action "scale" }} + {{- if .Values.winterSoldier.targetReplicas }} + targetReplicas: {{ $.Values.winterSoldier.targetReplicas }} + {{- end }} + {{- end }} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test-values.json b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test-values.json new file mode 100644 index 0000000000..a26806cb91 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test-values.json @@ -0,0 +1,292 @@ +{ + "ConfigMaps": { + "enabled": true, + "maps": [ + { + "data": { + "a": "b" + }, + "esoSecretData": {}, + "external": false, + "externalType": "", + "filePermission": "", + "mountPath": "", + "name": "abc", + "roleARN": "", + "subPath": false, + "type": "environment" + } + ] + }, + "ConfigSecrets": { + "enabled": true, + "secrets": [ + { + "data": { + "access-key": "QUtJQVdQVENFV0w1Wk4zVFBSRzY=", + "secret-access-key": "dkJ1bXRJL1YyZFUrQmVrSnM4QkVsblJnQzlRbEZueVZqL0dEdUc4Ng==" + }, + "esoSecretData": {}, + "external": false, + "externalType": "", + "filePermission": "", + "mountPath": "", + "name": "auth-aws", + "roleARN": "", + "subPath": false, + "type": "environment" + }, + { + "esoSecretData": { + "esoData": [ + { + "key": "ajay-secret-aws", + "property": "mob", + "secretKey": "mymob" + }, + { + "key": "ajay-secret-aws", + "property": "pin", + "secretKey": "mypin" + } + ], + "secretStore": { + "aws": { + "auth": { + "secretRef": { + "accessKeyIDSecretRef": { + "key": "access-key", + "name": "auth-aws-1" + }, + "secretAccessKeySecretRef": { + "key": "secret-access-key", + "name": "auth-aws-1" + } + } + }, + "region": "ap-south-1", + "service": "SecretsManager" + } + } + }, + "external": true, + "externalType": "ESO_AWSSecretsManager", + "filePermission": "", + "mountPath": "", + "name": "external-secret-aws", + "roleARN": "", + "subPath": false, + "type": "environment" + } + ] + }, + "ContainerPort": [ + { + "envoyPort": 8799, + "idleTimeout": "1800s", + "name": "app", + "port": 80, + "servicePort": 80, + "supportStreaming": false, + "useHTTP2": false + } + ], + "EnvVariables": [], + "GracePeriod": 30, + "LivenessProbe": { + "Path": "", + "command": [], + "failureThreshold": 3, + "httpHeaders": [], + "initialDelaySeconds": 20, + "periodSeconds": 10, + "port": 8080, + "scheme": "", + "successThreshold": 1, + "tcp": false, + "timeoutSeconds": 5 + }, + "MaxSurge": 1, + "MaxUnavailable": 0, + "MinReadySeconds": 60, + "ReadinessProbe": { + "Path": "", + "command": [], + "failureThreshold": 3, + "httpHeaders": [], + "initialDelaySeconds": 20, + "periodSeconds": 10, + "port": 8080, + "scheme": "", + "successThreshold": 1, + "tcp": false, + "timeoutSeconds": 5 + }, + "Spec": { + "Affinity": { + "Values": "nodes", + "key": "" + } + }, + "app": "1", + "appLabels": {}, + "appMetrics": false, + "args": { + "enabled": false, + "value": [ + "/bin/sh", + "-c", + "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600" + ] + }, + "autoscaling": { + "MaxReplicas": 2, + "MinReplicas": 1, + "TargetCPUUtilizationPercentage": 90, + "TargetMemoryUtilizationPercentage": 80, + "annotations": {}, + "behavior": {}, + "enabled": false, + "extraMetrics": [], + "labels": {} + }, + "command": { + "enabled": false, + "value": [], + "workingDir": {} + }, + "containerSecurityContext": {}, + "containers": [], + "dbMigrationConfig": { + "enabled": false + }, + "deployment": { + "strategy": { + "blueGreen": { + "autoPromotionEnabled": false, + "autoPromotionSeconds": 30, + "previewReplicaCount": 1, + "scaleDownDelaySeconds": 30 + } + } + }, + "deploymentType": "BLUE-GREEN", + "env": "1", + "envoyproxy": { + "configMapName": "", + "image": "quay.io/devtron/envoy:v1.14.1", + "resources": { + "limits": { + "cpu": "50m", + "memory": "50Mi" + }, + "requests": { + "cpu": "50m", + "memory": "50Mi" + } + } + }, + "hostAliases": [], + "image": { + "pullPolicy": "IfNotPresent" + }, + "imagePullSecrets": [], + "ingress": { + "annotations": {}, + "className": "", + "enabled": false, + "hosts": [ + { + "host": "chart-example1.local", + "pathType": "ImplementationSpecific", + "paths": [ + "/example1" + ] + } + ], + "labels": {}, + "tls": [] + }, + "ingressInternal": { + "annotations": {}, + "className": "", + "enabled": false, + "hosts": [ + { + "host": "chart-example1.internal", + "pathType": "ImplementationSpecific", + "paths": [ + "/example1" + ] + }, + { + "host": "chart-example2.internal", + "pathType": "ImplementationSpecific", + "paths": [ + "/example2", + "/example2/healthz" + ] + } + ], + "tls": [] + }, + "initContainers": [], + "kedaAutoscaling": { + "advanced": {}, + "authenticationRef": {}, + "enabled": false, + "envSourceContainerName": "", + "maxReplicaCount": 2, + "minReplicaCount": 1, + "triggerAuthentication": { + "enabled": false, + "name": "", + "spec": {} + }, + "triggers": [] + }, + "pauseForSecondsBeforeSwitchActive": 30, + "pipelineName": "cd-1-fpji", + "podAnnotations": {}, + "podLabels": {}, + "podSecurityContext": {}, + "prometheus": { + "release": "monitoring" + }, + "rawYaml": [], + "releaseVersion": "6", + "replicaCount": 1, + "resources": { + "limits": { + "cpu": "0.05", + "memory": "50Mi" + }, + "requests": { + "cpu": "0.01", + "memory": "10Mi" + } + }, + "secret": { + "data": {}, + "enabled": false + }, + "server": { + "deployment": { + "image": "aju121/test12", + "image_tag": "63118bf2-1-1" + } + }, + "service": { + "annotations": {}, + "loadBalancerSourceRanges": [], + "type": "ClusterIP" + }, + "servicemonitor": { + "additionalLabels": {} + }, + "tolerations": [], + "topologySpreadConstraints": [], + "volumeMounts": [], + "volumes": [], + "waitForSecondsBeforeScalingDown": 30 +} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test_values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test_values.yaml new file mode 100644 index 0000000000..48e62037f6 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/test_values.yaml @@ -0,0 +1,782 @@ +# Default values for myapp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +kedaAutoscaling: + enabled: true + envSourceContainerName: "" # Optional. Default: .spec.template.spec.containers[0] + cooldownPeriod: 300 # Optional. Default: 300 seconds + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 # Optional. Must be less than minReplicaCount + pollingInterval: 30 # Optional. Default: 30 seconds + # The fallback section is optional. It defines a number of replicas to fallback to if a scaler is in an error state. + fallback: {} # Optional. Section to specify fallback options + # failureThreshold: 3 # Mandatory if fallback section is included + # replicas: 6 + advanced: {} + # horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options + # behavior: # Optional. Use to modify HPA's scaling behavior + # scaleDown: + # stabilizationWindowSeconds: 300 + # policies: + # - type: Percent + # value: 100 + # periodSeconds: 15 + triggers: + - type: kubernetes-workload + name: trig_one + metadata: + podSelector: 'pod=workload-test' + - type: metrics-api + name: trig_two + metadata: + url: "https://mockbin.org/bin/336a8d99-9e09-4f1f-979d-851a6d1b1423" + valueLocation: "tasks" + + triggerAuthentication: + enabled: true + name: "trigger-test" + spec: {} + authenticationRef: {} + +deploymentLabels: + name: kunalverma + Company: Devtron + Job: DevRel + +deploymentAnnotations: + name: kunalverma + Company: Devtron + Job: DevRel + +containerSpec: + lifecycle: + enabled: true + preStop: + exec: + command: ["sleep","10"] + postStart: + httpGet: + host: example.com + path: /example + port: 90 + +imagePullSecrets: + - test1 + - test2 +replicaCount: 1 +MinReadySeconds: 5 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +ContainerPort: + - name: app + port: 8080 + servicePort: 80 + envoyTimeout: 15 + targetPort: 8080 + envoyPort: 8799 + useHTTP2: false + supportStreaming: false + idleTimeout: 1800s + servicemonitor: + enabled: true + path: /abc + scheme: 'http' + interval: 30s + scrapeTimeout: 20s + metricRelabelings: + - sourceLabels: [namespace] + regex: '(.*)' + replacement: myapp + targetLabel: target_namespace + + - name: app1 + port: 8090 + targetPort: 1234 + servicePort: 8080 + useGRPC: true + servicemonitor: + enabled: true + - name: app2 + port: 8091 + servicePort: 8081 + useGRPC: true + +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 +autoPromotionSeconds: 30 + +Spec: + Affinity: + Key: + # Key: kops.k8s.io/instancegroup + Values: + + +image: + pullPolicy: IfNotPresent + +autoscaling: + enabled: true + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + behavior: {} +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +secret: + enabled: false + +service: + type: ClusterIP + # name: "1234567890123456789012345678901234567890123456789012345678901234567890" + annotations: {} + # test1: test2 + # test3: test4 + +istio: + enable: true + gateway: + enabled: true + labels: {} + annotations: {} + # host: example.com + hosts: + - "example4.com" + tls: + enabled: true + secretName: example-tls-secret + virtualService: + enabled: true + labels: {} + annotations: {} + gateways: [] + hosts: + - example1.local + http: + # - match: + # - uri: + # prefix: /v1 + # - uri: + # prefix: /v2 + # rewriteUri: / + # timeout: 12 + # headers: + # request: + # add: + # x-some-header: "value" + # retries: + # attempts: 2 + # perTryTimeout: 3s + # route: + # - destination: + # host: service1 + # port: 80 + # - route: + # - destination: + # host: service2 + +flaggerCanary: + enabled: false + labels: {} + annotations: {} + createIstioGateway: + enabled: false + labels: {} + annotations: {} + host: example.com + tls: + enabled: false + secretName: example-tls-secret + # Istio gateways (optional) + addOtherGateways: [] + # Istio virtual service host names (optional) + addOtherHosts: [] + # Istio gateway refs (optional) + gatewayRefs: + # - name: istio-gateway + # namespace: istio-system + #service port + port: 80 + #containerPort + targetPort: 8080 + # discover all port open in container + portDiscovery: false + # application protocol (optional) + appProtocol: + # Istio retry policy (optional) + retries: + # attempts: 3 + # perTryTimeout: 1s + # retryOn: "gateway-error,connect-failure,refused-stream" + # HTTP match conditions (optional) + match: + - uri: + prefix: / + # HTTP rewrite (optional) + rewriteUri: + # timeout (optional) + timeout: + # Add headers (optional) + headers: + # request: + # add: + # x-some-header: "value" + # cross-origin resource sharing policy (optional) + corsPolicy: + # allowOrigin: + # - example.com + # allowMethods: + # - GET + # allowCredentials: false + # allowHeaders: + # - x-some-header + # maxAge: 24h + analysis: + # schedule interval (default 60s) + interval: 5s + # max number of failed metric checks before rollback + threshold: 10 + # max traffic percentage routed to canary + # percentage (0-100) + maxWeight: 50 + # canary increment step + # percentage (0-100) + stepWeight: 5 + thresholds: + # minimum req success rate (non 5xx responses) + # percentage (0-100) + successRate: 90 + # maximum req duration P99 + # milliseconds + latency: 500 + loadtest: + enabled: true + # load tester address + url: http://flagger-loadtester.test/ + +server: + deployment: + image_tag: 1-95af053 + image: "" +deploymentType: "RECREATE" + +topologySpreadConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: DoNotSchedule + autoLabelSelector: true + customLabelSelector: + foo: bar + +EnvVariables: + - name: FLASK_ENV + value: qa + +LivenessProbe: + Path: / + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + - name: Custom-Header2 + value: xyz + +ReadinessProbe: + Path: / + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + +StartupProbe: + Path: "/" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: [] + command: [] + tcp: false + +prometheus: + release: monitoring + +servicemonitor: + additionalLabels: {} + +prometheusRule: + enabled: true + additionalLabels: {} + namespace: "" + rules: + # These are just examples rules, please adapt them to your needs + - alert: TooMany500s + expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 + for: 1m + labels: + severity: critical + annotations: + description: Too many 5XXs + summary: More than 5% of the all requests did return 5XX, this require your attention + - alert: TooMany400s + expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 + for: 1m + labels: + severity: critical + annotations: + description: Too many 4XXs + summary: More than 5% of the all requests did return 4XX, this require your attention + + +ingress: + enabled: true + className: nginx + annotations: {} +# nginx.ingress.kubernetes.io/rewrite-target: / +# nginx.ingress.kubernetes.io/ssl-redirect: "false" +# kubernetes.io/ingress.class: nginx +# kubernetes.io/tls-acme: "true" +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" +# Old Ingress Format +# host: "ingress-example.com" +# path: "/app" + +# New Ingress Format + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + additionalBackends: + - path: /example1 + pathType: "ImplementationSpecific" + backend: + service: + name: test-service + port: + number: 80 + + tls: [] +### Legacy Ingress Format ## +# host: abc.com +# path: "/" +# pathType: "ImplementationSpecific" + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +ingressInternal: + enabled: true + className: nginx-internal + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + additionalBackends: + - path: /internal + pathType: "ImplementationSpecific" + backend: + service: + name: test-service-internal + port: + number: 80 + - path: /internal-01 + pathType: "ImplementationSpecific" + backend: + service: + name: test-service-internal + port: + number: 80 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +winterSoldier: + apiVersion: pincher.devtron.ai/v1alpha1 + enabled: true + annotations: {} + labels: {} + type: Deployment + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: + - timeFrom: 00:00 + timeTo: 23:59:59 + weekdayFrom: Sat + weekdayTo: Sun + - timeFrom: 00:00 + timeTo: 08:00 + weekdayFrom: Mon + weekdayTo: Fri + - timeFrom: 20:00 + timeTo: 23:59:59 + weekdayFrom: Mon + weekdayTo: Fri + action: scale + targetReplicas: [1,1,1] + fieldSelector: + - AfterTime(AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) + + +dbMigrationConfig: + enabled: false + +command: + workingDir: /app + enabled: false + value: ["ls"] + +args: + enabled: false + value: [] + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 1 + memory: 200Mi + requests: + cpu: 0.10 + memory: 100Mi + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + + +nodeSelector: {} + + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 + +ConfigMaps: + enabled: false + maps: [] +# - name: config-map-1 +# type: environment +# external: false +# data: +# key1: key1value-1 +# key2: key2value-1 +# key3: key3value-1 +# - name: config-map-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# filePermission: 0400 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 +# key3: abc-2 +# - name: config-map-3 +# type: environment +# external: true +# mountPath: /etc/config/3 +# data: [] +# - name: config-map-4 +# type: volume +# external: true +# mountPath: /etc/config/4 +# data: [] + + +ConfigSecrets: + enabled: true + secrets: + - name: config-secret-1 + type: environment + external: false + externalType: AWSSecretsManager + esoSecretData: + secretStore: + aws: + service: SecretsManager + region: us-east-1 + auth: + secretRef: + accessKeyIDSecretRef: + name: awssm-secret + key: access-key + secretAccessKeySecretRef: + name: awssm-secret + key: secret-access-key + esoData: + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + data: + key1: key1value-1 + key2: key2value-1 + key3: key3value-1 + - name: config-secret-2 + type: environment + external: false + externalType: ESO_HashiCorpVault + esoSecretData: + secretStore: + vault: + server: "http://my.vault.server:8200" + path: "secret" + version: "v2" + auth: + tokenSecretRef: + name: vault-token + key: token + esoData: + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + date: + key1: key1value-1 + key2: key2value-1 + key3: key3value-1 + +# - name: config-secret-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 + + +initContainers: + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + - command: ["sh", "-c", "chown -R 1000:1000 logs"] + reuseContainerImage: true + volumeMounts: + - mountPath: /usr/local/airflow/logs + name: logs-data + securityContext: + privileged: true + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + - name: init-migrate + image: busybox:latest + command: ["sh", "-c", "chown -R 1000:1000 logs"] + volumeMounts: + - mountPath: /usr/local/airflow/logs + name: logs-data + securityContext: + capabilities: + drop: + - ALL + +containers: + # Additional init containers to run before the Scheduler pods. + # for example, be used to run a sidecar that chown Logs storage . + - name: volume-mount-hack + image: busybox + command: ["sh", "-c", "chown -R 1000:1000 logs"] + volumeMounts: + - mountPath: /usr/local/airflow/logs + name: logs-data + + +rawYaml: + - apiVersion: v1 + kind: Service + metadata: + annotations: + labels: + app: sample-metrics-app + name: sample-metrics-app + namespace: default + spec: + ports: + - name: web + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: sample-metrics-app + sessionAffinity: None + type: ClusterIP + - apiVersion: v1 + kind: Service + metadata: + annotations: + labels: + app: sample-metrics-app + name: sample-metrics-app + namespace: default + spec: + ports: + - name: web + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: sample-metrics-app + sessionAffinity: None + type: ClusterIP + +# If you need to provide some extra specs for main container which are not included by default in deployment template +# then provide them here +containerExtraSpecs: {} + +# If you need to provide some extra specs for pod which are not included by default in deployment template +# then provide them here +podExtraSpecs: {} + +envoyproxy: + image: docker.io/envoyproxy/envoy:v1.16.0 + configMapName: "" + lifecycle: {} + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + +podDisruptionBudget: + minAvailable: 1 + maxUnavailable: 1 + + # Node tolerations for server scheduling to nodes with taints + # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ +# + +tolerations: + - key: "key" + operator: "Equal|Exists" + value: "value" + effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + +appMetrics: true +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "test1" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: + kubernetes.io/service-account.name: build-robot +containerSecurityContext: + allowPrivilegeEscalation: false +privileged: true +hostAliases: [] +# - ip: "127.0.0.1" +# hostnames: +# - "foo.local" + + +affinity: + enabled: false + values: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: security + operator: In + values: + - S1 + topologyKey: topology.kubernetes.io/zone + +secondaryWorkload: + enabled: false + postfix: "od" + replicaCount: 1 + affinity: {} + tolerations: [] + autoscaling: + enabled: true + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/values.yaml b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/values.yaml new file mode 100644 index 0000000000..d67a0b2560 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/deployment-chart_4-22-0/values.yaml @@ -0,0 +1,718 @@ +# Default values for myapp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 +MinReadySeconds: 5 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +ContainerPort: + - name: app + port: 8080 + servicePort: 80 + envoyPort: 8799 + envoyTimeout: 15s + useHTTP2: false + supportStreaming: false + idleTimeout: 1800s + protocol: TCP +# servicemonitor: +# enabled: true +# path: /abc +# scheme: 'http' +# interval: 30s +# scrapeTimeout: 20s +# metricRelabelings: +# - sourceLabels: [namespace] +# regex: '(.*)' +# replacement: myapp +# targetLabel: target_namespace + + - name: app1 + port: 8090 + servicePort: 8080 + useGRPC: true + +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 +autoPromotionSeconds: 30 + +Spec: + Affinity: + Key: "" +# Key: kops.k8s.io/instancegroup + Values: "" + +affinity: {} + +image: + pullPolicy: IfNotPresent + +restartPolicy: Always + +ambassadorMapping: + enabled: false + # labels: + # key1: value1 + # prefix: / + # ambassadorId: 1234 + # hostname: devtron.example.com + # rewrite: /foo/ + # retryPolicy: + # retry_on: "5xx" + # num_retries: 10 + # cors: + # origins: http://foo.example,http://bar.example + # methods: POST, GET, OPTIONS + # headers: Content-Type + # credentials: true + # exposed_headers: X-Custom-Header + # max_age: "86400" + # weight: 10 + # method: GET + # extraSpec: + # method_regex: true + # headers: + # x-quote-mode: backend + # x-random-header: devtron + # tls: + # context: httpd-context + # create: true + # secretName: httpd-secret + # hosts: + # - anything.example.info + # - devtron.example.com + # extraSpec: + # min_tls_version: v1.2 + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + annotations: {} + labels: {} + behavior: {} + containerResource: + enabled: false +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +kedaAutoscaling: + enabled: false + envSourceContainerName: "" # Optional. Default: .spec.template.spec.containers[0] + cooldownPeriod: 300 # Optional. Default: 300 seconds + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 # Optional. Must be less than minReplicaCount + pollingInterval: 30 # Optional. Default: 30 seconds + # The fallback section is optional. It defines a number of replicas to fallback to if a scaler is in an error state. + fallback: {} # Optional. Section to specify fallback options + # failureThreshold: 3 # Mandatory if fallback section is included + # replicas: 6 + advanced: {} + # horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options + # behavior: # Optional. Use to modify HPA's scaling behavior + # scaleDown: + # stabilizationWindowSeconds: 300 + # policies: + # - type: Percent + # value: 100 + # periodSeconds: 15 + triggers: [] + triggerAuthentication: + enabled: false + name: "" + spec: {} + authenticationRef: {} + +# kedaHttpScaledObject: +# enabled: false +# minReplicaCount: 1 +# maxReplicaCount: 2 +# targetPendingRequests: +# scaledownPeriod: +# servicePort: 80 # port of the service (required) + +secret: + enabled: false + +service: + type: ClusterIP + enabled: true +# name: "1234567890123456789012345678901234567890123456789012345678901234567890" + annotations: {} + # test1: test2 + # test3: test4 + sessionAffinity: + enabled: false + +istio: + enable: false + gateway: + enabled: false + labels: {} + annotations: {} + host: "" + tls: + enabled: false + secretName: "" + virtualService: + enabled: false + labels: {} + annotations: {} + gateways: [] + hosts: [] + http: [] + # - match: + # - uri: + # prefix: /v1 + # - uri: + # prefix: /v2 + # timeout: 12 + # headers: + # request: + # add: + # x-some-header: "value" + # retries: + # attempts: 2 + # perTryTimeout: 3s + destinationRule: + enabled: false + labels: {} + annotations: {} + subsets: [] + trafficPolicy: {} + peerAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + mtls: + mode: "" + portLevelMtls: {} + requestAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + jwtRules: [] + authorizationPolicy: + enabled: false + labels: {} + annotations: {} + action: + provider: {} + rules: [] + +flaggerCanary: + enabled: false + labels: {} + annotations: {} + createIstioGateway: + enabled: false + labels: {} + annotations: {} + host: "" + tls: + enabled: false + secretName: "" + # Istio gateways (optional) + addOtherGateways: [] + # Istio virtual service host names (optional) + addOtherHosts: [] + # Istio gateway refs (optional) + gatewayRefs: + # - name: istio-gateway + # namespace: istio-system + #service port + serviceport: 8080 + #containerPort + targetPort: 8080 + # discover all port open in container + portDiscovery: true + # application protocol (optional) + appProtocol: + # Istio retry policy (optional) + retries: + attempts: 3 + perTryTimeout: 1s + retryOn: "gateway-error,connect-failure,refused-stream" + # HTTP match conditions (optional) + match: + - uri: + prefix: / + # HTTP rewrite (optional) + rewriteUri: / + # timeout (optional) + timeout: + # Add headers (optional) + headers: + # request: + # add: + # x-some-header: "value" + # cross-origin resource sharing policy (optional) + corsPolicy: + # allowOrigin: + # - example.com + # allowMethods: + # - GET + # allowCredentials: false + # allowHeaders: + # - x-some-header + # maxAge: 24h + analysis: + # schedule interval (default 60s) + interval: 15s + # max number of failed metric checks before rollback + threshold: 5 + # max traffic percentage routed to canary + # percentage (0-100) + maxWeight: 50 + # canary increment step + # percentage (0-100) + stepWeight: 5 + thresholds: + # minimum req success rate (non 5xx responses) + # percentage (0-100) + successRate: 90 + # maximum req duration P99 + # milliseconds + latency: 500 + loadtest: + enabled: true + # load tester address + url: http://flagger-loadtester.istio-system/ + + +server: + deployment: + image_tag: 1-95af053 + image: "" + +EnvVariablesFromFieldPath: [] +# - name: POD_NAME +# fieldPath: metadata.name + +EnvVariables: [] + # - name: FLASK_ENV + # value: qa + +EnvVariablesFromSecretKeys: [] + # - name: ENV_NAME + # secretName: SECRET_NAME + # keyName: SECRET_KEY + +EnvVariablesFromConfigMapKeys: [] + # - name: ENV_NAME + # configMapName: CONFIG_MAP_NAME + # keyName: CONFIG_MAP_KEY + +LivenessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + grpc: {} + + +ReadinessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + grpc: {} + + +StartupProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: [] + command: [] + tcp: false + grpc: {} + + +prometheus: + release: monitoring + +servicemonitor: + additionalLabels: {} + + +prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" +# rules: +# # These are just examples rules, please adapt them to your needs +# - alert: TooMany500s +# expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 +# for: 1m +# labels: +# severity: critical +# annotations: +# description: Too many 5XXs +# summary: More than 5% of the all requests did return 5XX, this require your attention +# - alert: TooMany400s +# expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 +# for: 1m +# labels: +# severity: critical +# annotations: +# description: Too many 4XXs +# summary: More than 5% of the all requests did return 4XX, this require your attention +# + +ingress: + enabled: false + className: "" + labels: {} + annotations: {} +# nginx.ingress.kubernetes.io/rewrite-target: / +# nginx.ingress.kubernetes.io/ssl-redirect: "false" +# kubernetes.io/ingress.class: nginx +# kubernetes.io/tls-acme: "true" +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +ingressInternal: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +winterSoldier: + enabled: false + apiVersion: pincher.devtron.ai/v1alpha1 + labels: {} + annotations: {} + type: Deployment + timeRangesWithZone: {} + # timeZone: "Asia/Kolkata" + # timeRanges: [] + action: sleep + targetReplicas: [] + fieldSelector: [] + # - AfterTime(AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) + +networkPolicy: + enabled: false + annotations: {} + labels: {} + podSelector: + matchExpressions: [] + matchLabels: {} + policyTypes: [] + ingress: [] + egress: [] + +dbMigrationConfig: + enabled: false + +command: + enabled: false + value: [] + +args: + enabled: false + value: [] + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + + +nodeSelector: {} + +# If you need to provide some extra specs for pod which are not included by default in deployment template +# then provide them here +podExtraSpecs: {} + +# If you need to provide some extra specs for main container which are not included by default in deployment template +# then provide them here +containerExtraSpecs: {} + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 + +ConfigMaps: + enabled: false + maps: [] +# - name: config-map-1 +# type: environment +# external: false +# data: +# key1: key1value-1 +# key2: key2value-1 +# key3: key3value-1 +# - name: config-map-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 +# key3: abc-2 +# - name: config-map-3 +# type: environment +# external: true +# mountPath: /etc/config/3 +# data: [] +# - name: config-map-4 +# type: volume +# external: true +# mountPath: /etc/config/4 +# data: [] + + +ConfigSecrets: + enabled: false + secrets: [] + # data: + # key1: key1value-1 + # key2: key2value-1 + # key3: key3value-1 +# - name: config-secret-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 + + +initContainers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + # # Uncomment below line ONLY IF you want to reuse the container image. + # # This will assign your application's docker image to init container. + # reuseContainerImage: true + +containers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + +rawYaml: [] +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP + +topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: zone + # whenUnsatisfiable: DoNotSchedule + # autoLabelSelector: true + # minDomain: 1 + # nodeTaintsPolicy: Honor + +envoyproxy: + image: docker.io/envoyproxy/envoy:v1.16.0 + lifecycle: {} + configMapName: "" + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + +containerSpec: + lifecycle: + enabled: false + preStop: {} +# exec: +# command: ["sleep","10"] + postStart: {} +# httpGet: +# host: example.com +# path: /example +# port: 90 + +podDisruptionBudget: {} +# minAvailable: 1 +# maxUnavailable: 1 + + ## Node tolerations for server scheduling to nodes with taints + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + +podSecurityContext: {} + # runAsUser: 1000 + # runAsGroup: 3000 + # fsGroup: 2000 + +containerSecurityContext: {} + # allowPrivilegeEscalation: false +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: {} + +tolerations: [] + # - key: "key" + # operator: "Equal|Exists" + # value: "value" + # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + +imagePullSecrets: [] + # - test1 + # - test2 +persistentVolumeClaim: {} + +verticalPodScaling: + enabled: false + +customPodLabels: {} + +secondaryWorkload: + enabled: false + Spec: + Affinity: + Key: "" + Values: "" + replicaCount: 1 + affinity: {} + tolerations: [] + autoscaling: + enabled: false + containerResource: + enabled: false \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.helmignore b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.helmignore new file mode 100644 index 0000000000..50af031725 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.image_descriptor_template.json b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.image_descriptor_template.json new file mode 100644 index 0000000000..bd2472da07 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/.image_descriptor_template.json @@ -0,0 +1 @@ +{"server":{"deployment":{"image_tag":"{{.Tag}}","image":"{{.Name}}"}},"pipelineName": "{{.PipelineName}}","releaseVersion":"{{.ReleaseVersion}}","deploymentType": "{{.DeploymentType}}", "app": "{{.App}}", "env": "{{.Env}}", "appMetrics": {{.AppMetrics}}} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/Chart.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/Chart.yaml new file mode 100644 index 0000000000..a6e8dec01c --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: reference-chart_5-2-0 +version: 5.2.0 \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/README.md b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/README.md new file mode 100644 index 0000000000..fcd6785033 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/README.md @@ -0,0 +1,863 @@ + +# Rollout Deployment Chart - v5.0 + +## 1. Yaml File - + +### Container Ports + +This defines ports on which application services will be exposed to other services + +```yaml +ContainerPort: + - envoyPort: 8799 + idleTimeout: + name: app + port: 8080 + servicePort: 80 + nodePort: 32056 + supportStreaming: true + useHTTP2: true +``` + +| Key | Description | +| :--- | :--- | +| `envoyPort` | envoy port for the container. | +| `idleTimeout` | the duration of time that a connection is idle before the connection is terminated. | +| `name` | name of the port. | +| `port` | port for the container. | +| `servicePort` | port of the corresponding kubernetes service. | +| `nodePort` | nodeport of the corresponding kubernetes service. | +| `supportStreaming` | Used for high performance protocols like grpc where timeout needs to be disabled. | +| `useHTTP2` | Envoy container can accept HTTP2 requests. | + +### EnvVariables +```yaml +EnvVariables: [] +``` +To set environment variables for the containers that run in the Pod. + +### EnvVariablesFromSecretKeys +```yaml +EnvVariablesFromSecretKeys: + - name: ENV_NAME + secretName: SECRET_NAME + keyName: SECRET_KEY + +``` + It is use to get the name of Environment Variable name, Secret name and the Key name from which we are using the value in that corresponding Environment Variable. + + ### EnvVariablesFromConfigMapKeys +```yaml +EnvVariablesFromConfigMapKeys: + - name: ENV_NAME + configMapName: CONFIG_MAP_NAME + keyName: CONFIG_MAP_KEY + +``` + It is use to get the name of Environment Variable name, Config Map name and the Key name from which we are using the value in that corresponding Environment Variable. + +### Liveness Probe + +If this check fails, kubernetes restarts the pod. This should return error code in case of non-recoverable error. + +```yaml +LivenessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + scheme: "" + tcp: true +``` + +| Key | Description | +| :--- | :--- | +| `Path` | It define the path where the liveness needs to be checked. | +| `initialDelaySeconds` | It defines the time to wait before a given container is checked for liveliness. | +| `periodSeconds` | It defines the time to check a given container for liveness. | +| `successThreshold` | It defines the number of successes required before a given container is said to fulfil the liveness probe. | +| `timeoutSeconds` | It defines the time for checking timeout. | +| `failureThreshold` | It defines the maximum number of failures that are acceptable before a given container is not considered as live. | +| `httpHeaders` | Custom headers to set in the request. HTTP allows repeated headers,You can override the default headers by defining .httpHeaders for the probe. | +| `scheme` | Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP. +| `tcp` | The kubelet will attempt to open a socket to your container on the specified port. If it can establish a connection, the container is considered healthy. | + + +### MaxUnavailable + +```yaml + MaxUnavailable: 0 +``` +The maximum number of pods that can be unavailable during the update process. The value of "MaxUnavailable: " can be an absolute number or percentage of the replicas count. The default value of "MaxUnavailable: " is 25%. + +### MaxSurge + +```yaml +MaxSurge: 1 +``` +The maximum number of pods that can be created over the desired number of pods. For "MaxSurge: " also, the value can be an absolute number or percentage of the replicas count. +The default value of "MaxSurge: " is 25%. + +### Min Ready Seconds + +```yaml +MinReadySeconds: 60 +``` +This specifies the minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available. This defaults to 0 (the Pod will be considered available as soon as it is ready). + +### Readiness Probe + +If this check fails, kubernetes stops sending traffic to the application. This should return error code in case of errors which can be recovered from if traffic is stopped. + +```yaml +ReadinessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + scheme: "" + tcp: true +``` + +| Key | Description | +| :--- | :--- | +| `Path` | It define the path where the readiness needs to be checked. | +| `initialDelaySeconds` | It defines the time to wait before a given container is checked for readiness. | +| `periodSeconds` | It defines the time to check a given container for readiness. | +| `successThreshold` | It defines the number of successes required before a given container is said to fulfill the readiness probe. | +| `timeoutSeconds` | It defines the time for checking timeout. | +| `failureThreshold` | It defines the maximum number of failures that are acceptable before a given container is not considered as ready. | +| `httpHeaders` | Custom headers to set in the request. HTTP allows repeated headers,You can override the default headers by defining .httpHeaders for the probe. | +| `scheme` | Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP. +| `tcp` | The kubelet will attempt to open a socket to your container on the specified port. If it can establish a connection, the container is considered healthy. | + +### Pod Disruption Budget + +You can create `PodDisruptionBudget` for each application. A PDB limits the number of pods of a replicated application that are down simultaneously from voluntary disruptions. For example, an application would like to ensure the number of replicas running is never brought below the certain number. + +```yaml +podDisruptionBudget: + minAvailable: 1 +``` + +or + +```yaml +podDisruptionBudget: + maxUnavailable: 50% +``` + +You can specify either `maxUnavailable` or `minAvailable` in a PodDisruptionBudget and it can be expressed as integers or as a percentage + +| Key | Description | +| :--- | :--- | +| `minAvailable` | Evictions are allowed as long as they leave behind 1 or more healthy pods of the total number of desired replicas. | +| `maxUnavailable` | Evictions are allowed as long as at most 1 unhealthy replica among the total number of desired replicas. | + +### Ambassador Mappings + +You can create ambassador mappings to access your applications from outside the cluster. At its core a Mapping resource maps a resource to a service. + +```yaml +ambassadorMapping: + ambassadorId: "prod-emissary" + cors: {} + enabled: true + hostname: devtron.example.com + labels: {} + prefix: / + retryPolicy: {} + rewrite: "" + tls: + context: "devtron-tls-context" + create: false + hosts: [] + secretName: "" +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Set true to enable ambassador mapping else set false.| +| `ambassadorId` | used to specify id for specific ambassador mappings controller. | +| `cors` | used to specify cors policy to access host for this mapping. | +| `weight` | used to specify weight for canary ambassador mappings. | +| `hostname` | used to specify hostname for ambassador mapping. | +| `prefix` | used to specify path for ambassador mapping. | +| `labels` | used to provide custom labels for ambassador mapping. | +| `retryPolicy` | used to specify retry policy for ambassador mapping. | +| `corsPolicy` | Provide cors headers on flagger resource. | +| `rewrite` | used to specify whether to redirect the path of this mapping and where. | +| `tls` | used to create or define ambassador TLSContext resource. | +| `extraSpec` | used to provide extra spec values which not present in deployment template for ambassador resource. | + +### Autoscaling + +This is connected to HPA and controls scaling up and down in response to request load. + +```yaml +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + extraMetrics: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Set true to enable autoscaling else set false.| +| `MinReplicas` | Minimum number of replicas allowed for scaling. | +| `MaxReplicas` | Maximum number of replicas allowed for scaling. | +| `TargetCPUUtilizationPercentage` | The target CPU utilization that is expected for a container. | +| `TargetMemoryUtilizationPercentage` | The target memory utilization that is expected for a container. | +| `extraMetrics` | Used to give external metrics for autoscaling. | + +### Fullname Override + +```yaml +fullnameOverride: app-name +``` +`fullnameOverride` replaces the release fullname created by default by devtron, which is used to construct Kubernetes object names. By default, devtron uses {app-name}-{environment-name} as release fullname. + +### Image + +```yaml +image: + pullPolicy: IfNotPresent +``` + +Image is used to access images in kubernetes, pullpolicy is used to define the instances calling the image, here the image is pulled when the image is not present,it can also be set as "Always". + +### imagePullSecrets + +`imagePullSecrets` contains the docker credentials that are used for accessing a registry. + +```yaml +imagePullSecrets: + - regcred +``` +regcred is the secret that contains the docker credentials that are used for accessing a registry. Devtron will not create this secret automatically, you'll have to create this secret using dt-secrets helm chart in the App store or create one using kubectl. You can follow this documentation Pull an Image from a Private Registry [https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) . + +### Ingress + +This allows public access to the url, please ensure you are using right nginx annotation for nginx class, its default value is nginx + +```yaml +ingress: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + className: nginx + annotations: {} + hosts: + - host: example1.com + paths: + - /example + - host: example2.com + paths: + - /example2 + - /example2/healthz + tls: [] +``` +Legacy deployment-template ingress format + +```yaml +ingress: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + ingressClassName: nginx-internal + annotations: {} + path: "" + host: "" + tls: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Enable or disable ingress | +| `annotations` | To configure some options depending on the Ingress controller | +| `path` | Path name | +| `host` | Host name | +| `tls` | It contains security details | +### additionalBackends + +This defines additional backend path in the ingress . + +```yaml + hosts: + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + additionalBackends: + - path: /example1 + pathType: "ImplementationSpecific" + backend: + service: + name: test-service + port: + number: 80 +``` +### Ingress Internal + +This allows private access to the url, please ensure you are using right nginx annotation for nginx class, its default value is nginx + +```yaml +ingressInternal: + enabled: false + # For K8s 1.19 and above use ingressClassName instead of annotation kubernetes.io/ingress.class: + ingressClassName: nginx-internal + annotations: {} + hosts: + - host: example1.com + paths: + - /example + - host: example2.com + paths: + - /example2 + - /example2/healthz + tls: [] +``` + +| Key | Description | +| :--- | :--- | +| `enabled` | Enable or disable ingress | +| `annotations` | To configure some options depending on the Ingress controller | +| `path` | Path name | +| `host` | Host name | +| `tls` | It contains security details | + +### Init Containers +```yaml +initContainers: + - reuseContainerImage: true + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + volumeMounts: + - mountPath: /etc/ls-oms + name: ls-oms-cm-vol + command: + - flyway + - -configFiles=/etc/ls-oms/flyway.conf + - migrate + + - name: nginx + image: nginx:1.14.2 + securityContext: + privileged: true + ports: + - containerPort: 80 + command: ["/usr/local/bin/nginx"] + args: ["-g", "daemon off;"] +``` +Specialized containers that run before app containers in a Pod. Init containers can contain utilities or setup scripts not present in an app image. One can use base image inside initContainer by setting the reuseContainerImage flag to `true`. + +### Istio + +Istio is a service mesh which simplifies observability, traffic management, security and much more with it's virtual services and gateways. + +```yaml +istio: + enable: true + gateway: + annotations: {} + enabled: false + host: example.com + labels: {} + tls: + enabled: false + secretName: example-tls-secret + virtualService: + annotations: {} + enabled: false + gateways: [] + hosts: [] + http: + - corsPolicy: + allowCredentials: false + allowHeaders: + - x-some-header + allowMethods: + - GET + allowOrigin: + - example.com + maxAge: 24h + headers: + request: + add: + x-some-header: value + match: + - uri: + prefix: /v1 + - uri: + prefix: /v2 + retries: + attempts: 2 + perTryTimeout: 3s + rewriteUri: / + route: + - destination: + host: service1 + port: 80 + timeout: 12s + - route: + - destination: + host: service2 + labels: {} +``` + +### Pause For Seconds Before Switch Active +```yaml +pauseForSecondsBeforeSwitchActive: 30 +``` +To wait for given period of time before switch active the container. + + +### Winter-Soldier +Winter Soldier can be used to +- cleans up (delete) Kubernetes resources +- reduce workload pods to 0 + +**_NOTE:_** After deploying this we can create the Hibernator object and provide the custom configuration by which workloads going to delete, sleep and many more. for more information check [the main repo](https://github.com/devtron-labs/winter-soldier) + +Given below is template values you can give in winter-soldier: +```yaml +winterSoilder: + enable: false + apiVersion: pincher.devtron.ai/v1alpha1 + action: sleep + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: [] + targetReplicas: [] + fieldSelector: [] +``` +Here, +| Key | values | Description | +| :--- | :--- | :--- | +| `enable` | `fasle`,`true` | decide the enabling factor | +| `apiVersion` | `pincher.devtron.ai/v1beta1`, `pincher.devtron.ai/v1alpha1` | specific api version | +| `action` | `sleep`,`delete`, `scale` | This specify the action need to perform. | +| `timeRangesWithZone`:`timeZone` | eg:- `"Asia/Kolkata"`,`"US/Pacific"` | It use to specify the timeZone used. (It uses standard format. please refer [this](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) | +| `timeRangesWithZone`:`timeRanges` | array of [ `timeFrom`, `timeTo`, `weekdayFrom`, `weekdayTo`] | It use to define time period/range on which the user need to perform the specified action. you can have multiple timeRanges.
These settings will take `action` on Sat and Sun from 00:00 to 23:59:59, | +| `targetReplicas` | `[n]` : n - number of replicas to scale. | These is mandatory field when the `action` is `scale`
Defalut value is `[]`. | +| `fieldSelector` | `- AfterTime(AddTime( ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) ` | These value will take a list of methods to select the resources on which we perform specified `action` . | + + +here is an example, +```yaml +winterSoilder: + apiVersion: pincher.devtron.ai/v1alpha1 + enable: true + annotations: {} + labels: {} + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: + - timeFrom: 00:00 + timeTo: 23:59:59 + weekdayFrom: Sat + weekdayTo: Sun + - timeFrom: 00:00 + timeTo: 08:00 + weekdayFrom: Mon + weekdayTo: Fri + - timeFrom: 20:00 + timeTo: 23:59:59 + weekdayFrom: Mon + weekdayTo: Fri + action: scale + targetReplicas: [1,1,1] + fieldSelector: + - AfterTime(AddTime( ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '10h'), Now()) +``` +Above settings will take action on `Sat` and `Sun` from 00:00 to 23:59:59, and on `Mon`-`Fri` from 00:00 to 08:00 and 20:00 to 23:59:59. If `action:sleep` then runs hibernate at timeFrom and unhibernate at `timeTo`. If `action: delete` then it will delete workloads at `timeFrom` and `timeTo`. Here the `action:scale` thus it scale the number of resource replicas to `targetReplicas: [1,1,1]`. Here each element of `targetReplicas` array is mapped with the corresponding elments of array `timeRangesWithZone/timeRanges`. Thus make sure the length of both array is equal, otherwise the cnages cannot be observed. + +The above example will select the application objects which have been created 10 hours ago across all namespaces excluding application's namespace. Winter soldier exposes following functions to handle time, cpu and memory. + +- ParseTime - This function can be used to parse time. For eg to parse creationTimestamp use ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z') +- AddTime - This can be used to add time. For eg AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '-10h') ll add 10h to the time. Use d for day, h for hour, m for minutes and s for seconds. Use negative number to get earlier time. +- Now - This can be used to get current time. +- CpuToNumber - This can be used to compare CPU. For eg any({{spec.containers.#.resources.requests}}, { MemoryToNumber(.memory) < MemoryToNumber('60Mi')}) will check if any resource.requests is less than 60Mi. + + + +### Resources + +These define minimum and maximum RAM and CPU available to the application. + +```yaml +resources: + limits: + cpu: "1" + memory: "200Mi" + requests: + cpu: "0.10" + memory: "100Mi" +``` + +Resources are required to set CPU and memory usage. + +#### Limits + +Limits make sure a container never goes above a certain value. The container is only allowed to go up to the limit, and then it is restricted. + +#### Requests + +Requests are what the container is guaranteed to get. + +### Service + +This defines annotations and the type of service, optionally can define name also. + +```yaml + service: + type: ClusterIP + annotations: {} +``` + +### Volumes + +```yaml +volumes: + - name: log-volume + emptyDir: {} + - name: logpv + persistentVolumeClaim: + claimName: logpvc +``` + +It is required when some values need to be read from or written to an external disk. + +### Volume Mounts + +```yaml +volumeMounts: + - mountPath: /var/log/nginx/ + name: log-volume + - mountPath: /mnt/logs + name: logpvc + subPath: employee +``` + +It is used to provide mounts to the volume. + +### Affinity and anti-affinity + +```yaml +Spec: + Affinity: + Key: + Values: +``` + +Spec is used to define the desire state of the given container. + +Node Affinity allows you to constrain which nodes your pod is eligible to schedule on, based on labels of the node. + +Inter-pod affinity allow you to constrain which nodes your pod is eligible to be scheduled based on labels on pods. + +#### Key + +Key part of the label for node selection, this should be same as that on node. Please confirm with devops team. + +#### Values + +Value part of the label for node selection, this should be same as that on node. Please confirm with devops team. + +### Tolerations + +```yaml +tolerations: + - key: "key" + operator: "Equal" + value: "value" + effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" +``` + +Taints are the opposite, they allow a node to repel a set of pods. + +A given pod can access the given node and avoid the given taint only if the given pod satisfies a given taint. + +Taints and tolerations are a mechanism which work together that allows you to ensure that pods are not placed on inappropriate nodes. Taints are added to nodes, while tolerations are defined in the pod specification. When you taint a node, it will repel all the pods except those that have a toleration for that taint. A node can have one or many taints associated with it. + +### Arguments + +```yaml +args: + enabled: false + value: [] +``` + +This is used to give arguments to command. + +### Command + +```yaml +command: + enabled: false + value: [] +``` + +It contains the commands for the server. + +| Key | Description | +| :--- | :--- | +| `enabled` | To enable or disable the command. | +| `value` | It contains the commands. | + + +### Containers +Containers section can be used to run side-car containers along with your main container within same pod. Containers running within same pod can share volumes and IP Address and can address each other @localhost. We can use base image inside container by setting the reuseContainerImage flag to `true`. + +```yaml + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + command: ["/usr/local/bin/nginx"] + args: ["-g", "daemon off;"] + - reuseContainerImage: true + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + volumeMounts: + - mountPath: /etc/ls-oms + name: ls-oms-cm-vol + command: + - flyway + - -configFiles=/etc/ls-oms/flyway.conf + - migrate +``` + +### Prometheus + +```yaml + prometheus: + release: monitoring +``` + +It is a kubernetes monitoring tool and the name of the file to be monitored as monitoring in the given case.It describes the state of the prometheus. + +### rawYaml + +```yaml +rawYaml: + - apiVersion: v1 + kind: Service + metadata: + name: my-service + spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 + type: ClusterIP +``` +Accepts an array of Kubernetes objects. You can specify any kubernetes yaml here and it will be applied when your app gets deployed. + +### Grace Period + +```yaml +GracePeriod: 30 +``` +Kubernetes waits for the specified time called the termination grace period before terminating the pods. By default, this is 30 seconds. If your pod usually takes longer than 30 seconds to shut down gracefully, make sure you increase the `GracePeriod`. + +A Graceful termination in practice means that your application needs to handle the SIGTERM message and begin shutting down when it receives it. This means saving all data that needs to be saved, closing down network connections, finishing any work that is left, and other similar tasks. + +There are many reasons why Kubernetes might terminate a perfectly healthy container. If you update your deployment with a rolling update, Kubernetes slowly terminates old pods while spinning up new ones. If you drain a node, Kubernetes terminates all pods on that node. If a node runs out of resources, Kubernetes terminates pods to free those resources. It’s important that your application handle termination gracefully so that there is minimal impact on the end user and the time-to-recovery is as fast as possible. + + +### Server + +```yaml +server: + deployment: + image_tag: 1-95a53 + image: "" +``` + +It is used for providing server configurations. + +#### Deployment + +It gives the details for deployment. + +| Key | Description | +| :--- | :--- | +| `image_tag` | It is the image tag | +| `image` | It is the URL of the image | + +### Service Monitor + +```yaml +servicemonitor: + enabled: true + path: /abc + scheme: 'http' + interval: 30s + scrapeTimeout: 20s + metricRelabelings: + - sourceLabels: [namespace] + regex: '(.*)' + replacement: myapp + targetLabel: target_namespace +``` + +It gives the set of targets to be monitored. + +### Db Migration Config + +```yaml +dbMigrationConfig: + enabled: false +``` + +It is used to configure database migration. + + +### KEDA Autoscaling +[KEDA](https://keda.sh) is a Kubernetes-based Event Driven Autoscaler. With KEDA, you can drive the scaling of any container in Kubernetes based on the number of events needing to be processed. KEDA can be installed into any Kubernetes cluster and can work alongside standard Kubernetes components like the Horizontal Pod Autoscaler(HPA). + +Example for autosccaling with KEDA using Prometheus metrics is given below: +```yaml +kedaAutoscaling: + enabled: true + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 + pollingInterval: 30 + advanced: + restoreToOriginalReplicaCount: true + horizontalPodAutoscalerConfig: + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + triggers: + - type: prometheus + metadata: + serverAddress: http://:9090 + metricName: http_request_total + query: envoy_cluster_upstream_rq{appId="300", cluster_name="300-0", container="envoy",} + threshold: "50" + triggerAuthentication: + enabled: false + name: + spec: {} + authenticationRef: {} +``` +Example for autosccaling with KEDA based on kafka is given below : +```yaml +kedaAutoscaling: + enabled: true + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 + pollingInterval: 30 + advanced: {} + triggers: + - type: kafka + metadata: + bootstrapServers: b-2.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092,b-3.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092,b-1.kafka-msk-dev.example.c2.kafka.ap-southeast-1.amazonaws.com:9092 + topic: Orders-Service-ESP.info + lagThreshold: "100" + consumerGroup: oders-remove-delivered-packages + allowIdleConsumers: "true" + triggerAuthentication: + enabled: true + name: keda-trigger-auth-kafka-credential + spec: + secretTargetRef: + - parameter: sasl + name: keda-kafka-secrets + key: sasl + - parameter: username + name: keda-kafka-secrets + key: username + authenticationRef: + name: keda-trigger-auth-kafka-credential +``` + +### Security Context +A security context defines privilege and access control settings for a Pod or Container. + +To add a security context for main container: +```yaml +containerSecurityContext: + allowPrivilegeEscalation: false +``` + +To add a security context on pod level: +```yaml +podSecurityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 +``` + +### Topology Spread Constraints +You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. This can help to achieve high availability as well as efficient resource utilization. + +```yaml +topologySpreadConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: DoNotSchedule + autoLabelSelector: true + customLabelSelector: {} +``` + +### Deployment Metrics + +It gives the realtime metrics of the deployed applications + +| Key | Description | +| :--- | :--- | +| `Deployment Frequency` | It shows how often this app is deployed to production | +| `Change Failure Rate` | It shows how often the respective pipeline fails. | +| `Mean Lead Time` | It shows the average time taken to deliver a change to production. | +| `Mean Time to Recovery` | It shows the average time taken to fix a failed pipeline. | + +## 2. Show application metrics + +If you want to see application metrics like different HTTP status codes metrics, application throughput, latency, response time. Enable the Application metrics from below the deployment template Save button. After enabling it, you should be able to see all metrics on App detail page. By default it remains disabled. +![](../../../.gitbook/assets/deployment_application_metrics%20%282%29.png) + +Once all the Deployment template configurations are done, click on `Save` to save your deployment configuration. Now you are ready to create [Workflow](workflow/) to do CI/CD. + +### Helm Chart Json Schema + +Helm Chart [json schema](../../../scripts/devtron-reference-helm-charts/reference-chart_4-11-0/schema.json) is used to validate the deployment template values. + +### Other Validations in Json Schema + +The values of CPU and Memory in limits must be greater than or equal to in requests respectively. Similarly, In case of envoyproxy, the values of limits are greater than or equal to requests as mentioned below. +``` +resources.limits.cpu >= resources.requests.cpu +resources.limits.memory >= resources.requests.memory +envoyproxy.resources.limits.cpu >= envoyproxy.resources.requests.cpu +envoyproxy.resources.limits.memory >= envoyproxy.resources.requests.memory +``` diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/app-values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/app-values.yaml new file mode 100644 index 0000000000..d579b2259d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/app-values.yaml @@ -0,0 +1,448 @@ +# Mandatory configs +podDisruptionBudget: {} +rolloutLabels: {} +rolloutAnnotations: {} + +containerSpec: + lifecycle: + enabled: false + preStop: + exec: + command: ["sleep","10"] + postStart: + httpGet: + host: example.com + path: /example + port: 90 + +replicaCount: 1 +MinReadySeconds: 60 +GracePeriod: 30 +image: + pullPolicy: IfNotPresent +restartPolicy: Always +service: + # enabled: true + type: ClusterIP + #name: "service-1234567890" + loadBalancerSourceRanges: [] + # loadBalancerSourceRanges: + # - 1.2.3.4/32 + # - 1.2.5.6/23 + annotations: {} + # test1: test2 + # test3: test4 +ContainerPort: + - name: app + port: 8080 + servicePort: 80 + envoyPort: 8799 + useHTTP2: false + supportStreaming: false + idleTimeout: 1800s + protocol: TCP + resizePolicy: [] +# servicemonitor: +# enabled: true +# path: /abc +# scheme: 'http' +# interval: 30s +# scrapeTimeout: 20s +# metricRelabelings: +# - sourceLabels: [namespace] +# regex: '(.*)' +# replacement: myapp +# targetLabel: target_namespace +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 1 + memory: 200Mi + requests: + cpu: 0.10 + memory: 100Mi + +# Optional configs +LivenessProbe: + Path: "" + port: 8080 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + tcp: false + command: [] + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + +ReadinessProbe: + Path: "" + port: 8080 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + tcp: false + command: [] + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + +StartupProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: [] + command: [] + tcp: false + +ingress: + enabled: false + className: "" + labels: {} + annotations: {} +# nginx.ingress.kubernetes.io/force-ssl-redirect: 'false' +# nginx.ingress.kubernetes.io/ssl-redirect: 'false' +# kubernetes.io/ingress.class: nginx +# nginx.ingress.kubernetes.io/rewrite-target: /$2 +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +ingressInternal: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +command: + workingDir: {} + enabled: false + value: [] + +args: + enabled: false + value: + - /bin/sh + - -c + - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 + +#For adding custom labels to pods + +podLabels: {} +# customKey: customValue +podAnnotations: {} +# customKey: customValue + +rawYaml: [] + +topologySpreadConstraints: [] + +initContainers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + +containers: [] + ## Additional containers to run along with application pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + +dbMigrationConfig: + enabled: false + +tolerations: [] + +podSecurityContext: {} + +containerSecurityContext: {} + +Spec: + Affinity: + Key: + # Key: kops.k8s.io/instancegroup + Values: + +affinity: + enabled: false + values: {} + +ambassadorMapping: + enabled: false + labels: {} + prefix: / + ambassadorId: "" + hostname: devtron.example.com + rewrite: "" + retryPolicy: {} + cors: {} + tls: + context: "" + create: false + secretName: "" + hosts: [] + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 70 + TargetMemoryUtilizationPercentage: 80 + annotations: {} + labels: {} + behavior: {} + containerResource: + enabled: false + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +kedaAutoscaling: + enabled: false + envSourceContainerName: "" # Optional. Default: .spec.template.spec.containers[0] + minReplicaCount: 1 + maxReplicaCount: 2 + advanced: {} + triggers: [] + triggerAuthentication: + enabled: false + name: "" + spec: {} + authenticationRef: {} + +prometheus: + release: monitoring + +server: + deployment: + image_tag: 1-95af053 + image: "" + +servicemonitor: + additionalLabels: {} + +envoyproxy: + image: quay.io/devtron/envoy:v1.16.0 + configMapName: "" + lifecycle: {} + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + +istio: + enable: false + gateway: + enabled: false + labels: {} + annotations: {} + selector: {} + gatewayExtraSpec: {} + host: "example.com" + tls: + enabled: false + secretName: secret-name + virtualService: + enabled: false + labels: {} + annotations: {} + virtualServiceExtraSpec: {} + gateways: [] + hosts: [] + http: [] + # - match: + # - uri: + # prefix: /v1 + # - uri: + # prefix: /v2 + # timeout: 12 + # headers: + # request: + # add: + # x-some-header: "value" + # retries: + # attempts: 2 + # perTryTimeout: 3s + destinationRule: + enabled: false + labels: {} + annotations: {} + subsets: [] + trafficPolicy: {} + peerAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + mtls: + mode: "" + portLevelMtls: {} + requestAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + jwtRules: [] + authorizationPolicy: + enabled: false + labels: {} + annotations: {} + action: + provider: {} + rules: [] + +networkPolicy: + enabled: false + annotations: {} + labels: {} + podSelector: + matchExpressions: [] + matchLabels: {} + policyTypes: [] + ingress: [] + egress: [] + +winterSoldier: + enabled: false + apiVersion: pincher.devtron.ai/v1alpha1 + annotation: {} + labels: {} + type: Rollout + timeRangesWithZone: + timeZone: "Asia/Kolkata" + timeRanges: [] + action: sleep + targetReplicas: [] + fieldSelector: + - AfterTime(AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) + + + + +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: {} + +imagePullSecrets: [] + # - test1 + # - test2 +hostAliases: [] +# - ip: "127.0.0.1" +# hostnames: +# - "foo.local" +# - "bar.local" +# - ip: "10.1.2.3" +# hostnames: +# - "foo.remote" +# - "bar.remote" +peristentVolumeClaim: {} + +analysisTemplate: + enabled: false + templates: [] + +verticalPodScaling: + enabled: false diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/env-values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/env-values.yaml new file mode 100644 index 0000000000..5cd07c0269 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/env-values.yaml @@ -0,0 +1,66 @@ +replicaCount: 1 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 + +Spec: + Affinity: + key: "" + Values: nodes + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + behavior: {} +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# +secret: + enabled: false + data: {} +# my_own_secret: S3ViZXJuZXRlcyBXb3Jrcw== + +EnvVariables: [] +# - name: FLASK_ENV +# value: qa + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: "0.05" + memory: 50Mi + requests: + cpu: "0.01" + memory: 10Mi + + diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/pipeline-values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/pipeline-values.yaml new file mode 100644 index 0000000000..da8360dd02 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/pipeline-values.yaml @@ -0,0 +1,26 @@ +deployment: + strategy: + blueGreen: + autoPromotionSeconds: 30 + scaleDownDelaySeconds: 30 + previewReplicaCount: 1 + autoPromotionEnabled: true + rolling: + maxSurge: "25%" + maxUnavailable: 1 + canary: + maxSurge: "25%" + maxUnavailable: 1 + steps: + - setWeight: 25 + - pause: + duration: 15 # 1 min + - setWeight: 50 + - pause: + duration: 15 # 1 min + - setWeight: 75 + - pause: + duration: 15 # 1 min + recreate: + maxSurge: "0%" + maxUnavailable: "100%" \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/release-values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/release-values.yaml new file mode 100644 index 0000000000..48eb3f482c --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/release-values.yaml @@ -0,0 +1,14 @@ +server: + deployment: + image_tag: IMAGE_TAG + image: IMAGE_REPO + enabled: false +dbMigrationConfig: + enabled: false + +pauseForSecondsBeforeSwitchActive: 0 +waitForSecondsBeforeScalingDown: 0 +autoPromotionSeconds: 30 + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/schema.json b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/schema.json new file mode 100644 index 0000000000..2a43e937cd --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/schema.json @@ -0,0 +1,1363 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "containerExtraSpecs": { + "type": "object", + "title": "containerExtraSpecs", + "description": "Define container extra specs here" + }, + "ContainerPort": { + "type": "array", + "description": "defines ports on which application services will be exposed to other services", + "title": "Container Port", + "items": { + "type": "object", + "properties": { + "envoyPort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "envoy port for the container", + "title": "Envoy Port" + }, + "idleTimeout": { + "type": "string", + "description": "duration of time for which a connection is idle before the connection is terminated", + "title": "Idle Timeout" + }, + "name": { + "type": "string", + "description": "name of the port", + "title": "Name" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Port", + "title": "port for the container" + }, + "servicePort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port of the corresponding kubernetes service", + "title": "Service Port" + }, + "nodePort": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "nodeport of the corresponding kubernetes service", + "title": "Node Port" + }, + "supportStreaming": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "field to enable/disable timeout for high performance protocols like grpc", + "title": "Support Streaming" + }, + "useHTTP2": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": " field for setting if envoy container can accept(or not) HTTP2 requests", + "title": "Use HTTP2" + } + } + } + }, + "EnvVariables": { + "type": "array", + "items": {}, + "description": "contains environment variables needed by the containers", + "title": "Environment Variables" + }, + "EnvVariablesFromFieldPath": { + "type": "array", + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs", + "title": "EnvVariablesFromFieldPath", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name", + "description": "Env variable name to be" + }, + "fieldPath": { + "type": "string", + "title": "fieldPath", + "description": "Path of the field to select in the specified API version" + } + } + } + ] + }, + "EnvVariablesFromSecretKeys": { + "type": "array", + "description": "Selects a field of the deployment: It is use to get the name of Environment Variable name, Secret name and the Key name from which we are using the value in that corresponding Environment Variable.", + "title": "EnvVariablesFromSecretKeys", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name", + "description": "Env variable name to be used." + }, + "secretName": { + "type": "string", + "title": "secretName", + "description": "Name of Secret from which we are taking the value." + }, + "keyName": { + "type": "string", + "title": "keyName", + "description": "Name of The Key Where the value is mapped with." + } + } + } + ] + }, + "EnvVariablesFromConfigMapKeys": { + "type": "array", + "description": "Selects a field of the deployment: It is use to get the name of Environment Variable name, Config Map name and the Key name from which we are using the value in that corresponding Environment Variable.", + "title": "EnvVariablesFromConfigMapKeys", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "name", + "description": "Env variable name to be used." + }, + "configMapName": { + "type": "string", + "title": "configMapName", + "description": "Name of configMap from which we are taking the value." + }, + "keyName": { + "type": "string", + "title": "keyName", + "description": "Name of The Key Where the value is mapped with." + } + } + } + ] + }, + "GracePeriod": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "time for which Kubernetes waits before terminating the pods", + "title": "Grace Period" + }, + "LivenessProbe": { + "type": "object", + "description": "used by the kubelet to know when to restart a container", + "title": "Liveness Probe", + "properties": { + "Path": { + "type": "string", + "description": "defines the path where the liveness needs to be checked", + "title": "Path" + }, + "command": { + "type": "array", + "items": {}, + "description": "commands executed to perform a probe", + "title": "Command" + }, + "failureThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the maximum number of failures that are acceptable before a given container is not considered as live", + "title": "Failure Threshold" + }, + "httpHeaders": { + "type": "array", + "items": {}, + "description": "used to override the default headers by defining .httpHeaders for the probe", + "title": "HTTP headers" + }, + "initialDelaySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to wait before a given container is checked for liveness", + "title": "Initial Delay Seconds" + }, + "periodSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to check a given container for liveness", + "title": "Period Seconds" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port to access on the container", + "title": "Port" + }, + "scheme": { + "type": "string", + "description": "Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.", + "title": "Scheme" + }, + "successThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the number of successes required before a given container is said to fulfil the liveness probe", + "title": "Success Threshold" + }, + "tcp": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "If enabled, the kubelet will attempt to open a socket to container. If connection is established, the container is considered healthy", + "title": "TCP" + }, + "timeoutSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time for checking timeout", + "title": "Timeout Seconds" + } + } + }, + "MaxSurge": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "maximum number of pods that can be created over the desired number of pods", + "title": "Maximum Surge" + }, + "MaxUnavailable": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "maximum number of pods that can be unavailable during the update process", + "title": "Maximum Unavailable" + }, + "MinReadySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available", + "title": "Minimum Ready Seconds" + }, + "ReadinessProbe": { + "type": "object", + "description": "kubelet uses readiness probes to know when a container is ready to start accepting traffic", + "title": "Readiness Probe", + "properties": { + "Path": { + "type": "string", + "description": "defines the path where the readiness needs to be checked", + "title": "Path" + }, + "command": { + "type": "array", + "items": {}, + "description": "commands executed to perform a probe", + "title": "Command" + }, + "failureThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the maximum number of failures that are acceptable before a given container is not considered as ready", + "title": "Failure Threshold" + }, + "httpHeader": { + "type": "array", + "items": {}, + "description": "used to override the default headers by defining .httpHeaders for the probe", + "title": "HTTP headers" + }, + "initialDelaySeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to wait before a given container is checked for readiness", + "title": "Initial Delay Seconds" + }, + "periodSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time to check a given container for readiness", + "title": "Period Seconds" + }, + "port": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "port to access on the container", + "title": "Port" + }, + "scheme": { + "type": "string", + "description": "Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.", + "title": "Scheme" + }, + "successThreshold": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the number of successes required before a given container is said to fulfil the readiness probe", + "title": "Success Threshold" + }, + "tcp": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "If enabled, the kubelet will attempt to open a socket to container. If connection is established, the container is considered healthy", + "title": "TCP" + }, + "timeoutSeconds": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "defines the time for checking timeout", + "title": "Timeout Seconds" + } + } + }, + "Spec": { + "type": "object", + "description": "used to define the desire state of the given container", + "title": "Spec", + "properties": { + "Affinity": { + "type": "object", + "description": "Node/Inter-pod Affinity allows you to constrain which nodes your pod is eligible to schedule on, based on labels of the node/pods", + "title": "Affinity", + "properties": { + "Key": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "description": "Key part of the label for node/pod selection", + "title": "Key" + } + ] + }, + "Values": { + "type": "string", + "description": "Value part of the label for node/pod selection", + "title": "Values" + }, + "key": { + "type": "string" + } + } + } + } + }, + "ambassadorMapping": { + "type": "object", + "description": "used to create ambassador mapping resource", + "title": "Mapping", + "properties": { + "ambassadorId": { + "type": "string", + "description": "used to specify id for specific ambassador mappings controller", + "title": "Ambassador ID" + }, + "cors": { + "type": "object", + "description": "used to specify cors policy to access host for this mapping", + "title": "CORS" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to specify whether to create an ambassador mapping or not", + "title": "Enabled" + }, + "weight": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to specify weight for canary ambassador mappings" + }, + "hostname": { + "type": "string", + "description": "used to specify hostname for ambassador mapping", + "title": "Hostname" + }, + "labels": { + "type": "object", + "description": "used to provide custom labels for ambassador mapping", + "title": "Labels" + }, + "prefix": { + "type": "string", + "description": "used to specify path for ambassador mapping", + "title": "Prefix" + }, + "retryPolicy": { + "type": "object", + "description": "used to specify retry policy for ambassador mapping", + "title": "Retry Policy" + }, + "rewrite": { + "type": "string", + "description": "used to specify whether to redirect the path of this mapping and where", + "title": "Rewrite" + }, + "tls": { + "type": "object", + "description": "used to create or define ambassador TLSContext resource", + "title": "TLS Context" + }, + "extraSpec": { + "type": "object", + "description": "used to provide extra spec values which not present in deployment template for ambassador resource", + "title": "Extra Spec" + } + } + }, + "args": { + "type": "object", + "description": " used to give arguments to command", + "title": "Arguments", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling aruguments", + "title": "Enabled" + }, + "value": { + "type": "array", + "description": "values of the arguments", + "title": "Value", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "autoscaling": { + "type": "object", + "description": "connected to HPA and controls scaling up and down in response to request load", + "title": "Autoscaling", + "properties": { + "MaxReplicas": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Maximum number of replicas allowed for scaling", + "title": "Maximum Replicas" + }, + "MinReplicas": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Minimum number of replicas allowed for scaling", + "title": "Minimum Replicas" + }, + "TargetCPUUtilizationPercentage": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "The target CPU utilization that is expected for a container", + "title": "TargetCPUUtilizationPercentage" + }, + "TargetMemoryUtilizationPercentage": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "The target memory utilization that is expected for a container", + "title": "TargetMemoryUtilizationPercentage" + }, + "behavior": { + "type": "object", + "description": "describes behavior and scaling policies for that behavior", + "title": "Behavior" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling autoscaling", + "title": "Enabled" + }, + "labels": { + "type": "object", + "description": "labels for HPA", + "title": "labels" + }, + "annotations": { + "type": "object", + "description": "used to configure some options for HPA", + "title": "annotations" + }, + "extraMetrics": { + "type": "array", + "items": {}, + "description": "used to give external metrics for autoscaling", + "title": "Extra Metrics" + } + } + }, + "command": { + "type": "object", + "description": "contains the commands for the server", + "title": "Command", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling commands" + }, + "value": { + "type": "array", + "items": {}, + "description": "contains the commands", + "title": "Value" + }, + "workingDir": { + "type": "object", + "items": {}, + "description": "contains the working directory", + "title": "Working directory" + } + } + }, + "containerSecurityContext": { + "type": "object", + "description": " defines privilege and access control settings for a Container", + "title": "Container Security Context" + }, + "containers": { + "type": "array", + "items": {}, + "description": " used to run side-car containers along with the main container within same pod" + }, + "dbMigrationConfig": { + "type": "object", + "description": "used to configure database migration", + "title": "Db Migration Config", + "properties": { + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used for enabling/disabling the config", + "title": "Enabled" + } + } + }, + "envoyproxy": { + "type": "object", + "description": "envoy is attached as a sidecar to the application container to collect metrics like 4XX, 5XX, throughput and latency", + "title": "Envoy Proxy", + "properties": { + "configMapName": { + "type": "string", + "description": "configMap containing configuration for Envoy", + "title": "ConfigMap" + }, + "lifecycle": { + "type": "object", + "description": "Actions that the management system should take in response to container lifecycle events", + "title": "lifecycle", + "properties": { + "enabled": { + "type": "boolean" + }, + "postStart": { + "type": "object", + "title": "postStart", + "description": "PostStart is called immediately after a container is created" + }, + "preStop": { + "type": "object", + "title": "preStop", + "description": "PreStop is called immediately before a container is terminated" + } + } + }, + "image": { + "type": "string", + "description": "image of envoy to be used" + }, + "resources": { + "type": "object", + "description": "minimum and maximum RAM and CPU available to the application", + "title": "Resources", + "properties": { + "limits": { + "type": "object", + "description": "the maximum values a container can reach", + "title": "Limits", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "limit of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "limit of memory", + "title": "Memory" + } + } + }, + "requests": { + "type": "object", + "description": "request is what the container is guaranteed to get", + "title": "Requests", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "request value of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "request value of memory", + "title": "Memory" + } + } + } + } + } + } + }, + "hostAliases": { + "type": "array", + "title": "hostAliases", + "description": "HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file", + "items": [ + { + "type": "object", + "properties": { + "ip": { + "type": "string", + "title": "IP", + "description": "IP address of the host file entry" + }, + "hostnames": { + "type": "array", + "description": "Hostnames for the above IP address", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "image": { + "type": "object", + "description": "used to access images in kubernetes", + "title": "Image", + "properties": { + "pullPolicy": { + "type": "string", + "description": "used to define the instances calling the image", + "title": "Pull Policy", + "enum": [ + "IfNotPresent", + "Always" + ] + } + } + }, + "restartPolicy": { + "type": "string", + "description": "It restarts the docker container based on defined conditions.", + "title": "Restart Policy", + "enum": [ + "Always", + "OnFailure", + "Never" + ] + }, + "imagePullSecrets": { + "type": "array", + "items": {}, + "description": "contains the docker credentials that are used for accessing a registry", + "title": "Image PullSecrets" + }, + "winterSoldier": { + "type": "object", + "description": "allows to scale, sleep or delete the resource based on time.", + "title": "winterSoldier", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the winterSoldier controller", + "title": "Annotations" + }, + "labels": { + "type": "object", + "description": "labels for winterSoldier", + "title": "winterSoldier labels", + "default": "" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "apiVersion": { + "type": "string", + "description": "Api version for winterSoldier", + "title": "winterSoldier apiVersion", + "default": "pincher.devtron.ai/v1alpha1" + }, + "timeRangesWithZone": { + "type": "object", + "description": "describe time zone and time ranges to input in the winterSoldier", + "title": "Time Ranges With Zone", + "timeZone": { + "type": "string", + "description": "describe time zone, and follow standard format", + "title": "Time Zone" + }, + "timeRanges": { + "type": "array", + "items": {}, + "description": "used to take array of time ranges in which each element contains timeFrom, timeTo, weekdayFrom and weekdayTo.", + "title": "Time Ranges" + } + }, + "type": { + "type": "string", + "description": "describe the type of application Rollout/deployment.", + "title": "Type" + }, + "action": { + "type": "string", + "description": "describe the action to be performed by winterSoldier.", + "title": "Action" + }, + "targetReplicas": { + "type": "array", + "description": "describe the number of replicas to which the resource should scale up or down.", + "title": "Target Replicas" + }, + "fieldSelector": { + "type": "array", + "description": "it takes arrays of methods to select specific fields.", + "title": "Field Selector" + } + } + }, + "ingress": { + "type": "object", + "description": "allows public access to URLs", + "title": "Ingress", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the Ingress controller", + "title": "Annotations" + }, + "className": { + "type": "string", + "description": "name of ingress class, a reference to an IngressClass resource that contains additional configuration including the name of the controller", + "title": "Ingress class name", + "default": "nginx" + }, + "labels": { + "type": "object", + "description": "labels for ingress", + "title": "Ingress labels", + "default": "" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "hosts": { + "type": "array", + "description": "list of hosts in ingress", + "title": "Hosts", + "items": [ + { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "host URL", + "title": "Host" + }, + "pathType": { + "type": "string", + "description": "type of path", + "title": "PathType" + }, + "paths": { + "type": "array", + "description": "list of paths for a given host", + "title": "Paths", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "tls": { + "type": "array", + "items": {}, + "description": "contains security details - private key and certificate", + "title": "TLS" + } + } + }, + "ingressInternal": { + "type": "object", + "description": "allows private access to the URLs", + "properties": { + "annotations": { + "type": "object", + "description": "used to configure some options depending on the Ingress controller", + "title": "Annotations" + }, + "className": { + "type": "string", + "description": "name of ingress class, a reference to an IngressClass resource that contains additional configuration including the name of the controller", + "title": "Ingress class name", + "default": "nginx-internal" + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable ingress", + "title": "Enabled" + }, + "hosts": { + "type": "array", + "description": "list of hosts in ingress", + "title": "Hosts", + "items": [ + { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "host URL", + "title": "Host" + }, + "pathType": { + "type": "string", + "description": "type of path", + "title": "PathType" + }, + "paths": { + "type": "array", + "description": "list of paths for a given host", + "title": "Paths", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + }, + "tls": { + "type": "array", + "items": {}, + "description": "contains security details - private key and certificate", + "title": "TLS" + } + } + }, + "networkPolicy":{ + "type": "object", + "description": "NetworkPolicy describes what network traffic is allowed for a set of Pods", + "title": "Network Policy", + "properties": { + "enabled":{ + "type":"boolean", + "description": "used to enable or disable NetworkPolicy" + }, + "annotations":{ + "type": "object", + "description": "Annotations for NetworkPolicy" + }, + "labels":{ + "type":"object", + "description": "Labels for NetworkPolicy" + }, + "podSelector":{ + "type": "object", + "description": "Selects the pods to which this NetworkPolicy object applies", + "properties": { + "matchExpressions":{ + "type":"array", + "description": "list of label selector" + }, + "matchLabels":{ + "type":"object", + "description": "map of {key,value} pairs" + } + } + }, + "policyTypes":{ + "type":"array", + "description": "List of rule types that the NetworkPolicy relates to. Valid options are Ingress,Egress." + }, + "ingress":{ + "type":"array", + "description": "List of ingress rules to be applied to the selected pods" + }, + "egress":{ + "type":"array", + "description": "List of egress rules to be applied to the selected pods" + } + } + }, + "istio":{ + "type": "object", + "description": "Istio Service mesh", + "title": "Istio" + }, + "initContainers": { + "type": "array", + "items": {}, + "description": "specialized containers that run before app containers in a Pod, can contain utilities or setup scripts not present in an app image", + "title": "Init Containers" + }, + "kedaAutoscaling": { + "type": "object", + "description": "Kubernetes-based event driven autoscaler. With KEDA, one can drive the scaling of any container in Kubernetes based on the no. of events needing to be processed", + "title": "KEDA Autoscaling", + "properties": { + "advanced": { + "type": "object" + }, + "authenticationRef": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "envSourceContainerName": { + "type": "string" + }, + "maxReplicaCount": { + "type": "integer" + }, + "minReplicaCount": { + "type": "integer" + }, + "triggerAuthentication": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "spec": { + "type": "object" + } + } + }, + "triggers": { + "type": "array", + "items": {} + } + } + }, + "containerSpec": { + "type": "object", + "description": "define the container specic configuration", + "title": "containerSpec", + "properties": { + "lifecycle": { + "type": "object", + "description": "Actions that the management system should take in response to container lifecycle events", + "title": "lifecycle", + "properties": { + "enabled": { + "type": "boolean" + }, + "postStart": { + "type": "object", + "title": "postStart", + "description": "PostStart is called immediately after a container is created.You could use this event to check that a required API is available before the container’s main work begins" + }, + "preStop": { + "type": "object", + "title": "preStop", + "description": "PreStop is called immediately before a container is terminated" + } + } + } + } + }, + "pauseForSecondsBeforeSwitchActive": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "tell how much to wait for given period of time before switch active the container", + "title": "Pause For Seconds Before SwitchActive" + }, + "podAnnotations": { + "type": "object", + "description": "used to attach metadata and configs in Kubernetes", + "title": "Pod Annotations" + }, + "podDisruptionBudget": { + "type": "object", + "description": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", + "properties": { + "minAvailable": { + "type": "string", + "title": "minAvailable", + "description": "An eviction is allowed if at least \"minAvailable\" pods selected by \"selector\" will still be available after the eviction, i.e. even in the absence of the evicted pod" + }, + "maxUnavailable": { + "type": "string", + "title": "maxUnavailable", + "description": "An eviction is allowed if at most \"maxUnavailable\" pods selected by \"selector\" are unavailable after the eviction, i.e. even in absence of the evicted pod." + } + } + }, + "podExtraSpecs": { + "type": "object", + "description": "ExtraSpec for the pods to be configured", + "title": "podExtraSpecs" + }, + "podLabels": { + "type": "object", + "description": "key/value pairs that are attached to pods, are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users, but do not directly imply semantics to the core system", + "title": "Pod Labels" + }, + "podSecurityContext": { + "type": "object", + "description": "defines privilege and access control settings for a Pod or Container", + "title": "Pod Security Context" + }, + "prometheus": { + "type": "object", + "description": "a kubernetes monitoring tool", + "title": "Prometheus", + "properties": { + "release": { + "type": "string", + "description": "name of the file to be monitored, describes the state of prometheus" + } + } + }, + "rawYaml": { + "type": "array", + "items": {}, + "description": "Accepts an array of Kubernetes objects. One can specify any kubernetes yaml here & it will be applied when a app gets deployed.", + "title": "Raw YAML" + }, + "replicaCount": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "count of Replicas of pod", + "title": "REplica Count" + }, + "resources": { + "type": "object", + "description": "minimum and maximum RAM and CPU available to the application", + "title": "Resources", + "properties": { + "limits": { + "type": "object", + "description": "the maximum values a container can reach", + "title": "Limits", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "limit of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "limit of memory", + "title": "Memory" + } + } + }, + "requests": { + "type": "object", + "description": "request is what the container is guaranteed to get", + "title": "Requests", + "properties": { + "cpu": { + "type": "string", + "format": "cpu", + "description": "request value of CPU", + "title": "CPU" + }, + "memory": { + "type": "string", + "format": "memory", + "description": "request value of memory", + "title": "Memory" + } + } + } + } + }, + "secret": { + "type": "object", + "properties": { + "data": { + "type": "object" + }, + "enabled": { + "type": "boolean" + } + } + }, + "server": { + "type": "object", + "description": "used for providing server configurations.", + "title": "Server", + "properties": { + "deployment": { + "type": "object", + "description": "gives the details for deployment", + "title": "Deployment", + "properties": { + "image": { + "type": "string", + "description": "URL of the image", + "title": "Image" + }, + "image_tag": { + "type": "string", + "description": "tag of the image", + "title": "Image Tag" + } + } + } + } + }, + "service": { + "type": "object", + "description": "defines annotations and the type of service", + "title": "Service", + "properties": { + "annotations": { + "type": "object", + "title": "Annotations", + "description": "annotations of service" + }, + "type": { + "type": "string", + "description": "type of service", + "title": "Type", + "enum": [ + "ClusterIP", + "LoadBalancer", + "NodePort", + "ExternalName" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "used to enable or disable service", + "title": "Enabled" + } + } + }, + "serviceAccount": { + "type": "object", + "description": "defines service account for pods", + "title": "Service Account", + "properties": { + "annotations": { + "type": "object", + "title": "Annotations", + "description": "annotations of service account" + }, + "name": { + "type": "string", + "description": "name of service account", + "title": "Name" + }, + "create": { + "type": "boolean" + } + } + }, + "servicemonitor": { + "type": "object", + "description": "gives the set of targets to be monitored", + "title": "Service Monitor", + "properties": { + "additionalLabels": { + "type": "object" + } + } + }, + "tolerations": { + "type": "array", + "items": {}, + "description": "a mechanism which work together with Taints which ensures that pods are not placed on inappropriate nodes", + "title": "Tolerations" + }, + "topologySpreadConstraints": { + "type": "array", + "items": {}, + "description": "used to control how Pods are spread across a cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains", + "title": "Topology Spread Constraints" + }, + "volumeMounts": { + "type": "array", + "items": {}, + "description": "used to provide mounts to the volume", + "title": "Volume Mounts" + }, + "volumes": { + "type": "array", + "items": {}, + "description": "required when some values need to be read from or written to an external disk", + "title": "Volumes" + }, + "waitForSecondsBeforeScalingDown": { + "type": [ + "integer", + "string" + ], + "pattern": "^@{{[a-zA-Z0-9-+/*%_\\s]+}}$", + "description": "Wait for given period of time before scaling down the container", + "title": "Wait For Seconds Before Scaling Down" + } + } +} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/secrets-test-values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/secrets-test-values.yaml new file mode 100644 index 0000000000..4a20404db8 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/secrets-test-values.yaml @@ -0,0 +1 @@ +{"ConfigSecrets":{"enabled":true,"secrets":[{"data":{"standard_key":"c3RhbmRhcmQtdmFsdWU="},"external":false,"externalType":"","mountPath":"/test","name":"normal-secret","type":"volume"},{"data":{"secret_key":"U0VDUkVUIERBVEE="},"external":true,"externalType":"AWSSecretsManager","mountPath":"","name":"external-secret-3","type":"environment"}]}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/NOTES.txt b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/NOTES.txt new file mode 100644 index 0000000000..2b14478168 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range $.Values.ingress.paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include ".Chart.Name .fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ include ".Chart.Name .fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include ".Chart.Name .fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include ".Chart.Name .name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/_helpers.tpl b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/_helpers.tpl new file mode 100644 index 0000000000..813a7186ff --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/_helpers.tpl @@ -0,0 +1,167 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define ".Chart.Name .name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create service name +*/}} +{{- define ".servicename" -}} +{{- if .Values.service.name -}} +{{- .Values.service.name | trunc 63 | trimSuffix "-" -}} +{{- else if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 55 | trimSuffix "-" -}}-service +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 55 | trimSuffix "-" -}}-service +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 55 | trimSuffix "-" -}}-service +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create preview service name +*/}} +{{- define ".previewservicename" -}} +{{- if .Values.service.name -}} +{{- .Values.service.name | trunc 55 | trimSuffix "-" -}}-preview +{{- else if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 47 | trimSuffix "-" -}}-preview-service +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 47 | trimSuffix "-" -}}-preview-service +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 47 | trimSuffix "-" -}}-preview-service +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define ".Chart.Name .fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define ".Chart.Name .chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define ".Chart.Name .color" -}} +{{- $active0 := (index .Values.server.deployment 0).enabled -}} +{{/* +{{- $active1 := (index .Values.server.deployment 1).enabled -}} +*/}} +{{- $active1 := include "safeenabledcheck" . -}} +{{- $active := and $active0 $active1 -}} +{{- $active -}} +{{- end -}} + +{{- define "safeenabledcheck" -}} +{{- if (eq (len .Values.server.deployment) 2) -}} + {{- if (index .Values.server.deployment 1).enabled -}} + {{- $active := true -}} + {{- $active -}} + {{- else -}} + {{- $active := false -}} + {{- $active -}} + {{- end -}} +{{- else -}} + {{- $active := false -}} + {{- $active -}} +{{- end -}} +{{- end -}} + + +{{- define "isCMVolumeExists" -}} + {{- $isCMVolumeExists := false -}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $isCMVolumeExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{- $isCMVolumeExists -}} +{{- end -}} + +{{- define "isSecretVolumeExists" -}} + {{- $isSecretVolumeExists := false -}} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $isSecretVolumeExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{- $isSecretVolumeExists -}} +{{- end -}} + + + + +{{- define "serviceMonitorEnabled" -}} + {{- $SMenabled := false -}} + {{- range .Values.ContainerPort }} + {{- if .servicemonitor }} + {{- if and .servicemonitor.enabled }} + {{- $SMenabled = true -}} + {{- end }} + {{- end }} + {{- end }} + {{- $SMenabled -}} +{{- end -}} + +{{/* Create the name of the service account to use */}} +{{- define "serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include ".Chart.Name .fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{- define "VerticalPodAutoScalingEnabled" -}} + {{- $SMenabled := false -}} + {{- if and .Values.verticalPodScaling.enabled }} + {{- $SMenabled = true -}} + {{- end }} + {{- $SMenabled -}} +{{- end -}} + +{{/* Check for app/release labels in customPodLabels and replace accordingly */}} +{{- define "customPodLabelsContainsApp" -}} + {{- $LabelsContain := false -}} + {{- if hasKey .Values.customPodLabels "app" }} + {{- $LabelsContain = true -}} + {{- end }} + {{- $LabelsContain -}} +{{- end -}} + +{{- define "customPodLabelsContainsRelease" -}} + {{- $LabelsContain := false -}} + {{- if hasKey .Values.customPodLabels "release" }} + {{- $LabelsContain = true -}} + {{- end }} + {{- $LabelsContain -}} +{{- end -}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ambassador.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ambassador.yaml new file mode 100644 index 0000000000..7c374a70e8 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ambassador.yaml @@ -0,0 +1,86 @@ +{{ $svcName := include ".servicename" . }} +{{ $svcPort := (index .Values.ContainerPort 0).servicePort }} +{{- if $.Values.ambassadorMapping.enabled }} +{{- with $.Values.ambassadorMapping }} +apiVersion: getambassador.io/v3alpha1 +kind: Mapping +metadata: + name: {{ include ".Chart.Name .fullname" $ }}-mapping + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ $.Values.pipelineName }} + {{- if .labels }} +{{ toYaml .labels | nindent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .ambassadorId }} + ambassador_id: {{ .ambassadorId }} + {{- end }} + {{- if .hostname }} + hostname: {{ .hostname | quote }} + {{- end }} + prefix: {{ .prefix }} + {{- if .rewrite }} + rewrite: {{ .rewrite }} + {{- end }} + service: {{ $svcName }}.{{ $.Release.Namespace }}:{{ $svcPort }} + {{- if .retryPolicy }} + retry_policy: +{{ toYaml .retryPolicy | indent 4 }} + {{- end }} + {{- if .cors }} + cors: +{{ toYaml .cors | indent 4 }} + {{- end }} + {{- if .weight }} + weight: {{ .weight }} + {{- end }} + {{- if .method }} + method: {{ .method }} + {{- end }} + {{- if .extraSpec }} +{{ toYaml .extraSpec | indent 2 }} + {{- end }} + {{- if .tls }} + {{- if .tls.context }} + tls: {{ .tls.context }} +{{- if .tls.create }} +--- +apiVersion: getambassador.io/v3alpha1 +kind: TLSContext +metadata: + name: {{ .tls.context }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ $.Values.pipelineName }} + {{- if .tls.labels }} +{{ toYaml .tls.labels | nindent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .tls.secretName }} + secret: {{ .tls.secretName }} + {{- end }} + {{- if .tls.hosts }} + hosts: +{{ toYaml .tls.hosts | nindent 4 }} + {{- end }} + {{- if .tls.extraSpec }} +{{ toYaml .tls.extraSpec | indent 2 }} + {{- end }} +{{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/analysis-template.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/analysis-template.yaml new file mode 100644 index 0000000000..53ff5f6909 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/analysis-template.yaml @@ -0,0 +1,34 @@ +{{- if .Values.analysisTemplate.enabled }} +{{- range .Values.analysisTemplate.templates }} +apiVersion: argoproj.io/v1alpha1 +kind: AnalysisTemplate +metadata: + {{- if .annotations }} + annotations: +{{ toYaml .annotations | indent 4 }} + {{- end }} + name: {{ .name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + release: {{ $.Release.Name }} + pipelineName: {{ $.Values.pipelineName }} + {{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} + {{- end }} + {{- if .labels }} +{{ toYaml .labels | indent 4 }} + {{- end }} +spec: + {{- if .args }} + args: +{{ toYaml .args | indent 2 }} + {{- end }} + {{- if .measurementRetention }} + measurementRetention: +{{ toYaml .measurementRetention | indent 2 }} + {{- end }} + metrics: +{{ toYaml .metrics | indent 2 }} +--- +{{- end }} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/configmap.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/configmap.yaml new file mode 100644 index 0000000000..4e7879665e --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/configmap.yaml @@ -0,0 +1,22 @@ +{{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{if eq .external false}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .name}}-{{ $.Values.app }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +data: +{{ toYaml .data | trim | indent 2 }} + {{- end}} + {{- end}} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/deployment.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/deployment.yaml new file mode 100644 index 0000000000..0f95412921 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/deployment.yaml @@ -0,0 +1,755 @@ + {{- $hasCMEnvExists := false -}} + {{- $hasCMVolumeExists := false -}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $hasCMVolumeExists = true}} + {{- end }} + {{- if eq .type "environment"}} + {{- $hasCMEnvExists = true}} + {{- end }} + {{- end }} + {{- end }} + + {{- $hasPVCExists := false -}} + {{- if .Values.persistentVolumeClaim.name }} + {{- $hasPVCExists = true }} + {{- end }} + + {{- $hasSecretEnvExists := false -}} + {{- $hasSecretVolumeExists := false -}} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $hasSecretVolumeExists = true}} + {{- end }} + {{- if eq .type "environment"}} + {{- $hasSecretEnvExists = true}} + {{- end }} + {{- end }} + {{- end }} + {{ $CustomLabelsApp:= include "customPodLabelsContainsApp" . }} + {{ $CustomLabelsRelease:= include "customPodLabelsContainsRelease" . }} + + +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: {{ include ".Chart.Name .fullname" $ }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + releaseVersion: {{ $.Values.releaseVersion | quote }} + pipelineName: {{ .Values.pipelineName }} +{{- if .Values.rolloutLabels }} +{{ toYaml .Values.rolloutLabels | indent 4 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- if .Values.rolloutAnnotations }} + annotations: +{{ toYaml .Values.rolloutAnnotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.workloadRef }} +{{ toYaml .Values.workloadRef | indent 4 }} +{{- end }} +{{- if .Values.rollbackWindow.revisions }} + rollbackWindow: + revisions: {{ .Values.rollbackWindow.revisions }} +{{- end }} + {{- if .Values.analysis }} + analysis: +{{ toYaml .Values.analysis | indent 4 }} + {{- end }} + selector: + matchLabels: +{{- if .Values.customMatchLabels }} +{{ toYaml .Values.customMatchLabels | indent 6 }} +{{- else }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + release: {{ .Values.customPodLabels.release | default $.Release.Name }} +{{- end }} + replicas: {{ $.Values.replicaCount }} + minReadySeconds: {{ $.Values.MinReadySeconds }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: + {{- range $key, $value := .Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + labels: + {{- if not (eq "true" $CustomLabelsApp) }} + app: {{ .Values.customPodLabels.app | default (include ".Chart.Name .name" $) }} + {{- end }} + {{- if not (eq "true" $CustomLabelsRelease) }} + release: {{ .Values.customPodLabels.release |default $.Release.Name }} + {{- end }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} +{{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 8 }} +{{- end }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 8 }} +{{- end }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + spec: +{{- if $.Values.schedulingGates.name }} + schedulingGates: + name: {{ $.Values.schedulingGates.name }} +{{- end }} +{{- if $.Values.podExtraSpecs }} +{{ toYaml .Values.podExtraSpecs | indent 6 }} +{{- end }} + terminationGracePeriodSeconds: {{ $.Values.GracePeriod }} +{{- if $.Values.hostAliases }} + hostAliases: +{{ toYaml .Values.hostAliases | indent 8 }} +{{- end }} +{{- if and $.Values.Spec.Affinity.Key $.Values.Spec.Affinity.Values }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ $.Values.Spec.Affinity.Key }} + operator: In + values: + - {{ $.Values.Spec.Affinity.Values | default "nodes" }} +{{- else if $.Values.affinity.enabled }} + affinity: +{{ toYaml .Values.affinity.values | indent 8 }} +{{- end }} +{{- if $.Values.serviceAccountName }} + serviceAccountName: {{ $.Values.serviceAccountName }} +{{- else }} + serviceAccountName: {{ template "serviceAccountName" . }} +{{- end }} +{{- if $.Values.schedulerName }} + schedulerName: {{ .Values.schedulerName }} +{{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} +{{- if $.Values.imagePullSecrets}} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end }} +{{- end}} +{{- if $.Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range $.Values.topologySpreadConstraints }} + - maxSkew: {{ .maxSkew }} + topologyKey: {{ .topologyKey }} + whenUnsatisfiable: {{ .whenUnsatisfiable }} + {{- if semverCompare "<=1.30-0" $.Capabilities.KubeVersion.GitVersion }} + {{- if .minDomains }} + minDomains: {{ .minDomains }} + {{- end }} + {{- end }} + {{- if .nodeAffinityPolicy }} + nodeAffinityPolicy: {{ .nodeAffinityPolicy }} + {{- end }} + {{- if .nodeTaintsPolicy }} + nodeTaintsPolicy: {{ .nodeTaintsPolicy }} + {{- end }} + labelSelector: + matchLabels: + {{- if and .autoLabelSelector .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- else if .autoLabelSelector }} + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} + {{- else if .customLabelSelector }} +{{ toYaml .customLabelSelector | indent 12 }} + {{- end }} +{{- end }} +{{- end }} +{{- if $.Values.topologySpreadConstraint }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraint }} +{{- end }} +{{- if $.Values.podSecurityContext }} + securityContext: +{{ toYaml .Values.podSecurityContext | indent 8 }} +{{- end }} +{{- if $.Values.restartPolicy }} + restartPolicy: {{ $.Values.restartPolicy }} +{{- else }} + restartPolicy: Always +{{- end }} +{{- if $.Values.initContainers}} + initContainers: +{{- range $i, $c := .Values.initContainers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-init-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .args}} + args: +{{ toYaml .args | indent 12 -}} +{{- end}} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + containers: + - name: {{ $.Chart.Name }} + image: "{{ .Values.server.deployment.image }}:{{ .Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} + {{- if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- if $.Values.containerSpec.lifecycle.postStart }} + postStart: +{{ toYaml $.Values.containerSpec.lifecycle.postStart | indent 12 -}} + {{- end }} + {{- end }} +{{- if and $.Values.containerSecurityContext $.Values.privileged }} + securityContext: + privileged: true +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- else if $.Values.privileged }} + securityContext: + privileged: true +{{- else if $.Values.containerSecurityContext }} + securityContext: +{{ toYaml .Values.containerSecurityContext | indent 12 }} +{{- end }} +{{- if $.Values.containerExtraSpecs }} +{{ toYaml .Values.containerExtraSpecs | indent 10 }} +{{- end }} +{{- if $.Values.resizePolicy }} + resizePolicy: +{{ toYaml .Values.resizePolicy | indent 12 }} +{{- end }} + ports: + {{- range $.Values.ContainerPort }} + - name: {{ .name}} + containerPort: {{ .port }} + protocol: {{ .protocol | default "TCP" }} + {{- end}} +{{- if and $.Values.command.enabled $.Values.command.workingDir }} + workingDir: {{ $.Values.command.workingDir }} +{{- end}} +{{- if and $.Values.command.value $.Values.command.enabled}} + command: +{{ toYaml $.Values.command.value | indent 12 -}} +{{- end}} +{{- if and $.Values.args.value $.Values.args.enabled}} + args: +{{ toYaml $.Values.args.value | indent 12 -}} +{{- end }} + env: + - name: CONFIG_HASH + value: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.ConfigHash) }}{{ .Values.devtronInternal.containerSpecs.ConfigHash }}{{ end }} + - name: SECRET_HASH + value: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}{{ if and (.Values.devtronInternal) (.Values.devtronInternal.containerSpecs.SecretHash) }}{{ .Values.devtronInternal.containerSpecs.SecretHash }}{{ end }} + - name: DEVTRON_APP_NAME + value: {{ template ".Chart.Name .name" $ }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DEVTRON_CONTAINER_REPO + value: "{{ .Values.server.deployment.image }}" + - name: DEVTRON_CONTAINER_TAG + value: "{{ .Values.server.deployment.image_tag }}" + {{- range $.Values.EnvVariablesFromFieldPath }} + {{- if and .name .fieldPath }} + - name: {{ .name }} + valueFrom: + fieldRef: + fieldPath: {{ .fieldPath }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariables }} + {{- if and .name .value }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromSecretKeys }} + {{- if and .name .secretName .keyName }} + - name: {{ .name }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- range $.Values.EnvVariablesFromConfigMapKeys }} + {{- if and .name .configMapName .keyName }} + - name: {{ .name }} + valueFrom: + configMapKeyRef: + name: {{ .configMapName }} + key: {{ .keyName }} + {{- end }} + {{- end }} + {{- if or (and ($hasCMEnvExists) (.Values.ConfigMaps.enabled)) (and ($hasSecretEnvExists) (.Values.ConfigSecrets.enabled)) }} + envFrom: + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "environment" }} + - configMapRef: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "environment" }} + - secretRef: + {{if eq .external true}} + name: {{ .name }} + {{else if eq .external false}} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + +{{- if or $.Values.LivenessProbe.Path $.Values.LivenessProbe.command $.Values.LivenessProbe.tcp }} + livenessProbe: +{{- if $.Values.LivenessProbe.Path }} + httpGet: + path: {{ $.Values.LivenessProbe.Path }} + port: {{ $.Values.LivenessProbe.port }} + scheme: {{ $.Values.LivenessProbe.scheme }} + {{- if $.Values.LivenessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.LivenessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.LivenessProbe.command }} + exec: + command: +{{ toYaml .Values.LivenessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.LivenessProbe.tcp }} + tcpSocket: + port: {{ $.Values.LivenessProbe.port }} +{{- end}} +{{- if and $.Values.LivenessProbe.grpc }} + grpc: + port: {{ $.Values.LivenessProbe.port }} + service: {{ $.Values.service.name }} +{{- end}} + initialDelaySeconds: {{ $.Values.LivenessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.LivenessProbe.periodSeconds }} + successThreshold: {{ $.Values.LivenessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.LivenessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.LivenessProbe.failureThreshold }} +{{- end }} +{{- if or $.Values.ReadinessProbe.Path $.Values.ReadinessProbe.command $.Values.ReadinessProbe.tcp }} + readinessProbe: +{{- if $.Values.ReadinessProbe.Path }} + httpGet: + path: {{ $.Values.ReadinessProbe.Path }} + port: {{ $.Values.ReadinessProbe.port }} + scheme: {{ $.Values.ReadinessProbe.scheme }} + {{- if $.Values.ReadinessProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.ReadinessProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.ReadinessProbe.command }} + exec: + command: +{{ toYaml .Values.ReadinessProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.ReadinessProbe.tcp }} + tcpSocket: + port: {{ $.Values.ReadinessProbe.port }} +{{- end}} +{{- if and $.Values.ReadinessProbe.grpc }} + grpc: + port: {{ $.Values.ReadinessProbe.port }} + service: {{ $.Values.service.name }} +{{- end}} + initialDelaySeconds: {{ $.Values.ReadinessProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.ReadinessProbe.periodSeconds }} + successThreshold: {{ $.Values.ReadinessProbe.successThreshold }} + timeoutSeconds: {{ $.Values.ReadinessProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.ReadinessProbe.failureThreshold }} +{{- end }} + resources: +{{ toYaml $.Values.resources | trim | indent 12 }} +{{- if or $.Values.StartupProbe.Path $.Values.StartupProbe.command $.Values.StartupProbe.tcp }} + startupProbe: +{{- if $.Values.StartupProbe.Path }} + httpGet: + path: {{ $.Values.StartupProbe.Path }} + port: {{ $.Values.StartupProbe.port }} + {{- if $.Values.StartupProbe.httpHeaders }} + httpHeaders: + {{- range $.Values.StartupProbe.httpHeaders}} + - name: {{.name}} + value: {{.value}} + {{- end}} + {{- end }} +{{- end }} +{{- if $.Values.StartupProbe.command }} + exec: + command: +{{ toYaml .Values.StartupProbe.command | indent 16 }} +{{- end}} +{{- if and $.Values.StartupProbe.tcp }} + tcpSocket: + port: {{ $.Values.StartupProbe.port }} +{{- end}} + initialDelaySeconds: {{ $.Values.StartupProbe.initialDelaySeconds }} + periodSeconds: {{ $.Values.StartupProbe.periodSeconds }} + successThreshold: {{ $.Values.StartupProbe.successThreshold }} + timeoutSeconds: {{ $.Values.StartupProbe.timeoutSeconds }} + failureThreshold: {{ $.Values.StartupProbe.failureThreshold }} +{{- end }} + volumeMounts: +{{- with .Values.volumeMounts }} +{{ toYaml . | trim | indent 12 }} +{{- end }} +{{- if $.Values.persistentVolumeClaim.name }} + - name: {{ .Values.persistentVolumeClaim.name }}-vol + mountPath: {{ .Values.persistentVolumeClaim.mountPath | default "/tmp" }} +{{- end}} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{- range $k, $v := .data }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + {{- $cmName := .name -}} + {{- $cmMountPath := .mountPath -}} + {{- if eq .subPath false }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath }} + + {{- else }} + {{if (or (eq .externalType "ESO_GoogleSecretsManager") (eq .externalType "ESO_AWSSecretsManager") (eq .externalType "ESO_HashiCorpVault") (eq .externalType "ESO_AzureSecretsManager"))}} + {{- if and (.esoSubPath) (ne (len .esoSubPath) 0) }} + {{- range .esoSubPath }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ . }} + subPath: {{ . }} + {{- end }} + {{- else }} + {{- range .esoSecretData.esoData }} + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ .secretKey }} + subPath: {{ .secretKey }} + {{- end }} + {{- end }} + {{- else }} + {{- range $k, $v := .data }} # for others secrets the mount path will be .data[i].secretKey + - name: {{ $cmName | replace "." "-"}}-vol + mountPath: {{ $cmMountPath}}/{{ $k}} + subPath: {{ $k}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) }} []{{- end }} + {{- if and (eq (len .Values.volumeMounts) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) }} [] {{- end }} +{{- if $.Values.appMetrics }} + - name: envoy + image: {{ $.Values.envoyproxy.image | default "quay.io/devtron/envoy:v1.16.0"}} + {{- if $.Values.envoyproxy.lifecycle }} + lifecycle: +{{ toYaml .Values.envoyproxy.lifecycle | indent 12 -}} + {{- else if $.Values.containerSpec.lifecycle.enabled }} + lifecycle: + {{- if $.Values.containerSpec.lifecycle.preStop }} + preStop: +{{ toYaml $.Values.containerSpec.lifecycle.preStop | indent 12 -}} + {{- end }} + {{- end }} + resources: +{{ toYaml $.Values.envoyproxy.resources | trim | indent 12 }} + ports: + - containerPort: 9901 + protocol: TCP + name: envoy-admin + {{- range $index, $element := .Values.ContainerPort }} + - name: envoy-{{ $element.name}} + containerPort: {{ $element.envoyPort | default (add 8790 $index) }} + protocol: TCP + {{- end }} + command: ["/usr/local/bin/envoy"] + args: ["-c", "/etc/envoy-config/envoy-config.json", "-l", "info", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"] + volumeMounts: + - name: {{ $.Values.envoyproxy.configMapName | default "envoy-config-volume" }} + mountPath: /etc/envoy-config/ +{{- if $.Values.envoyproxy.readinessProbe}} + readinessProbe: +{{ toYaml $.Values.envoyproxy.readinessProbe | indent 12}} +{{- end }} +{{- if $.Values.envoyproxy.livenessProbe}} + livenessProbe: +{{ toYaml $.Values.envoyproxy.livenessProbe | indent 12}} +{{- end }} +{{- end}} +{{- if $.Values.containers }} +{{- range $i, $c := .Values.containers }} +{{- if .reuseContainerImage}} + - name: {{ $.Chart.Name }}-sidecontainer-{{ add1 $i }} + image: "{{ $.Values.server.deployment.image }}:{{ $.Values.server.deployment.image_tag }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} +{{- if .env }} + env: +{{ toYaml .env | indent 12 }} +{{- end }} + {{- if .envFrom }} + envFrom: +{{ toYaml .env | indent 12 }} +{{- end }} +{{- if .securityContext }} + securityContext: +{{ toYaml .securityContext | indent 12 }} +{{- end }} +{{- if .command}} + command: +{{ toYaml .command | indent 12 -}} +{{- end}} +{{- if .resizePolicy }} + resizePolicy: +{{ toYaml .resziePolicy | indent 12}} +{{- end }} +{{- if .resources}} + resources: +{{ toYaml .resources | indent 12 -}} +{{- end}} +{{- if .volumeMounts}} + volumeMounts: +{{ toYaml .volumeMounts | indent 12 -}} +{{- end}} +{{- else}} + - +{{ toYaml . | indent 10 }} +{{- end}} +{{- end}} +{{- end}} + volumes: + {{- if $.Values.appMetrics }} + - name: envoy-config-volume + configMap: + name: sidecar-config-{{ template ".Chart.Name .name" $ }} + {{- end }} +{{- if .Values.persistentVolumeClaim.name }} + - name: {{.Values.persistentVolumeClaim.name}}-vol + persistentVolumeClaim: + claimName: {{.Values.persistentVolumeClaim.name }} +{{- end}} +{{- with .Values.volumes }} +{{ toYaml . | trim | indent 8 }} +{{- end }} + {{- if .Values.ConfigMaps.enabled }} + {{- range .Values.ConfigMaps.maps }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + configMap: + {{- if eq .external true }} + name: {{ .name }} + {{- else if eq .external false }} + name: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{- if eq .type "volume"}} + - name: {{ .name | replace "." "-"}}-vol + secret: + {{- if eq .external true }} + secretName: {{ .name }} + {{- else if eq .external false }} + secretName: {{ .name}}-{{ $.Values.app }} + {{- end }} + {{- if eq (len .filePermission) 0 }} + {{- else }} + defaultMode: {{ .filePermission}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (or (eq (.Values.ConfigSecrets.enabled) true) (eq (.Values.ConfigMaps.enabled) true)) (eq ($hasCMVolumeExists) false) (eq ($hasSecretVolumeExists) false) (eq (.Values.appMetrics) false) }} []{{- end }} + {{- if and (eq (len .Values.volumes) 0) (eq ($hasPVCExists) false) (eq (.Values.ConfigSecrets.enabled) false) (eq (.Values.ConfigMaps.enabled) false) (eq (.Values.appMetrics) false) }} []{{- end }} + revisionHistoryLimit: 3 +## pauseForSecondsBeforeSwitchActive: {{ $.Values.pauseForSecondsBeforeSwitchActive }} +# waitForSecondsBeforeScalingDown: {{ $.Values.waitForSecondsBeforeScalingDown }} + strategy: + {{- if eq .Values.deploymentType "BLUE-GREEN" }} + blueGreen: # A new field that used to provide configurable options for a BlueGreenUpdate strategy + previewService: {{ template ".previewservicename" . }} # Reference to a service that can serve traffic to a new image before it receives the active traffic + activeService: {{ template ".servicename" . }} # Reference to a service that serves end-user traffic to the replica set + autoPromotionSeconds: {{ $.Values.deployment.strategy.blueGreen.autoPromotionSeconds }} + scaleDownDelaySeconds: {{ $.Values.deployment.strategy.blueGreen.scaleDownDelaySeconds }} + previewReplicaCount: {{ $.Values.deployment.strategy.blueGreen.previewReplicaCount }} + autoPromotionEnabled: {{ $.Values.deployment.strategy.blueGreen.autoPromotionEnabled }} + {{- else if eq .Values.deploymentType "RECREATE" }} + canary: + maxSurge: {{ $.Values.deployment.strategy.recreate.maxSurge }} + maxUnavailable: {{ $.Values.deployment.strategy.recreate.maxUnavailable }} + {{- else if eq .Values.deploymentType "ROLLING" }} + canary: + stableService: {{ template ".servicename" . }} # Reference to a service that serves end-user traffic to the replica set + maxSurge: {{ $.Values.deployment.strategy.rolling.maxSurge }} + maxUnavailable: {{ $.Values.deployment.strategy.rolling.maxUnavailable }} + {{- else if eq .Values.deploymentType "CANARY" }} + canary: + {{- if .Values.deployment.strategy.canary.antiAffinity }} + antiAffinity: +{{ toYaml .Values.deployment.strategy.canary.antiAffinity | indent 8 }} + {{- end }} + {{- if .Values.deployment.strategy.canary.canaryMetadata }} + canaryMetadata: +{{ toYaml .Values.deployment.strategy.canary.canaryMetadata | indent 8 }} + {{- end }} + {{- if .Values.deployment.strategy.canary.pingPong }} + pingPong: +{{ toYaml .Values.deployment.strategy.canary.pingPong | indent 8 }} + {{- end }} + {{- if .Values.deployment.strategy.canary.stableMetadata }} + stableMetadata: +{{ toYaml .Values.deployment.strategy.canary.stableMetadata | indent 8 }} + {{- end }} + {{- if .Values.deployment.strategy.canary.analysis }} + analysis: +{{ toYaml .Values.deployment.strategy.canary.analysis | indent 8 }} + {{- end }} + stableService: {{ template ".servicename" . }} # Reference to a service that serves end-user traffic to the replica set + {{- if .Values.deployment.strategy.canary.canaryService }} + canaryService: {{ $.Values.deployment.strategy.canary.canaryService }} + {{- else }} + canaryService: {{ template ".previewservicename" . }} + {{- end }} + maxSurge: {{ $.Values.deployment.strategy.canary.maxSurge }} + maxUnavailable: {{ $.Values.deployment.strategy.canary.maxUnavailable }} + steps: +{{ toYaml .Values.deployment.strategy.canary.steps | indent 8 }} + {{- if .Values.deployment.strategy.canary.trafficRouting }} + trafficRouting: + {{- if .Values.deployment.strategy.canary.trafficRouting.smi }} + smi: + {{- if .Values.deployment.strategy.canary.trafficRouting.smi.rootService }} + rootService: {{ .Values.deployment.strategy.canary.trafficRouting.smi.rootService }} + {{- else }} + rootService: {{ template ".servicename" . }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.smi.trafficSplitName }} + trafficSplitName: {{ .Values.deployment.strategy.canary.trafficRouting.smi.trafficSplitName }} + {{- else }} + trafficSplitName: {{ template ".Chart.Name .fullname" $ }}-traffic-split + {{- end }} + {{- else if .Values.deployment.strategy.canary.trafficRouting.istio }} + istio: + {{ toYaml .Values.deployment.strategy.canary.trafficRouting.istio | indent 10 }} + {{- else if .Values.deployment.strategy.canary.trafficRouting.alb }} + alb: + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.ingress }} + ingress: {{ .Values.deployment.strategy.canary.trafficRouting.alb.ingress }} + {{- else if $.Values.ingress.name }} + ingress: .Values.ingress.name + {{- else }} + ingress: {{ template ".Chart.Name .fullname" . }}-ingress + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.rootService }} + rootService: {{ .Values.deployment.strategy.canary.trafficRouting.alb.rootService }} + {{- else }} + rootService: {{ template ".servicename" . }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.annotationPrefix }} + annotationPrefix: {{ .Values.deployment.strategy.canary.trafficRouting.alb.annotationPrefix }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.servicePort }} + servicePort: {{ .Values.deployment.strategy.canary.trafficRouting.alb.servicePort }} + {{- else }} + {{- with index .Values.ContainerPort 0 }} + servicePort: {{ .servicePort }} + {{- end }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.stickinessConfig }} + stickinessConfig: +{{ toYaml .Values.deployment.strategy.canary.trafficRouting.alb.stickinessConfig | nindent 12 }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.alb.ingresses }} + ingresses: + {{- range .Values.deployment.strategy.canary.trafficRouting.alb.ingresses }} + - {{ . }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.deployment.strategy.canary.trafficRouting.managedRoutes }} + managedRoutes: + {{ toYaml .Values.deployment.strategy.canary.trafficRouting.managedRoutes | indent 10 }} + {{- end }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/externalsecrets.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/externalsecrets.yaml new file mode 100644 index 0000000000..efd291af5d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/externalsecrets.yaml @@ -0,0 +1,76 @@ +{{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{if eq .external true }} + {{if (or (eq .externalType "ESO_GoogleSecretsManager") (eq .externalType "ESO_AWSSecretsManager") (eq .externalType "ESO_HashiCorpVault") (eq .externalType "ESO_AzureSecretsManager"))}} +{{- if .esoSecretData.secretStore }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: {{ .name}} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + provider: + {{- toYaml .esoSecretData.secretStore | nindent 4 }} +{{- end }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ .name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .esoSecretData.refreshInterval }} + refreshInterval: {{ .esoSecretData.refreshInterval }} + {{- else }} + refreshInterval: 1h + {{- end}} + {{- if and .esoSecretData.secretStoreRef (not .esoSecretData.secretStore) }} + secretStoreRef: +{{ toYaml .esoSecretData.secretStoreRef | indent 4 }} + {{- else }} + secretStoreRef: + name: {{ .name}} + kind: SecretStore + {{- end }} + target: + name: {{ .name}} + {{- if .esoSecretData.template }} + template: + {{- toYaml .esoSecretData.template | nindent 6 }} + {{- end }} + creationPolicy: Owner + {{- if .esoSecretData.esoDataFrom }} + dataFrom: + {{- toYaml .esoSecretData.esoDataFrom | nindent 4 }} + {{- else }} + data: + {{- range .esoSecretData.esoData }} + - secretKey: {{ .secretKey }} + remoteRef: + key: {{ .key }} + {{- if .property }} + property: {{ .property }} + {{- end }} + {{- end}} +{{- end}} +{{- end}} +{{- end}} +{{- end}} +{{- end}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/generic.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/generic.yaml new file mode 100644 index 0000000000..db95e84267 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/generic.yaml @@ -0,0 +1,4 @@ +{{- range .Values.rawYaml }} +--- +{{ toYaml . }} + {{- end -}} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/hpa.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/hpa.yaml new file mode 100644 index 0000000000..76ba9455c2 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/hpa.yaml @@ -0,0 +1,93 @@ +{{- if $.Values.autoscaling.enabled }} +{{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2 +{{- else if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: autoscaling/v2beta2 +{{- else }} +apiVersion: autoscaling/v2beta1 +{{- end }} +kind: HorizontalPodAutoscaler +metadata: + {{- if $.Values.autoscaling.name }} + name: {{ $.Values.autoscaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-hpa + {{- end }} + {{- if .Values.autoscaling.annotations }} + annotations: +{{ toYaml .Values.autoscaling.annotations | indent 4 }} + {{- end }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + {{- if .Values.autoscaling.labels }} +{{ toYaml .Values.autoscaling.labels | indent 4 }} + {{- end }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + scaleTargetRef: + apiVersion: argoproj.io/v1alpha1 + kind: Rollout + name: {{ include ".Chart.Name .fullname" $ }} + minReplicas: {{ $.Values.autoscaling.MinReplicas }} + maxReplicas: {{ $.Values.autoscaling.MaxReplicas }} + metrics: + {{- if $.Values.autoscaling.containerResource.enabled }} + {{- with $.Values.autoscaling.containerResource }} + {{- if .TargetCPUUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: cpu + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetCPUUtilizationPercentage }} + {{- end}} + {{- if .TargetMemoryUtilizationPercentage }} + - type: ContainerResource + containerResource: + name: memory + container: {{ $.Chart.Name }} + target: + type: Utilization + averageUtilization: {{ .TargetMemoryUtilizationPercentage }} + {{- end}} + {{- end }} + {{- end }} + {{- if $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ $.Values.autoscaling.TargetMemoryUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if $.Values.autoscaling.TargetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} + target: + type: Utilization + averageUtilization: {{ $.Values.autoscaling.TargetCPUUtilizationPercentage }} + {{- else }} + targetAverageUtilization: {{ $.Values.autoscaling.TargetCPUUtilizationPercentage }} + {{- end }} + {{- end }} + {{- if and $.Values.autoscaling.extraMetrics (semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion) }} + {{- toYaml $.Values.autoscaling.extraMetrics | nindent 2 }} + {{- end}} + {{- if and $.Values.autoscaling.behavior (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + behavior: + {{- toYaml $.Values.autoscaling.behavior | nindent 4 }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ingress.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ingress.yaml new file mode 100644 index 0000000000..1d47899d0b --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/ingress.yaml @@ -0,0 +1,187 @@ +{{ $svcName := include ".servicename" . }} +{{ $svcPort := (index .Values.ContainerPort 0).servicePort }} +{{- if $.Values.ingress.enabled -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- if and .Values.ingressInternal.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingressInternal.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingressInternal.annotations "kubernetes.io/ingress.class" .Values.ingressInternal.className}} + {{- end }} +{{- end }} +{{- end }} +--- +{{ if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + {{- if $.Values.ingress.name }} + name: {{ $.Values.ingress.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-ingress + {{- end }} + namespace: {{ $.Values.NameSpace }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + {{- if .Values.ingress.labels }} +{{ toYaml .Values.ingress.labels | indent 4 }} + {{- end }} +{{- if .Values.ingress.annotations }} + annotations: +{{ toYaml .Values.ingress.annotations | indent 4 }} +{{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- if or .Values.ingress.host .Values.ingress.path }} + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.path }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $.Values.ingress.pathType | default "ImplementationSpecific" }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if and ($.Values.ingress.hosts) (not ($.Values.ingress.host )) }} + {{- range .Values.ingress.hosts }} + {{ $outer := . -}} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $outer.pathType | default "ImplementationSpecific" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if .additionalBackends }} +{{ toYaml .additionalBackends | indent 10 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end }} +{{- if $.Values.ingressInternal.enabled }} +--- +{{ if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{ else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{ else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + {{- if $.Values.ingressInternal.name }} + name: {{ $.Values.ingressInternal.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-ingress-internal + {{- end }} + namespace: {{ $.Values.NameSpace }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- if .Values.ingressInternal.annotations }} + annotations: +{{ toYaml .Values.ingressInternal.annotations | indent 4 }} +{{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingressInternal.className }} + {{- end }} + rules: + {{- if or .Values.ingressInternal.host .Values.ingressInternal.path }} + - host: {{ .Values.ingressInternal.host }} + http: + paths: + - path: {{ .Values.ingressInternal.path }} + {{- if and .Values.ingressInternal.pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $.Values.ingressInternal.pathType | default "Prefix" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if and ($.Values.ingressInternal.hosts) (not ($.Values.ingressInternal.host )) }} + {{- range .Values.ingressInternal.hosts }} + {{ $outer := . -}} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + {{- if (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ $outer.pathType | default "ImplementationSpecific" | quote }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $svcName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $svcName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- if .additionalBackends }} +{{ toYaml .additionalBackends | indent 10 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ingressInternal.tls }} + tls: +{{ toYaml .Values.ingressInternal.tls | indent 4 }} + {{- end -}} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-authorizationpolicy.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-authorizationpolicy.yaml new file mode 100644 index 0000000000..df063920a7 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-authorizationpolicy.yaml @@ -0,0 +1,45 @@ +{{- with .Values.istio }} +{{- if and .enable .authorizationPolicy.enabled }} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: security.istio.io/v1 +{{- else -}} +apiVersion: security.istio.io/v1beta1 +{{- end }} +kind: AuthorizationPolicy +metadata: + {{- if .authorizationPolicy.name }} + name: {{ .authorizationPolicy.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .authorizationPolicy.labels }} +{{ toYaml .authorizationPolicy.labels | indent 4 }} + {{- end }} +{{- if .authorizationPolicy.annotations }} + annotations: +{{ toYaml .authorizationPolicy.annotations | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} + action: {{ .authorizationPolicy.action }} +{{- if $.Values.istio.authorizationPolicy.provider }} + provider: +{{ toYaml $.Values.istio.authorizationPolicy.provider | indent 4 }} +{{- end }} +{{- if $.Values.istio.authorizationPolicy.rules }} + rules: +{{ toYaml $.Values.istio.authorizationPolicy.rules | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-destinationrule.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-destinationrule.yaml new file mode 100644 index 0000000000..bc665e6ec0 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-destinationrule.yaml @@ -0,0 +1,42 @@ +{{- with .Values.istio }} +{{- if and .enable .destinationRule.enabled }} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.istio.io/v1 +{{ else }} +apiVersion: networking.istio.io/v1beta1 +{{- end }} +kind: DestinationRule +metadata: + {{- if .destinationRule.name }} + name: {{ .destinationRule.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-destinationrule + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .destinationRule.labels }} +{{ toYaml .destinationRule.labels | indent 4 }} + {{- end }} +{{- if .destinationRule.annotations }} + annotations: +{{ toYaml .destinationRule.annotations | indent 4 }} +{{- end }} +spec: + host: "{{ include ".servicename" $ }}.{{ $.Release.Namespace }}.svc.cluster.local" +{{- if $.Values.istio.destinationRule.subsets }} + subsets: +{{ toYaml $.Values.istio.destinationRule.subsets | indent 4 }} +{{- end }} +{{- if $.Values.istio.destinationRule.trafficPolicy }} + trafficPolicy: +{{ toYaml $.Values.istio.destinationRule.trafficPolicy | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-gateway.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-gateway.yaml new file mode 100644 index 0000000000..425cc48c12 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-gateway.yaml @@ -0,0 +1,73 @@ +{{- if and .Values.istio.enable .Values.istio.gateway.enabled -}} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.istio.io/v1 +{{ else }} +apiVersion: networking.istio.io/v1beta1 +{{- end }} +kind: Gateway +metadata: + {{- if .Values.istio.gateway.name }} + name: {{ .Values.istio.gateway.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-istio-gateway + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if $.Values.istio.gateway.labels }} +{{ toYaml $.Values.istio.gateway.labels | indent 4 }} + {{- end }} +{{- if $.Values.istio.gateway.annotations }} + annotations: +{{ toYaml $.Values.istio.gateway.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.istio.gateway.gatewayExtraSpec }} +{{ toYaml $.Values.istio.gateway.gatewayExtraSpec | indent 2}} +{{- else}} +{{- if .Values.istio.gateway.selector }} + selector: +{{ toYaml $.Values.istio.gateway.selector | indent 4}} +{{- end }} + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: +{{- if .Values.istio.gateway.host }} + - {{ .Values.istio.gateway.host | quote -}} +{{- else if .Values.istio.gateway.hosts }} +{{- range .Values.istio.gateway.hosts }} + - {{ . | quote }} +{{- end }} +{{- end }} +{{ with .Values.istio.gateway }} +{{- if .tls.enabled }} + tls: + httpsRedirect: true + - port: + number: 443 + name: https + protocol: HTTPS + hosts: +{{- if .host }} + - {{ .host | quote }} +{{- else if .hosts }} +{{- range .hosts }} + - {{ . | quote }} +{{- end }} +{{- end }} + tls: + mode: SIMPLE + credentialName: {{ .tls.secretName }} +{{ end }} +{{ end }} +{{ end }} +{{ end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-peerauthentication.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-peerauthentication.yaml new file mode 100644 index 0000000000..5e143c8530 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-peerauthentication.yaml @@ -0,0 +1,44 @@ +{{- with .Values.istio }} +{{- if and .enable .peerAuthentication.enabled }} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: security.istio.io/v1 +{{- else -}} +apiVersion: security.istio.io/v1beta1 +{{- end }} +kind: PeerAuthentication +metadata: + {{- if .peerAuthentication.name }} + name: {{ .peerAuthentication.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .peerAuthentication.labels }} +{{ toYaml .peerAuthentication.labels | indent 4 }} + {{- end }} +{{- if .peerAuthentication.annotations }} + annotations: +{{ toYaml .peerAuthentication.annotations | indent 4 }} +{{- end }} +spec: +{{- if .peerAuthentication.selector.enabled }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} +{{- end }} + mtls: + mode: {{ .peerAuthentication.mtls.mode }} +{{- if $.Values.istio.peerAuthentication.portLevelMtls }} + portLevelMtls: +{{ toYaml $.Values.istio.peerAuthentication.portLevelMtls | indent 4 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-requestauthentication.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-requestauthentication.yaml new file mode 100644 index 0000000000..d8082bd34d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-requestauthentication.yaml @@ -0,0 +1,42 @@ +{{- with .Values.istio }} +{{- if and .enable .requestAuthentication.enabled }} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: security.istio.io/v1 +{{- else -}} +apiVersion: security.istio.io/v1beta1 +{{- end }} +kind: RequestAuthentication +metadata: + {{- if .requestAuthentication.name }} + name: {{ .requestAuthentication.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .requestAuthentication.labels }} +{{ toYaml .requestAuthentication.labels | indent 4 }} + {{- end }} +{{- if .requestAuthentication.annotations }} + annotations: +{{ toYaml .requestAuthentication.annotations | indent 4 }} +{{- end }} +spec: +{{- if .requestAuthentication.selector.enabled }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template ".Chart.Name .fullname" $ }} +{{- end }} +{{- if $.Values.istio.requestAuthentication.jwtRules }} + jwtRules: +{{ toYaml $.Values.istio.requestAuthentication.jwtRules | indent 2 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-virtualservice.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-virtualservice.yaml new file mode 100644 index 0000000000..dae81522cb --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/istio-virtualservice.yaml @@ -0,0 +1,68 @@ +{{- with .Values.istio }} +{{- if and .enable .virtualService.enabled }} +{{ if semverCompare ">=1.22-0" $.Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.istio.io/v1 +{{ else }} +apiVersion: networking.istio.io/v1beta1 +{{- end }} +kind: VirtualService +metadata: + {{- if .virtualService.name }} + name: {{ .virtualService.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-virtualservice + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if .virtualService.labels }} +{{ toYaml .virtualService.labels | indent 4 }} + {{- end }} +{{- if .virtualService.annotations }} + annotations: +{{ toYaml .virtualService.annotations | indent 4 }} +{{- end }} +spec: +{{- if or .gateway.enabled .virtualService.gateways }} +{{- if .virtualService.virtualServiceExtraSpec }} +{{ toYaml .virtualService.virtualServiceExtraSpec | indent 2}} +{{- else }} + gateways: + {{- if .gateway.enabled }} + - {{ template ".Chart.Name .fullname" $ }}-istio-gateway + {{- end }} + {{- range .virtualService.gateways }} + - {{ . | quote }} + {{- end }} +{{- end }} +{{- if or .gateway.enabled .virtualService.hosts }} + hosts: + {{- if .gateway.enabled }} + {{- if .gateway.host }} + - {{ .gateway.host | quote }} + {{- else if .gateway.hosts }} +{{- range .gateway.hosts }} + - {{ . | quote }} +{{- end }} + {{- end }} + {{- end }} + {{- range .virtualService.hosts }} + - {{ . | quote }} + {{- end }} +{{- else }} + hosts: + - "{{ include ".servicename" $ }}.{{ $.Release.Namespace }}.svc.cluster.local" +{{- end }} +{{- if $.Values.istio.virtualService.http }} + http: +{{ toYaml $.Values.istio.virtualService.http | indent 4 }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/keda-autoscaling.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/keda-autoscaling.yaml new file mode 100644 index 0000000000..850312e16d --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/keda-autoscaling.yaml @@ -0,0 +1,78 @@ +{{- if $.Values.kedaAutoscaling.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + {{- if $.Values.kedaAutoscaling.name }} + name: {{ $.Values.kedaAutoscaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-keda + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + release: {{ .Release.Name }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} + {{- if .Values.kedaAutoscaling.labels }} +{{ toYaml .Values.kedaAutoscaling.labels | indent 4 }} + {{- end }} + {{- if .Values.kedaAutoscaling.annotations }} + annotations: +{{ toYaml .Values.kedaAutoscaling.annotations | indent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: argoproj.io/v1alpha1 + kind: Rollout + name: {{ include ".Chart.Name .fullname" $ }} +{{- if $.Values.kedaAutoscaling.envSourceContainerName }} + envSourceContainerName: {{ $.Values.kedaAutoscaling.envSourceContainerName }} +{{- end }} +{{- if $.Values.kedaAutoscaling.pollingInterval }} + pollingInterval: {{ $.Values.kedaAutoscaling.pollingInterval }} +{{- end }} +{{- if $.Values.kedaAutoscaling.cooldownPeriod }} + cooldownPeriod: {{ $.Values.kedaAutoscaling.cooldownPeriod }} +{{- end }} +{{- if $.Values.kedaAutoscaling.idleReplicaCount }} + idleReplicaCount: {{ $.Values.kedaAutoscaling.idleReplicaCount }} +{{- end }} + minReplicaCount: {{ $.Values.kedaAutoscaling.minReplicaCount }} + maxReplicaCount: {{ $.Values.kedaAutoscaling.maxReplicaCount }} +{{- if $.Values.kedaAutoscaling.fallback }} + fallback: +{{ toYaml $.Values.kedaAutoscaling.fallback | indent 4 }} +{{- end }} +{{- if $.Values.kedaAutoscaling.advanced }} + advanced: +{{ toYaml $.Values.kedaAutoscaling.advanced | indent 4 }} +{{- end }} + triggers: +{{ toYaml .Values.kedaAutoscaling.triggers | indent 2}} +{{- if $.Values.kedaAutoscaling.authenticationRef }} + authenticationRef: +{{ toYaml $.Values.kedaAutoscaling.authenticationRef | indent 6 }} +{{- end }} +--- +{{- if $.Values.kedaAutoscaling.triggerAuthentication.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{ $.Values.kedaAutoscaling.triggerAuthentication.name }} + labels: + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: +{{ toYaml $.Values.kedaAutoscaling.triggerAuthentication.spec | indent 2 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/metrics-service-monitor.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/metrics-service-monitor.yaml new file mode 100644 index 0000000000..4e9e544f50 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/metrics-service-monitor.yaml @@ -0,0 +1,35 @@ +{{- if $.Values.appMetrics -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template ".Chart.Name .fullname" $ }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} +spec: + jobLabel: {{ template ".Chart.Name .name" $ }} + endpoints: + - port: envoy-admin + interval: 30s + path: /stats/prometheus + relabelings: + - action: replace + sourceLabels: + - __meta_kubernetes_pod_label_rollouts_pod_template_hash + targetLabel: devtron_app_hash + selector: + matchLabels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + namespaceSelector: + matchNames: + - {{.Release.Namespace}} + podTargetLabels: + - appId + - envId + - devtron_app_hash +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/networkpolicy.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/networkpolicy.yaml new file mode 100644 index 0000000000..ee8bdaf8be --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/networkpolicy.yaml @@ -0,0 +1,52 @@ +{{- if .Values.networkPolicy.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + {{- if .Values.networkPolicy.name }} + name: {{ .Values.networkPolicy.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-networkpolicy + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if $.Values.appLabels }} +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} + {{- if $.Values.networkPolicy.labels }} +{{ toYaml $.Values.networkPolicy.labels | indent 4 }} + {{- end }} +{{- if $.Values.networkPolicy.annotations }} + annotations: +{{ toYaml $.Values.networkPolicy.annotations | indent 4 }} +{{- end }} +spec: + podSelector: +{{- if .podSelector.matchExpressions }} + matchExpressions: +{{ toYaml $.Values.networkPolicy.podSelector.matchExpressions | indent 6 }} +{{- end }} +{{- if .podSelector.matchLabels }} + matchLabels: +{{ toYaml $.Values.networkPolicy.podSelector.matchLabels | indent 6 }} +{{- else }} + matchLabels: + app: {{ template ".Chart.Name .name" $ }} + release: {{ $.Release.Name }} +{{- end }} +{{- if .policyTypes }} + policyTypes: +{{ toYaml $.Values.networkPolicy.policyTypes | indent 4 }} +{{- end }} +{{- if .ingress }} + ingress: +{{ toYaml $.Values.networkPolicy.ingress | indent 4 }} +{{- end }} +{{- if .egress }} + egress: +{{ toYaml $.Values.networkPolicy.ingress | indent 4}} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/persistent-volume-claim.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/persistent-volume-claim.yaml new file mode 100644 index 0000000000..cee0fb2fde --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/persistent-volume-claim.yaml @@ -0,0 +1,27 @@ +{{- if .Values.persistentVolumeClaim.name }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{.Values.persistentVolumeClaim.name }} + labels: + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + app: {{ template ".Chart.Name .name" $ }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- with .Values.persistentVolumeClaim }} +spec: + accessModes: +{{- range .accessMode }} + - {{ . }} +{{- end }} + resources: + requests: + storage: {{ .storage | default "5Gi" }} + storageClassName: {{ .storageClassName | default "default" }} + volumeMode: {{ .volumeMode | default "Filesystem" }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/poddisruptionbudget.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000..869d380d40 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/poddisruptionbudget.yaml @@ -0,0 +1,38 @@ +{{- if .Values.podDisruptionBudget }} +{{- if semverCompare ">=1.21-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: policy/v1 +{{- else -}} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + {{- if .Values.podDisruptionBudget.name }} + name: {{ .Values.podDisruptionBudget.name }} + {{- else }} + name: {{ include ".Chart.Name .fullname" $ }} + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 6 }} + {{- else }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/pre-sync-job.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/pre-sync-job.yaml new file mode 100644 index 0000000000..cd733d4857 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/pre-sync-job.yaml @@ -0,0 +1,23 @@ +{{- if $.Values.dbMigrationConfig.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template ".Chart.Name .fullname" $ }}-migrator + annotations: + argocd.argoproj.io/hook: PreSync +# argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + template: + spec: + containers: + - name: migrator + image: 686244538589.dkr.ecr.us-east-2.amazonaws.com/migrator:0.0.1-rc14 + env: + {{- range $.Values.dbMigrationConfig.envValues }} + - name: {{ .key}} + value: {{ .value | quote }} + {{- end}} + restartPolicy: Never + backoffLimit: 0 +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/prometheusrules.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/prometheusrules.yaml new file mode 100644 index 0000000000..90f398bff4 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/prometheusrules.yaml @@ -0,0 +1,22 @@ +{{- if .Values.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template ".Chart.Name .fullname" . }} + {{- if .Values.prometheusRule.namespace }} + namespace: {{ .Values.prometheusRule.namespace }} + {{- end }} + labels: + kind: Prometheus + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} + {{- if .Values.prometheusRule.additionalLabels }} +{{ toYaml .Values.prometheusRule.additionalLabels | indent 4 }} + {{- end }} +spec: + {{- with .Values.prometheusRule.rules }} + groups: + - name: {{ template ".Chart.Name .fullname" $ }} + rules: {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/secret.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/secret.yaml new file mode 100644 index 0000000000..26a17b968c --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/secret.yaml @@ -0,0 +1,69 @@ +{{- if $.Values.secret.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: app-secret +{{- if $.Values.appLabels }} + labels: +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +type: Opaque +data: +{{ toYaml $.Values.secret.data | indent 2 }} +{{- end }} + + +{{- if .Values.ConfigSecrets.enabled }} + {{- range .Values.ConfigSecrets.secrets }} + {{if eq .external false}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name}}-{{ $.Values.app }} +{{- if $.Values.appLabels }} + labels: +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +type: Opaque +data: +{{ toYaml .data | trim | indent 2 }} +{{- end}} + {{if eq .external true }} + {{if (or (eq .externalType "AWSSecretsManager") (eq .externalType "AWSSystemManager") (eq .externalType "HashiCorpVault"))}} +--- +apiVersion: kubernetes-client.io/v1 +kind: ExternalSecret +metadata: + name: {{ .name}} +{{- if $.Values.appLabels }} + labels: +{{ toYaml $.Values.appLabels | indent 4 }} +{{- end }} +spec: + {{- if .roleARN }} + roleArn: .roleARN + {{- end}} + {{- if eq .externalType "AWSSecretsManager"}} + backendType: secretsManager + {{- end}} + {{- if eq .externalType "AWSSystemManager"}} + backendType: systemManager + {{- end}} + {{- if eq .externalType "HashiCorpVault"}} + backendType: vault + {{- end}} + data: + {{- range .secretData }} + - key: {{.key}} + name: {{.name}} + {{- if .property }} + property: {{.property}} + {{- end}} + isBinary: {{.isBinary}} + {{- end}} + {{- end}} + {{- end}} + {{- end}} + {{- end}} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/service.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/service.yaml new file mode 100644 index 0000000000..6853027e9a --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/service.yaml @@ -0,0 +1,106 @@ +{{- if .Values.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template ".servicename" . }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end}} +spec: + type: {{ .Values.service.type | default "ClusterIP" }} +{{- if (and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerSourceRanges )}} + loadBalancerSourceRanges: + {{- range .Values.service.loadBalancerSourceRanges }} + - {{ . }} + {{- end }} +{{- end }} + ports: + {{- range .Values.ContainerPort }} + {{- if .servicePort }} + - port: {{ .servicePort }} + {{- else }} + - port: {{ .port }} + {{- end }} + {{- if .targetPort }} + targetPort: {{ .targetPort }} + {{- else if $.Values.appMetrics }} + targetPort: envoy-{{ .name }} + {{- else }} + targetPort: {{ .name }} + {{- end }} + {{- if (and (eq $.Values.service.type "NodePort") .nodePort )}} + nodePort: {{ .nodePort }} + {{- end }} + protocol: {{ .protocol | default "TCP"}} + name: {{ .name }} + {{- end }} + {{- if $.Values.appMetrics }} + - port: 9901 + name: envoy-admin + {{- end }} + selector: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 4 }} + {{- else }} + app: {{ template ".Chart.Name .name" . }} + {{- end }} +{{- if .Values.service.sessionAffinity.enabled }} + sessionAffinity: ClientIP +{{- end }} +{{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: +{{ toYaml .Values.service.sessionAffinityConfig | indent 4 }} +{{- end }} +{{- if or (eq .Values.deploymentType "BLUE-GREEN") (eq .Values.deploymentType "CANARY") }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template ".previewservicename" . }} + labels: + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Release.Name }} +spec: + type: ClusterIP + ports: + {{- range .Values.ContainerPort }} + {{- if .servicePort }} + - port: {{ .servicePort }} + {{- else }} + - port: {{ .port }} + {{- end }} + {{- if .targetPort }} + targetPort: {{ .targetPort }} + {{- else if $.Values.appMetrics }} + targetPort: envoy-{{ .name }} + {{- else }} + targetPort: {{ .name }} + {{- end }} + protocol: {{ .protocol | default "TCP"}} + name: {{ .name }} + {{- end }} + {{- if $.Values.appMetrics }} + - port: 9901 + name: envoy-admin + {{- end }} + selector: + {{- if .Values.customPodLabels }} +{{ toYaml .Values.customPodLabels | indent 4 }} + {{- else }} + app: {{ template ".Chart.Name .name" . }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/serviceaccount.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/serviceaccount.yaml new file mode 100644 index 0000000000..ac258610fa --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if $.Values.serviceAccount }} +{{- if $.Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "serviceAccountName" . }} + {{- if .Values.podLabels }} + labels: +{{ toYaml .Values.podLabels | indent 4 }} + {{- end }} + {{- if .Values.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.serviceAccount.annotations | indent 4 }} + {{- end }} +{{- end -}} +{{- end -}} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/servicemonitor.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/servicemonitor.yaml new file mode 100644 index 0000000000..8600f9d65b --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/servicemonitor.yaml @@ -0,0 +1,117 @@ +{{ $serviceMonitorEnabled := include "serviceMonitorEnabled" . }} +{{- if eq "true" $serviceMonitorEnabled -}} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + {{- if .Values.servicemonitor.name }} + name: {{ .Values.servicemonitor.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-sm + {{- end }} + labels: + kind: Prometheus + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} + {{- if .Values.servicemonitor.additionalLabels }} +{{ toYaml .Values.servicemonitor.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} +spec: + endpoints: + {{- range .Values.ContainerPort }} + {{- if .servicemonitor }} + {{- if .servicemonitor.enabled}} + {{- if .servicemonitor.targetPort }} + - targetPort: {{ .servicemonitor.targetPort }} + {{- else if .servicePort }} + - port: {{ .name }} + {{- end }} + {{- if .servicemonitor.path }} + path: {{ .servicemonitor.path}} + {{- end }} + {{- if .servicemonitor.scheme }} + scheme: {{ .servicemonitor.scheme}} + {{- end }} + {{- if .servicemonitor.interval }} + interval: {{ .servicemonitor.interval}} + {{- end }} + {{- if .servicemonitor.scrapeTimeout }} + scrapeTimeout: {{ .servicemonitor.scrapeTimeout | quote }} + {{- end }} + {{- if .servicemonitor.basicAuth }} + basicAuth: + {{- toYaml .servicemonitor.basicAuth | nindent 8 }} + {{- end }} + {{- if .servicemonitor.insecureTLS }} + tlsConfig: + insecureSkipVerify: true + {{- else if .servicemonitor.tlsConfig }} + tlsConfig: + {{- toYaml .servicemonitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .servicemonitor.metricRelabelings}} + metricRelabelings: +{{toYaml .servicemonitor.metricRelabelings | indent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- range .Values.containers }} + {{- range .ports }} + {{- if .servicemonitor }} + {{- if .servicemonitor.enabled}} + {{- if .servicemonitor.targetPort }} + - targetPort: {{ .servicemonitor.targetPort }} + {{- else if .servicePort }} + - port: {{ .name }} + {{- end }} + {{- if .servicemonitor.path }} + path: {{ .servicemonitor.path}} + {{- end }} + {{- if .servicemonitor.scheme }} + scheme: {{ .servicemonitor.scheme}} + {{- end }} + {{- if .servicemonitor.interval }} + interval: {{ .servicemonitor.interval}} + {{- end }} + {{- if .servicemonitor.scrapeTimeout }} + scrapeTimeout: {{ .servicemonitor.scrapeTimeout}} + {{- end }} + {{- if .servicemonitor.basicAuth }} + basicAuth: + {{- toYaml .servicemonitor.basicAuth | nindent 8 }} + {{- end }} + {{- if .servicemonitor.insecureTLS }} + tlsConfig: + insecureSkipVerify: true + {{- else if .servicemonitor.tlsConfig }} + tlsConfig: + {{- toYaml .servicemonitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .servicemonitor.metricRelabelings}} + metricRelabelings: +{{toYaml .servicemonitor.metricRelabelings | indent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.servicemonitor.namespaceSelector }} + namespaceSelector: + matchNames: + {{- toYaml .Values.servicemonitor.namespaceSelector | nindent 6 }} + {{- end }} + selector: + matchLabels: + {{- if .Values.servicemonitor.matchLabels }} + {{- toYaml .Values.servicemonitor.matchLabels | nindent 6 }} + {{- else }} + app: {{ template ".Chart.Name .name" $ }} + {{- end }} +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/sidecar-configmap.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/sidecar-configmap.yaml new file mode 100644 index 0000000000..cf32679409 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/sidecar-configmap.yaml @@ -0,0 +1,169 @@ +{{- if .Values.appMetrics }} +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: 2019-08-12T18:38:34Z + name: sidecar-config-{{ template ".Chart.Name .name" $ }} +data: + envoy-config.json: | + { + "stats_config": { + "use_all_default_tags": false, + "stats_tags": [ + { + "tag_name": "cluster_name", + "regex": "^cluster\\.((.+?(\\..+?\\.svc\\.cluster\\.local)?)\\.)" + }, + { + "tag_name": "tcp_prefix", + "regex": "^tcp\\.((.*?)\\.)\\w+?$" + }, + { + "tag_name": "response_code", + "regex": "_rq(_(\\d{3}))$" + }, + { + "tag_name": "response_code_class", + "regex": ".*_rq(_(\\dxx))$" + }, + { + "tag_name": "http_conn_manager_listener_prefix", + "regex": "^listener(?=\\.).*?\\.http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "http_conn_manager_prefix", + "regex": "^http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "listener_address", + "regex": "^listener\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "mongo_prefix", + "regex": "^mongo\\.(.+?)\\.(collection|cmd|cx_|op_|delays_|decoding_)(.*?)$" + } + ], + "stats_matcher": { + "inclusion_list": { + "patterns": [ + { + "regex": ".*_rq_\\dxx$" + }, + { + "regex": ".*_rq_time$" + }, + { + "regex": "cluster.*" + }, + ] + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "0.0.0.0", + "port_value": 9901 + } + } + }, + "static_resources": { + "clusters": [ + {{- range $index, $element := .Values.ContainerPort }} + { + "name": "{{ $.Values.app }}-{{ $index }}", + "type": "STATIC", + "connect_timeout": "0.250s", + "lb_policy": "ROUND_ROBIN", +{{- if $element.idleTimeout }} + "common_http_protocol_options": { + "idle_timeout": {{ $element.idleTimeout | quote }} + }, +{{- end }} +{{- if or $element.useHTTP2 $element.useGRPC }} + "http2_protocol_options": {}, +{{- end }} +{{- if and (not $element.useGRPC) (not $element.supportStreaming) }} + "max_requests_per_connection": "1", +{{- end }} + "load_assignment": { + "cluster_name": "9", + "endpoints": { + "lb_endpoints": [ + { + "endpoint": { + "address": { + "socket_address": { + "protocol": "TCP", + "address": "127.0.0.1", + "port_value": {{ $element.port }} + } + } + } + } + ] + } + } + }, + {{- end }} + ], + "listeners":[ + {{- range $index, $element := .Values.ContainerPort }} + { + "address": { + "socket_address": { + "protocol": "TCP", + "address": "0.0.0.0", + "port_value": {{ $element.envoyPort | default (add 8790 $index) }} + } + }, + "filter_chains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "config": { + "codec_type": "AUTO", + "stat_prefix": "stats", + "route_config": { + "virtual_hosts": [ + { + "name": "backend", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { +{{- if $element.supportStreaming }} + "timeout": "0s", +{{- end }} +{{- if and ($element.envoyTimeout) (not $element.supportStreaming) }} + "timeout": "{{ $element.envoyTimeout }}", +{{- end }} + "cluster": "{{ $.Values.app }}-{{ $index }}" + } + } + ] + } + ] + }, + "http_filters": { + "name": "envoy.filters.http.router" + } + } + } + ] + } + ] + }, + {{- end }} + ] + } + } +--- +{{- end }} diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/vertical-pod-autoscaler.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/vertical-pod-autoscaler.yaml new file mode 100644 index 0000000000..7d1d1db475 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/vertical-pod-autoscaler.yaml @@ -0,0 +1,41 @@ +{{ $VerticalPodAutoScalingEnabled := include "VerticalPodAutoScalingEnabled" . }} +{{- if eq "true" $VerticalPodAutoScalingEnabled -}} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + {{- if .Values.verticalPodScaling.name }} + name: {{ .Values.verticalPodScaling.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" . }}-vpa + {{- end }} + labels: + kind: Prometheus + app: {{ template ".Chart.Name .name" . }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" . }} + release: {{ .Values.prometheus.release }} + {{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} + {{- end }} + {{- if $.Values.verticalPodScaling.labels }} +{{ toYaml $.Values.verticalPodScaling.labels | indent 4 }} + {{- end }} + {{- if $.Values.verticalPodScaling.annotations }} + annotations: +{{ toYaml $.Values.verticalPodScaling.annotations | indent 4 }} + {{- end }} +spec: +{{- if .Values.verticalPodScaling.resourcePolicy }} + resourcePolicy: +{{ toYaml .Values.verticalPodScaling.resourcePolicy}} +{{- end }} +{{- if .Values.verticalPodScaling.updatePolicy }} + updatePolicy: +{{ toYaml .Values.verticalPodScaling.updatePolicy}} +{{- end }} + targetRef: + apiVersion: argoproj.io/v1alpha1 + kind: Rollout + name: {{ include ".Chart.Name .fullname" $ }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/winter-soldier.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/winter-soldier.yaml new file mode 100644 index 0000000000..5ac2fd8443 --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/templates/winter-soldier.yaml @@ -0,0 +1,45 @@ +{{- if .Values.winterSoldier.enabled }} +apiVersion: {{ $.Values.winterSoldier.apiVersion }} +kind: Hibernator +metadata: + {{- if .Values.winterSoldier.name }} + name: {{ .Values.winterSoldier.name }} + {{- else }} + name: {{ template ".Chart.Name .fullname" $ }}-hibernator + {{- end }} + labels: + app: {{ template ".Chart.Name .name" $ }} + appId: {{ $.Values.app | quote }} + envId: {{ $.Values.env | quote }} + chart: {{ template ".Chart.Name .chart" $ }} + release: {{ $.Release.Name }} +{{- if .Values.appLabels }} +{{ toYaml .Values.appLabels | indent 4 }} +{{- end }} + {{- if .Values.winterSoldier.labels }} +{{ toYaml .Values.winterSoldier.labels | indent 4 }} + {{- end }} +{{- if .Values.winterSoldier.annotations }} + annotations: +{{ toYaml .Values.winterSoldier.annotations | indent 4 }} +{{- end }} +spec: + timeRangesWithZone: +{{ toYaml $.Values.winterSoldier.timeRangesWithZone | indent 4}} + selectors: + - inclusions: + - objectSelector: + name: {{ include ".Chart.Name .fullname" $ }} + type: {{ .Values.winterSoldier.type | quote }} + fieldSelector: +{{toYaml $.Values.winterSoldier.fieldSelector | indent 14}} + namespaceSelector: + name: {{ $.Release.Namespace }} + exclusions: [] + action: {{ $.Values.winterSoldier.action }} + {{- if eq .Values.winterSoldier.action "scale" }} + {{- if .Values.winterSoldier.targetReplicas }} + targetReplicas: {{ $.Values.winterSoldier.targetReplicas }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/test_values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/test_values.yaml new file mode 100644 index 0000000000..97e72df42e --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/test_values.yaml @@ -0,0 +1,716 @@ +# Default values for myapp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +rolloutLabels: + name: devops-team + Company: Devtron + Job: DevOps + +rolloutAnnotations: + name: devops-team + Company: Devtron + Job: DevOps + +containerSpec: + lifecycle: + enabled: true + preStop: + exec: + command: ["sleep","10"] + postStart: + httpGet: + host: example.com + path: /example + port: 90 + +imagePullSecrets: + - test1 + - test2 +replicaCount: 1 +MinReadySeconds: 5 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +ContainerPort: + - name: app + port: 8080 + servicePort: 8000 + envoyTimeout: 15 + targetPort: 8080 + envoyPort: 8799 + useHTTP2: false + protocol: UDP + supportStreaming: false + idleTimeout: 1800s + servicemonitor: + enabled: true + path: /abc + scheme: 'http' + interval: 30s + scrapeTimeout: 20s + metricRelabelings: + - sourceLabels: [namespace] + regex: '(.*)' + replacement: myapp + targetLabel: target_namespace + + - name: app1 + port: 8090 + targetPort: 1234 + servicePort: 8080 + useGRPC: true + servicemonitor: + enabled: true + - name: app2 + port: 8091 + servicePort: 8081 + useGRPC: true + +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 +autoPromotionSeconds: 30 + +Spec: + Affinity: + Key: + # Key: kops.k8s.io/instancegroup + Values: + + +image: + pullPolicy: IfNotPresent + +autoscaling: + enabled: true + MinReplicas: 1 + MaxReplicas: 2 + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 + behavior: {} + containerResource: + enable: false + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +secret: + enabled: false + +service: + type: ClusterIP + # name: "1234567890123456789012345678901234567890123456789012345678901234567890" + annotations: {} + # test1: test2 + # test3: test4 + sessionAffinity: + enabled: false + sessionAffinityConfig: {} + +server: + deployment: + image_tag: 1-95af053 + image: "" +deploymentType: "CANARY" + +topologySpreadConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: DoNotSchedule + autoLabelSelector: true + customLabelSelector: + foo: bar + +EnvVariables: + - name: FLASK_ENV + value: qa + +deployment: + strategy: + blueGreen: + autoPromotionSeconds: 30 + scaleDownDelaySeconds: 30 + previewReplicaCount: 1 + autoPromotionEnabled: false + rolling: + maxSurge: "25%" + maxUnavailable: 1 + canary: + maxSurge: 30% + maxUnavailable: 0 + stableService: api-svc + canaryService: canary-api-svc + steps: + - setCanaryScale: + weight: 25 + - setHeaderRoute: + name: api-canary + match: + - headerName: X-Version + headerValue: + prefix: v2 + - pause: + duration: 2m + - analysis: + templates: + - templateName: success-rate + args: + - name: service-name + value: canary-api-svc.api.svc.cluster.local + - setWeight: 50 + - pause: + duration: 2m + - analysis: + templates: + - templateName: success-rate + args: + - name: service-name + value: canary-api-svc.api.svc.cluster.local + - setWeight: 100 + - pause: {} # final manual approval (optional) + + trafficRouting: + # managedRoutes: + # - name: api-canary + istio: + virtualService: + name: api-vs + routes: + - api-svc + recreate: {} + +pipelineName: ci-axhbc + +analysis: + successfulRunHistoryLimit: 4 + unsuccessfulRunHistoryLimit: 3 + +appLabels: + hello: hii + hey: hello + +analysisTemplate: + enabled: true + templates: + - name: success-rate + annotations: {} + labels: {} + args: + - name: service-name + value: example-svc.default.svc.cluster.local + measurementRetention: + - limit: 34 + metricName: test + metrics: + - name: success-rate + interval: 5m + # NOTE: prometheus queries return results in the form of a vector. + # So it is common to access the index 0 of the returned array to obtain the value + successCondition: result[0] >= 0.95 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m] + )) / + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m] + )) + +LivenessProbe: + Path: / + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + - name: Custom-Header2 + value: xyz + +ReadinessProbe: + Path: / + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: + - name: Custom-Header + value: abc + +prometheus: + release: monitoring + +servicemonitor: + additionalLabels: {} + + +prometheusRule: + enabled: true + additionalLabels: {} + namespace: "" + rules: + # These are just examples rules, please adapt them to your needs + - alert: TooMany500s + expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 + for: 1m + labels: + severity: critical + annotations: + description: Too many 5XXs + summary: More than 5% of the all requests did return 5XX, this require your attention + - alert: TooMany400s + expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 + for: 1m + labels: + severity: critical + annotations: + description: Too many 4XXs + summary: More than 5% of the all requests did return 4XX, this require your attention + + +ingress: + enabled: true + className: nginx + annotations: {} +# nginx.ingress.kubernetes.io/rewrite-target: / +# nginx.ingress.kubernetes.io/ssl-redirect: "false" +# kubernetes.io/ingress.class: nginx +# kubernetes.io/tls-acme: "true" +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" +# Old Ingress Format +# host: "ingress-example.com" +# path: "/app" + +# New Ingress Format + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + additionalBackends: + - path: /ingress + pathType: "ImplementationSpecific" + backend: + service: + name: test-service-ingress + port: + number: 80 + tls: [] +### Legacy Ingress Format ## +# host: abc.com +# path: "/" +# pathType: "ImplementationSpecific" + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +ingressInternal: + enabled: false + className: nginx-internal + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + additionalBackends: + - path: /ingress-internal + pathType: "ImplementationSpecific" + backend: + service: + name: test-service-internal + port: + number: 80 + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +dbMigrationConfig: + enabled: false + +command: + workingDir: /app + enabled: false + value: ["ls"] + +args: + enabled: false + value: [] + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 1 + memory: 200Mi + requests: + cpu: 0.10 + memory: 100Mi + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + + +nodeSelector: {} + + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 + +ConfigMaps: + enabled: false + maps: [] +# - name: config-map-1 +# type: environment +# external: false +# data: +# key1: key1value-1 +# key2: key2value-1 +# key3: key3value-1 +# - name: config-map-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 +# key3: abc-2 +# - name: config-map-3 +# type: environment +# external: true +# mountPath: /etc/config/3 +# data: [] +# - name: config-map-4 +# type: volume +# external: true +# mountPath: /etc/config/4 +# data: [] + + +ConfigSecrets: + enabled: false + secrets: + - name: config-secret-1 + type: environment + external: false + externalType: AWSSecretsManager + esoSecretData: + secretStore: + aws: + service: SecretsManager + region: us-east-1 + auth: + secretRef: + accessKeyIDSecretRef: + name: awssm-secret + key: access-key + secretAccessKeySecretRef: + name: awssm-secret + key: secret-access-key + esoData: + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + data: + key1: key1value-1 + key2: key2value-1 + key3: key3value-1 + - name: config-secret-2 + type: environment + external: false + externalType: ESO_HashiCorpVault + esoSecretData: + secretStore: + vault: + server: "http://my.vault.server:8200" + path: "secret" + version: "v2" + auth: + tokenSecretRef: + name: vault-token + key: token + esoData: + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + - secretKey: prod-mysql-password + key: secrets/prod-mysql-secrets + property: prodPassword + date: + key1: key1value-1 + key2: key2value-1 + key3: key3value-1 + +# - name: config-secret-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 + + +initContainers: + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + - command: ["sh", "-c", "chown -R 1000:1000 logs"] + reuseContainerImage: true + volumeMounts: + - mountPath: /usr/local/airflow/logs + name: logs-data + securityContext: + privileged: true + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + - name: init-migrate + image: busybox:latest + command: ["sh", "-c", "chown -R 1000:1000 logs"] + volumeMounts: + - mountPath: /usr/local/airflow/logs + name: logs-data + securityContext: + capabilities: + drop: + - ALL + +containers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs +# name: logs-data + + +rawYaml: [] +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP + +# If you need to provide some extra specs for main container which are not included by default in deployment template +# then provide them here +containerExtraSpecs: {} + +# If you need to provide some extra specs for pod which are not included by default in deployment template +# then provide them here +podExtraSpecs: {} + +envoyproxy: + image: envoyproxy/envoy:v1.14.1 + configMapName: "" + lifecycle: {} + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + readinessProbe: + path: / + livenessProbe: + path: / + +podDisruptionBudget: {} + # minAvailable: 1 + # maxUnavailable: 1 + + ## Node tolerations for server scheduling to nodes with taints + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ +## + +tolerations: [] + # - key: "key" + # operator: "Equal|Exists" + # value: "value" +# effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + +appMetrics: true +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "test1" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: + kubernetes.io/service-account.name: build-robot +containerSecurityContext: + allowPrivilegeEscalation: false +privileged: true +hostAliases: [] +# - ip: "127.0.0.1" +# hostnames: +# - "foo.local" + + + +verticalPodScaling: + enabled: false + +rollbackWindow: {} +schedulingGates: {} +deploymentType: CANARY + + +topologySpreadConstraints: {} + +istio: + enable: true + gateway: + enabled: true + labels: {} + annotations: {} + selector: + istiokj: sdkj + host: "istio.example.com" + tls: + enabled: true + secretName: "asjkj" + gatewayExtraSpec: {} + # selector: + # istio: "istio-1" + # servers: + # - port: + # number: 8080 + # name: http + # protocol: HTTP + # hosts: + # - "istio.example.com" + virtualService: + enabled: true + labels: {} + annotations: {} + gateways: + - sdkk + hosts: + - istio-2.exmap.com + - ksdj.sdkj.ckj + http: + - match: + - uri: + prefix: /v1 + - uri: + prefix: /v2 + timeout: 12 + headers: + request: + add: + x-some-header: "value" + retries: + attempts: 2 + perTryTimeout: 3s + virtualServiceExtraSpec: + tcp: + skldjlkjds: kdjjk diff --git a/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/values.yaml b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/values.yaml new file mode 100644 index 0000000000..59220b01ad --- /dev/null +++ b/scripts/devtron-reference-helm-charts/reference-chart_5-2-0/values.yaml @@ -0,0 +1,668 @@ +# Default values for myapp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 +MinReadySeconds: 5 +MaxSurge: 1 +MaxUnavailable: 0 +GracePeriod: 30 +ContainerPort: + - name: app + port: 8080 + servicePort: 80 + envoyPort: 8799 + envoyTimeout: 15s + useHTTP2: false + supportStreaming: false + idleTimeout: 1800s +# servicemonitor: +# enabled: true +# path: /abc +# scheme: 'http' +# interval: 30s +# scrapeTimeout: 20s +# metricRelabelings: +# - sourceLabels: [namespace] +# regex: '(.*)' +# replacement: myapp +# targetLabel: target_namespace + + - name: app1 + port: 8090 + servicePort: 8080 + useGRPC: true + +pauseForSecondsBeforeSwitchActive: 30 +waitForSecondsBeforeScalingDown: 30 +autoPromotionSeconds: 30 + +Spec: + Affinity: + Key: +# Key: kops.k8s.io/instancegroup + Values: + + +image: + pullPolicy: IfNotPresent + +restartPolicy: Always + +analysisTemplate: + enabled: false + templates: [] + # - name: success-rate + # annotations: {} + # labels: {} + # args: + # - name: service-name + # value: example-svc.default.svc.cluster.local + # measurementRetention: + # - limit: 34 + # metricName: test + # metrics: + # - name: success-rate + # interval: 5m + # # NOTE: prometheus queries return results in the form of a vector. + # # So it is common to access the index 0 of the returned array to obtain the value + # successCondition: result[0] >= 0.95 + # failureLimit: 3 + # provider: + # prometheus: + # address: http://prometheus.example.com:9090 + # query: | + # sum(irate( + # istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m] + # )) / + # sum(irate( + # istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m] + # )) + +autoscaling: + enabled: false + MinReplicas: 1 + MaxReplicas: 2 + # TargetCPUUtilizationPercentage: 90 + # TargetMemoryUtilizationPercentage: 80 + annotations: {} + labels: {} + behavior: {} + containerResource: + enable: false + TargetCPUUtilizationPercentage: 90 + TargetMemoryUtilizationPercentage: 80 +# scaleDown: +# stabilizationWindowSeconds: 300 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# scaleUp: +# stabilizationWindowSeconds: 0 +# policies: +# - type: Percent +# value: 100 +# periodSeconds: 15 +# - type: Pods +# value: 4 +# periodSeconds: 15 +# selectPolicy: Max + extraMetrics: [] +# - external: +# metricName: pubsub.googleapis.com|subscription|num_undelivered_messages +# metricSelector: +# matchLabels: +# resource.labels.subscription_id: echo-read +# targetAverageValue: "2" +# type: External +# + +kedaAutoscaling: + enabled: false + envSourceContainerName: "" # Optional. Default: .spec.template.spec.containers[0] + cooldownPeriod: 300 # Optional. Default: 300 seconds + minReplicaCount: 1 + maxReplicaCount: 2 + idleReplicaCount: 0 # Optional. Must be less than minReplicaCount + pollingInterval: 30 # Optional. Default: 30 seconds + # The fallback section is optional. It defines a number of replicas to fallback to if a scaler is in an error state. + fallback: {} # Optional. Section to specify fallback options + # failureThreshold: 3 # Mandatory if fallback section is included + # replicas: 6 + advanced: {} + # horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options + # behavior: # Optional. Use to modify HPA's scaling behavior + # scaleDown: + # stabilizationWindowSeconds: 300 + # policies: + # - type: Percent + # value: 100 + # periodSeconds: 15 + triggers: [] + triggerAuthentication: + enabled: false + name: "" + spec: {} + authenticationRef: {} + +secret: + enabled: false + +service: + enabled: true + type: ClusterIP +# name: "1234567890123456789012345678901234567890123456789012345678901234567890" + annotations: {} + # test1: test2 + # test3: test4 + sessionAffinity: + enabled: false + sessionAffinityConfig: {} + + +server: + deployment: + image_tag: 1-95af053 + image: "" + +EnvVariablesFromFieldPath: [] +# - name: POD_NAME +# fieldPath: metadata.name + +EnvVariables: [] + # - name: FLASK_ENV + # value: qa + +EnvVariablesFromSecretKeys: [] + # - name: ENV_NAME + # secretName: SECRET_NAME + # keyName: SECRET_KEY + +EnvVariablesFromConfigMapKeys: [] + # - name: ENV_NAME + # configMapName: CONFIG_MAP_NAME + # keyName: CONFIG_MAP_KEY + +LivenessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + +ReadinessProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + scheme: "" + httpHeaders: [] +# - name: Custom-Header +# value: abc + +StartupProbe: + Path: "" + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + failureThreshold: 3 + httpHeaders: [] + command: [] + tcp: false + +prometheus: + release: monitoring + +servicemonitor: + additionalLabels: {} + + +prometheusRule: + enabled: false + additionalLabels: {} + namespace: "" +# rules: +# # These are just examples rules, please adapt them to your needs +# - alert: TooMany500s +# expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 +# for: 1m +# labels: +# severity: critical +# annotations: +# description: Too many 5XXs +# summary: More than 5% of the all requests did return 5XX, this require your attention +# - alert: TooMany400s +# expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 +# for: 1m +# labels: +# severity: critical +# annotations: +# description: Too many 4XXs +# summary: More than 5% of the all requests did return 4XX, this require your attention +# + +ingress: + enabled: false + className: "" + labels: {} + annotations: {} +# nginx.ingress.kubernetes.io/rewrite-target: / +# nginx.ingress.kubernetes.io/ssl-redirect: "false" +# kubernetes.io/ingress.class: nginx +# kubernetes.io/tls-acme: "true" +# nginx.ingress.kubernetes.io/canary: "true" +# nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.local + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.local + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +ingressInternal: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/canary: "true" + # nginx.ingress.kubernetes.io/canary-weight: "10" + + hosts: + - host: chart-example1.internal + pathType: "ImplementationSpecific" + paths: + - /example1 + - host: chart-example2.internal + pathType: "ImplementationSpecific" + paths: + - /example2 + - /example2/healthz + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +istio: + enable: false + gateway: + enabled: false + labels: {} + annotations: {} + selector: {} + host: "" + tls: + enabled: false + secretName: "" + gatewayExtraSpec: {} + virtualService: + enabled: false + labels: {} + virtualServiceExtraSpec: {} + annotations: {} + gateways: [] + hosts: [] + http: [] + # - match: + # - uri: + # prefix: /v1 + # - uri: + # prefix: /v2 + # timeout: 12 + # headers: + # request: + # add: + # x-some-header: "value" + # retries: + # attempts: 2 + # perTryTimeout: 3s + destinationRule: + enabled: false + labels: {} + annotations: {} + subsets: [] + trafficPolicy: {} + peerAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + mtls: + mode: "" + portLevelMtls: {} + requestAuthentication: + enabled: false + labels: {} + annotations: {} + selector: + enabled: false + jwtRules: [] + authorizationPolicy: + enabled: false + labels: {} + annotations: {} + action: + provider: {} + rules: [] + +networkPolicy: + enabled: false + annotations: {} + labels: {} + podSelector: + matchExpressions: [] + matchLabels: {} + policyTypes: [] + ingress: [] + egress: [] + +hibernator: + enable: false + +dbMigrationConfig: + enabled: false + +command: + enabled: false + value: [] + +args: + enabled: false + value: [] + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + +volumeMounts: [] +# - name: log-volume +# mountPath: /var/log + +volumes: [] +# - name: log-volume +# emptyDir: {} + + +nodeSelector: {} + +# If you need to provide some extra specs for pod which are not included by default in deployment template +# then provide them here +podExtraSpecs: {} + +# If you need to provide some extra specs for main container which are not included by default in deployment template +# then provide them here +containerExtraSpecs: {} + +#used for deployment algo selection +orchestrator.deploymant.algo: 1 + +ConfigMaps: + enabled: false + maps: [] +# - name: config-map-1 +# type: environment +# external: false +# data: +# key1: key1value-1 +# key2: key2value-1 +# key3: key3value-1 +# - name: config-map-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 +# key3: abc-2 +# - name: config-map-3 +# type: environment +# external: true +# mountPath: /etc/config/3 +# data: [] +# - name: config-map-4 +# type: volume +# external: true +# mountPath: /etc/config/4 +# data: [] + + +ConfigSecrets: + enabled: false + secrets: [] +# - name: config-secret-1 +# type: environment +# external: false +# data: +# key1: key1value-1 +# key2: key2value-1 +# key3: key3value-1 +# - name: config-secret-2 +# type: volume +# external: false +# mountPath: /etc/config/2 +# data: +# key1: | +# club : manchester utd +# nation : england +# key2: abc-2 + + +initContainers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + # - name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + # # Uncomment below line ONLY IF you want to reuse the container image. + # # This will assign your application's docker image to init container. + # reuseContainerImage: true + +containers: [] + ## Additional init containers to run before the Scheduler pods. + ## for example, be used to run a sidecar that chown Logs storage . + #- name: volume-mount-hack + # image: busybox + # command: ["sh", "-c", "chown -R 1000:1000 logs"] + # volumeMounts: + # - mountPath: /usr/local/airflow/logs + # name: logs-data + + +rawYaml: [] +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP +# - apiVersion: v1 +# kind: Service +# metadata: +# annotations: +# labels: +# app: sample-metrics-app +# name: sample-metrics-app +# namespace: default +# spec: +# ports: +# - name: web +# port: 80 +# protocol: TCP +# targetPort: 8080 +# selector: +# app: sample-metrics-app +# sessionAffinity: None +# type: ClusterIP + +winterSoldier: + enabled: false + apiVersion: pincher.devtron.ai/v1alpha1 + labels: {} + annotations: {} + timeRangesWithZone: {} + # timeZone: "Asia/Kolkata" + # timeRanges: [] + action: sleep + targetReplicas: [] + fieldSelector: [] + type: Rollout + # - AfterTime(AddTime(ParseTime({{metadata.creationTimestamp}}, '2006-01-02T15:04:05Z'), '5m'), Now()) + +topologySpreadConstraints: [] + +schedulerName: "" + +envoyproxy: + image: docker.io/envoyproxy/envoy:v1.16.0 + lifecycle: {} + configMapName: "" + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 50m + memory: 50Mi + +ambassadorMapping: + enabled: false + # labels: + # key1: value1 + # prefix: / + # ambassadorId: 1234 + # hostname: devtron.example.com + # rewrite: /foo/ + # retryPolicy: + # retry_on: "5xx" + # num_retries: 10 + # cors: + # origins: http://foo.example,http://bar.example + # methods: POST, GET, OPTIONS + # headers: Content-Type + # credentials: true + # exposed_headers: X-Custom-Header + # max_age: "86400" + # weight: 10 + # method: GET + # extraSpec: + # method_regex: true + # headers: + # x-quote-mode: backend + # x-random-header: devtron + # tls: + # context: httpd-context + # create: true + # secretName: httpd-secret + # hosts: + # - anything.example.info + # - devtron.example.com + # extraSpec: + # min_tls_version: v1.2 + +containerSpec: + lifecycle: + enabled: false + preStop: {} +# exec: +# command: ["sleep","10"] + postStart: {} +# httpGet: +# host: example.com +# path: /example +# port: 90 + +podDisruptionBudget: {} +# minAvailable: 1 +# maxUnavailable: 1 + + ## Node tolerations for server scheduling to nodes with taints + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + +podSecurityContext: {} + # runAsUser: 1000 + # runAsGroup: 3000 + # fsGroup: 2000 + +containerSecurityContext: {} + # allowPrivilegeEscalation: false +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for pods + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `.Chart.Name .fullname` template + name: "" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: {} + +tolerations: [] + # - key: "key" + # operator: "Equal|Exists" + # value: "value" + # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + +imagePullSecrets: [] + # - test1 + # - test2 + +persistentVolumeClaim: {} + + +affinity: + enabled: false + values: {} + +verticalPodScaling: + enabled: false + +rollbackWindow: {} +schedulingGates: {} + +customPodLabels: {} \ No newline at end of file diff --git a/scripts/sql/33803900_deployment-chart-ref_4-22-0.down.sql b/scripts/sql/33803900_deployment-chart-ref_4-22-0.down.sql new file mode 100644 index 0000000000..f9a44667c1 --- /dev/null +++ b/scripts/sql/33803900_deployment-chart-ref_4-22-0.down.sql @@ -0,0 +1,3 @@ +DELETE FROM global_strategy_metadata_chart_ref_mapping WHERE chart_ref_id=(select id from chart_ref where version='4.22.0' and name='Deployment'); + +DELETE FROM "public"."chart_ref" WHERE ("location" = 'deployment-chart_4-22-0' AND "version" = '4.22.0'); diff --git a/scripts/sql/33803900_deployment-chart-ref_4-22-0.up.sql b/scripts/sql/33803900_deployment-chart-ref_4-22-0.up.sql new file mode 100644 index 0000000000..f038dd3d31 --- /dev/null +++ b/scripts/sql/33803900_deployment-chart-ref_4-22-0.up.sql @@ -0,0 +1,18 @@ +UPDATE chart_ref SET is_default=false; +INSERT INTO "public"."chart_ref" ("name","location", "version", "deployment_strategy_path","is_default", "active", "created_on", "created_by", "updated_on", "updated_by") VALUES + ('Rollout Deployment','reference-chart_5-2-0', '5.2.0','pipeline-values.yaml','t', 't', 'now()', 1, 'now()', 1); + +INSERT INTO global_strategy_metadata_chart_ref_mapping ("global_strategy_metadata_id", "chart_ref_id", "active", "created_on", "created_by", "updated_on", "updated_by","default") +VALUES (1,(select id from chart_ref where version='5.2.0' and name='Rollout Deployment'), true, now(), 1, now(), 1,true), + (2,(select id from chart_ref where version='5.2.0' and name='Rollout Deployment'), true, now(), 1, now(), 1,false), + (3,(select id from chart_ref where version='5.2.0' and name='Rollout Deployment'), true, now(), 1, now(), 1,false), + (4,(select id from chart_ref where version='5.2.0' and name='Rollout Deployment'), true, now(), 1, now(), 1,false); + +UPDATE chart_ref SET is_default=false; +INSERT INTO "public"."chart_ref" ("name","location", "version", "deployment_strategy_path","is_default", "active", "created_on", "created_by", "updated_on", "updated_by") VALUES + ('Deployment','deployment-chart_4-22-0', '4.22.0','pipeline-values.yaml','t', 't', 'now()', 1, 'now()', 1); + +INSERT INTO global_strategy_metadata_chart_ref_mapping ("global_strategy_metadata_id", "chart_ref_id", "active", "created_on", "created_by", "updated_on", "updated_by","default") +VALUES (1,(select id from chart_ref where version='4.22.0' and name='Deployment'), true, now(), 1, now(), 1,true), + (4,(select id from chart_ref where version='4.22.0' and name='Deployment'), true, now(), 1, now(), 1,false); + diff --git a/util/GlobalConfig.go b/util/GlobalConfig.go index f64460f2c5..bf74431907 100644 --- a/util/GlobalConfig.go +++ b/util/GlobalConfig.go @@ -37,6 +37,8 @@ type DeploymentServiceTypeConfig struct { MigrateDeploymentConfigData bool `env:"MIGRATE_DEPLOYMENT_CONFIG_DATA" envDefault:"false" description:"migrate deployment config data from charts table to deployment_config table" deprecated:"false"` FeatureMigrateArgoCdApplicationEnable bool `env:"FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE" envDefault:"false" description:"enable migration of external argocd application to devtron pipeline" deprecated:"false"` ShouldCheckNamespaceOnClone bool `env:"SHOULD_CHECK_NAMESPACE_ON_CLONE" envDefault:"false" description:"should we check if namespace exists or not while cloning app" deprecated:"false"` + ValidateExtAppChart bool `env:"VALIDATE_EXT_APP_CHART_TYPE" envDefault:"false" description:"validate external flux app chart" deprecated:"false"` + FeatureMigrateFluxApplicationEnable bool `env:"FEATURE_MIGRATE_FLUX_APPLICATION_ENABLE" envDefault:"false" description:"enable flux application services" deprecated:"false"` } func (d *DeploymentServiceTypeConfig) IsFeatureMigrateArgoCdApplicationEnable() bool { @@ -46,16 +48,23 @@ func (d *DeploymentServiceTypeConfig) IsFeatureMigrateArgoCdApplicationEnable() return d.FeatureMigrateArgoCdApplicationEnable } +func (d *DeploymentServiceTypeConfig) IsFeatureMigrateFluxApplicationEnable() bool { + if d == nil { + return false + } + return d.FeatureMigrateFluxApplicationEnable +} + type GlobalEnvVariables struct { GitOpsRepoPrefix string `env:"GITOPS_REPO_PREFIX" envDefault:"" description:"Prefix for Gitops repo being creation for argocd application"` EnableAsyncHelmInstallDevtronChart bool `env:"ENABLE_ASYNC_INSTALL_DEVTRON_CHART" envDefault:"false" description:"To enable async installation of no-gitops application"` EnableAsyncArgoCdInstallDevtronChart bool `env:"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART" envDefault:"false" description:"To enable async installation of gitops application"` ArgoGitCommitRetryCountOnConflict int `env:"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT" envDefault:"3" description:"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)" ` - ArgoGitCommitRetryDelayOnConflict int `env:"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT" envDefault:"1" description:"Delay on retrying the maifest commit the on gitops"` - ExposeCiMetrics bool `env:"EXPOSE_CI_METRICS" envDefault:"false" description:"To expose CI metrics"` - ExecuteWireNilChecker bool `env:"EXECUTE_WIRE_NIL_CHECKER" envDefault:"false" description:"checks for any nil pointer in wire.go"` - IsAirGapEnvironment bool `json:"isAirGapEnvironment" env:"IS_AIR_GAP_ENVIRONMENT" envDefault:"false"` + ArgoGitCommitRetryDelayOnConflict int `env:"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT" envDefault:"1" description:"Delay on retrying the maifest commit the on gitops"` + ExposeCiMetrics bool `env:"EXPOSE_CI_METRICS" envDefault:"false" description:"To expose CI metrics"` + ExecuteWireNilChecker bool `env:"EXECUTE_WIRE_NIL_CHECKER" envDefault:"false" description:"checks for any nil pointer in wire.go"` + IsAirGapEnvironment bool `json:"isAirGapEnvironment" env:"IS_AIR_GAP_ENVIRONMENT" envDefault:"false"` } type GlobalClusterConfig struct { diff --git a/util/SQLUtil.go b/util/SQLUtil.go index af64343e49..676a0be9fa 100644 --- a/util/SQLUtil.go +++ b/util/SQLUtil.go @@ -9,6 +9,10 @@ func GetLIKEClauseQueryParam(s string) string { return fmt.Sprintf("%%%s%%", s) } +func GetLIKEClauseQueryParamEnd(s string) string { + return fmt.Sprintf("%s%%", s) +} + func GetCopyByValueObject[T any](input []T) []T { res := make([]T, 0, len(input)) for _, item := range input { diff --git a/vendor/github.com/evanphx/json-patch/v5/LICENSE b/vendor/github.com/evanphx/json-patch/v5/LICENSE new file mode 100644 index 0000000000..df76d7d771 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2014, Evan Phoenix +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the Evan Phoenix nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/evanphx/json-patch/v5/errors.go b/vendor/github.com/evanphx/json-patch/v5/errors.go new file mode 100644 index 0000000000..75304b4437 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/errors.go @@ -0,0 +1,38 @@ +package jsonpatch + +import "fmt" + +// AccumulatedCopySizeError is an error type returned when the accumulated size +// increase caused by copy operations in a patch operation has exceeded the +// limit. +type AccumulatedCopySizeError struct { + limit int64 + accumulated int64 +} + +// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError. +func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError { + return &AccumulatedCopySizeError{limit: l, accumulated: a} +} + +// Error implements the error interface. +func (a *AccumulatedCopySizeError) Error() string { + return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit) +} + +// ArraySizeError is an error type returned when the array size has exceeded +// the limit. +type ArraySizeError struct { + limit int + size int +} + +// NewArraySizeError returns an ArraySizeError. +func NewArraySizeError(l, s int) *ArraySizeError { + return &ArraySizeError{limit: l, size: s} +} + +// Error implements the error interface. +func (a *ArraySizeError) Error() string { + return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit) +} diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go new file mode 100644 index 0000000000..e9bb0efe77 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go @@ -0,0 +1,1385 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If the JSON-encoded data contain a syntax error, Unmarshal returns a SyntaxError. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// “not present,” unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +func Unmarshal(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +var ds = sync.Pool{ + New: func() any { + return new(decodeState) + }, +} + +func UnmarshalWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return nil, err + } + + d.init(data) + err = d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +func UnmarshalValid(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + return d.unmarshal(v) +} + +func UnmarshalValidWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + err := d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Pointer { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v any) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Pointer || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool + lastKeys []string +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() any { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Pointer { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + var keys []string + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + keys = append(keys, string(key)) + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + if i, ok := fields.nameIndex[string(key)]; ok { + // Found an exact name match. + f = &fields.list[i] + } else { + // Fall back to the expensive case-insensitive + // linear search. + for i := range fields.list { + ff := &fields.list[i] + if ff.equalFold(ff.nameBytes, key) { + f = ff + break + } + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Pointer { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + switch { + case reflect.PointerTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + v.SetMapIndex(kv, subv) + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + + if v.Kind() == reflect.Map { + d.lastKeys = keys + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (any, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + if v.Type() == numberType && !isValidNumber(string(s)) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(s) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val any) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []any { + var v = make([]any, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]any { + m := make(map[string]any) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() any { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go new file mode 100644 index 0000000000..2e6eca4487 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go @@ -0,0 +1,1486 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML