Skip to content

Commit 49a2f56

Browse files
committed
frontend: workloads: Validate explicit rollback targets and cache history
1 parent 114f039 commit 49a2f56

File tree

3 files changed

+66
-24
lines changed

3 files changed

+66
-24
lines changed

frontend/src/lib/k8s/daemonSet.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
4848
static apiName = 'daemonsets';
4949
static apiVersion = 'apps/v1';
5050
static isNamespaced = true;
51+
private revisionHistoryCache?: { resourceVersion?: string; history: RevisionInfo[] };
5152

5253
get spec() {
5354
return this.jsonData.spec;
@@ -156,13 +157,6 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
156157
.filter(rev => rev.revision > 0)
157158
.sort((a, b) => b.revision - a.revision);
158159

159-
if (sortedRevisions.length < 2) {
160-
return {
161-
success: false,
162-
message: 'No previous revision available to rollback to',
163-
};
164-
}
165-
166160
// Find target revision: specific or previous (second in sorted list)
167161
let targetRev;
168162
if (toRevision !== undefined && toRevision > 0) {
@@ -180,6 +174,12 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
180174
};
181175
}
182176
} else {
177+
if (sortedRevisions.length < 2) {
178+
return {
179+
success: false,
180+
message: 'No previous revision available to rollback to',
181+
};
182+
}
183183
targetRev = sortedRevisions[1];
184184
}
185185

@@ -211,6 +211,7 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
211211
const url = `${apiRoot}/namespaces/${this.getNamespace()}/daemonsets/${this.getName()}`;
212212

213213
await jsonPatch(url, patchOperations, true, { cluster: this.cluster });
214+
this.revisionHistoryCache = undefined;
214215

215216
return {
216217
success: true,
@@ -231,6 +232,12 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
231232
* Returns a list of RevisionInfo objects sorted by revision number (descending).
232233
*/
233234
async getRevisionHistory(): Promise<RevisionInfo[]> {
235+
const resourceVersion = this.metadata?.resourceVersion;
236+
const cachedHistory = this.revisionHistoryCache;
237+
if (cachedHistory && cachedHistory.resourceVersion === resourceVersion) {
238+
return cachedHistory.history;
239+
}
240+
234241
const revisions = await this.getOwnedControllerRevisions();
235242

236243
// Determine the current revision (highest revision number)
@@ -240,7 +247,7 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
240247

241248
const highestRevision = sortedRevisions.length > 0 ? sortedRevisions[0].revision : 0;
242249

243-
return sortedRevisions.map(rev => {
250+
const history = sortedRevisions.map(rev => {
244251
const template = rev.data?.spec?.template;
245252
const images = (template?.spec?.containers || []).map(
246253
(c: { image?: string }) => c.image || ''
@@ -253,6 +260,13 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
253260
podTemplate: template,
254261
};
255262
});
263+
264+
this.revisionHistoryCache = {
265+
resourceVersion,
266+
history,
267+
};
268+
269+
return history;
256270
}
257271
}
258272

frontend/src/lib/k8s/deployment.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Deployment extends KubeObject<KubeDeployment> {
5050
static apiVersion = 'apps/v1';
5151
static isNamespaced = true;
5252
static isScalable = true;
53+
private revisionHistoryCache?: { resourceVersion?: string; history: RevisionInfo[] };
5354

5455
get spec() {
5556
return this.getValue('spec');
@@ -138,13 +139,6 @@ class Deployment extends KubeObject<KubeDeployment> {
138139
.filter(r => r.revision > 0)
139140
.sort((a, b) => b.revision - a.revision);
140141

141-
if (sortedRS.length < 2) {
142-
return {
143-
success: false,
144-
message: 'No previous revision available to rollback to',
145-
};
146-
}
147-
148142
// Find target revision: specific or previous (second in sorted list)
149143
let targetEntry;
150144
if (toRevision !== undefined && toRevision > 0) {
@@ -162,6 +156,12 @@ class Deployment extends KubeObject<KubeDeployment> {
162156
};
163157
}
164158
} else {
159+
if (sortedRS.length < 2) {
160+
return {
161+
success: false,
162+
message: 'No previous revision available to rollback to',
163+
};
164+
}
165165
targetEntry = sortedRS[1];
166166
}
167167

@@ -187,6 +187,7 @@ class Deployment extends KubeObject<KubeDeployment> {
187187
const url = `${apiRoot}/namespaces/${this.getNamespace()}/deployments/${this.getName()}`;
188188

189189
await jsonPatch(url, patchOperations, true, { cluster: this.cluster });
190+
this.revisionHistoryCache = undefined;
190191

191192
return {
192193
success: true,
@@ -207,10 +208,16 @@ class Deployment extends KubeObject<KubeDeployment> {
207208
* Returns a list of RevisionInfo objects sorted by revision number (descending).
208209
*/
209210
async getRevisionHistory(): Promise<RevisionInfo[]> {
211+
const resourceVersion = this.metadata?.resourceVersion;
212+
const cachedHistory = this.revisionHistoryCache;
213+
if (cachedHistory && cachedHistory.resourceVersion === resourceVersion) {
214+
return cachedHistory.history;
215+
}
216+
210217
const replicaSets = await this.getOwnedReplicaSets();
211218
const currentRevision = this.getCurrentRevision();
212219

213-
return replicaSets
220+
const history = replicaSets
214221
.map(rs => {
215222
const revision = parseInt(
216223
rs.metadata.annotations?.['deployment.kubernetes.io/revision'] || '0',
@@ -229,6 +236,13 @@ class Deployment extends KubeObject<KubeDeployment> {
229236
})
230237
.filter(r => r.revision > 0)
231238
.sort((a, b) => b.revision - a.revision);
239+
240+
this.revisionHistoryCache = {
241+
resourceVersion,
242+
history,
243+
};
244+
245+
return history;
232246
}
233247

234248
static getBaseObject(): KubeDeployment {

frontend/src/lib/k8s/statefulSet.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
5050
static apiVersion = 'apps/v1';
5151
static isNamespaced = true;
5252
static isScalable = true;
53+
private revisionHistoryCache?: { resourceVersion?: string; history: RevisionInfo[] };
5354

5455
get spec() {
5556
return this.jsonData.spec;
@@ -151,13 +152,6 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
151152
.filter(rev => rev.revision > 0)
152153
.sort((a, b) => b.revision - a.revision);
153154

154-
if (sortedRevisions.length < 2) {
155-
return {
156-
success: false,
157-
message: 'No previous revision available to rollback to',
158-
};
159-
}
160-
161155
// Find target revision: specific or previous (second in sorted list)
162156
let targetRev;
163157
if (toRevision !== undefined && toRevision > 0) {
@@ -175,6 +169,12 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
175169
};
176170
}
177171
} else {
172+
if (sortedRevisions.length < 2) {
173+
return {
174+
success: false,
175+
message: 'No previous revision available to rollback to',
176+
};
177+
}
178178
targetRev = sortedRevisions[1];
179179
}
180180

@@ -206,6 +206,7 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
206206
const url = `${apiRoot}/namespaces/${this.getNamespace()}/statefulsets/${this.getName()}`;
207207

208208
await jsonPatch(url, patchOperations, true, { cluster: this.cluster });
209+
this.revisionHistoryCache = undefined;
209210

210211
return {
211212
success: true,
@@ -226,6 +227,12 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
226227
* Returns a list of RevisionInfo objects sorted by revision number (descending).
227228
*/
228229
async getRevisionHistory(): Promise<RevisionInfo[]> {
230+
const resourceVersion = this.metadata?.resourceVersion;
231+
const cachedHistory = this.revisionHistoryCache;
232+
if (cachedHistory && cachedHistory.resourceVersion === resourceVersion) {
233+
return cachedHistory.history;
234+
}
235+
229236
const revisions = await this.getOwnedControllerRevisions();
230237

231238
// Determine the current revision (highest revision number)
@@ -235,7 +242,7 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
235242

236243
const highestRevision = sortedRevisions.length > 0 ? sortedRevisions[0].revision : 0;
237244

238-
return sortedRevisions.map(rev => {
245+
const history = sortedRevisions.map(rev => {
239246
const template = rev.data?.spec?.template;
240247
const images = (template?.spec?.containers || []).map(
241248
(c: { image?: string }) => c.image || ''
@@ -248,6 +255,13 @@ class StatefulSet extends KubeObject<KubeStatefulSet> {
248255
podTemplate: template,
249256
};
250257
});
258+
259+
this.revisionHistoryCache = {
260+
resourceVersion,
261+
history,
262+
};
263+
264+
return history;
251265
}
252266
}
253267

0 commit comments

Comments
 (0)