mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { EventEmitter } from 'eventemitter3';
|
|
import equal from 'deep-equal';
|
|
|
|
import type { CustomResource } from './custom-resources.custom-resource.ts';
|
|
import type { CustomResourceStatus } from './custom-resources.types.ts';
|
|
|
|
type CustomResourceStatusOptions = {
|
|
resource: CustomResource<ExpectedAny>;
|
|
};
|
|
|
|
type CustomResourceConditionsEvents = {
|
|
changed: (type: string, condition: Condition) => void;
|
|
};
|
|
|
|
type Condition = {
|
|
lastTransitionTime: Date;
|
|
status: 'True' | 'False' | 'Unknown';
|
|
syncing?: boolean;
|
|
failed?: boolean;
|
|
resource?: boolean;
|
|
reason?: string;
|
|
message?: string;
|
|
observedGeneration?: number;
|
|
};
|
|
|
|
class CustomResourceConditions extends EventEmitter<CustomResourceConditionsEvents> {
|
|
#options: CustomResourceStatusOptions;
|
|
#conditions: Record<string, Condition>;
|
|
|
|
constructor(options: CustomResourceStatusOptions) {
|
|
super();
|
|
this.#options = options;
|
|
this.#conditions = Object.fromEntries(
|
|
(options.resource.status?.conditions || []).map(({ type, lastTransitionTime, ...condition }) => [
|
|
type,
|
|
{
|
|
...condition,
|
|
lastTransitionTime: new Date(lastTransitionTime),
|
|
},
|
|
]),
|
|
);
|
|
options.resource.on('changed', this.#handleChange);
|
|
}
|
|
|
|
#handleChange = () => {
|
|
const { resource } = this.#options;
|
|
for (const { type, ...condition } of resource.status?.conditions || []) {
|
|
const next = {
|
|
...condition,
|
|
lastTransitionTime: new Date(condition.lastTransitionTime),
|
|
};
|
|
const current = this.#conditions[type];
|
|
const isEqual = equal(current, next);
|
|
const isNewer = !current || next.lastTransitionTime > current.lastTransitionTime;
|
|
if (isEqual || !isNewer) {
|
|
return;
|
|
}
|
|
this.#conditions[type] = next;
|
|
this.emit('changed', type, next);
|
|
}
|
|
};
|
|
|
|
public get = (type: string): Condition | undefined => {
|
|
return this.#conditions[type];
|
|
};
|
|
|
|
public set = async (type: string, condition: Omit<Condition, 'lastTransitionTime'>) => {
|
|
const current = this.#conditions[type];
|
|
this.#conditions[type] = {
|
|
...condition,
|
|
|
|
lastTransitionTime: current && current.status === condition.status ? current.lastTransitionTime : new Date(),
|
|
observedGeneration: this.#options.resource.metadata?.generation,
|
|
};
|
|
await this.save();
|
|
};
|
|
|
|
public save = async () => {
|
|
const { resource } = this.#options;
|
|
const status: CustomResourceStatus = {
|
|
conditions: Object.entries(this.#conditions).map(([type, condition]) => ({
|
|
...condition,
|
|
type,
|
|
lastTransitionTime: condition.lastTransitionTime.toISOString(),
|
|
})),
|
|
};
|
|
await resource.patchStatus(status);
|
|
};
|
|
}
|
|
|
|
export { CustomResourceConditions };
|