diff --git a/services.go b/services.go index f6a9043..e8b3a3d 100644 --- a/services.go +++ b/services.go @@ -51,8 +51,8 @@ func (sr *ServicesResource) Get(ctx context.Context, name string) (*Service, err return body[Service](sr, req) } -// CreateOrUpdate creates or updates a [Service]. -func (sr *ServicesResource) CreateOrUpdate(ctx context.Context, svc Service) error { +// Create creates a new [Service]. +func (sr *ServicesResource) Create(ctx context.Context, svc Service) error { req, err := sr.buildRequest(ctx, http.MethodPut, sr.buildTailnetURL("vip-services", svc.Name), requestBody(svc)) if err != nil { return err @@ -61,6 +61,25 @@ func (sr *ServicesResource) CreateOrUpdate(ctx context.Context, svc Service) err return sr.do(req, nil) } +// Update updates an existing [Service] identified by name. The name parameter +// is the current name of the service and is used to build the request URL. +// If svc.Name differs from name, the service will be renamed, preserving its +// assigned VIPs. +func (sr *ServicesResource) Update(ctx context.Context, name string, svc Service) error { + req, err := sr.buildRequest(ctx, http.MethodPut, sr.buildTailnetURL("vip-services", name), requestBody(svc)) + if err != nil { + return err + } + + return sr.do(req, nil) +} + +// CreateOrUpdate creates or updates a [Service]. +// Deprecated: use [ServicesResource.Create] or [ServicesResource.Update] instead. +func (sr *ServicesResource) CreateOrUpdate(ctx context.Context, svc Service) error { + return sr.Create(ctx, svc) +} + // Delete deletes a specific [Service]. func (sr *ServicesResource) Delete(ctx context.Context, name string) error { req, err := sr.buildRequest(ctx, http.MethodDelete, sr.buildTailnetURL("vip-services", name)) diff --git a/services_test.go b/services_test.go index 2a2aed5..62f03d2 100644 --- a/services_test.go +++ b/services_test.go @@ -58,6 +58,54 @@ func TestClient_GetService(t *testing.T) { assert.Equal(t, expected, actual) } +func TestClient_CreateService(t *testing.T) { + t.Parallel() + + client, server := NewTestHarness(t) + server.ResponseCode = http.StatusOK + + svc := Service{ + Name: "svc:my-service", + Comment: "new service", + Ports: []string{"443"}, + Tags: []string{"tag:web"}, + } + + err := client.Services().Create(context.Background(), svc) + assert.NoError(t, err) + assert.Equal(t, http.MethodPut, server.Method) + assert.Equal(t, "/api/v2/tailnet/example.com/vip-services/svc:my-service", server.Path) + + var received Service + err = json.Unmarshal(server.Body.Bytes(), &received) + assert.NoError(t, err) + assert.Equal(t, svc, received) +} + +func TestClient_UpdateService(t *testing.T) { + t.Parallel() + + client, server := NewTestHarness(t) + server.ResponseCode = http.StatusOK + + svc := Service{ + Name: "svc:my-service-renamed", + Comment: "updated service", + Ports: []string{"443"}, + Tags: []string{"tag:web"}, + } + + err := client.Services().Update(context.Background(), "svc:my-service", svc) + assert.NoError(t, err) + assert.Equal(t, http.MethodPut, server.Method) + assert.Equal(t, "/api/v2/tailnet/example.com/vip-services/svc:my-service", server.Path) + + var received Service + err = json.Unmarshal(server.Body.Bytes(), &received) + assert.NoError(t, err) + assert.Equal(t, svc, received) +} + func TestClient_CreateOrUpdateService(t *testing.T) { t.Parallel()