Skip to content

Commit 83a783d

Browse files
committed
feat: add status to the ModelValidation CRs, tracking pod and modelvalidations
Signed-off-by: Kevin Conner <[email protected]>
1 parent e9cb175 commit 83a783d

28 files changed

+3227
-63
lines changed

api/v1alpha1/modelvalidation_types.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"crypto/sha256"
21+
"fmt"
22+
2023
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2124
)
2225

@@ -69,15 +72,54 @@ type ModelValidationSpec struct {
6972
Config ValidationConfig `json:"config"`
7073
}
7174

75+
// PodTrackingInfo contains information about a tracked pod
76+
type PodTrackingInfo struct {
77+
// Name is the name of the pod
78+
Name string `json:"name"`
79+
// UID is the unique identifier of the pod
80+
UID string `json:"uid"`
81+
// InjectedAt is when the pod was injected
82+
InjectedAt metav1.Time `json:"injectedAt"`
83+
}
84+
7285
// ModelValidationStatus defines the observed state of ModelValidation
7386
type ModelValidationStatus struct {
7487
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
7588
// Important: Run "make" to regenerate code after modifying this file
7689
Conditions []metav1.Condition `json:"conditions,omitempty"`
90+
91+
// InjectedPodCount is the number of pods that have been injected with validation
92+
InjectedPodCount int32 `json:"injectedPodCount"`
93+
94+
// UninjectedPodCount is the number of pods that have the label but were not injected
95+
UninjectedPodCount int32 `json:"uninjectedPodCount"`
96+
97+
// OrphanedPodCount is the number of injected pods that reference this CR but are inconsistent
98+
OrphanedPodCount int32 `json:"orphanedPodCount"`
99+
100+
// AuthMethod indicates which authentication method is being used
101+
AuthMethod string `json:"authMethod,omitempty"`
102+
103+
// InjectedPods contains detailed information about injected pods
104+
InjectedPods []PodTrackingInfo `json:"injectedPods,omitempty"`
105+
106+
// UninjectedPods contains detailed information about pods that should have been injected but weren't
107+
UninjectedPods []PodTrackingInfo `json:"uninjectedPods,omitempty"`
108+
109+
// OrphanedPods contains detailed information about pods that are injected but inconsistent
110+
OrphanedPods []PodTrackingInfo `json:"orphanedPods,omitempty"`
111+
112+
// LastUpdated is the timestamp of the last status update
113+
LastUpdated metav1.Time `json:"lastUpdated,omitempty"`
77114
}
78115

79116
// +kubebuilder:object:root=true
80117
// +kubebuilder:subresource:status
118+
// +kubebuilder:printcolumn:name="Auth Method",type=string,JSONPath=`.status.authMethod`
119+
// +kubebuilder:printcolumn:name="Injected Pods",type=integer,JSONPath=`.status.injectedPodCount`
120+
// +kubebuilder:printcolumn:name="Uninjected Pods",type=integer,JSONPath=`.status.uninjectedPodCount`
121+
// +kubebuilder:printcolumn:name="Orphaned Pods",type=integer,JSONPath=`.status.orphanedPodCount`
122+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
81123

82124
// ModelValidation is the Schema for the modelvalidations API
83125
type ModelValidation struct {
@@ -97,6 +139,42 @@ type ModelValidationList struct {
97139
Items []ModelValidation `json:"items"`
98140
}
99141

142+
// GetAuthMethod returns the authentication method being used
143+
func (mv *ModelValidation) GetAuthMethod() string {
144+
if mv.Spec.Config.SigstoreConfig != nil {
145+
return "sigstore"
146+
} else if mv.Spec.Config.PkiConfig != nil {
147+
return "pki"
148+
} else if mv.Spec.Config.PrivateKeyConfig != nil {
149+
return "private-key"
150+
}
151+
return "unknown"
152+
}
153+
154+
// GetConfigHash returns a hash of the validation configuration for drift detection
155+
func (mv *ModelValidation) GetConfigHash() string {
156+
return mv.Spec.Config.GetConfigHash()
157+
}
158+
159+
// GetConfigHash returns a hash of the validation configuration for drift detection
160+
func (vc *ValidationConfig) GetConfigHash() string {
161+
hasher := sha256.New()
162+
163+
if vc.SigstoreConfig != nil {
164+
hasher.Write([]byte("sigstore"))
165+
hasher.Write([]byte(vc.SigstoreConfig.CertificateIdentity))
166+
hasher.Write([]byte(vc.SigstoreConfig.CertificateOidcIssuer))
167+
} else if vc.PkiConfig != nil {
168+
hasher.Write([]byte("pki"))
169+
hasher.Write([]byte(vc.PkiConfig.CertificateAuthority))
170+
} else if vc.PrivateKeyConfig != nil {
171+
hasher.Write([]byte("privatekey"))
172+
hasher.Write([]byte(vc.PrivateKeyConfig.KeyPath))
173+
}
174+
175+
return fmt.Sprintf("%x", hasher.Sum(nil))[:16] // Use first 16 chars for brevity
176+
}
177+
100178
func init() {
101179
SchemeBuilder.Register(&ModelValidation{}, &ModelValidationList{})
102180
}

api/v1alpha1/zz_generated.deepcopy.go

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

cmd/main.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222
"flag"
2323
"os"
2424
"path/filepath"
25+
"time"
2526

2627
"github.com/sigstore/model-validation-operator/internal/constants"
28+
"github.com/sigstore/model-validation-operator/internal/controller"
29+
"github.com/sigstore/model-validation-operator/internal/tracker"
2730
"github.com/sigstore/model-validation-operator/internal/utils"
2831
"github.com/sigstore/model-validation-operator/internal/webhooks"
2932
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -47,6 +50,16 @@ import (
4750
// +kubebuilder:scaffold:imports
4851
)
4952

53+
const (
54+
// Default configuration values for the status tracker
55+
defaultDebounceDuration = 500 * time.Millisecond
56+
defaultRetryBaseDelay = 100 * time.Millisecond
57+
defaultRetryMaxDelay = 16 * time.Second
58+
defaultRateLimitQPS = 10.0
59+
defaultRateLimitBurst = 100
60+
defaultStatusUpdateTimeout = 30 * time.Second
61+
)
62+
5063
var (
5164
scheme = runtime.NewScheme()
5265
setupLog = ctrl.Log.WithName("setup")
@@ -69,6 +82,14 @@ func main() {
6982
var secureMetrics bool
7083
var enableHTTP2 bool
7184
var tlsOpts []func(*tls.Config)
85+
86+
// Status tracker configuration
87+
var debounceDuration time.Duration
88+
var retryBaseDelay time.Duration
89+
var retryMaxDelay time.Duration
90+
var rateLimitQPS float64
91+
var rateLimitBurst int
92+
var statusUpdateTimeout time.Duration
7293
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
7394
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
7495
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
@@ -91,6 +112,20 @@ func main() {
91112
"MODEL_TRANSPARENCY_CLI_IMAGE",
92113
constants.ModelTransparencyCliImage,
93114
"Model transparency CLI image to be used.")
115+
116+
// Status tracker configuration flags
117+
flag.DurationVar(&debounceDuration, "debounce-duration", defaultDebounceDuration,
118+
"Time to wait for more changes before updating status")
119+
flag.DurationVar(&retryBaseDelay, "retry-base-delay", defaultRetryBaseDelay,
120+
"Base delay for exponential backoff retries")
121+
flag.DurationVar(&retryMaxDelay, "retry-max-delay", defaultRetryMaxDelay,
122+
"Maximum delay for exponential backoff retries")
123+
flag.Float64Var(&rateLimitQPS, "rate-limit-qps", defaultRateLimitQPS,
124+
"Overall rate limit for status updates (queries per second)")
125+
flag.IntVar(&rateLimitBurst, "rate-limit-burst", defaultRateLimitBurst,
126+
"Burst capacity for overall rate limit")
127+
flag.DurationVar(&statusUpdateTimeout, "status-update-timeout", defaultStatusUpdateTimeout,
128+
"Timeout for status update operations")
94129
opts := zap.Options{
95130
Development: true,
96131
}
@@ -246,6 +281,36 @@ func main() {
246281
Handler: interceptor,
247282
})
248283

284+
statusTracker := tracker.NewStatusTracker(mgr.GetClient(), tracker.StatusTrackerConfig{
285+
DebounceDuration: debounceDuration,
286+
RetryBaseDelay: retryBaseDelay,
287+
RetryMaxDelay: retryMaxDelay,
288+
RateLimitQPS: rateLimitQPS,
289+
RateLimitBurst: rateLimitBurst,
290+
StatusUpdateTimeout: statusUpdateTimeout,
291+
})
292+
defer statusTracker.Stop()
293+
294+
podReconciler := &controller.PodReconciler{
295+
Client: mgr.GetClient(),
296+
Scheme: mgr.GetScheme(),
297+
Tracker: statusTracker,
298+
}
299+
if err := podReconciler.SetupWithManager(mgr); err != nil {
300+
setupLog.Error(err, "unable to create pod controller")
301+
os.Exit(1)
302+
}
303+
304+
mvReconciler := &controller.ModelValidationReconciler{
305+
Client: mgr.GetClient(),
306+
Scheme: mgr.GetScheme(),
307+
Tracker: statusTracker,
308+
}
309+
if err := mvReconciler.SetupWithManager(mgr); err != nil {
310+
setupLog.Error(err, "unable to create ModelValidation controller")
311+
os.Exit(1)
312+
}
313+
249314
setupLog.Info("starting manager")
250315
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
251316
setupLog.Error(err, "problem running manager")

config/crd/bases/ml.sigstore.dev_modelvalidations.yaml

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,23 @@ spec:
1414
singular: modelvalidation
1515
scope: Namespaced
1616
versions:
17-
- name: v1alpha1
17+
- additionalPrinterColumns:
18+
- jsonPath: .status.authMethod
19+
name: Auth Method
20+
type: string
21+
- jsonPath: .status.injectedPodCount
22+
name: Injected Pods
23+
type: integer
24+
- jsonPath: .status.uninjectedPodCount
25+
name: Uninjected Pods
26+
type: integer
27+
- jsonPath: .status.orphanedPodCount
28+
name: Orphaned Pods
29+
type: integer
30+
- jsonPath: .metadata.creationTimestamp
31+
name: Age
32+
type: date
33+
name: v1alpha1
1834
schema:
1935
openAPIV3Schema:
2036
description: ModelValidation is the Schema for the modelvalidations API
@@ -89,6 +105,10 @@ spec:
89105
status:
90106
description: ModelValidationStatus defines the observed state of ModelValidation
91107
properties:
108+
authMethod:
109+
description: AuthMethod indicates which authentication method is being
110+
used
111+
type: string
92112
conditions:
93113
description: |-
94114
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
@@ -148,6 +168,98 @@ spec:
148168
- type
149169
type: object
150170
type: array
171+
injectedPodCount:
172+
description: InjectedPodCount is the number of pods that have been
173+
injected with validation
174+
format: int32
175+
type: integer
176+
injectedPods:
177+
description: InjectedPods contains detailed information about injected
178+
pods
179+
items:
180+
description: PodTrackingInfo contains information about a tracked
181+
pod
182+
properties:
183+
injectedAt:
184+
description: InjectedAt is when the pod was injected
185+
format: date-time
186+
type: string
187+
name:
188+
description: Name is the name of the pod
189+
type: string
190+
uid:
191+
description: UID is the unique identifier of the pod
192+
type: string
193+
required:
194+
- injectedAt
195+
- name
196+
- uid
197+
type: object
198+
type: array
199+
lastUpdated:
200+
description: LastUpdated is the timestamp of the last status update
201+
format: date-time
202+
type: string
203+
orphanedPodCount:
204+
description: OrphanedPodCount is the number of injected pods that
205+
reference this CR but are inconsistent
206+
format: int32
207+
type: integer
208+
orphanedPods:
209+
description: OrphanedPods contains detailed information about pods
210+
that are injected but inconsistent
211+
items:
212+
description: PodTrackingInfo contains information about a tracked
213+
pod
214+
properties:
215+
injectedAt:
216+
description: InjectedAt is when the pod was injected
217+
format: date-time
218+
type: string
219+
name:
220+
description: Name is the name of the pod
221+
type: string
222+
uid:
223+
description: UID is the unique identifier of the pod
224+
type: string
225+
required:
226+
- injectedAt
227+
- name
228+
- uid
229+
type: object
230+
type: array
231+
uninjectedPodCount:
232+
description: UninjectedPodCount is the number of pods that have the
233+
label but were not injected
234+
format: int32
235+
type: integer
236+
uninjectedPods:
237+
description: UninjectedPods contains detailed information about pods
238+
that should have been injected but weren't
239+
items:
240+
description: PodTrackingInfo contains information about a tracked
241+
pod
242+
properties:
243+
injectedAt:
244+
description: InjectedAt is when the pod was injected
245+
format: date-time
246+
type: string
247+
name:
248+
description: Name is the name of the pod
249+
type: string
250+
uid:
251+
description: UID is the unique identifier of the pod
252+
type: string
253+
required:
254+
- injectedAt
255+
- name
256+
- uid
257+
type: object
258+
type: array
259+
required:
260+
- injectedPodCount
261+
- orphanedPodCount
262+
- uninjectedPodCount
151263
type: object
152264
type: object
153265
served: true

0 commit comments

Comments
 (0)