From 23290fbd5d7d92b77c20871691c6c8dd5d3a6d93 Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Sun, 27 Aug 2023 19:44:58 +0200 Subject: [PATCH] fix(dockerCompose): add ServiceDeployResources.MergeFirstWin() --- pkg/domain/dockerCompose/config.go | 50 +++++++- pkg/domain/dockerCompose/config_test.go | 149 ++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 1 deletion(-) diff --git a/pkg/domain/dockerCompose/config.go b/pkg/domain/dockerCompose/config.go index 0bcbddf..5b6ffaf 100644 --- a/pkg/domain/dockerCompose/config.go +++ b/pkg/domain/dockerCompose/config.go @@ -798,6 +798,27 @@ func (sdr *ServiceDeployResources) Equal(equalable Equalable) bool { } } +// MergeFirstWin adds only attributes of the passed serviceDeployResources if +// they are not already exists. +func (sdr *ServiceDeployResources) MergeFirstWin(serviceDeployResources *ServiceDeployResources) { + switch { + case sdr == nil && serviceDeployResources == nil: + fallthrough + case sdr != nil && serviceDeployResources == nil: + return + + // WARN: It's not possible to change the memory pointer sdr *ServiceDeployResources + // to a new initialized serviceDeployResources without returning the + // serviceDeployResources it self. + case sdr == nil && serviceDeployResources != nil: + sdr = NewServiceDeployResources() + fallthrough + default: + sdr.mergeFirstWinLimits(serviceDeployResources.Limits) + sdr.mergeFirstWinReservations(serviceDeployResources.Reservations) + } +} + // MergeLastWin merges adds or overwrite the attributes of the passed // serviceDeployResources with the existing one. func (sdr *ServiceDeployResources) MergeLastWin(serviceDeployResources *ServiceDeployResources) { @@ -819,6 +840,32 @@ func (sdr *ServiceDeployResources) MergeLastWin(serviceDeployResources *ServiceD } } +func (sdr *ServiceDeployResources) mergeFirstWinLimits(limits *ServiceDeployResourcesLimits) { + switch { + case sdr.Limits == nil && limits != nil: + sdr.Limits = limits + case sdr.Limits != nil && limits == nil: + fallthrough + case sdr.Limits == nil && limits == nil: + return + default: + sdr.Limits.MergeFirstWin(limits) + } +} + +func (sdr *ServiceDeployResources) mergeFirstWinReservations(reservations *ServiceDeployResourcesLimits) { + switch { + case sdr.Reservations == nil && reservations != nil: + sdr.Reservations = reservations + case sdr.Reservations != nil && reservations == nil: + fallthrough + case sdr.Reservations == nil && reservations == nil: + return + default: + sdr.Reservations.MergeFirstWin(reservations) + } +} + func (sdr *ServiceDeployResources) mergeLastWinLimits(limits *ServiceDeployResourcesLimits) { switch { case sdr.Limits == nil && limits != nil: @@ -991,7 +1038,8 @@ func (sn *ServiceNetwork) MergeFirstWin(serviceNetwork *ServiceNetwork) { // fallthrough case sn == nil && serviceNetwork != nil: - sn = serviceNetwork + sn = NewServiceNetwork() + fallthrough default: sn.mergeFirstWinAliases(serviceNetwork.Aliases) } diff --git a/pkg/domain/dockerCompose/config_test.go b/pkg/domain/dockerCompose/config_test.go index 6841db9..0850f75 100644 --- a/pkg/domain/dockerCompose/config_test.go +++ b/pkg/domain/dockerCompose/config_test.go @@ -1543,6 +1543,155 @@ func TestServiceDeployResources_MergeLastWin(t *testing.T) { } } +func TestServiceDeployResources_MergeFirstWin(t *testing.T) { + require := require.New(t) + + testCases := []struct { + serviceDeploymentResourcesA *dockerCompose.ServiceDeployResources + serviceDeploymentResourcesB *dockerCompose.ServiceDeployResources + expectedServiceDeploymentResources *dockerCompose.ServiceDeployResources + }{ + { + serviceDeploymentResourcesA: nil, + serviceDeploymentResourcesB: nil, + expectedServiceDeploymentResources: nil, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Limits: nil, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Limits: nil, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "2", + Memory: "1000", + }, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Limits: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Reservations: nil, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Reservations: nil, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "2", + Memory: "1000", + }, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + { + serviceDeploymentResourcesA: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "", + Memory: "", + }, + }, + serviceDeploymentResourcesB: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + expectedServiceDeploymentResources: &dockerCompose.ServiceDeployResources{ + Reservations: &dockerCompose.ServiceDeployResourcesLimits{ + CPUs: "1", + Memory: "500", + }, + }, + }, + } + + for i, testCase := range testCases { + testCase.serviceDeploymentResourcesA.MergeFirstWin(testCase.serviceDeploymentResourcesB) + require.True(testCase.expectedServiceDeploymentResources.Equal(testCase.serviceDeploymentResourcesA), "Failed test case %v", i) + } +} + func TestServiceDeployResourcesLimits_Equal(t *testing.T) { require := require.New(t)