Skip to content

Commit

Permalink
fix(metrics-operator): flush status when analysis is finished (#2122)
Browse files Browse the repository at this point in the history
Signed-off-by: realanna <anna.reale@dynatrace.com>
  • Loading branch information
RealAnna committed Sep 19, 2023
1 parent 38c8332 commit 276b609
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 0 deletions.
6 changes: 6 additions & 0 deletions metrics-operator/controllers/analysis/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ func (a *AnalysisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c

err = a.evaluateObjectives(ctx, res, analysisDef, analysis)

// if evaluation was successful remove the stored values
if err == nil {
analysis.Status.StoredValues = nil
err = a.updateStatus(ctx, analysis)
}

return ctrl.Result{}, err
}

Expand Down
55 changes: 55 additions & 0 deletions metrics-operator/controllers/analysis/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,61 @@ func TestAnalysisReconciler_Reconcile_BasicControlLoop(t *testing.T) {
}
}

func TestAnalysisReconciler_ExistingAnalysisStatusIsFlushedWhenEvaluationFinishes(t *testing.T) {
analysis, analysisDef, template, _ := getTestCRDs()

analysis.Status = metricsapi.AnalysisStatus{
StoredValues: map[string]metricsapi.ProviderResult{
"default": {
Objective: metricsapi.ObjectReference{
Name: "my-analysis-def",
Namespace: "default",
},
Value: "1",
},
},
}

mockFactory := func(ctx context.Context, analysisMoqParam *metricsapi.Analysis, obj []metricsapi.Objective, numWorkers int, c client.Client, log logr.Logger, namespace string) (context.Context, IAnalysisPool) {
mymock := fake.IAnalysisPoolMock{
DispatchAndCollectFunc: func(ctx context.Context) (map[string]metricsapi.ProviderResult, error) {
return map[string]metricsapi.ProviderResult{}, nil
},
}
return ctx, &mymock
}

fclient := fake2.NewClient(&analysis, &analysisDef, &template)
a := &AnalysisReconciler{
Client: fclient,
Scheme: fclient.Scheme(),
Log: testr.New(t),
MaxWorkers: 2,
NewWorkersPoolFactory: mockFactory,
IAnalysisEvaluator: &fakeEvaluator.IAnalysisEvaluatorMock{
EvaluateFunc: func(values map[string]metricsapi.ProviderResult, ad *metricsapi.AnalysisDefinition) metricstypes.AnalysisResult {
return metricstypes.AnalysisResult{Pass: true}
}},
}

req := controllerruntime.Request{
NamespacedName: types.NamespacedName{Namespace: "default", Name: "my-analysis"},
}

status := &metricsapi.AnalysisStatus{Raw: "{\"objectiveResults\":null,\"totalScore\":0,\"maximumScore\":0,\"pass\":true,\"warning\":false}", Pass: true}

got, err := a.Reconcile(context.TODO(), req)

require.Nil(t, err)
require.Equal(t, controllerruntime.Result{}, got)
resAnalysis := metricsapi.Analysis{}
err = fclient.Get(context.TODO(), req.NamespacedName, &resAnalysis)
require.Nil(t, err)
require.Nil(t, resAnalysis.Status.StoredValues)
require.Equal(t, *status, resAnalysis.Status)

}

func getTestCRDs() (metricsapi.Analysis, metricsapi.AnalysisDefinition, metricsapi.AnalysisValueTemplate, metricsapi.KeptnMetricsProvider) {
analysis := metricsapi.Analysis{
ObjectMeta: metav1.ObjectMeta{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: metrics.keptn.sh/v1alpha3
kind: Analysis
metadata:
name: analysis-sample
namespace: testy
spec:
analysisDefinition:
name: ed-my-proj-dev-svc1
status:
storedValues:
ready-testy:
objectiveReference:
name: ready
namespace: testy
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
apiVersion: v1
kind: Namespace
metadata:
name: testy
---
apiVersion: metrics.keptn.sh/v1alpha3
kind: AnalysisValueTemplate
metadata:
name: ready
namespace: testy
spec:
provider:
name: my-mocked-provider
namespace: testy
query: 'sum(kube_pod_container_status_ready{namespace="{{.ns}}"})'
---
apiVersion: metrics.keptn.sh/v1alpha3
kind: AnalysisDefinition
metadata:
name: ed-my-proj-dev-svc1
namespace: testy
spec:
objectives:
- analysisValueTemplateRef:
name: ready
namespace: testy
target:
failure:
lessThan:
fixedValue: 2
warning:
lessThan:
fixedValue: 3
weight: 1
keyObjective: false
totalScore:
passPercentage: 90
warningPercentage: 75
---
apiVersion: metrics.keptn.sh/v1alpha3
kind: Analysis
metadata:
name: analysis-sample
namespace: testy
spec:
timeframe:
from: 2023-09-14T07:33:19Z
to: 2023-09-14T07:33:19Z
args:
"ns": "keptn-lifecycle-toolkit-system"
analysisDefinition:
name: ed-my-proj-dev-svc1
namespace: testy
status:
storedValues:
my-provider-query-1:
objectiveReference:
name: objective-template-1
value: 1
errMsg: ""

---
apiVersion: metrics.keptn.sh/v1alpha3
kind: KeptnMetricsProvider
metadata:
name: my-mocked-provider
namespace: testy
spec:
type: prometheus
targetServer: "http://mockserver.testy.svc.cluster.local:1080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: metrics.keptn.sh/v1alpha3
kind: Analysis
metadata:
name: analysis-sample
namespace: testy
spec:
analysisDefinition:
name: ed-my-proj-dev-svc1
status:
pass: true
# yamllint disable-line rule:line-length
raw: '{"objectiveResults":[{"result":{"failResult":{"operator":{"lessThan":{"fixedValue":"2"}},"fulfilled":false},"warnResult":{"operator":{"lessThan":{"fixedValue":"3"}},"fulfilled":false},"warning":false,"pass":true},"value":4,"score":1}],"totalScore":1,"maximumScore":1,"pass":true,"warning":false}'
143 changes: 143 additions & 0 deletions test/integration/analysis-controller-existing-status/01-install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
apiVersion: v1
kind: Service
metadata:
name: mockserver
namespace: testy
spec:
ports:
- name: serviceport
port: 1080
protocol: TCP
targetPort: serviceport
selector:
app: mockserver
sessionAffinity: None
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: mockserver
name: mockserver
namespace: testy
spec:
replicas: 1
selector:
matchLabels:
app: mockserver
template:
metadata:
labels:
app: mockserver
name: mockserver
spec:
containers:
- env:
- name: MOCKSERVER_LOG_LEVEL
value: INFO
- name: SERVER_PORT
value: "1080"
image: mockserver/mockserver:mockserver-5.13.0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 10
initialDelaySeconds: 10
periodSeconds: 5
successThreshold: 1
tcpSocket:
port: serviceport
timeoutSeconds: 1
name: mockserver
ports:
- containerPort: 1080
name: serviceport
protocol: TCP
readinessProbe:
failureThreshold: 10
initialDelaySeconds: 2
periodSeconds: 2
successThreshold: 1
tcpSocket:
port: serviceport
timeoutSeconds: 1
volumeMounts:
- mountPath: /config
name: config-volume
- mountPath: /libs
name: libs-volume
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 420
name: mockserver-config
optional: true
name: config-volume
- configMap:
defaultMode: 420
name: mockserver-config
optional: true
name: libs-volume
---
kind: ConfigMap
apiVersion: v1
metadata:
name: mockserver-config
namespace: testy
data:
initializerJson.json: |-
[
{
"httpRequest": {
"path": "/api/v1/query_range",
"method": "POST"
},
"httpResponse": {
"body": {
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "metric-name",
"job": "",
"instance": ""
},
"values": [[1669714193.275, "4"]]
}
]
}
},
"statusCode": 200
}
}
]
mockserver.properties: |-
###############################
# MockServer & Proxy Settings #
###############################
# Socket & Port Settings
# socket timeout in milliseconds (default 120000)
mockserver.maxSocketTimeout=120000
# Certificate Generation
# dynamically generated CA key pair (if they don't already exist in
specified directory)
mockserver.dynamicallyCreateCertificateAuthorityCertificate=true
# save dynamically generated CA key pair in working directory
mockserver.directoryToSaveDynamicSSLCertificate=.
# certificate domain name (default "localhost")
mockserver.sslCertificateDomainName=localhost
# comma separated list of ip addresses for Subject Alternative Name domain
names (default empty list)
mockserver.sslSubjectAlternativeNameDomains=www.example.com,www.another.com
# comma separated list of ip addresses for Subject Alternative Name ips
(default empty list)
mockserver.sslSubjectAlternativeNameIps=127.0.0.1
# CORS
# enable CORS for MockServer REST API
mockserver.enableCORSForAPI=true
# enable CORS for all responses
mockserver.enableCORSForAllResponses=true
# Json Initialization
mockserver.initializationJsonPath=/config/initializerJson.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: kubectl delete ns testy

0 comments on commit 276b609

Please sign in to comment.