diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 547715b..31648da 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -177,14 +177,16 @@ func createPatch(httpProxy *contourv1.HTTPProxy, rollout *v1alpha1.Rollout, cana return nil, "", fmt.Errorf("failed to marshal the current configuration: %w", err) } - canarySvc, stableSvc, totalWeight, err := getRouteServices(httpProxy, rollout) + canarySvcs, stableSvcs, totalWeights, err := getRouteServices(httpProxy, rollout) if err != nil { return nil, types.MergePatchType, err } - slog.Debug("old weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight)) - canarySvc.Weight, stableSvc.Weight = utils.CalcWeight(totalWeight, float32(canaryWeightPercent)) - slog.Debug("new weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight)) + for i := range canarySvcs { + slog.Debug("old weight", slog.Int64("canary", canarySvcs[i].Weight), slog.Int64("stable", stableSvcs[i].Weight)) + canarySvcs[i].Weight, stableSvcs[i].Weight = utils.CalcWeight(totalWeights[i], float32(canaryWeightPercent)) + slog.Debug("new weight", slog.Int64("canary", canarySvcs[i].Weight), slog.Int64("stable", stableSvcs[i].Weight)) + } newData, err := json.Marshal(httpProxy) if err != nil { @@ -221,53 +223,64 @@ func (r *RpcPlugin) verifyHTTPProxy( return false, nil } - canarySvc, stableSvc, totalWeight, err := getRouteServices(httpProxy, rollout) + canarySvcs, stableSvcs, totalWeights, err := getRouteServices(httpProxy, rollout) if err != nil { return false, err } - canaryWeight, stableWeight := utils.CalcWeight(totalWeight, float32(canaryWeightPercent)) - if canarySvc.Weight != canaryWeight || stableSvc.Weight != stableWeight { - slog.Debug(fmt.Sprintf("expected weights are canary=%d and stable=%d, but got canary=%d and stable=%d", canaryWeight, stableWeight, canarySvc.Weight, stableSvc.Weight), slog.String("name", httpProxyName)) - return false, nil + for i := range canarySvcs { + canaryWeight, stableWeight := utils.CalcWeight(totalWeights[i], float32(canaryWeightPercent)) + if canarySvcs[i].Weight != canaryWeight || stableSvcs[i].Weight != stableWeight { + slog.Debug(fmt.Sprintf("expected weights are canary=%d and stable=%d, but got canary=%d and stable=%d", canaryWeight, stableWeight, canarySvcs[i].Weight, stableSvcs[i].Weight), slog.String("name", httpProxyName)) + return false, nil + } } return true, nil } func getRouteServices(httpProxy *contourv1.HTTPProxy, rollout *v1alpha1.Rollout) ( - *contourv1.Service, *contourv1.Service, int64, error) { + []*contourv1.Service, []*contourv1.Service, []int64, error) { canarySvcName := rollout.Spec.Strategy.Canary.CanaryService stableSvcName := rollout.Spec.Strategy.Canary.StableService slog.Debug("the services name", slog.String("stable", stableSvcName), slog.String("canary", canarySvcName)) - svcMap := getServiceMap(httpProxy, canarySvcName) + svcMaps := getRouteServiceMaps(httpProxy, canarySvcName) + canarySvcs := []*contourv1.Service{} + stableSvcs := []*contourv1.Service{} + totalWeights := []int64{} - canarySvc, err := getService(canarySvcName, svcMap) - if err != nil { - return nil, nil, 0, err - } + for _, svcMap := range svcMaps { + canarySvc, err := getService(canarySvcName, svcMap) + if err != nil { + return nil, nil, nil, err + } - stableSvc, err := getService(stableSvcName, svcMap) - if err != nil { - return nil, nil, 0, err - } + stableSvc, err := getService(stableSvcName, svcMap) + if err != nil { + return nil, nil, nil, err + } - otherWeight := int64(0) - for name, svc := range svcMap { - if name == stableSvcName || name == canarySvcName { - continue + otherWeight := int64(0) + for name, svc := range svcMap { + if name == stableSvcName || name == canarySvcName { + continue + } + otherWeight += svc.Weight } - otherWeight += svc.Weight - } - // the total weight must equals to 100 - if otherWeight+canarySvc.Weight+stableSvc.Weight != 100 { - return nil, nil, 0, fmt.Errorf("the total weight must equals to 100") + // the total weight must equals to 100 + if otherWeight+canarySvc.Weight+stableSvc.Weight != 100 { + return nil, nil, nil, fmt.Errorf("the total weight must equals to 100") + } + + canarySvcs = append(canarySvcs, canarySvc) + stableSvcs = append(stableSvcs, stableSvc) + totalWeights = append(totalWeights, 100-otherWeight) } - return canarySvc, stableSvc, 100 - otherWeight, nil + return canarySvcs, stableSvcs, totalWeights, nil } func getContourTrafficRouting(rollout *v1alpha1.Rollout) (*ContourTrafficRouting, error) { @@ -286,9 +299,8 @@ func getService(name string, svcMap map[string]*contourv1.Service) (*contourv1.S return svc, nil } -func getServiceMap(httpProxy *contourv1.HTTPProxy, canarySvcName string) map[string]*contourv1.Service { - svcMap := make(map[string]*contourv1.Service) - +func getRouteServiceMaps(httpProxy *contourv1.HTTPProxy, canarySvcName string) []map[string]*contourv1.Service { + svcMaps := []map[string]*contourv1.Service{} // filter the services by canary service name filter := func(services []contourv1.Service) bool { for _, svc := range services { @@ -298,9 +310,11 @@ func getServiceMap(httpProxy *contourv1.HTTPProxy, canarySvcName string) map[str } return false } - // TODO: same service in multi conditions + for _, r := range httpProxy.Spec.Routes { + svcMap := make(map[string]*contourv1.Service) if filter(r.Services) { + svcMaps = append(svcMaps, svcMap) for i := range r.Services { s := &r.Services[i] svcMap[s.Name] = s @@ -308,7 +322,7 @@ func getServiceMap(httpProxy *contourv1.HTTPProxy, canarySvcName string) map[str } } - return svcMap + return svcMaps } func validateRolloutParameters(rollout *v1alpha1.Rollout) error { diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index f606295..7bfd60f 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -280,6 +280,66 @@ func Test_createPatch(t *testing.T) { wantPatchType: k8stypes.MergePatchType, wantErr: false, }, + { + name: "test create http proxy patch", + args: args{ + httpProxy: &contourv1.HTTPProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: mocks.HTTPProxyName, + }, + Spec: contourv1.HTTPProxySpec{ + Routes: []contourv1.Route{ + { + Services: []contourv1.Service{ + { + Name: mocks.StableServiceName, + Weight: 70, + }, + { + Name: mocks.CanaryServiceName, + Weight: 20, + }, + { + Name: "others-service", + Weight: 10, + }, + }, + }, + { + Services: []contourv1.Service{ + { + Name: mocks.StableServiceName, + Weight: 70, + }, + { + Name: mocks.CanaryServiceName, + Weight: 10, + }, + { + Name: "others-service", + Weight: 20, + }, + }, + }, + }, + }, + }, + rollout: &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: mocks.StableServiceName, + CanaryService: mocks.CanaryServiceName, + }, + }, + }, + }, + desiredWeight: 50, + }, + want: []byte(`{"spec":{"routes":[{"services":[{"name":"argo-rollouts-stable","port":0,"weight":45},{"name":"argo-rollouts-canary","port":0,"weight":45},{"name":"others-service","port":0,"weight":10}]},{"services":[{"name":"argo-rollouts-stable","port":0,"weight":40},{"name":"argo-rollouts-canary","port":0,"weight":40},{"name":"others-service","port":0,"weight":20}]}]}}`), + wantPatchType: k8stypes.MergePatchType, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -292,7 +352,7 @@ func Test_createPatch(t *testing.T) { t.Errorf("createPatch() gotPatchType = %v, want %v", gotPatchType, tt.wantPatchType) } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("createPatch() got = %v, want %v", got, tt.want) + t.Errorf("createPatch() got = %s, want %s", got, tt.want) } }) }