Skip to content

Commit

Permalink
[#764] Check version when images are specified
Browse files Browse the repository at this point in the history
  • Loading branch information
brusdev committed Jan 2, 2024
1 parent 2703b3d commit af33131
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 46 deletions.
4 changes: 4 additions & 0 deletions api/v1beta1/activemqartemis_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,4 +741,8 @@ const (
ConfigAppliedConditionUnknownReason = "UnableToRetrieveStatus"
ConfigAppliedConditionOutOfSyncReason = "OutOfSync"
ConfigAppliedConditionNoJolokiaClientsAvailableReason = "NoJolokiaClientsAvailable"

BrokerVersionAlignedConditionType = "BrokerVersionAligned"
BrokerVersionAlignedConditionMatchReason = "VersionMatch"
BrokerVersionAlignedConditionMismatchReason = "VersionMismatch"
)
18 changes: 17 additions & 1 deletion controllers/activemqartemis_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func validate(customResource *brokerv1beta1.ActiveMQArtemis, client rtclient.Cli
}

if validationCondition.Status == metav1.ConditionTrue {
condition := common.ValidateBrokerVersion(customResource)
condition := common.ValidateBrokerImageVersion(customResource)
if condition != nil {
validationCondition = *condition
}
Expand Down Expand Up @@ -662,6 +662,10 @@ type statusOutOfSyncMissingKeyError struct {
cause string
}

type versionMismatchError struct {
cause string
}

func NewUnknownJolokiaError(err error) unknownJolokiaError {
return unknownJolokiaError{
err,
Expand Down Expand Up @@ -744,3 +748,15 @@ func (e *inSyncApplyError) ErrorApplyDetail(container string, reason string) {
e.detail[container] = reason
}
}

func NewVersionMismatchError(err error) versionMismatchError {
return versionMismatchError{err.Error()}
}

func (e versionMismatchError) Error() string {
return e.cause
}

func (e versionMismatchError) Requeue() bool {
return false
}
150 changes: 140 additions & 10 deletions controllers/activemqartemis_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,26 @@ var _ = Describe("artemis controller", func() {
candidate.Spec.DeploymentPlan.InitImage = "myrepo/my-init-image:1.0"
})

By("checking the CR gets status updated")
brokerKey := types.NamespacedName{Name: createdBrokerCr.Name, Namespace: createdBrokerCr.Namespace}
Eventually(func(g Gomega) {

g.Expect(k8sClient.Get(ctx, brokerKey, createdBrokerCr)).Should(Succeed())
g.Expect(meta.IsStatusConditionTrue(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)).Should(BeTrue())
}, timeout, interval).Should(Succeed())

CleanResource(brokerCr, brokerCr.Name, defaultNamespace)
})

It("version validation when version is loosly specified and images are explicitly specified", func() {
By("deploy a broker with images specified")
latestVersion := semver.MustParse(version.LatestVersion)
brokerCr, createdBrokerCr := DeployCustomBroker(defaultNamespace, func(candidate *brokerv1beta1.ActiveMQArtemis) {
candidate.Spec.Version = strconv.FormatUint(latestVersion.Major, 10)
candidate.Spec.DeploymentPlan.Image = "myrepo/my-image:1.0"
candidate.Spec.DeploymentPlan.InitImage = "myrepo/my-init-image:1.0"
})

By("checking the CR gets status updated")
brokerKey := types.NamespacedName{Name: createdBrokerCr.Name, Namespace: createdBrokerCr.Namespace}
Eventually(func(g Gomega) {
Expand All @@ -710,7 +730,7 @@ var _ = Describe("artemis controller", func() {
condition := meta.FindStatusCondition(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)
g.Expect(condition).NotTo(BeNil())
g.Expect(condition.Reason).To(Equal(brokerv1beta1.ValidConditionUnknownReason))
g.Expect(condition.Message).To(ContainSubstring(common.ImageVersionConflictMessage))
g.Expect(condition.Message).To(ContainSubstring(common.NotSupportedImageVersionMessage))
}, timeout, interval).Should(Succeed())

CleanResource(brokerCr, brokerCr.Name, defaultNamespace)
Expand Down Expand Up @@ -757,7 +777,7 @@ var _ = Describe("artemis controller", func() {
By("checking status has useful info on what the operator would deploy")
g.Expect(createdBrokerCr.Status.Version.Image).ShouldNot(BeEmpty())
g.Expect(createdBrokerCr.Status.Version.InitImage).Should(ContainSubstring("my"))
g.Expect(createdBrokerCr.Status.Version.BrokerVersion).Should(BeEmpty())
g.Expect(createdBrokerCr.Status.Version.BrokerVersion).ShouldNot(BeEmpty())

g.Expect(createdBrokerCr.Status.Upgrade.MajorUpdates).Should(BeFalse())
g.Expect(createdBrokerCr.Status.Upgrade.MinorUpdates).Should(BeFalse())
Expand Down Expand Up @@ -866,11 +886,16 @@ var _ = Describe("artemis controller", func() {
Eventually(func(g Gomega) {

g.Expect(k8sClient.Get(ctx, brokerKey, createdBrokerCr)).Should(Succeed())
g.Expect(meta.IsStatusConditionTrue(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)).Should(BeTrue())
g.Expect(meta.IsStatusConditionPresentAndEqual(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType, metav1.ConditionUnknown)).Should(BeTrue())

condition := meta.FindStatusCondition(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)
g.Expect(condition).NotTo(BeNil())
g.Expect(condition.Reason).To(Equal(brokerv1beta1.ValidConditionUnknownReason))
g.Expect(condition.Message).To(ContainSubstring(common.UnkonwonImageVersionMessage))

g.Expect(createdBrokerCr.Status.Version.Image).Should(ContainSubstring("my"))
g.Expect(createdBrokerCr.Status.Version.InitImage).Should(ContainSubstring("my"))
g.Expect(createdBrokerCr.Status.Version.BrokerVersion).Should(BeEmpty())
g.Expect(createdBrokerCr.Status.Version.BrokerVersion).ShouldNot(BeEmpty())

g.Expect(createdBrokerCr.Status.Upgrade.MajorUpdates).Should(BeFalse())
g.Expect(createdBrokerCr.Status.Upgrade.MinorUpdates).Should(BeFalse())
Expand Down Expand Up @@ -1078,12 +1103,7 @@ var _ = Describe("artemis controller", func() {

By("verifying unknown validation status but ok")

g.Expect(meta.IsStatusConditionPresentAndEqual(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType, metav1.ConditionUnknown)).Should(BeTrue())

condition := meta.FindStatusCondition(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)
g.Expect(condition).NotTo(BeNil())
g.Expect(condition.Reason).To(Equal(brokerv1beta1.ValidConditionUnknownReason))
g.Expect(condition.Message).To(ContainSubstring(common.ImageVersionConflictMessage))
g.Expect(meta.IsStatusConditionTrue(createdBrokerCr.Status.Conditions, brokerv1beta1.ValidConditionType)).Should(BeTrue())

}, existingClusterTimeout, existingClusterInterval).Should(Succeed())
}
Expand Down Expand Up @@ -5331,6 +5351,116 @@ var _ = Describe("artemis controller", func() {
})
})

Context("BrokerVersion", func() {

It("expect version match when version is loosly specified", func() {
By("By creating a crd with a floating version")
ctx := context.Background()
crd := generateArtemisSpec(defaultNamespace)

latestVersion := semver.MustParse(version.LatestVersion)
crd.Spec.Version = strconv.FormatUint(latestVersion.Major, 10)
Expect(k8sClient.Create(ctx, &crd)).Should(Succeed())

crdRef := types.NamespacedName{
Namespace: crd.Namespace,
Name: crd.Name,
}

if os.Getenv("USE_EXISTING_CLUSTER") == "true" {
createdCrd := &brokerv1beta1.ActiveMQArtemis{}

Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, crdRef, createdCrd)).Should(Succeed())

condition := meta.FindStatusCondition(createdCrd.Status.Conditions, brokerv1beta1.BrokerVersionAlignedConditionType)
g.Expect(condition).NotTo(BeNil())

g.Expect(condition.Status).To(Equal(metav1.ConditionTrue))

g.Expect(condition.Reason).Should(Equal(brokerv1beta1.BrokerVersionAlignedConditionMatchReason))
}, existingClusterTimeout, existingClusterInterval).Should(Succeed())
}

// cleanup
Expect(k8sClient.Delete(ctx, &crd)).Should(Succeed())
})

It("expect version match on latest version", func() {
By("By creating a crd with latest image and version")
ctx := context.Background()
crd := generateArtemisSpec(defaultNamespace)

crd.Spec.DeploymentPlan.Image = version.LatestKubeImage
crd.Spec.Version = version.LatestVersion
Expect(k8sClient.Create(ctx, &crd)).Should(Succeed())

crdRef := types.NamespacedName{
Namespace: crd.Namespace,
Name: crd.Name,
}

if os.Getenv("USE_EXISTING_CLUSTER") == "true" {
createdCrd := &brokerv1beta1.ActiveMQArtemis{}

Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, crdRef, createdCrd)).Should(Succeed())

condition := meta.FindStatusCondition(createdCrd.Status.Conditions, brokerv1beta1.BrokerVersionAlignedConditionType)
g.Expect(condition).NotTo(BeNil())

g.Expect(condition.Status).To(Equal(metav1.ConditionTrue))

g.Expect(condition.Reason).Should(Equal(brokerv1beta1.BrokerVersionAlignedConditionMatchReason))
}, existingClusterTimeout, existingClusterInterval).Should(Succeed())
}

// cleanup
Expect(k8sClient.Delete(ctx, &crd)).Should(Succeed())
})

It("expect error message on wrong image version", func() {
By("By creating a crd with latest image and wong version")
ctx := context.Background()
crd := generateArtemisSpec(defaultNamespace)

crd.Spec.DeploymentPlan.Image = version.LatestKubeImage
crd.Spec.Version = version.SupportedActiveMQArtemisVersions[0]
Expect(k8sClient.Create(ctx, &crd)).Should(Succeed())

crdRef := types.NamespacedName{
Namespace: crd.Namespace,
Name: crd.Name,
}

if os.Getenv("USE_EXISTING_CLUSTER") == "true" {
createdCrd := &brokerv1beta1.ActiveMQArtemis{}

Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, crdRef, createdCrd)).Should(Succeed())

brokerVersionAlignedCondition := meta.FindStatusCondition(createdCrd.Status.Conditions, brokerv1beta1.BrokerVersionAlignedConditionType)
g.Expect(brokerVersionAlignedCondition).NotTo(BeNil())

g.Expect(brokerVersionAlignedCondition.Status).To(Equal(metav1.ConditionUnknown))

g.Expect(brokerVersionAlignedCondition.Reason).Should(Equal(brokerv1beta1.BrokerVersionAlignedConditionMismatchReason))
g.Expect(brokerVersionAlignedCondition.Message).Should(ContainSubstring(crd.Spec.Version))
g.Expect(brokerVersionAlignedCondition.Message).Should(ContainSubstring(version.LatestVersion))

readyCondition := meta.FindStatusCondition(createdCrd.Status.Conditions, brokerv1beta1.ReadyConditionType)
g.Expect(readyCondition).NotTo(BeNil())

g.Expect(readyCondition.Status).To(Equal(metav1.ConditionTrue))
}, existingClusterTimeout, existingClusterInterval).Should(Succeed())
}

// cleanup
Expect(k8sClient.Delete(ctx, &crd)).Should(Succeed())
})

})

Context("LoggerProperties", Label("LoggerProperties-test"), func() {
It("logging configmap validation", func() {

Expand Down
81 changes: 74 additions & 7 deletions controllers/activemqartemis_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2526,7 +2526,11 @@ type brokerStatus struct {
}

type serverStatus struct {
Jaas jaasStatus `json:"jaas"`
Jaas jaasStatus `json:"jaas"`
State string `json:"state"`
Version string `json:"version"`
NodeId string `json:"nodeId"`
Uptime string `json:"uptime"`
}

type jaasStatus struct {
Expand Down Expand Up @@ -2558,6 +2562,19 @@ func ProcessBrokerStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Clie
return err.Requeue()
}

err = AssertBrokerImageVersion(cr, client, scheme)
if err == nil {
condition = metav1.Condition{
Type: brokerv1beta1.BrokerVersionAlignedConditionType,
Status: metav1.ConditionTrue,
Reason: brokerv1beta1.BrokerVersionAlignedConditionMatchReason,
}
} else {
condition = trapErrorAsCondition(err, brokerv1beta1.BrokerVersionAlignedConditionType)
retry = err.Requeue()
}
meta.SetStatusCondition(&cr.Status.Conditions, condition)

err = AssertBrokerPropertiesStatus(cr, client, scheme)
if err == nil {
condition = metav1.Condition{
Expand Down Expand Up @@ -2620,6 +2637,13 @@ func trapErrorAsCondition(err ArtemisError, conditionType string) metav1.Conditi
Reason: brokerv1beta1.ConfigAppliedConditionSynchedWithErrorReason,
Message: err.Error(),
}
case versionMismatchError:
condition = metav1.Condition{
Type: conditionType,
Status: metav1.ConditionUnknown,
Reason: brokerv1beta1.BrokerVersionAlignedConditionMismatchReason,
Message: err.Error(),
}
default:
condition = metav1.Condition{
Type: conditionType,
Expand Down Expand Up @@ -2664,7 +2688,7 @@ func AssertBrokerPropertiesStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtcl
return NewUnknownJolokiaError(err)
}

errorStatus := checkStatus(cr, client, secretProjection, func(BrokerStatus brokerStatus, FileName string) (propertiesStatus, bool) {
errorStatus := checkProjectionStatus(cr, client, secretProjection, func(BrokerStatus *brokerStatus, FileName string) (propertiesStatus, bool) {
current, present := BrokerStatus.BrokerConfigStatus.PropertiesStatus[FileName]
return current, present
})
Expand All @@ -2678,7 +2702,7 @@ func AssertBrokerPropertiesStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtcl
reqLogger.V(2).Info("error retrieving -bp extra mount resource. requeing")
return NewUnknownJolokiaError(err)
}
errorStatus = checkStatus(cr, client, secretProjection, func(BrokerStatus brokerStatus, FileName string) (propertiesStatus, bool) {
errorStatus = checkProjectionStatus(cr, client, secretProjection, func(BrokerStatus *brokerStatus, FileName string) (propertiesStatus, bool) {
current, present := BrokerStatus.BrokerConfigStatus.PropertiesStatus[FileName]
return current, present
})
Expand All @@ -2704,7 +2728,7 @@ func AssertJaasPropertiesStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclie
return NewUnknownJolokiaError(err)
}

statusError := checkStatus(cr, client, Projection, func(BrokerStatus brokerStatus, FileName string) (propertiesStatus, bool) {
statusError := checkProjectionStatus(cr, client, Projection, func(BrokerStatus *brokerStatus, FileName string) (propertiesStatus, bool) {
current, present := BrokerStatus.ServerStatus.Jaas.PropertiesStatus[FileName]
return current, present
})
Expand All @@ -2716,7 +2740,28 @@ func AssertJaasPropertiesStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclie
return statusError
}

func checkStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, secretProjection *projection, extractStatus func(BrokerStatus brokerStatus, FileName string) (propertiesStatus, bool)) ArtemisError {
func AssertBrokerImageVersion(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, scheme *runtime.Scheme) ArtemisError {
reqLogger := ctrl.Log.WithValues("ActiveMQArtemis Name", cr.Name)

// The ResolveBrokerVersionFromCR should never fail because validation succeeded
resolvedFullVersion, _ := common.ResolveBrokerVersionFromCR(cr)

statusError := checkStatus(cr, client, func(brokerStatus *brokerStatus, jk *jolokia_client.JkInfo) ArtemisError {

if brokerStatus.ServerStatus.Version != resolvedFullVersion {
err := errors.Errorf("broker version non aligned on pod %s-%s, the detected version [%s] doesn't match the spec.version [%s] resolved as [%s]",
namer.CrToSS(cr.Name), jk.Ordinal, brokerStatus.ServerStatus.Version, cr.Spec.Version, resolvedFullVersion)
reqLogger.V(1).Info(err.Error(), "status", brokerStatus, "tracked", cr.Spec.Version)
return NewVersionMismatchError(err)
}

return nil
})

return statusError
}

func checkStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, checkBrokerStatus func(BrokerStatus *brokerStatus, jk *jolokia_client.JkInfo) ArtemisError) ArtemisError {
reqLogger := ctrl.Log.WithValues("ActiveMQArtemis Name", cr.Name)

resource := types.NamespacedName{
Expand All @@ -2733,8 +2778,6 @@ func checkStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, secr
return NewJolokiaClientsNotFoundError(errors.New("Waiting for Jolokia Clients to become available"))
}

reqLogger.V(2).Info("in sync check", "projection", secretProjection)

for _, jk := range jks {
currentJson, err := jk.Artemis.GetStatus()

Expand All @@ -2753,8 +2796,25 @@ func checkStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, secr

reqLogger.V(2).Info("broker status", "ordinal", jk.Ordinal, "status", brokerStatus)

artemisError := checkBrokerStatus(&brokerStatus, jk)
if artemisError != nil {
return artemisError
}
}

return nil
}

func checkProjectionStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, secretProjection *projection, extractStatus func(BrokerStatus *brokerStatus, FileName string) (propertiesStatus, bool)) ArtemisError {
reqLogger := ctrl.Log.WithValues("ActiveMQArtemis Name", cr.Name)

reqLogger.V(2).Info("in sync check", "projection", secretProjection)

checkErr := checkStatus(cr, client, func(brokerStatus *brokerStatus, jk *jolokia_client.JkInfo) ArtemisError {

var current propertiesStatus
var present bool
var err error
missingKeys := []string{}
var applyError *inSyncApplyError = nil

Expand Down Expand Up @@ -2814,9 +2874,16 @@ func checkStatus(cr *brokerv1beta1.ActiveMQArtemis, client rtclient.Client, secr

// this oridinal is happy
secretProjection.Ordinals = append(secretProjection.Ordinals, jk.Ordinal)

return nil
})

if checkErr != nil {
return checkErr
}

reqLogger.V(1).Info("successfully synced with broker", "status", statusMessageFromProjection(secretProjection))

return nil
}

Expand Down
Loading

0 comments on commit af33131

Please sign in to comment.