diff --git a/api/v1/runtimecomponent_types.go b/api/v1/runtimecomponent_types.go index cd05e1f9..583268d0 100644 --- a/api/v1/runtimecomponent_types.go +++ b/api/v1/runtimecomponent_types.go @@ -437,6 +437,7 @@ const ( StatusConditionTypeReconciled StatusConditionType = "Reconciled" StatusConditionTypeResourcesReady StatusConditionType = "ResourcesReady" StatusConditionTypeReady StatusConditionType = "Ready" + StatusConditionTypeWarning StatusConditionType = "Warning" // Status Endpoint Scopes StatusEndpointScopeExternal StatusEndpointScope = "External" @@ -462,6 +463,9 @@ type StatusVersions struct { // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",priority=0,description="Status of the component ready condition" // +kubebuilder:printcolumn:name="ReadyReason",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].reason",priority=1,description="Reason for the failure of component ready condition" // +kubebuilder:printcolumn:name="ReadyMessage",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message",priority=1,description="Failure message from component ready condition" +// +kubebuilder:printcolumn:name="Warning",type="string",JSONPath=".status.conditions[?(@.type=='Warning')].status",priority=0,description="Status of the component warning condition" +// +kubebuilder:printcolumn:name="WarningReason",type="string",JSONPath=".status.conditions[?(@.type=='Warning')].reason",priority=1,description="Reason for the failure of component warning condition" +// +kubebuilder:printcolumn:name="WarningMessage",type="string",JSONPath=".status.conditions[?(@.type=='Warning')].message",priority=1,description="Failure message from component warning condition" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",priority=0,description="Age of the resource" // +operator-sdk:csv:customresourcedefinitions:displayName="RuntimeComponent",resources={{Deployment,v1},{Service,v1},{StatefulSet,v1},{Route,v1},{HorizontalPodAutoscaler,v1},{ServiceAccount,v1},{Secret,v1},{NetworkPolicy,v1}} @@ -1140,6 +1144,22 @@ func (s *RuntimeComponentStatus) SetCondition(c common.StatusCondition) { } } +func (s *RuntimeComponentStatus) UnsetCondition(c common.StatusCondition) { + for i := range s.Conditions { + if s.Conditions[i].GetType() == c.GetType() { + // Found the condition to remove + if i+1 == len(s.Conditions) { + // the match is the last element, can just shorten by one + s.Conditions = s.Conditions[:i] + } else { + // there are more elements after the match. + s.Conditions = append(s.Conditions[:i], s.Conditions[i+1]) + } + return + } + } +} + func (s *RuntimeComponentStatus) GetReferences() common.StatusReferences { if s.References == nil { s.References = make(common.StatusReferences) @@ -1166,6 +1186,8 @@ func convertToCommonStatusConditionType(c StatusConditionType) common.StatusCond return common.StatusConditionTypeResourcesReady case StatusConditionTypeReady: return common.StatusConditionTypeReady + case StatusConditionTypeWarning: + return common.StatusConditionTypeWarning default: panic(c) } @@ -1179,6 +1201,8 @@ func convertFromCommonStatusConditionType(c common.StatusConditionType) StatusCo return StatusConditionTypeResourcesReady case common.StatusConditionTypeReady: return StatusConditionTypeReady + case common.StatusConditionTypeWarning: + return StatusConditionTypeWarning default: panic(c) } diff --git a/api/v1beta2/runtimecomponent_types.go b/api/v1beta2/runtimecomponent_types.go index 6be32cb5..f1824921 100644 --- a/api/v1beta2/runtimecomponent_types.go +++ b/api/v1beta2/runtimecomponent_types.go @@ -945,6 +945,10 @@ func (s *RuntimeComponentStatus) GetCondition(t common.StatusConditionType) comm } return nil } +func (s *RuntimeComponentStatus) UnsetCondition(c common.StatusCondition) { + // Intentional dummy + return +} // SetCondition ... func (s *RuntimeComponentStatus) SetCondition(c common.StatusCondition) { diff --git a/common/types.go b/common/types.go index ffaa55a8..7c8c141c 100644 --- a/common/types.go +++ b/common/types.go @@ -66,6 +66,7 @@ type BaseComponentStatus interface { GetConditions() []StatusCondition GetCondition(StatusConditionType) StatusCondition SetCondition(StatusCondition) + UnsetCondition(StatusCondition) NewCondition(StatusConditionType) StatusCondition GetStatusEndpoint(string) StatusEndpoint @@ -89,6 +90,7 @@ const ( StatusConditionTypeReconciled StatusConditionType = "Reconciled" StatusConditionTypeResourcesReady StatusConditionType = "ResourcesReady" StatusConditionTypeReady StatusConditionType = "Ready" + StatusConditionTypeWarning StatusConditionType = "Warning" // Status Condition Type Messages StatusConditionTypeReadyMessage string = "Application is reconciled and resources are ready." diff --git a/utils/reconciler.go b/utils/reconciler.go index 9565db01..8f57a8d5 100644 --- a/utils/reconciler.go +++ b/utils/reconciler.go @@ -175,6 +175,29 @@ func (r *ReconcilerBase) GetOpConfigMap(name string, ns string) (*corev1.ConfigM return configMap, nil } +func addStatusWarnings(ba common.BaseComponent) { + + s := ba.GetStatus() + + mtls := ba.GetManageTLS() + svc := ba.GetService() + if (mtls == nil || *mtls == true) && svc != nil && svc.GetPort() == 9080 { + status := corev1.ConditionTrue + msg := "ManageTLS is true but port is set to 9080" + statusCondition := s.NewCondition(common.StatusConditionTypeWarning) + statusCondition.SetReason("") + statusCondition.SetMessage(msg) + statusCondition.SetStatus(status) + s.SetCondition(statusCondition) + } else { + // The warning condition may previously have been set, but is now not needed. + // Removing the warning is clearer than have a warning condition set to 'false' + statusCondition := s.NewCondition(common.StatusConditionTypeWarning) + s.UnsetCondition(statusCondition) + } + +} + // ManageError ... func (r *ReconcilerBase) ManageError(issue error, conditionType common.StatusConditionType, ba common.BaseComponent) (reconcile.Result, error) { s := ba.GetStatus() @@ -191,6 +214,8 @@ func (r *ReconcilerBase) ManageError(issue error, conditionType common.StatusCon newCondition.SetStatus(corev1.ConditionFalse) s.SetCondition(newCondition) + addStatusWarnings(ba) + if conditionType != common.StatusConditionTypeResourcesReady { //Check Application status (reconciliation & resource status & endpoint status) r.CheckApplicationStatus(ba) @@ -247,6 +272,8 @@ func (r *ReconcilerBase) ManageSuccess(conditionType common.StatusConditionType, statusCondition.SetStatus(corev1.ConditionTrue) s.SetCondition(statusCondition) + addStatusWarnings(ba) + //Check application status (reconciliation & resource status & endpoint status) readyStatus := r.CheckApplicationStatus(ba) diff --git a/utils/reconciler_test.go b/utils/reconciler_test.go index ec10857f..03c65d60 100644 --- a/utils/reconciler_test.go +++ b/utils/reconciler_test.go @@ -454,6 +454,48 @@ func TestGetRouteTLSValues(t *testing.T) { testGetRouteTLSValues(t) } +func TestAddStatusWarnings(t *testing.T) { + testData := []Test{} + tr := true + fl := false + svc := appstacksv1.RuntimeComponentService{Port: 9080} + spec := appstacksv1.RuntimeComponentSpec{Service: &svc} + comp := createRuntimeComponent(name, namespace, spec) + + // manageTLS is implicitly true, service port 9080 + addStatusWarnings(comp) + status := comp.GetStatus() + c := status.GetConditions() + testData = append(testData, Test{test: "serviceport=9080, condition type should be warning", actual: c[0].GetType(), expected: common.StatusConditionTypeWarning}) + + // manageTLS is implicitly true, Service is nil + comp.Spec.Service = nil + addStatusWarnings(comp) + testData = append(testData, Test{test: "service=nil, length of conditions should be zero", actual: len(comp.GetStatus().GetConditions()), expected: 0}) + + // manageTLS is explicitly true, service is nil + comp.Spec.ManageTLS = &tr + addStatusWarnings(comp) + testData = append(testData, Test{test: "manageTLS=true, service=nil, length of conditions should be zero", actual: len(comp.GetStatus().GetConditions()), expected: 0}) + + // manageTLS is explicitly true, service port is 9080 + comp.Spec.Service = &svc + addStatusWarnings(comp) + testData = append(testData, Test{test: "mangeTLS=true, serviceport=9080, condition type should be warning", actual: comp.GetStatus().GetConditions()[0].GetType(), expected: common.StatusConditionTypeWarning}) + + // manageTLS is explicitly false, service port is 9080 + comp.Spec.ManageTLS = &fl + addStatusWarnings(comp) + testData = append(testData, Test{test: "mangeTLS=false, serviceport=9080, length of conditions should be zero", actual: len(comp.GetStatus().GetConditions()), expected: 0}) + + // manageTLS is explicitly false, service port is 9443 + svc.Port = 9443 + addStatusWarnings(comp) + testData = append(testData, Test{test: "mangeTLS=false, serviceport=9443, length of conditions should be zero", actual: len(comp.GetStatus().GetConditions()), expected: 0}) + + verifyTests(testData, t) +} + func createFakeDiscoveryClient() discovery.DiscoveryInterface { fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}} fakeDiscoveryClient.Resources = []*metav1.APIResourceList{