Skip to content

Fix bug where Operator fails to connecting to Coherence Pods when using Istio #691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 14, 2025
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

.github/
.idea/
artifacts/
build/
converter/
dashboards/
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/istio-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ jobs:
make deploy
ISTIO_VERSION=${{ matrix.istioVersion }} make install-istio
make e2e-client-test
make e2e-test
make undeploy
ISTIO_VERSION=${{ matrix.istioVersion }} make uninstall-istio

Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ jobs:
asset_name: coherence-operator.yaml
asset_content_type: text/plain

- name: Upload Restricted Release Yaml
id: upload-release-yaml
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: /tmp/coherence-operator/_output/coherence-operator-restricted.yaml
asset_name: coherence-operator-restricted.yaml
asset_content_type: text/plain

- name: Upload Release CRD
id: upload-release-crd
uses: actions/upload-release-asset@v1
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ bin/
bundle/
temp/

# OpenShift pre-flight
artifacts/
preflight.log

# licensed
.licenses/
meta/
Expand Down
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@ copyright: ## Check copyright headers
@java -cp hack/glassfish-copyright-maven-plugin-2.1.jar \
org.glassfish.copyright.Copyright -C hack/copyright.txt \
-X .adoc \
-X artifacts/ \
-X bin/ \
-X build/ \
-X clientset/ \
Expand Down Expand Up @@ -812,6 +813,7 @@ copyright: ## Check copyright headers
-X mvnw \
-X mvnw.cmd \
-X .png \
-X preflight.log \
-X PROJECT \
-X .sh \
-X tanzu/package/package.yml \
Expand Down Expand Up @@ -1612,6 +1614,9 @@ $(BUILD_MANIFESTS_PKG): $(TOOLS_BIN)/kustomize $(TOOLS_BIN)/yq
cp config/namespace/namespace.yaml $(BUILD_OUTPUT)/coherence-operator.yaml
$(KUSTOMIZE) build $(BUILD_DEPLOY)/default >> $(BUILD_OUTPUT)/coherence-operator.yaml
$(SED) -e 's/name: coherence-operator-env-vars-.*/name: coherence-operator-env-vars/g' $(BUILD_OUTPUT)/coherence-operator.yaml
$(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/restricted >> $(BUILD_OUTPUT)/coherence-operator-restricted.yaml
$(SED) -e 's/name: coherence-operator-env-vars-.*/name: coherence-operator-env-vars/g' $(BUILD_OUTPUT)//coherence-operator-restricted.yaml
$(SED) -e 's/ClusterRole/Role/g' $(BUILD_OUTPUT)//coherence-operator-restricted.yaml
cd $(BUILD_MANIFESTS)/crd && $(TOOLS_BIN)/yq --no-doc -s '.metadata.name + ".yaml"' temp.yaml
rm $(BUILD_MANIFESTS)/crd/temp.yaml
mv $(BUILD_MANIFESTS)/crd/coherence.coherence.oracle.com.yaml $(BUILD_MANIFESTS)/crd/coherence.oracle.com_coherence.yaml
Expand Down Expand Up @@ -2404,15 +2409,23 @@ uninstall-metallb: ## Uninstall MetalLB
# ----------------------------------------------------------------------------------------------------------------------
.PHONY: install-istio
install-istio: delete-istio-config get-istio ## Install the latest version of Istio into k8s (or override the version using the ISTIO_VERSION env var)
ifeq (true,$(ISTIO_USE_CONFIG))
$(ISTIO_HOME)/bin/istioctl install -f $(BUILD_OUTPUT)/istio-config.yaml -y
kubectl -n istio-system wait --for condition=available deployment.apps/istiod-$(ISTIO_REVISION)
else
$(ISTIO_HOME)/bin/istioctl install --set profile=demo -y
kubectl -n istio-system wait --for condition=available deployment.apps/istiod
endif
kubectl -n istio-system wait --for condition=available deployment.apps/istio-ingressgateway
kubectl -n istio-system wait --for condition=available deployment.apps/istio-egressgateway
kubectl apply -f $(SCRIPTS_DIR)/istio-strict.yaml
kubectl -n $(OPERATOR_NAMESPACE) apply -f $(SCRIPTS_DIR)/istio-operator.yaml
kubectl label namespace $(OPERATOR_NAMESPACE) istio-injection=enabled --overwrite=true
kubectl label namespace $(OPERATOR_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true
kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio-injection=enabled --overwrite=true
kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio.io/rev=$(ISTIO_REVISION) --overwrite=true
kubectl label namespace $(CLUSTER_NAMESPACE) istio-injection=enabled --overwrite=true
kubectl label namespace $(CLUSTER_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true
kubectl apply -f $(ISTIO_HOME)/samples/addons

# ----------------------------------------------------------------------------------------------------------------------
Expand Down
20 changes: 8 additions & 12 deletions api/v1/coherenceresourcespec_types.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates.
* Copyright (c) 2020, 2025, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -671,20 +671,16 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou
podLabels[k] = v
}

var annotations map[string]string
annotations := make(map[string]string)
// Add the default Istio config annotation.
// Adding this first allows it to be overridden in Coherence or CoherenceJob spec
annotations[AnnotationIstioConfig] = DefaultIstioConfigAnnotationValue

globalAnnotations := deployment.CreateGlobalAnnotations()
if globalAnnotations != nil {
if annotations == nil {
annotations = make(map[string]string)
}
for k, v := range globalAnnotations {
annotations[k] = v
}
for k, v := range globalAnnotations {
annotations[k] = v
}
if in.Annotations != nil {
if annotations == nil {
annotations = make(map[string]string)
}
for k, v := range in.Annotations {
annotations[k] = v
}
Expand Down
6 changes: 5 additions & 1 deletion api/v1/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,13 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe
initContainer.Image = *operatorImage
}

annotations := make(map[string]string)
annotations[coh.AnnotationIstioConfig] = coh.DefaultIstioConfigAnnotationValue

podTemplate := corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: podLabels,
Labels: podLabels,
Annotations: annotations,
},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{initContainer},
Expand Down
8 changes: 7 additions & 1 deletion api/v1/constants.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates.
* Copyright (c) 2020, 2025, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -64,6 +64,12 @@ const (
AnnotationFeatureSuspend = "com.oracle.coherence.operator/feature.suspend"
// AnnotationOperatorVersion is the Operator version annotations
AnnotationOperatorVersion = "com.oracle.coherence.operator/version"
// AnnotationIstioConfig is the Istio config annotation applied to Pods.
AnnotationIstioConfig = "proxy.istio.io/config"
// DefaultIstioConfigAnnotationValue is the default for the istio config annotation.
// This makes the Istio Sidecar the first container in the Pod to allow it to ideally
// be started before the Coherence container
DefaultIstioConfigAnnotationValue = "{ \"holdApplicationUntilProxyStarts\": true }"

// DefaultServiceAccount is the default k8s service account name.
DefaultServiceAccount = "default"
Expand Down
4 changes: 4 additions & 0 deletions config/manager/no-jobs-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- op: add
path: /spec/template/spec/containers/0/args/-
value:
- --install-job-crd=false
9 changes: 9 additions & 0 deletions config/overlays/restricted/cluster_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -------------------------------------------------------------
# This is the Cluster Roles required by the Coherence Operator
# to self-manage its CRDs and Web-Hooks.
# -------------------------------------------------------------
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: crd-webhook-install-role
$patch: delete
5 changes: 5 additions & 0 deletions config/overlays/restricted/cluster_role_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: crd-webhook-install-rolebinding
$patch: delete
15 changes: 15 additions & 0 deletions config/overlays/restricted/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../default

patches:
- path: single-namespace-patch.yaml
target:
kind: Deployment
name: controller-manager
- path: node-viewer-role.yaml
- path: node_viewer_role_binding.yaml
- path: cluster_role.yaml
- path: cluster_role_binding.yaml
5 changes: 5 additions & 0 deletions config/overlays/restricted/node-viewer-role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-viewer-role
$patch: delete
5 changes: 5 additions & 0 deletions config/overlays/restricted/node_viewer_role_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-viewer-rolebinding
$patch: delete
16 changes: 16 additions & 0 deletions config/overlays/restricted/single-namespace-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- op: add
path: /spec/template/spec/containers/0/args/-
value: --enable-webhook=false
- op: add
path: /spec/template/spec/containers/0/args/-
value: --install-crd=false
- op: add
path: /spec/template/spec/containers/0/args/-
value: --node-lookup-enabled=false
2 changes: 1 addition & 1 deletion controllers/job/job_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ func (in *ReconcileJob) maybeExecuteProbe(ctx context.Context, job *batchv1.Job,
probeStatus := status.FindJobProbeStatus(name)
podCondition := in.findPodReadyCondition(pod)
if in.shouldExecuteProbe(probeStatus, podCondition) {
_, err := p.RunProbe(ctx, pod, &action.Probe)
_, err := p.RunProbe(ctx, pod, deployment.GetWkaServiceName(), &action.Probe)
if err == nil {
logger.Info(fmt.Sprintf("Executed probe using pod %s", name), "Error", "nil")
probeStatus.Success = ptr.To(true)
Expand Down
4 changes: 2 additions & 2 deletions controllers/statefulset/statefulset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func (in *ReconcileStatefulSet) execActions(ctx context.Context, sts *appsv1.Sta

for _, action := range spec.Actions {
if action.Probe != nil {
if ok := coherenceProbe.ExecuteProbe(ctx, sts, action.Probe); !ok {
if ok := coherenceProbe.ExecuteProbe(ctx, sts, deployment.GetWkaServiceName(), action.Probe); !ok {
log.Info("Action probe execution failed.", "probe", action.Probe)
}
}
Expand Down Expand Up @@ -367,7 +367,7 @@ func (in *ReconcileStatefulSet) patchStatefulSet(ctx context.Context, deployment
return reconcile.Result{}, nil
}

return strategy.RollingUpgrade(ctx, current, in.GetClientSet().KubeClient)
return strategy.RollingUpgrade(ctx, current, deployment.GetWkaServiceName(), in.GetClientSet().KubeClient)
}
}

Expand Down
27 changes: 17 additions & 10 deletions controllers/statefulset/upgrade_strategy.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates.
* Copyright (c) 2020, 2025, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand All @@ -21,8 +21,15 @@ import (
)

type UpgradeStrategy interface {
// IsOperatorManaged returns true if this strategy requires the Operator to manage the upgrade
IsOperatorManaged() bool
RollingUpgrade(context.Context, *appsv1.StatefulSet, kubernetes.Interface) (reconcile.Result, error)
// RollingUpgrade performs the rolling upgrade
// Parameters:
// context.Context - the Go context to use
// *appsv1.StatefulSet - a pointer to the StatefulSet to upgrade
// string - the name of the WKA service
// kubernetes.Interface - the K8s client
RollingUpgrade(context.Context, *appsv1.StatefulSet, string, kubernetes.Interface) (reconcile.Result, error)
}

func GetUpgradeStrategy(c coh.CoherenceResource, p probe.CoherenceProbe) UpgradeStrategy {
Expand Down Expand Up @@ -66,7 +73,7 @@ var _ UpgradeStrategy = ByPodUpgradeStrategy{}
type ByPodUpgradeStrategy struct {
}

func (in ByPodUpgradeStrategy) RollingUpgrade(context.Context, *appsv1.StatefulSet, kubernetes.Interface) (reconcile.Result, error) {
func (in ByPodUpgradeStrategy) RollingUpgrade(context.Context, *appsv1.StatefulSet, string, kubernetes.Interface) (reconcile.Result, error) {
return reconcile.Result{}, nil
}

Expand All @@ -81,7 +88,7 @@ var _ UpgradeStrategy = ManualUpgradeStrategy{}
type ManualUpgradeStrategy struct {
}

func (in ManualUpgradeStrategy) RollingUpgrade(context.Context, *appsv1.StatefulSet, kubernetes.Interface) (reconcile.Result, error) {
func (in ManualUpgradeStrategy) RollingUpgrade(context.Context, *appsv1.StatefulSet, string, kubernetes.Interface) (reconcile.Result, error) {
return reconcile.Result{}, nil
}

Expand All @@ -98,8 +105,8 @@ type ByNodeUpgradeStrategy struct {
scalingProbe *coh.Probe
}

func (in ByNodeUpgradeStrategy) RollingUpgrade(ctx context.Context, sts *appsv1.StatefulSet, c kubernetes.Interface) (reconcile.Result, error) {
return rollingUpgrade(in.cp, in.scalingProbe, &PodNodeName{}, "NodeName", ctx, sts, c)
func (in ByNodeUpgradeStrategy) RollingUpgrade(ctx context.Context, sts *appsv1.StatefulSet, svc string, c kubernetes.Interface) (reconcile.Result, error) {
return rollingUpgrade(in.cp, in.scalingProbe, &PodNodeName{}, "NodeName", ctx, sts, svc, c)
}

func (in ByNodeUpgradeStrategy) IsOperatorManaged() bool {
Expand All @@ -116,8 +123,8 @@ type ByNodeLabelUpgradeStrategy struct {
label string
}

func (in ByNodeLabelUpgradeStrategy) RollingUpgrade(ctx context.Context, sts *appsv1.StatefulSet, c kubernetes.Interface) (reconcile.Result, error) {
return rollingUpgrade(in.cp, in.scalingProbe, &PodNodeLabel{Label: in.label}, in.label, ctx, sts, c)
func (in ByNodeLabelUpgradeStrategy) RollingUpgrade(ctx context.Context, sts *appsv1.StatefulSet, svc string, c kubernetes.Interface) (reconcile.Result, error) {
return rollingUpgrade(in.cp, in.scalingProbe, &PodNodeLabel{Label: in.label}, in.label, ctx, sts, svc, c)
}

func (in ByNodeLabelUpgradeStrategy) IsOperatorManaged() bool {
Expand Down Expand Up @@ -170,7 +177,7 @@ func (p *PodNodeLabel) GetNodeId(ctx context.Context, c kubernetes.Interface, po

// ----- helper methods ----------------------------------------------------------------------------

func rollingUpgrade(cp probe.CoherenceProbe, scalingProbe *coh.Probe, fn PodNodeIdSupplier, idName string, ctx context.Context, sts *appsv1.StatefulSet, c kubernetes.Interface) (reconcile.Result, error) {
func rollingUpgrade(cp probe.CoherenceProbe, scalingProbe *coh.Probe, fn PodNodeIdSupplier, idName string, ctx context.Context, sts *appsv1.StatefulSet, svc string, c kubernetes.Interface) (reconcile.Result, error) {
var err error
var replicas int32

Expand Down Expand Up @@ -263,7 +270,7 @@ func rollingUpgrade(cp probe.CoherenceProbe, scalingProbe *coh.Probe, fn PodNode
// We have Pods to be upgraded
nodeId, _ := fn.GetNodeId(ctx, c, pods.Items[0])
// Check Pods are "safe"
if cp.ExecuteProbeForSubSetOfPods(ctx, sts, scalingProbe, pods, podsToUpdate) {
if cp.ExecuteProbeForSubSetOfPods(ctx, sts, svc, scalingProbe, pods, podsToUpdate) {
// delete the Pods
log.Info("Upgrading all Pods for Node identifier", "Namespace", sts.Namespace, "Name", sts.Name, "NodeId", idName, "IdValue", nodeId, "Count", len(podsToUpdate.Items))
err = deletePods(ctx, podsToUpdate, c)
Expand Down
Loading
Loading