Skip to content

Commit 583c75a

Browse files
aalexandruaalexandru
andauthored
Add spec wrapper for cluster patch (#60)
Co-authored-by: aalexandru <[email protected]>
1 parent cb055ee commit 583c75a

File tree

2 files changed

+38
-33
lines changed

2 files changed

+38
-33
lines changed

pkg/apiserver/web/handler/v2/handler.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@ type Handler interface {
4141
Register(*echo.Group)
4242
}
4343

44-
// ClusterPatch is the struct for updating a cluster's dynamic fields
44+
// ClusterSpec is the struct for updating a cluster's dynamic fields
45+
type ClusterSpec struct {
46+
Status *string `json:"status,omitempty" validate:"omitempty,oneof=Inactive Active Deprecated Deleted"`
47+
Phase *string `json:"phase,omitempty" validate:"omitempty,oneof=Building Testing Running Upgrading"`
48+
Tags *map[string]string `json:"tags,omitempty" validate:"omitempty"`
49+
}
50+
4551
type ClusterPatch struct {
46-
Status string `json:"status" validate:"omitempty,oneof=Inactive Active Deprecated Deleted"`
47-
Phase string `json:"phase" validate:"omitempty,oneof=Building Testing Running Upgrading"`
48-
Tags map[string]string `json:"tags" validate:"omitempty"`
52+
Spec ClusterSpec `json:"spec" validate:"required"`
4953
}
5054

5155
// handler struct
@@ -162,7 +166,7 @@ func (h *handler) ListClusters(c echo.Context) error {
162166
// @Accept json
163167
// @Produce json
164168
// @Param name path string true "Name of the cluster to patch"
165-
// @Param clusterPatch body ClusterPatch true "Request body"
169+
// @Param clusterSpec body ClusterSpec true "Request body"
166170
// @Success 200 {object} registryv1.ClusterSpec
167171
// @Failure 400 {object} errors.Error
168172
// @Failure 500 {object} errors.Error
@@ -181,17 +185,17 @@ func (h *handler) PatchCluster(c echo.Context) error {
181185
return c.JSON(http.StatusNotFound, errors.NotFound())
182186
}
183187

184-
var clusterPatch ClusterPatch
188+
var clusterSpec ClusterSpec
185189

186-
if err = c.Bind(&clusterPatch); err != nil {
190+
if err = c.Bind(&clusterSpec); err != nil {
187191
return c.JSON(http.StatusBadRequest, errors.NewError(err))
188192
}
189193

190-
if err = clusterPatch.Validate(c); err != nil {
194+
if err = clusterSpec.Validate(c); err != nil {
191195
return c.JSON(http.StatusBadRequest, errors.NewError(err))
192196
}
193197

194-
err = h.patchCluster(cluster, clusterPatch)
198+
err = h.patchCluster(cluster, clusterSpec)
195199
if err != nil {
196200
return c.JSON(http.StatusInternalServerError, errors.NewError(err))
197201
}
@@ -225,13 +229,13 @@ func (h *handler) getCluster(db database.Db, name string) (*registryv1.Cluster,
225229
}
226230

227231
// patchCluster
228-
func (h *handler) patchCluster(cluster *registryv1.Cluster, patch ClusterPatch) error {
232+
func (h *handler) patchCluster(cluster *registryv1.Cluster, spec ClusterSpec) error {
229233
client, err := h.kcp.GetClient(h.appConfig, cluster)
230234
if err != nil {
231235
return fmt.Errorf("failed to get client for cluster %s: %v", cluster.Spec.Name, err)
232236
}
233237

234-
jsonPatch, err := json.Marshal(patch)
238+
patch, err := json.Marshal(&ClusterPatch{Spec: spec})
235239
if err != nil {
236240
return err
237241
}
@@ -242,7 +246,7 @@ func (h *handler) patchCluster(cluster *registryv1.Cluster, patch ClusterPatch)
242246
Namespace("cluster-registry").
243247
Resource("clusters").
244248
Name(cluster.Spec.Name).
245-
Body(jsonPatch).
249+
Body(patch).
246250
DoRaw(context.TODO())
247251

248252
log.Debugf("Patch response: %s", string(res))
@@ -263,13 +267,13 @@ func getQueryConditions(c echo.Context) []string {
263267
return []string{}
264268
}
265269

266-
func (patch *ClusterPatch) Validate(c echo.Context) error {
270+
func (patch *ClusterSpec) Validate(c echo.Context) error {
267271
if err := c.Validate(patch); err != nil {
268272
return err
269273
}
270274

271-
if len(patch.Tags) > 0 {
272-
for key, value := range patch.Tags {
275+
if patch.Tags != nil && len(*patch.Tags) > 0 {
276+
for key, value := range *patch.Tags {
273277
if err := validateTag(key, value); err != nil {
274278
return err
275279
}

pkg/apiserver/web/handler/v2/handler_test.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/stretchr/testify/assert"
2929
"k8s.io/client-go/kubernetes"
3030
testclient "k8s.io/client-go/kubernetes/fake"
31+
"k8s.io/utils/pointer"
3132
"net/http"
3233
"net/http/httptest"
3334
"strings"
@@ -269,7 +270,7 @@ func TestPatchCluster(t *testing.T) {
269270
tcs := []struct {
270271
name string
271272
cluster *registryv1.Cluster
272-
clusterPatch ClusterPatch
273+
clusterSpec ClusterSpec
273274
expectedStatus int
274275
expectedBody string
275276
}{
@@ -285,11 +286,11 @@ func TestPatchCluster(t *testing.T) {
285286
Tags: map[string]string{"onboarding": "on", "scaling": "off"},
286287
},
287288
},
288-
clusterPatch: ClusterPatch{
289-
Status: "inactive",
289+
clusterSpec: ClusterSpec{
290+
Status: pointer.String("inactive"),
290291
},
291292
expectedStatus: http.StatusBadRequest,
292-
expectedBody: `{"errors":{"body":"Key: 'ClusterPatch.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"}}`,
293+
expectedBody: `{"errors":{"body":"Key: 'ClusterSpec.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"}}`,
293294
},
294295
{
295296
name: "invalid phase (case sensitive)",
@@ -303,12 +304,12 @@ func TestPatchCluster(t *testing.T) {
303304
Tags: map[string]string{"onboarding": "on", "scaling": "off"},
304305
},
305306
},
306-
clusterPatch: ClusterPatch{
307-
Status: "Inactive",
308-
Phase: "upgrading",
307+
clusterSpec: ClusterSpec{
308+
Status: pointer.String("Inactive"),
309+
Phase: pointer.String("upgrading"),
309310
},
310311
expectedStatus: http.StatusBadRequest,
311-
expectedBody: `{"errors":{"body":"Key: 'ClusterPatch.Phase' Error:Field validation for 'Phase' failed on the 'oneof' tag"}}`,
312+
expectedBody: `{"errors":{"body":"Key: 'ClusterSpec.Phase' Error:Field validation for 'Phase' failed on the 'oneof' tag"}}`,
312313
},
313314
{
314315
name: "invalid value for `scaling` tag",
@@ -322,9 +323,9 @@ func TestPatchCluster(t *testing.T) {
322323
Tags: map[string]string{"onboarding": "on", "scaling": "off"},
323324
},
324325
},
325-
clusterPatch: ClusterPatch{
326-
Status: "Inactive",
327-
Tags: map[string]string{
326+
clusterSpec: ClusterSpec{
327+
Status: pointer.String("Inactive"),
328+
Tags: &map[string]string{
328329
"onboarding": "off",
329330
"scaling": "enabled",
330331
},
@@ -344,9 +345,9 @@ func TestPatchCluster(t *testing.T) {
344345
Tags: map[string]string{"onboarding": "on", "scaling": "off"},
345346
},
346347
},
347-
clusterPatch: ClusterPatch{
348-
Status: "Inactive",
349-
Tags: map[string]string{
348+
clusterSpec: ClusterSpec{
349+
Status: pointer.String("Inactive"),
350+
Tags: &map[string]string{
350351
"onboarding": "false",
351352
},
352353
},
@@ -365,9 +366,9 @@ func TestPatchCluster(t *testing.T) {
365366
Tags: map[string]string{"onboarding": "on", "scaling": "off"},
366367
},
367368
},
368-
clusterPatch: ClusterPatch{
369-
Status: "Inactive",
370-
Tags: map[string]string{
369+
clusterSpec: ClusterSpec{
370+
Status: pointer.String("Inactive"),
371+
Tags: &map[string]string{
371372
"some-made-up-tag": "on",
372373
},
373374
},
@@ -381,7 +382,7 @@ func TestPatchCluster(t *testing.T) {
381382
r := web.NewRouter()
382383
h := NewHandler(appConfig, db, m, &TestClientProvider{})
383384

384-
patch, _ := json.Marshal(tc.clusterPatch)
385+
patch, _ := json.Marshal(tc.clusterSpec)
385386
body := strings.NewReader(string(patch))
386387
req := httptest.NewRequest(echo.PATCH, "/api/v2/clusters/:name", body)
387388
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)

0 commit comments

Comments
 (0)