Skip to content

Commit bac9a59

Browse files
committed
oss sync
2 parents 10f6378 + c3b18cc commit bac9a59

14 files changed

+522
-8
lines changed

api/restHandler/app/BuildPipelineRestHandler.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,18 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiMaterialSourceWithAppIdAndEn
280280
patchRequest, userId, err := handler.parseSourceChangeRequest(w, r)
281281
if err != nil {
282282
handler.Logger.Errorw("Parse error, PatchCiMaterialSource", "err", err, "PatchCiMaterialSource", patchRequest)
283+
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
284+
return
285+
}
286+
if !(patchRequest.Source.Type == pipelineConfig.SOURCE_TYPE_BRANCH_FIXED || patchRequest.Source.Type == pipelineConfig.SOURCE_TYPE_BRANCH_REGEX) {
287+
handler.Logger.Errorw("Unsupported source type, PatchCiMaterialSource", "err", err, "PatchCiMaterialSource", patchRequest)
288+
common.WriteJsonResp(w, err, "source.type not supported", http.StatusBadRequest)
283289
return
284290
}
285291
token := r.Header.Get("token")
286292
if err = handler.authorizeCiSourceChangeRequest(w, patchRequest, token); err != nil {
287293
handler.Logger.Errorw("Authorization error, PatchCiMaterialSource", "err", err, "PatchCiMaterialSource", patchRequest)
294+
common.WriteJsonResp(w, err, nil, http.StatusUnauthorized)
288295
return
289296
}
290297

api/restHandler/app/BuildPipelineRestHandler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func TestPipelineConfigRestHandlerImpl_PatchCiMaterialSource(t *testing.T) {
7979
fields: fields{
8080
validator: validator.New(),
8181
},
82-
body: "{\"appId\":4, \"id\": 5 ,\"ciMaterial\":[{\"gitMaterialId\":4,\"id\":5,\"source\":{\"type\":\"SOURCE_TYPE_BRANCH_FIXED\",\"value\":\"main3\",\"regex\":\"\"}}]}",
82+
body: "{\"appId\":4, \"id\": 5 ,\"source\":{\"type\":\"SOURCE_TYPE_BRANCH_FIXED\",\"value\":\"main3\",\"regex\":\"\"}}",
8383
setup: func(fields2 *fields) {
8484
ctrl := gomock.NewController(t)
8585
fields2.pipelineBuilder = mock_pipeline.NewMockPipelineBuilder(ctrl)

api/restHandler/app/DeploymentPipelineRestHandler.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type DevtronAppDeploymentRestHandler interface {
5151
GetCdPipelinesByEnvironment(w http.ResponseWriter, r *http.Request)
5252
GetCdPipelinesByEnvironmentMin(w http.ResponseWriter, r *http.Request)
5353
PerformDeploymentApprovalAction(w http.ResponseWriter, r *http.Request)
54+
ChangeChartRef(w http.ResponseWriter, r *http.Request)
5455
}
5556

5657
type DevtronAppDeploymentConfigRestHandler interface {
@@ -498,6 +499,150 @@ func (handler PipelineConfigRestHandlerImpl) HandleTriggerDeploymentAfterTypeCha
498499
return
499500
}
500501

502+
func (handler PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWriter, r *http.Request) {
503+
userId, err := handler.userAuthService.GetLoggedInUser(r)
504+
if userId == 0 || err != nil {
505+
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
506+
return
507+
}
508+
decoder := json.NewDecoder(r.Body)
509+
var request chart.ChartRefChangeRequest
510+
err = decoder.Decode(&request)
511+
if err != nil || request.EnvId == 0 || request.TargetChartRefId == 0 || request.AppId == 0 {
512+
handler.Logger.Errorw("request err, ChangeChartRef", "err", err, "payload", request)
513+
common.WriteJsonResp(w, err, request, http.StatusBadRequest)
514+
return
515+
}
516+
envConfigProperties, err := handler.propertiesConfigService.GetLatestEnvironmentProperties(request.AppId, request.EnvId)
517+
if err != nil || envConfigProperties == nil {
518+
handler.Logger.Errorw("env properties not found, ChangeChartRef", "err", err, "payload", request)
519+
common.WriteJsonResp(w, err, "env properties not found", http.StatusNotFound)
520+
return
521+
}
522+
if !envConfigProperties.IsOverride {
523+
handler.Logger.Errorw("isOverride is not true, ChangeChartRef", "err", err, "payload", request)
524+
common.WriteJsonResp(w, err, "specific environment is not overriden", http.StatusUnprocessableEntity)
525+
return
526+
}
527+
compatible, oldChartType, newChartType := handler.chartService.ChartRefIdsCompatible(envConfigProperties.ChartRefId, request.TargetChartRefId)
528+
if !compatible {
529+
common.WriteJsonResp(w, fmt.Errorf("charts not compatible"), "chart not compatible", http.StatusUnprocessableEntity)
530+
return
531+
}
532+
533+
envConfigProperties.EnvOverrideValues, err = handler.chartService.PatchEnvOverrides(envConfigProperties.EnvOverrideValues, oldChartType, newChartType)
534+
if err != nil {
535+
common.WriteJsonResp(w, err, "error in patching env override", http.StatusInternalServerError)
536+
return
537+
}
538+
539+
if newChartType == chart.RolloutChartType {
540+
enabled, err := handler.chartService.FlaggerCanaryEnabled(envConfigProperties.EnvOverrideValues)
541+
if err != nil || enabled {
542+
handler.Logger.Errorw("rollout charts do not support flaggerCanary, ChangeChartRef", "err", err, "payload", request)
543+
common.WriteJsonResp(w, err, "rollout charts do not support flaggerCanary, ChangeChartRef", http.StatusBadRequest)
544+
return
545+
}
546+
}
547+
548+
envMetrics, err := handler.propertiesConfigService.FindEnvLevelAppMetricsByAppIdAndEnvId(request.AppId, request.EnvId)
549+
if err != nil {
550+
handler.Logger.Errorw("could not find envMetrics for, ChangeChartRef", "err", err, "payload", request)
551+
common.WriteJsonResp(w, err, "env metric could not be fetched", http.StatusBadRequest)
552+
return
553+
}
554+
envConfigProperties.ChartRefId = request.TargetChartRefId
555+
envConfigProperties.UserId = userId
556+
envConfigProperties.EnvironmentId = request.EnvId
557+
envConfigProperties.AppMetrics = envMetrics.AppMetrics
558+
559+
token := r.Header.Get("token")
560+
handler.Logger.Infow("request payload, EnvConfigOverrideCreate", "payload", request)
561+
resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(request.AppId)
562+
if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok {
563+
common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden)
564+
return
565+
}
566+
object := handler.enforcerUtil.GetEnvRBACNameByAppId(request.AppId, request.EnvId)
567+
if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionUpdate, object); !ok {
568+
common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden)
569+
return
570+
}
571+
572+
validate, err2 := handler.chartService.DeploymentTemplateValidate(r.Context(), envConfigProperties.EnvOverrideValues, envConfigProperties.ChartRefId)
573+
if !validate {
574+
handler.Logger.Errorw("validation err, UpdateAppOverride", "err", err2, "payload", request)
575+
common.WriteJsonResp(w, err2, "validation err, UpdateAppOverrid", http.StatusBadRequest)
576+
return
577+
}
578+
envConfigPropertiesOld, err := handler.propertiesConfigService.FetchEnvProperties(request.AppId, request.EnvId, request.TargetChartRefId)
579+
if err == nil {
580+
envConfigProperties.Id = envConfigPropertiesOld.Id
581+
createResp, err := handler.propertiesConfigService.UpdateEnvironmentProperties(request.AppId, envConfigProperties, userId)
582+
if err != nil {
583+
handler.Logger.Errorw("service err, EnvConfigOverrideUpdate", "err", err, "payload", envConfigProperties)
584+
common.WriteJsonResp(w, err, createResp, http.StatusInternalServerError)
585+
return
586+
}
587+
common.WriteJsonResp(w, err, createResp, http.StatusOK)
588+
return
589+
}
590+
createResp, err := handler.propertiesConfigService.CreateEnvironmentProperties(request.AppId, envConfigProperties)
591+
592+
if err != nil {
593+
if err.Error() == bean2.NOCHARTEXIST {
594+
ctx, cancel := context.WithCancel(r.Context())
595+
if cn, ok := w.(http.CloseNotifier); ok {
596+
go func(done <-chan struct{}, closed <-chan bool) {
597+
select {
598+
case <-done:
599+
case <-closed:
600+
cancel()
601+
}
602+
}(ctx.Done(), cn.CloseNotify())
603+
}
604+
acdToken, err := handler.argoUserService.GetLatestDevtronArgoCdUserToken()
605+
if err != nil {
606+
handler.Logger.Errorw("error in getting acd token", "err", err)
607+
common.WriteJsonResp(w, err, "error in getting acd token", http.StatusInternalServerError)
608+
return
609+
}
610+
ctx = context.WithValue(r.Context(), "token", acdToken)
611+
appMetrics := false
612+
if envConfigProperties.AppMetrics != nil {
613+
appMetrics = *envMetrics.AppMetrics
614+
}
615+
templateRequest := chart.TemplateRequest{
616+
AppId: request.AppId,
617+
ChartRefId: request.TargetChartRefId,
618+
ValuesOverride: []byte("{}"),
619+
UserId: userId,
620+
IsAppMetricsEnabled: appMetrics,
621+
}
622+
623+
_, err = handler.chartService.CreateChartFromEnvOverride(templateRequest, ctx)
624+
if err != nil {
625+
handler.Logger.Errorw("service err, CreateChartFromEnvOverride", "err", err, "payload", request)
626+
common.WriteJsonResp(w, err, "could not create chart from env override", http.StatusInternalServerError)
627+
return
628+
}
629+
createResp, err = handler.propertiesConfigService.CreateEnvironmentProperties(request.AppId, envConfigProperties)
630+
if err != nil {
631+
handler.Logger.Errorw("service err, CreateEnvironmentProperties", "err", err, "payload", request)
632+
common.WriteJsonResp(w, err, "could not create env properties", http.StatusInternalServerError)
633+
return
634+
}
635+
common.WriteJsonResp(w, err, createResp, http.StatusOK)
636+
return
637+
} else {
638+
handler.Logger.Errorw("service err, EnvConfigOverrideCreate", "err", err, "payload", request)
639+
common.WriteJsonResp(w, err, "service err, EnvConfigOverrideCreate", http.StatusInternalServerError)
640+
return
641+
}
642+
}
643+
common.WriteJsonResp(w, err, createResp, http.StatusOK)
644+
}
645+
501646
func (handler PipelineConfigRestHandlerImpl) EnvConfigOverrideCreate(w http.ResponseWriter, r *http.Request) {
502647
userId, err := handler.userAuthService.GetLoggedInUser(r)
503648
if userId == 0 || err != nil {

api/router/PipelineConfigRouter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func (router PipelineConfigRouterImpl) initPipelineConfigRouter(configRouter *mu
7777
configRouter.Path("/cd-pipeline/approve").HandlerFunc(router.restHandler.PerformDeploymentApprovalAction).Methods("POST")
7878
//save environment specific override
7979
configRouter.Path("/env/{appId}/{environmentId}").HandlerFunc(router.restHandler.EnvConfigOverrideCreate).Methods("POST")
80+
configRouter.Path("/env/patch").HandlerFunc(router.restHandler.ChangeChartRef).Methods("PATCH")
8081
configRouter.Path("/env").HandlerFunc(router.restHandler.EnvConfigOverrideUpdate).Methods("PUT")
8182
configRouter.Path("/env/{appId}/{environmentId}/{chartRefId}").HandlerFunc(router.restHandler.GetEnvConfigOverride).Methods("GET")
8283

pkg/chart/ChartCompatibility.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package chart
2+
3+
type stringSet map[string]struct{}
4+
5+
const (
6+
DeploymentChartType = "Deployment"
7+
RolloutChartType = "Rollout Deployment"
8+
)
9+
10+
var chartCompatibilityMatrix = map[string]stringSet{
11+
DeploymentChartType: {RolloutChartType: {}, DeploymentChartType: {}},
12+
RolloutChartType: {DeploymentChartType: {}, RolloutChartType: {}},
13+
}
14+
15+
func CheckCompatibility(oldChartType, newChartType string) bool {
16+
compatibilityOfOld, found := chartCompatibilityMatrix[oldChartType]
17+
if !found {
18+
return false
19+
}
20+
_, found = compatibilityOfOld[newChartType]
21+
if !found {
22+
return false
23+
}
24+
return true
25+
}
26+
27+
func CompatibleChartsWith(chartType string) []string {
28+
resultSet, found := chartCompatibilityMatrix[chartType]
29+
if !found {
30+
return []string{}
31+
}
32+
var result []string
33+
for k, _ := range resultSet {
34+
result = append(result, k)
35+
}
36+
return result
37+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package chart
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func Test_checkCompatibility(t *testing.T) {
9+
type args struct {
10+
oldChartType string
11+
newChartType string
12+
}
13+
tests := []struct {
14+
name string
15+
args args
16+
want bool
17+
}{
18+
{
19+
name: "when charts are compatible, it should return true",
20+
args: args{
21+
oldChartType: DeploymentChartType,
22+
newChartType: RolloutChartType,
23+
},
24+
want: true,
25+
},
26+
{
27+
name: "when oldChart is not found, it should return false",
28+
args: args{
29+
oldChartType: "Sdfasdf",
30+
newChartType: RolloutChartType,
31+
},
32+
want: false,
33+
},
34+
{
35+
name: "when newChart is not found, it should return false",
36+
args: args{
37+
oldChartType: DeploymentChartType,
38+
newChartType: "random sdfasdf saldfj",
39+
},
40+
want: false,
41+
},
42+
}
43+
for _, tt := range tests {
44+
t.Run(tt.name, func(t *testing.T) {
45+
if got := CheckCompatibility(tt.args.oldChartType, tt.args.newChartType); got != tt.want {
46+
t.Errorf("checkCompatibility() = %v, want %v", got, tt.want)
47+
}
48+
})
49+
}
50+
}
51+
52+
func TestCompatibleChartsWith(t *testing.T) {
53+
type args struct {
54+
chartType string
55+
}
56+
tests := []struct {
57+
name string
58+
args args
59+
want []string
60+
}{
61+
{
62+
name: "when chart is not found, it should return empty slice",
63+
args: args{
64+
chartType: "sdfsdf",
65+
},
66+
want: []string{},
67+
},
68+
{
69+
name: "when chart is found, it should return a slice of all cpmpatible chartIds",
70+
args: args{
71+
chartType: DeploymentChartType,
72+
},
73+
want: []string{RolloutChartType},
74+
},
75+
}
76+
for _, tt := range tests {
77+
t.Run(tt.name, func(t *testing.T) {
78+
if got := CompatibleChartsWith(tt.args.chartType); !reflect.DeepEqual(got, tt.want) {
79+
t.Errorf("CompatibleChartsWith() = %v, want %v", got, tt.want)
80+
}
81+
})
82+
}
83+
}

0 commit comments

Comments
 (0)