Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bed6401
Added changeAnnotation method
tgarg-splunk Jun 14, 2023
7de6f36
Refined changeClusterManagerAnnotations
tgarg-splunk Jun 15, 2023
f4453a1
test case for upgrade scenario
vivekr-splunk Jun 15, 2023
32c385d
Modified kuttl cases
tgarg-splunk Jun 21, 2023
8efb456
Added kuttl tests; Updated LicenseMaster
tgarg-splunk Jun 22, 2023
3c75c99
Fixed uninstall kuttl test
tgarg-splunk Jun 22, 2023
ee474fc
Fixed unit test
tgarg-splunk Jun 22, 2023
35a2eb0
Removed changeAnnotation from licenseMaster
tgarg-splunk Jun 23, 2023
d9540fd
Added branch in int-tests
tgarg-splunk Jun 23, 2023
5a17a5f
Completed code coverage tests
tgarg-splunk Jun 26, 2023
706dc96
Added upgradeScenario and related methods for CM
tgarg-splunk Jun 15, 2023
c5af670
Added label selectors to get Current Image
tgarg-splunk Jun 15, 2023
237ecdf
Changed pod.Spec to pod.Status
tgarg-splunk Jun 15, 2023
5966d87
Added changeAnnotations for MC
tgarg-splunk Jun 21, 2023
b827bd9
Added kuttl test cases
tgarg-splunk Jun 22, 2023
a1159a8
Fixed unit test
tgarg-splunk Jun 23, 2023
3aa032b
Fixed SmartStore unit test
tgarg-splunk Jun 23, 2023
f0e73c8
Added code coverage test
tgarg-splunk Jun 26, 2023
53f6f68
using fake client instead of mock
vivekr-splunk Jun 27, 2023
8301fd9
removed creating statefulset and service
vivekr-splunk Jun 27, 2023
8353d25
Corrected LMCurrentImage method
tgarg-splunk Jun 26, 2023
dab93db
Completed Coverage tests for CM
tgarg-splunk Jun 27, 2023
fb77880
Refined changeClusterManagerAnnotations
tgarg-splunk Jun 15, 2023
b6c70d5
test case for upgrade scenario
vivekr-splunk Jun 15, 2023
6957966
Modified kuttl cases
tgarg-splunk Jun 21, 2023
70c73c2
Added kuttl tests; Updated LicenseMaster
tgarg-splunk Jun 22, 2023
4a945eb
Fixed unit test
tgarg-splunk Jun 22, 2023
a2c9f6d
Removed changeAnnotation from licenseMaster
tgarg-splunk Jun 23, 2023
86baa21
Completed code coverage tests
tgarg-splunk Jun 26, 2023
b24fca7
Resolved all conflict issues
tgarg-splunk Jun 28, 2023
1d0cc57
Added comments
tgarg-splunk Jun 28, 2023
10cc0b6
Updated upgradeScenario to check if statefulSet exists
tgarg-splunk Jun 30, 2023
27ddd67
Fixed Unit tests
tgarg-splunk Jun 30, 2023
0378e94
Added common APIs, changed upgrade condition
tgarg-splunk Jul 10, 2023
a116e9c
Added only warning if annotation not found
tgarg-splunk Jul 10, 2023
3695b41
Add warning
tgarg-splunk Jul 10, 2023
80e6acc
Updated upgradeCondition
tgarg-splunk Jul 11, 2023
3db7d4c
updated changeAnnotation to work with no ref
tgarg-splunk Jul 11, 2023
1c1531a
Fixed unit tests
tgarg-splunk Jul 11, 2023
f9c171f
Handled not found error
tgarg-splunk Jul 11, 2023
e2e4433
Removed blank lines; handled errors in changeAnnotation
tgarg-splunk Jul 12, 2023
fe1d66f
Only call changeAnnotation if LM is ready
tgarg-splunk Jul 12, 2023
4515880
Removed redundant checks
tgarg-splunk Jul 12, 2023
b2d7bc1
Return if CM list is empty
tgarg-splunk Jul 13, 2023
0d178a1
removed superfluous nil err check
tgarg-splunk Jul 13, 2023
77f9a74
Removed branch from workflow
tgarg-splunk Jul 14, 2023
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
10 changes: 10 additions & 0 deletions kuttl/kuttl-test-helm-upgrade.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Entrypoint for helm automation
apiVersion: kuttl.dev/v1beta1
kind: TestSuite
testDirs:
- ./kuttl/tests/upgrade
parallel: 3
timeout: 5000
startKIND: false
artifactsDir: kuttl-artifacts
kindNodeCache: false
9 changes: 9 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/00-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# assert for splunk operator deployment to be ready
apiVersion: apps/v1
kind: Deployment
metadata:
name: splunk-operator-controller-manager
status:
readyReplicas: 1
availableReplicas: 1
6 changes: 6 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/00-install-c3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: helm install splunk-c3 $HELM_REPO_PATH/splunk-enterprise -f c3_config.yaml --set splunk-operator.splunkOperator.image.repository=${KUTTL_SPLUNK_OPERATOR_IMAGE} --set splunk-operator.image.repository=${KUTTL_SPLUNK_ENTERPRISE_IMAGE} --namespace ${NAMESPACE}
namespaced: true
9 changes: 9 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/01-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# assert for splunk operator pod to be ready
apiVersion: apps/v1
kind: Deployment
metadata:
name: splunk-operator-controller-manager
status:
readyReplicas: 1
availableReplicas: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: helm upgrade splunk-c3 $HELM_REPO_PATH/splunk-enterprise --reuse-values -f c3_config.yaml --set splunk-operator.splunkOperator.image.repository=${KUTTL_SPLUNK_OPERATOR_IMAGE} --set splunk-operator.image.repository=${KUTTL_SPLUNK_ENTERPRISE_NEW_IMAGE} --namespace ${NAMESPACE}
namespaced: true
24 changes: 24 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/02-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
# assert for cluster manager custom resource to be ready
apiVersion: enterprise.splunk.com/v4
kind: ClusterManager
metadata:
name: cm
status:
phase: Ready

---
# check if stateful sets are created
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: splunk-cm-cluster-manager
status:
replicas: 1

---
# check if secret object are created
apiVersion: v1
kind: Secret
metadata:
name: splunk-cm-cluster-manager-secret-v1
40 changes: 40 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/03-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
# assert for SearchHeadCluster custom resource to be ready
apiVersion: enterprise.splunk.com/v4
kind: SearchHeadCluster
metadata:
name: shc
status:
phase: Ready

---
# check if secret object are created
apiVersion: v1
kind: Secret
metadata:
name: splunk-shc-deployer-secret-v1

---
# check if secret object are created
apiVersion: v1
kind: Secret
metadata:
name: splunk-shc-search-head-secret-v1

---
# check for stateful set and replicas as configured
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: splunk-shc-search-head
status:
replicas: 3

---
# check for statefull set
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: splunk-shc-deployer
status:
replicas: 1
24 changes: 24 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/04-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
# assert for indexer cluster custom resource to be ready
apiVersion: enterprise.splunk.com/v4
kind: IndexerCluster
metadata:
name: idxc
status:
phase: Ready

---
# check for stateful set and replicas as configured
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: splunk-idxc-indexer
status:
replicas: 3

---
# check if secret object are created
apiVersion: v1
kind: Secret
metadata:
name: splunk-idxc-indexer-secret-v1
5 changes: 5 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/05-uninstall-c3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: helm uninstall splunk-c3 --namespace ${NAMESPACE}
namespaced: true
50 changes: 50 additions & 0 deletions kuttl/tests/upgrade/c3-with-operator/c3_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
splunk-operator:
enabled: true
splunkOperator:
clusterWideAccess: false

sva:
c3:
enabled: true

clusterManager:
name: cm

indexerClusters:
- name: idxc

searchHeadClusters:
- name: shc


indexerCluster:
enabled: true

additionalLabels:
label: "true"

additionalAnnotations:
annotation: "true"
service.beta.kubernetes.io/azure-load-balancer-internal: "true"

serviceTemplate:
spec:
type: LoadBalancer

clusterManager:
enabled: true

additionalLabels:
label: "true"

additionalAnnotations:
annotation: "true"

searchHeadCluster:
enabled: true

additionalLabels:
label: "true"

additionalAnnotations:
annotation: "true"
138 changes: 138 additions & 0 deletions pkg/splunk/enterprise/clustermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

enterpriseApi "github.com/splunk/splunk-operator/api/v4"
"sigs.k8s.io/controller-runtime/pkg/client"
rclient "sigs.k8s.io/controller-runtime/pkg/client"

"github.com/go-logr/logr"
splclient "github.com/splunk/splunk-operator/pkg/splunk/client"
Expand All @@ -31,6 +32,8 @@ import (
splutil "github.com/splunk/splunk-operator/pkg/splunk/util"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"

"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand Down Expand Up @@ -177,6 +180,12 @@ func ApplyClusterManager(ctx context.Context, client splcommon.ControllerClient,
return result, err
}

// check if the ClusterManager is ready for version upgrade, if required
continueReconcile, err := isClusterManagerReadyForUpgrade(ctx, client, cr)
if err != nil || !continueReconcile {
return result, err
}

clusterManagerManager := splctrl.DefaultStatefulSetPodManager{}
phase, err := clusterManagerManager.Update(ctx, client, statefulSet, 1)
if err != nil {
Expand Down Expand Up @@ -434,3 +443,132 @@ func VerifyCMisMultisite(ctx context.Context, cr *enterpriseApi.ClusterManager,
}
return extraEnv, err
}

// isClusterManagerReadyForUpgrade checks if ClusterManager can be upgraded if a version upgrade is in-progress
// No-operation otherwise; returns bool, err accordingly
func isClusterManagerReadyForUpgrade(ctx context.Context, c splcommon.ControllerClient, cr *enterpriseApi.ClusterManager) (bool, error) {
reqLogger := log.FromContext(ctx)
scopedLog := reqLogger.WithName("isClusterManagerReadyForUpgrade").WithValues("name", cr.GetName(), "namespace", cr.GetNamespace())
eventPublisher, _ := newK8EventPublisher(c, cr)

// check if a LicenseManager is attached to the instance
licenseManagerRef := cr.Spec.LicenseManagerRef
if licenseManagerRef.Name == "" {
return true, nil
}

namespacedName := types.NamespacedName{
Namespace: cr.GetNamespace(),
Name: GetSplunkStatefulsetName(SplunkClusterManager, cr.GetName()),
}

// check if the stateful set is created at this instance
statefulSet := &appsv1.StatefulSet{}
err := c.Get(ctx, namespacedName, statefulSet)
if err != nil && k8serrors.IsNotFound(err) {
return true, nil
}

namespacedName = types.NamespacedName{Namespace: cr.GetNamespace(), Name: licenseManagerRef.Name}
licenseManager := &enterpriseApi.LicenseManager{}

// get the license manager referred in cluster manager
err = c.Get(ctx, namespacedName, licenseManager)
if err != nil {
if k8serrors.IsNotFound(err) {
return true, nil
}
eventPublisher.Warning(ctx, "isClusterManagerReadyForUpgrade", fmt.Sprintf("Could not find the License Manager. Reason %v", err))
scopedLog.Error(err, "Unable to get licenseManager")
return false, err
}

lmImage, err := getCurrentImage(ctx, c, cr, SplunkLicenseManager)
if err != nil {
eventPublisher.Warning(ctx, "isClusterManagerReadyForUpgrade", fmt.Sprintf("Could not get the License Manager Image. Reason %v", err))
scopedLog.Error(err, "Unable to get licenseManager current image")
return false, err
}

cmImage, err := getCurrentImage(ctx, c, cr, SplunkClusterManager)
if err != nil {
eventPublisher.Warning(ctx, "isClusterManagerReadyForUpgrade", fmt.Sprintf("Could not get the Cluster Manager Image. Reason %v", err))
scopedLog.Error(err, "Unable to get clusterManager current image")
return false, err
}

// check if an image upgrade is happening and whether the ClusterManager is ready for the upgrade
if (cr.Spec.Image != cmImage) && (licenseManager.Status.Phase != enterpriseApi.PhaseReady || lmImage != cr.Spec.Image) {
return false, nil
}

return true, nil
}

// changeClusterManagerAnnotations updates the splunk/image-tag field of the ClusterManager annotations to trigger the reconcile loop
// on update, and returns error if something is wrong
func changeClusterManagerAnnotations(ctx context.Context, c splcommon.ControllerClient, cr *enterpriseApi.LicenseManager) error {
reqLogger := log.FromContext(ctx)
scopedLog := reqLogger.WithName("changeClusterManagerAnnotations").WithValues("name", cr.GetName(), "namespace", cr.GetNamespace())
eventPublisher, _ := newK8EventPublisher(c, cr)

clusterManagerInstance := &enterpriseApi.ClusterManager{}
if len(cr.Spec.ClusterManagerRef.Name) > 0 {
// if the LicenseManager holds the ClusterManagerRef
namespacedName := types.NamespacedName{
Namespace: cr.GetNamespace(),
Name: cr.Spec.ClusterManagerRef.Name,
}
err := c.Get(ctx, namespacedName, clusterManagerInstance)
if err != nil {
if k8serrors.IsNotFound(err) {
return nil
}
return err
}
} else {
// List out all the ClusterManager instances in the namespace
opts := []rclient.ListOption{
rclient.InNamespace(cr.GetNamespace()),
}
objectList := enterpriseApi.ClusterManagerList{}
err := c.List(ctx, &objectList, opts...)
if err != nil {
if err.Error() == "NotFound" {
return nil
}
return err
}

if len(objectList.Items) == 0 {
return nil
}

// check if instance has the required LicenseManagerRef
for _, cm := range objectList.Items {
if cm.Spec.LicenseManagerRef.Name == cr.GetName() {
clusterManagerInstance = &cm
break
}
}

if len(clusterManagerInstance.GetName()) == 0 {
return nil
}
}

image, err := getCurrentImage(ctx, c, cr, SplunkLicenseManager)
if err != nil {
eventPublisher.Warning(ctx, "changeClusterManagerAnnotations", fmt.Sprintf("Could not get the LicenseManager Image. Reason %v", err))
scopedLog.Error(err, "Get LicenseManager Image failed with", "error", err)
return err
}
err = changeAnnotations(ctx, c, image, clusterManagerInstance)
if err != nil {
eventPublisher.Warning(ctx, "changeClusterManagerAnnotations", fmt.Sprintf("Could not update annotations. Reason %v", err))
scopedLog.Error(err, "ClusterManager types update after changing annotations failed with", "error", err)
return err
}

return nil
}
Loading