Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/resourceapply/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ func ApplyService(client coreclientv1.ServicesGetter, required *corev1.Service)

modified := pointer.BoolPtr(false)
resourcemerge.EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta)
resourcemerge.EnsureServicePorts(modified, &existing.Spec.Ports, required.Spec.Ports)
selectorSame := equality.Semantic.DeepEqual(existing.Spec.Selector, required.Spec.Selector)
typeSame := equality.Semantic.DeepEqual(existing.Spec.Type, required.Spec.Type)

if selectorSame && typeSame && !*modified {
return nil, false, nil
}
Expand Down
45 changes: 45 additions & 0 deletions lib/resourcemerge/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,51 @@ func ensureContainerPort(modified *bool, existing *corev1.ContainerPort, require
}
}

func EnsureServicePorts(modified *bool, existing *[]corev1.ServicePort, required []corev1.ServicePort) {
for i, existingServicePort := range *existing {
var existingCurr *corev1.ServicePort
for _, requiredServicePort := range required {
if existingServicePort.Name == requiredServicePort.Name {
Copy link
Member

@wking wking Nov 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Matching by name and then taking the union of in-cluster and in-manifest ports means there's no way to remove an entry. Also, name is optional, although I'm not clear on how that squares with:

All ports within a ServiceSpec must have unique names.

Maybe it's "If you set a name, it must not duplicate an existing ports entry in the same Service"?

Do we even need to support folks adding additional ports values to Service manifests managed by the CVO? Can we just clobber the existing value with the required value and set modified if that changed anything?

Copy link
Member Author

@enxebre enxebre Nov 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice that:

// Optional if only one ServicePort is defined on this service.

https://github.com/kubernetes/api/blob/11707872ac1cab52aefea0325f4698eaffeda3c8/core/v1/types.go#L3984

Matching by name and then taking the union of in-cluster and in-manifest ports means there's no way to remove an entry

There's no union, required overwrite existing via ensureServicePort. Entries are removed via https://github.com/openshift/cluster-version-operator/pull/272/files#diff-f7675c7b39553e431cdc6c3ba8f5c482R215-R218.

See test cases for each scenario (with/without name) https://github.com/openshift/cluster-version-operator/pull/272/files#diff-415c13f11ffc32696c5d69b900b3fe58R283.

Instead of a nested loop this could get better performance by hashing the port name but I just wanted to replicate the pattern already present for similar funcs, e.g ensureContainers

func ensureContainers(modified *bool, existing *[]corev1.Container, required []corev1.Container) {

Also I'm wondering why the need for the merge library rather than just unconditionally overwrite/apply with whatever is required, but that's another discussion.

existingCurr = &(*existing)[i]
ensureServicePort(modified, existingCurr, requiredServicePort)
break
}
}
if existingCurr == nil {
*modified = true
*existing = append((*existing)[:i], (*existing)[i+1:]...)
}
}

for _, requiredServicePort := range required {
match := false
for _, existingServicePort := range *existing {
if existingServicePort.Name == requiredServicePort.Name {
match = true
break
}
}
if !match {
*modified = true
*existing = append(*existing, requiredServicePort)
}
}
}

func ensureServicePort(modified *bool, existing *corev1.ServicePort, required corev1.ServicePort) {
ensureServicePortDefaults(&required)
if !equality.Semantic.DeepEqual(required, *existing) {
*modified = true
*existing = required
}
}

func ensureServicePortDefaults(servicePort *corev1.ServicePort) {
if servicePort.Protocol == "" {
servicePort.Protocol = corev1.ProtocolTCP
}
}

func ensureVolumeMount(modified *bool, existing *corev1.VolumeMount, required corev1.VolumeMount) {
if !equality.Semantic.DeepEqual(required, *existing) {
*modified = true
Expand Down
Loading