Skip to content

Commit 4ffef10

Browse files
committed
feat: added success/failure stats
Signed-off-by: AlexsJones <[email protected]>
1 parent e1fbdc8 commit 4ffef10

File tree

12 files changed

+148
-126
lines changed

12 files changed

+148
-126
lines changed

api/v1alpha1/mutation_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ type MutationSpec struct {
3030
// Important: Run "make" to regenerate code after modifying this file
3131
SimilarityScore string `json:"similarityScore,omitempty"`
3232
ResourceGVK string `json:"resourceGVK,omitempty"`
33-
Resource corev1.ObjectReference `json:"resource,omitempty"`
34-
Result Result `json:"result,omitempty"`
33+
ResourceRef corev1.ObjectReference `json:"resource,omitempty"`
34+
ResultRef corev1.ObjectReference `json:"result,omitempty"`
3535
OriginConfiguration string `json:"originConfiguration,omitempty"`
3636
TargetConfiguration string `json:"targetConfiguration,omitempty"`
3737
}

api/v1alpha1/result_types.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const (
4141
AutoRemediationPhaseNotStarted AutoRemediationPhase = iota
4242
AutoRemediationPhaseInProgress
4343
AutoRemediationPhaseCompleted
44+
AutoRemediationPhaseSuccessful
4445
AutoRemediationPhaseFailed
4546
)
4647

@@ -65,12 +66,11 @@ type ResultStatus struct {
6566
Webhook string `json:"webhook,omitempty"`
6667
}
6768

68-
//+kubebuilder:object:root=true
69-
//+kubebuilder:subresource:status
70-
//+kubebuilder:printcolumn:name="Kind",type="string",JSONPath=".spec.kind",description="Kind"
71-
//+kubebuilder:printcolumn:name="Backend",type="string",JSONPath=".spec.backend",description="Backend"
72-
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age"
73-
69+
// +kubebuilder:object:root=true
70+
// +kubebuilder:subresource:status
71+
// +kubebuilder:printcolumn:name="Kind",type="string",JSONPath=".spec.kind",description="Kind"
72+
// +kubebuilder:printcolumn:name="Backend",type="string",JSONPath=".spec.backend",description="Backend"
73+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age"
7474
// Result is the Schema for the results API
7575
type Result struct {
7676
metav1.TypeMeta `json:",inline"`

api/v1alpha1/result_types_test.go

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var _ = Describe("The test cases for the K8sGPT CRDs result types", func() {
3232
var (
3333
ctx context.Context
3434
Namespace = "k8sGPT"
35-
Kind = "Result"
35+
Kind = "ResultRef"
3636
Unmasked = "This is unmasked"
3737
Masked = "This is masked"
3838
Text = "This is a failure"
@@ -79,59 +79,59 @@ var _ = Describe("The test cases for the K8sGPT CRDs result types", func() {
7979
ctx = context.Background()
8080
})
8181

82-
Context("Create a new Result object", func() {
83-
It("Should create a new Result object", func() {
82+
Context("Create a new ResultRef object", func() {
83+
It("Should create a new ResultRef object", func() {
8484
Expect(fakeClient.Create(ctx, &result)).Should(Succeed())
8585
})
8686
})
8787

88-
// Get the Result object
89-
Context("Get the Result object", func() {
90-
It("Should get the Result object", func() {
88+
// Get the ResultRef object
89+
Context("Get the ResultRef object", func() {
90+
It("Should get the ResultRef object", func() {
9191
Expect(fakeClient.Get(ctx, typeNamespace, &result)).Should(Succeed())
9292
})
93-
// Check the Result object's filed values
94-
It("Should check the Result object's filed values", func() {
93+
// Check the ResultRef object's filed values
94+
It("Should check the ResultRef object's filed values", func() {
9595
Expect(result.Spec.Kind).Should(Equal(Kind))
9696
Expect(result.Spec.Name).Should(Equal(Name))
9797
Expect(result.Spec.Error[0].Text).Should(Equal(Text))
9898
Expect(result.Spec.Details).Should(Equal(Details))
9999
Expect(result.Spec.ParentObject).Should(Equal(ParentObject))
100100
})
101101
})
102-
// Update the Result object
103-
Context("Update the Result object", func() {
104-
It("Should update the Result object", func() {
102+
// Update the ResultRef object
103+
Context("Update the ResultRef object", func() {
104+
It("Should update the ResultRef object", func() {
105105
result.Spec.Details = "This is a new result"
106106
Expect(fakeClient.Update(ctx, &result)).Should(Succeed())
107107
})
108-
// Check the Result object's filed values
109-
It("Should check the Result object's filed values", func() {
108+
// Check the ResultRef object's filed values
109+
It("Should check the ResultRef object's filed values", func() {
110110
Expect(result.Spec.Kind).Should(Equal(Kind))
111111
Expect(result.Spec.Name).Should(Equal(Name))
112112
Expect(result.Spec.Error[0].Text).Should(Equal(Text))
113113
Expect(result.Spec.Details).Should(Equal("This is a new result"))
114114
Expect(result.Spec.ParentObject).Should(Equal(ParentObject))
115115
})
116116
})
117-
// Get the Result object by list
118-
Context("Get the Result object by list", func() {
119-
It("Should get the Result object by list", func() {
117+
// Get the ResultRef object by list
118+
Context("Get the ResultRef object by list", func() {
119+
It("Should get the ResultRef object by list", func() {
120120
resultList := ResultList{}
121121
Expect(fakeClient.List(ctx, &resultList)).Should(Succeed())
122122
})
123-
// Check the length of Result object list
124-
It("Should check the length of Result object list", func() {
123+
// Check the length of ResultRef object list
124+
It("Should check the length of ResultRef object list", func() {
125125
Expect(len(result.Spec.Error)).Should(Equal(1))
126126
})
127127
})
128-
// delete the Result object
129-
Context("Delete the Result object", func() {
130-
It("Should delete the Result object", func() {
128+
// delete the ResultRef object
129+
Context("Delete the ResultRef object", func() {
130+
It("Should delete the ResultRef object", func() {
131131
Expect(fakeClient.Delete(ctx, &result)).Should(Succeed())
132132
})
133-
// Check the Result object has been deleted
134-
It("Should check the Result object has been deleted", func() {
133+
// Check the ResultRef object has been deleted
134+
It("Should check the ResultRef object has been deleted", func() {
135135
Expect(fakeClient.Get(ctx, typeNamespace, &result)).ShouldNot(Succeed())
136136
})
137137
})

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/core.k8sgpt.ai_mutations.yaml

Lines changed: 51 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -116,78 +116,66 @@ spec:
116116
resourceGVK:
117117
type: string
118118
result:
119-
description: Result is the Schema for the results API
119+
description: |-
120+
ObjectReference contains enough information to let you inspect or modify the referred object.
121+
---
122+
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
123+
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
124+
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
125+
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
126+
Those cannot be well described when embedded.
127+
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
128+
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
129+
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
130+
and the version of the actual struct is irrelevant.
131+
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
132+
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
133+
134+
135+
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
136+
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
120137
properties:
121138
apiVersion:
139+
description: API version of the referent.
140+
type: string
141+
fieldPath:
122142
description: |-
123-
APIVersion defines the versioned schema of this representation of an object.
124-
Servers should convert recognized schemas to the latest internal value, and
125-
may reject unrecognized values.
126-
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
143+
If referring to a piece of an object instead of an entire object, this string
144+
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
145+
For example, if the object reference is to a container within a pod, this would take on a value like:
146+
"spec.containers{name}" (where "name" refers to the name of the container that triggered
147+
the event) or if no container name is specified "spec.containers[2]" (container with
148+
index 2 in this pod). This syntax is chosen only to have some well-defined way of
149+
referencing a part of an object.
150+
TODO: this design is not final and this field is subject to change in the future.
127151
type: string
128152
kind:
129153
description: |-
130-
Kind is a string value representing the REST resource this object represents.
131-
Servers may infer this from the endpoint the client submits requests to.
132-
Cannot be updated.
133-
In CamelCase.
154+
Kind of the referent.
134155
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
135156
type: string
136-
metadata:
137-
type: object
138-
spec:
139-
description: ResultSpec defines the desired state of Result
140-
properties:
141-
autoRemediationStatus:
142-
properties:
143-
phase:
144-
description: Enum for Phase
145-
type: integer
146-
type: object
147-
backend:
148-
type: string
149-
details:
150-
type: string
151-
error:
152-
items:
153-
properties:
154-
sensitive:
155-
items:
156-
properties:
157-
masked:
158-
type: string
159-
unmasked:
160-
type: string
161-
type: object
162-
type: array
163-
text:
164-
type: string
165-
type: object
166-
type: array
167-
kind:
168-
type: string
169-
name:
170-
type: string
171-
parentObject:
172-
type: string
173-
required:
174-
- autoRemediationStatus
175-
- backend
176-
- details
177-
- error
178-
- kind
179-
- name
180-
- parentObject
181-
type: object
182-
status:
183-
description: ResultStatus defines the observed state of Result
184-
properties:
185-
lifecycle:
186-
type: string
187-
webhook:
188-
type: string
189-
type: object
157+
name:
158+
description: |-
159+
Name of the referent.
160+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
161+
type: string
162+
namespace:
163+
description: |-
164+
Namespace of the referent.
165+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
166+
type: string
167+
resourceVersion:
168+
description: |-
169+
Specific resourceVersion to which this reference is made, if any.
170+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
171+
type: string
172+
uid:
173+
description: |-
174+
UID of the referent.
175+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
176+
type: string
190177
type: object
178+
x-kubernetes-map-type: atomic
191179
similarityScore:
192180
description: |-
193181
INSERT ADDITIONAL SPEC FIELDS - desired state of cluster

internal/controller/k8sgpt/analysis_step.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (step *AnalysisStep) processRawResults(rawResults map[string]corev1alpha1.R
162162
if err != nil {
163163
return err
164164
}
165-
// Rather than using the raw corev1alpha.Result from the RPC, we log on the v1alpha.Result from KubeBuilder
165+
// Rather than using the raw corev1alpha.ResultRef from the RPC, we log on the v1alpha.ResultRef from KubeBuilder
166166
if step.enableResultLogging {
167167

168168
// check if result.spec.error is nil

internal/controller/k8sgpt/calculate_remediation_step.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
)
1717

1818
type eligibleResource struct {
19-
Result corev1alpha1.Result
19+
ResultRef corev1.ObjectReference
2020
ObjectRef corev1.ObjectReference
2121
GVK string
2222
OriginConfiguration string
@@ -54,13 +54,13 @@ func (step *calculateRemediationStep) execute(instance *K8sGPTInstance) (ctrl.Re
5454
for _, eligibleResource := range eligibleResources {
5555
mutation := corev1alpha1.Mutation{
5656
ObjectMeta: metav1.ObjectMeta{
57-
Name: eligibleResource.Result.Name,
57+
Name: eligibleResource.ResultRef.Name,
5858
Namespace: instance.K8sgptConfig.Namespace,
5959
},
6060
Spec: corev1alpha1.MutationSpec{
61-
Resource: eligibleResource.ObjectRef,
61+
ResourceRef: eligibleResource.ObjectRef,
6262
ResourceGVK: eligibleResource.GVK,
63-
Result: eligibleResource.Result,
63+
ResultRef: eligibleResource.ResultRef,
6464
OriginConfiguration: eligibleResource.OriginConfiguration,
6565
TargetConfiguration: "",
6666
},
@@ -69,14 +69,14 @@ func (step *calculateRemediationStep) execute(instance *K8sGPTInstance) (ctrl.Re
6969
},
7070
}
7171
// Check if the mutation exists, else create it
72-
mutationKey := client.ObjectKey{Namespace: instance.K8sgptConfig.Namespace, Name: eligibleResource.Result.Name}
72+
mutationKey := client.ObjectKey{Namespace: instance.K8sgptConfig.Namespace, Name: eligibleResource.ResultRef.Name}
7373
var existingMutation corev1alpha1.Mutation
7474
if err := instance.R.Get(instance.Ctx, mutationKey, &existingMutation); err != nil {
7575
if client.IgnoreNotFound(err) != nil {
76-
return instance.R.FinishReconcile(err, false, eligibleResource.Result.Name)
76+
return instance.R.FinishReconcile(err, false, eligibleResource.ResultRef.Name)
7777
}
7878
if err := instance.R.Create(instance.Ctx, &mutation); err != nil {
79-
return instance.R.FinishReconcile(err, false, eligibleResource.Result.Name)
79+
return instance.R.FinishReconcile(err, false, eligibleResource.ResultRef.Name)
8080
}
8181
}
8282
}
@@ -97,9 +97,14 @@ func (step *calculateRemediationStep) parseEligibleResources(instance *K8sGPTIns
9797
namespace := names[0]
9898
name := names[1]
9999
if len(names) != 2 {
100-
instance.logger.Error(fmt.Errorf("invalid resource name"), "unable to parse resource name", "Resource", item.Name)
100+
instance.logger.Error(fmt.Errorf("invalid resource name"), "unable to parse resource name", "ResourceRef", item.Name)
101101
continue
102102
}
103+
// create reference from the result
104+
resultRef, err := reference.GetReference(instance.R.Scheme, &item)
105+
if err != nil {
106+
k8sgptControllerLog.Error(err, "Unable to create reference for ResultRef", "Name", item.Name)
107+
}
103108
// Support Service/Ingress currently
104109
switch item.Spec.Kind {
105110
case "Service":
@@ -116,7 +121,7 @@ func (step *calculateRemediationStep) parseEligibleResources(instance *K8sGPTIns
116121
if err != nil {
117122
step.logger.Error(err, "unable to marshal Service to yaml", "Service", item.Name)
118123
}
119-
eligibleResources = append(eligibleResources, eligibleResource{Result: item, ObjectRef: *serviceRef, OriginConfiguration: string(yamlData),
124+
eligibleResources = append(eligibleResources, eligibleResource{ResultRef: *resultRef, ObjectRef: *serviceRef, OriginConfiguration: string(yamlData),
120125
GVK: serviceRef.GroupVersionKind().String()})
121126

122127
case "Ingress":
@@ -133,7 +138,7 @@ func (step *calculateRemediationStep) parseEligibleResources(instance *K8sGPTIns
133138
if err != nil {
134139
step.logger.Error(err, "unable to marshal Ingress to yaml", "Service", item.Name)
135140
}
136-
eligibleResources = append(eligibleResources, eligibleResource{Result: item, ObjectRef: *ingressRef, OriginConfiguration: string(yamlData),
141+
eligibleResources = append(eligibleResources, eligibleResource{ResultRef: *resultRef, ObjectRef: *ingressRef, OriginConfiguration: string(yamlData),
137142
GVK: ingressRef.GroupVersionKind().String()})
138143
}
139144
}

internal/controller/k8sgpt/k8sgpt_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (r *K8sGPTReconciler) FinishReconcile(err error, requeueImmediate bool, nam
146146
if requeueImmediate {
147147
interval = 0
148148
}
149-
k8sgptControllerLog.Info("Finished Reconciling k8sGPT with error: %s\n", err.Error())
149+
k8sgptControllerLog.Info("Finished Reconciling k8sGPT with error: %s\n", "error", err.Error())
150150
reconcileErrorCounter := r.MetricsBuilder.GetCounterVec("k8sgpt_reconcile_error_count")
151151
if reconcileErrorCounter != nil {
152152
reconcileErrorCounter.WithLabelValues(name).Inc()

0 commit comments

Comments
 (0)