mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] Do not change external service ports (#1204)
This commit is contained in:
parent
237af92b60
commit
3fc881c949
5 changed files with 220 additions and 14 deletions
|
@ -40,6 +40,7 @@
|
|||
- (Bugfix) Wait for Pod to be Ready in post-restart actions
|
||||
- (Bugfix) Prevent Runtime update restarts
|
||||
- (Bugfix) Change member port discovery
|
||||
- (Feature) Do not change external service ports
|
||||
|
||||
## [1.2.20](https://github.com/arangodb/kube-arangodb/tree/1.2.20) (2022-10-25)
|
||||
- (Feature) Add action progress
|
||||
|
|
2
Makefile
2
Makefile
|
@ -499,8 +499,6 @@ tools: update-vendor
|
|||
@GOBIN=$(GOPATH)/bin go install golang.org/x/tools/cmd/goimports@0bb7e5c47b1a31f85d4f173edc878a8e049764a5
|
||||
@echo ">> Fetching license check"
|
||||
@GOBIN=$(GOPATH)/bin go install github.com/google/addlicense@6d92264d717064f28b32464f0f9693a5b4ef0239
|
||||
@echo ">> Fetching GO Assets Builder"
|
||||
@GOBIN=$(GOPATH)/bin go install github.com/jessevdk/go-assets-builder@b8483521738fd2198ecfc378067a4e8a6079f8e5
|
||||
@echo ">> Fetching gci"
|
||||
@GOBIN=$(GOPATH)/bin go install github.com/daixiang0/gci@v0.3.0
|
||||
@echo ">> Downloading protobuf compiler..."
|
||||
|
|
|
@ -184,7 +184,7 @@ func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorIn
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServicePorts(clientServicePorts), patcher.PatchServiceSelector(clientServiceSelectors)); err != nil {
|
||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServiceOnlyPorts(clientServicePorts...), patcher.PatchServiceSelector(clientServiceSelectors)); err != nil {
|
||||
log.Err(err).Debug("Failed to patch database client service")
|
||||
return errors.WithStack(err)
|
||||
} else if changed {
|
||||
|
@ -254,9 +254,12 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
|||
log := r.log.Str("section", "service-ea").Str("role", role).Str("service", eaServiceName)
|
||||
createExternalAccessService := false
|
||||
deleteExternalAccessService := false
|
||||
owned := false
|
||||
eaServiceType := spec.GetType().AsServiceType() // Note: Type auto defaults to ServiceTypeLoadBalancer
|
||||
if existing, exists := cachedStatus.Service().V1().GetSimple(eaServiceName); exists {
|
||||
// External access service exists
|
||||
owned = apiObject.OwnerOf(existing)
|
||||
|
||||
updateExternalAccessService := false
|
||||
loadBalancerIP := spec.GetLoadBalancerIP()
|
||||
loadBalancerSourceRanges := spec.LoadBalancerSourceRanges
|
||||
|
@ -285,7 +288,7 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
|||
} else if existing.Spec.Type == core.ServiceTypeLoadBalancer && (loadBalancerIP != "" && existing.Spec.LoadBalancerIP != loadBalancerIP) {
|
||||
deleteExternalAccessService = true // LoadBalancerIP is wrong, remove the current and replace with proper one
|
||||
createExternalAccessService = true
|
||||
} else if existing.Spec.Type == core.ServiceTypeNodePort && len(existing.Spec.Ports) == 1 && (nodePort != 0 && existing.Spec.Ports[0].NodePort != int32(nodePort)) {
|
||||
} else if existing.Spec.Type == core.ServiceTypeNodePort && len(existing.Spec.Ports) < 1 || existing.Spec.Ports[0].Name != shared.ServerPortName && (nodePort != 0 && existing.Spec.Ports[0].NodePort != int32(nodePort)) {
|
||||
deleteExternalAccessService = true // NodePort is wrong, remove the current and replace with proper one
|
||||
createExternalAccessService = true
|
||||
}
|
||||
|
@ -300,7 +303,7 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
|||
existing.Spec.LoadBalancerSourceRanges = loadBalancerSourceRanges
|
||||
}
|
||||
} else if spec.GetType().IsNodePort() {
|
||||
if existing.Spec.Type != core.ServiceTypeNodePort || len(existing.Spec.Ports) != 1 || (nodePort != 0 && existing.Spec.Ports[0].NodePort != int32(nodePort)) {
|
||||
if existing.Spec.Type != core.ServiceTypeNodePort || len(existing.Spec.Ports) < 1 || existing.Spec.Ports[0].Name != shared.ServerPortName || (nodePort != 0 && existing.Spec.Ports[0].NodePort != int32(nodePort)) {
|
||||
deleteExternalAccessService = true // Remove the current and replace with proper one
|
||||
createExternalAccessService = true
|
||||
}
|
||||
|
@ -316,7 +319,9 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
|||
}
|
||||
}
|
||||
if !createExternalAccessService && !deleteExternalAccessService {
|
||||
if changed, err := patcher.ServicePatcher(ctx, svcs, existing, meta.PatchOptions{}, patcher.PatchServicePorts(eaPorts), patcher.PatchServiceSelector(eaSelector)); err != nil {
|
||||
if changed, err := patcher.ServicePatcher(ctx, svcs, existing, meta.PatchOptions{},
|
||||
patcher.PatchServiceSelector(eaSelector),
|
||||
patcher.Optional(patcher.PatchServiceOnlyPorts(eaPorts...), owned)); err != nil {
|
||||
log.Err(err).Debug("Failed to patch database client service")
|
||||
return errors.WithStack(err)
|
||||
} else if changed {
|
||||
|
@ -331,13 +336,15 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
|||
}
|
||||
|
||||
if deleteExternalAccessService {
|
||||
log.Info("Removing obsolete external access service")
|
||||
err := globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
|
||||
return svcs.Delete(ctxChild, eaServiceName, meta.DeleteOptions{})
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Debug("Failed to remove external access service")
|
||||
return errors.WithStack(err)
|
||||
if owned {
|
||||
log.Info("Removing obsolete external access service")
|
||||
err := globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
|
||||
return svcs.Delete(ctxChild, eaServiceName, meta.DeleteOptions{})
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Debug("Failed to remove external access service")
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if createExternalAccessService {
|
||||
|
@ -368,7 +375,7 @@ func (r *Resources) ensureExternalAccessManagedServices(ctx context.Context, cac
|
|||
|
||||
apply := func(svc *core.Service) (bool, error) {
|
||||
return patcher.ServicePatcher(ctx, cachedStatus.ServicesModInterface().V1(), svc, meta.PatchOptions{},
|
||||
patcher.PatchServicePorts(ports),
|
||||
patcher.PatchServiceOnlyPorts(ports...),
|
||||
patcher.PatchServiceSelector(selectors))
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,72 @@ func PatchServicePorts(ports []core.ServicePort) ServicePatch {
|
|||
}
|
||||
}
|
||||
|
||||
func Optional(p ServicePatch, enabled bool) ServicePatch {
|
||||
return func(in *core.Service) []patch.Item {
|
||||
if !enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
return p(in)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func PatchServiceOnlyPorts(ports ...core.ServicePort) ServicePatch {
|
||||
return func(in *core.Service) []patch.Item {
|
||||
psvc := in.Spec.DeepCopy()
|
||||
cp := psvc.Ports
|
||||
|
||||
changed := false
|
||||
|
||||
for pid := range ports {
|
||||
got := false
|
||||
for id := range cp {
|
||||
if ports[pid].Name == cp[id].Name {
|
||||
got = true
|
||||
|
||||
// Set ignored fields
|
||||
if ports[pid].NodePort == 0 {
|
||||
ports[pid].NodePort = cp[id].NodePort
|
||||
}
|
||||
if ports[pid].AppProtocol == nil {
|
||||
ports[pid].AppProtocol = cp[id].AppProtocol
|
||||
}
|
||||
if ports[pid].Protocol == "" {
|
||||
ports[pid].Protocol = cp[id].Protocol
|
||||
}
|
||||
if ports[pid].TargetPort.StrVal == "" && ports[pid].TargetPort.IntVal == 0 {
|
||||
ports[pid].TargetPort = cp[id].TargetPort
|
||||
}
|
||||
|
||||
if !equality.Semantic.DeepEqual(ports[pid], cp[id]) {
|
||||
q := ports[pid].DeepCopy()
|
||||
cp[id] = *q
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !got {
|
||||
q := ports[pid].DeepCopy()
|
||||
cp = append(cp, *q)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if !changed {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []patch.Item{
|
||||
patch.ItemReplace(patch.NewPath("spec", "ports"), cp),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PatchServiceSelector(selector map[string]string) ServicePatch {
|
||||
return func(in *core.Service) []patch.Item {
|
||||
if equality.Semantic.DeepEqual(in.Spec.Selector, selector) {
|
||||
|
|
|
@ -25,6 +25,9 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
core "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
)
|
||||
|
||||
func Test_Service_Ports(t *testing.T) {
|
||||
|
@ -67,3 +70,134 @@ func Test_Service_Ports(t *testing.T) {
|
|||
require.Len(t, q, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Service_OnlyPorts(t *testing.T) {
|
||||
t.Run("Equal", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 0)
|
||||
})
|
||||
|
||||
t.Run("Missing", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test2",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 1)
|
||||
})
|
||||
|
||||
t.Run("Different", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
Port: 8529,
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test1",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 1)
|
||||
})
|
||||
|
||||
t.Run("Different Port", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
Port: 8529,
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 1)
|
||||
})
|
||||
|
||||
t.Run("Changed NodePort", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
Port: 8529,
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test",
|
||||
Port: 8529,
|
||||
NodePort: 12345,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 0)
|
||||
})
|
||||
|
||||
t.Run("Changed Port", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
Port: 8528,
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test",
|
||||
Port: 8529,
|
||||
NodePort: 12345,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 1)
|
||||
})
|
||||
|
||||
t.Run("Ignore fields", func(t *testing.T) {
|
||||
q := PatchServiceOnlyPorts(core.ServicePort{
|
||||
Name: "test",
|
||||
Port: 8528,
|
||||
})(&core.Service{
|
||||
Spec: core.ServiceSpec{
|
||||
Ports: []core.ServicePort{
|
||||
{
|
||||
Name: "test",
|
||||
Protocol: core.ProtocolTCP,
|
||||
AppProtocol: util.NewString("test"),
|
||||
Port: 8528,
|
||||
TargetPort: intstr.IntOrString{
|
||||
StrVal: "TEST",
|
||||
IntVal: 0,
|
||||
},
|
||||
NodePort: 6543,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Len(t, q, 0)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue