Skip to content

Commit 20f9bf8

Browse files
Merge pull request #113 from kuudori/HYPERFLEET-971
HYPERFLEET-971 - feat: reject nodepool create/patch on soft-deleted cluster
2 parents 1d45541 + 65f3aad commit 20f9bf8

6 files changed

Lines changed: 565 additions & 17 deletions

File tree

openapi/openapi.yaml

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.0.0
22
info:
33
title: HyperFleet API
4-
version: 1.0.8
4+
version: 1.0.9
55
contact:
66
name: HyperFleet Team
77
license:
@@ -125,6 +125,8 @@ paths:
125125
description: The server could not understand the request due to invalid syntax.
126126
'404':
127127
description: The server cannot find the requested resource.
128+
'409':
129+
description: The request conflicts with the current state of the server.
128130
default:
129131
description: An unexpected error response.
130132
content:
@@ -173,8 +175,8 @@ paths:
173175
conditions:
174176
- type: Ready
175177
status: 'True'
176-
reason: All adapters reported Ready True for the current generation
177-
message: All adapters reported Ready True for the current generation
178+
reason: All adapters reported Available=True for the current generation
179+
message: All adapters reported Available=True for the current generation
178180
observed_generation: 2
179181
created_time: '2021-01-01T10:00:00Z'
180182
last_updated_time: '2021-01-01T10:00:00Z'
@@ -283,6 +285,8 @@ paths:
283285
$ref: '#/components/schemas/NodePoolCreateResponse'
284286
'400':
285287
description: The server could not understand the request due to invalid syntax.
288+
'409':
289+
description: The request conflicts with the current state of the server.
286290
default:
287291
description: An unexpected error response.
288292
content:
@@ -376,8 +380,8 @@ paths:
376380
conditions:
377381
- type: Ready
378382
status: 'True'
379-
reason: All adapters reported Ready True for the current generation
380-
message: All adapters reported Ready True for the current generation
383+
reason: All adapters reported Available=True for the current generation
384+
message: All adapters reported Available=True for the current generation
381385
observed_generation: 2
382386
created_time: '2021-01-01T10:00:00Z'
383387
last_updated_time: '2021-01-01T10:00:00Z'
@@ -460,6 +464,8 @@ paths:
460464
description: The server could not understand the request due to invalid syntax.
461465
'404':
462466
description: The server cannot find the requested resource.
467+
'409':
468+
description: The request conflicts with the current state of the server.
463469
default:
464470
description: An unexpected error response.
465471
content:
@@ -1055,8 +1061,8 @@ components:
10551061
conditions:
10561062
- type: Ready
10571063
status: 'True'
1058-
reason: All adapters reported Ready True for the current generation
1059-
message: All adapters reported Ready True for the current generation
1064+
reason: All adapters reported Available=True for the current generation
1065+
message: All adapters reported Available=True for the current generation
10601066
observed_generation: 1
10611067
created_time: '2021-01-01T10:00:00Z'
10621068
last_updated_time: '2021-01-01T10:00:00Z'
@@ -1354,8 +1360,8 @@ components:
13541360
conditions:
13551361
- type: Ready
13561362
status: 'True'
1357-
reason: All adapters reported Ready True for the current generation
1358-
message: All adapters reported Ready True for the current generation
1363+
reason: All adapters reported Available=True for the current generation
1364+
message: All adapters reported Available=True for the current generation
13591365
observed_generation: 1
13601366
created_time: '2021-01-01T10:00:00Z'
13611367
last_updated_time: '2021-01-01T10:00:00Z'

pkg/errors/errors.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const (
5252
// Conflict errors (CNF) - 409
5353
CodeConflictExists = "HYPERFLEET-CNF-001"
5454
CodeConflictVersion = "HYPERFLEET-CNF-002"
55+
CodeConflictState = "HYPERFLEET-CNF-003"
5556

5657
// Rate Limit errors (LMT) - 429
5758
CodeRateLimitExceeded = "HYPERFLEET-LMT-001"
@@ -166,6 +167,10 @@ var errorDefinitions = map[string]errorDefinition{
166167
CodeConflictVersion: {
167168
ErrorTypeConflict, "Version Conflict", "The resource version does not match", http.StatusConflict,
168169
},
170+
CodeConflictState: {
171+
ErrorTypeConflict, "State Conflict",
172+
"Operation not allowed in current state", http.StatusConflict,
173+
},
169174

170175
// Rate Limit errors (LMT) - 429
171176
CodeRateLimitExceeded: {
@@ -363,6 +368,10 @@ func Conflict(reason string, values ...interface{}) *ServiceError {
363368
return New(CodeConflictExists, reason, values...)
364369
}
365370

371+
func ConflictState(reason string, values ...interface{}) *ServiceError {
372+
return New(CodeConflictState, reason, values...)
373+
}
374+
366375
func Validation(reason string, values ...interface{}) *ServiceError {
367376
return New(CodeValidationMultiple, reason, values...)
368377
}

pkg/handlers/cluster.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ func (h ClusterHandler) Patch(w http.ResponseWriter, r *http.Request) {
7676
return nil, err
7777
}
7878

79+
if found.DeletedTime != nil {
80+
return nil, errors.ConflictState("Cluster '%s' is marked for deletion", id)
81+
}
82+
7983
if patch.Spec != nil {
8084
specJSON, err := json.Marshal(*patch.Spec)
8185
if err != nil {

pkg/handlers/cluster_nodepools.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,15 @@ func (h ClusterNodePoolsHandler) Patch(w http.ResponseWriter, r *http.Request) {
190190
clusterID := mux.Vars(r)["id"]
191191
nodePoolID := mux.Vars(r)["nodepool_id"]
192192

193-
_, err := h.clusterService.Get(ctx, clusterID)
193+
cluster, err := h.clusterService.Get(ctx, clusterID)
194194
if err != nil {
195195
return nil, err
196196
}
197197

198+
if cluster.DeletedTime != nil {
199+
return nil, errors.ConflictState("Cluster '%s' is marked for deletion", clusterID)
200+
}
201+
198202
found, err := h.nodePoolService.Get(ctx, nodePoolID)
199203
if err != nil {
200204
return nil, err
@@ -204,6 +208,10 @@ func (h ClusterNodePoolsHandler) Patch(w http.ResponseWriter, r *http.Request) {
204208
return nil, errors.NotFound("NodePool '%s' not found for cluster '%s'", nodePoolID, clusterID)
205209
}
206210

211+
if found.DeletedTime != nil {
212+
return nil, errors.ConflictState("NodePool '%s' is marked for deletion", nodePoolID)
213+
}
214+
207215
if patch.Spec != nil {
208216
specJSON, jsonErr := json.Marshal(*patch.Spec)
209217
if jsonErr != nil {
@@ -258,6 +266,10 @@ func (h ClusterNodePoolsHandler) Create(w http.ResponseWriter, r *http.Request)
258266
return nil, err
259267
}
260268

269+
if cluster.DeletedTime != nil {
270+
return nil, errors.ConflictState("Cluster '%s' is marked for deletion", clusterID)
271+
}
272+
261273
// Use the presenters.ConvertNodePool helper to convert the request
262274
nodePoolModel, convErr := presenters.ConvertNodePool(&req, cluster.ID, "system@hyperfleet.local")
263275
if convErr != nil {

0 commit comments

Comments
 (0)