diff --git a/cmd/metal-api/internal/service/partition-service.go b/cmd/metal-api/internal/service/partition-service.go index 5182cbc07..4075a119e 100644 --- a/cmd/metal-api/internal/service/partition-service.go +++ b/cmd/metal-api/internal/service/partition-service.go @@ -382,8 +382,10 @@ func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityReque partitionCapacities := []v1.PartitionCapacity{} for _, p := range ps { + p := p capacities := make(map[string]*v1.ServerCapacity) for _, m := range machines { + m := m if m.Partition == nil { continue } diff --git a/cmd/metal-api/internal/service/project-service_test.go b/cmd/metal-api/internal/service/project-service_test.go index d3e8b40a8..7a4a7fe30 100644 --- a/cmd/metal-api/internal/service/project-service_test.go +++ b/cmd/metal-api/internal/service/project-service_test.go @@ -17,7 +17,6 @@ import ( "github.com/metal-stack/security" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" - "gopkg.in/rethinkdb/rethinkdb-go.v6" r "gopkg.in/rethinkdb/rethinkdb-go.v6" ) @@ -210,7 +209,7 @@ func Test_projectResource_deleteProject(t *testing.T) { name string userScenarios []security.User projectServiceMock func(mock *mdmv1mock.ProjectServiceClient) - dsMock func(mock *rethinkdb.Mock) + dsMock func(mock *r.Mock) id string wantStatus int want *v1.ProjectResponse @@ -241,7 +240,7 @@ func Test_projectResource_deleteProject(t *testing.T) { mock.On("Get", context.Background(), &mdmv1.ProjectGetRequest{Id: "123"}).Return(&mdmv1.ProjectResponse{Project: &mdmv1.Project{Meta: &mdmv1.Meta{Id: "123"}}}, nil) mock.On("Delete", context.Background(), &mdmv1.ProjectDeleteRequest{Id: "123"}).Return(&mdmv1.ProjectResponse{Project: &mdmv1.Project{}}, nil) }, - dsMock: func(mock *rethinkdb.Mock) { + dsMock: func(mock *r.Mock) { mock.On(r.DB("mockdb").Table("machine").Filter(r.MockAnything(), r.FilterOpts{})).Return([]metal.Machines{}, nil) mock.On(r.DB("mockdb").Table("network").Filter(r.MockAnything(), r.FilterOpts{})).Return([]metal.Networks{}, nil) mock.On(r.DB("mockdb").Table("ip").Filter(r.MockAnything(), r.FilterOpts{})).Return([]metal.IPs{}, nil) diff --git a/cmd/metal-api/internal/service/tenant-service.go b/cmd/metal-api/internal/service/tenant-service.go index c7480dbed..88a16500a 100644 --- a/cmd/metal-api/internal/service/tenant-service.go +++ b/cmd/metal-api/internal/service/tenant-service.go @@ -1,7 +1,7 @@ package service import ( - "context" + "errors" "net/http" "github.com/metal-stack/masterdata-api/api/rest/mapper" @@ -9,9 +9,11 @@ import ( mdmv1 "github.com/metal-stack/masterdata-api/api/v1" mdm "github.com/metal-stack/masterdata-api/pkg/client" "go.uber.org/zap" + "google.golang.org/protobuf/types/known/wrapperspb" restfulspec "github.com/emicklei/go-restful-openapi/v2" restful "github.com/emicklei/go-restful/v3" + "github.com/metal-stack/metal-lib/auditing" "github.com/metal-stack/metal-lib/httperrors" ) @@ -59,13 +61,54 @@ func (r *tenantResource) webService() *restful.WebService { Returns(http.StatusOK, "OK", []v1.TenantResponse{}). DefaultReturns("Error", httperrors.HTTPErrorResponse{})) + ws.Route(ws.POST("/find"). + To(viewer(r.findTenants)). + Operation("findTenants"). + Doc("get all tenants that match given properties"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Metadata(auditing.Exclude, true). + Reads(v1.TenantFindRequest{}). + Writes([]v1.TenantResponse{}). + Returns(http.StatusOK, "OK", []v1.TenantResponse{}). + DefaultReturns("Error", httperrors.HTTPErrorResponse{})) + + ws.Route(ws.DELETE("/{id}"). + To(admin(r.deleteTenant)). + Operation("deleteTenant"). + Doc("deletes a tenant and returns the deleted entity"). + Param(ws.PathParameter("id", "identifier of the tenant").DataType("string")). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(v1.TenantResponse{}). + Returns(http.StatusOK, "OK", v1.TenantResponse{}). + DefaultReturns("Error", httperrors.HTTPErrorResponse{})) + + ws.Route(ws.PUT("/"). + To(admin(r.createTenant)). + Operation("createTenant"). + Doc("create a tenant. if the given ID already exists a conflict is returned"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Reads(v1.TenantCreateRequest{}). + Returns(http.StatusCreated, "Created", v1.TenantResponse{}). + Returns(http.StatusConflict, "Conflict", httperrors.HTTPErrorResponse{}). + DefaultReturns("Error", httperrors.HTTPErrorResponse{})) + + ws.Route(ws.POST("/"). + To(admin(r.updateTenant)). + Operation("updateTenant"). + Doc("update a tenant. optimistic lock error can occur."). + Metadata(restfulspec.KeyOpenAPITags, tags). + Reads(v1.TenantUpdateRequest{}). + Returns(http.StatusOK, "Updated", v1.TenantResponse{}). + Returns(http.StatusPreconditionFailed, "OptimisticLock", httperrors.HTTPErrorResponse{}). + DefaultReturns("Error", httperrors.HTTPErrorResponse{})) + return ws } func (r *tenantResource) getTenant(request *restful.Request, response *restful.Response) { id := request.PathParameter("id") - tres, err := r.mdc.Tenant().Get(context.Background(), &mdmv1.TenantGetRequest{Id: id}) + tres, err := r.mdc.Tenant().Get(request.Request.Context(), &mdmv1.TenantGetRequest{Id: id}) if err != nil { r.sendError(request, response, defaultError(err)) return @@ -77,7 +120,7 @@ func (r *tenantResource) getTenant(request *restful.Request, response *restful.R } func (r *tenantResource) listTenants(request *restful.Request, response *restful.Response) { - tres, err := r.mdc.Tenant().Find(context.Background(), &mdmv1.TenantFindRequest{}) + tres, err := r.mdc.Tenant().Find(request.Request.Context(), &mdmv1.TenantFindRequest{}) if err != nil { r.sendError(request, response, defaultError(err)) return @@ -91,3 +134,124 @@ func (r *tenantResource) listTenants(request *restful.Request, response *restful r.send(request, response, http.StatusOK, v1ts) } + +func (r *tenantResource) findTenants(request *restful.Request, response *restful.Response) { + var requestPayload v1.TenantFindRequest + err := request.ReadEntity(&requestPayload) + if err != nil { + r.sendError(request, response, httperrors.BadRequest(err)) + return + } + + res, err := r.mdc.Tenant().Find(request.Request.Context(), mapper.ToMdmV1TenantFindRequest(&requestPayload)) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + + var ps []*v1.Tenant + for i := range res.Tenants { + v1p := mapper.ToV1Tenant(res.Tenants[i]) + ps = append(ps, v1p) + } + + r.send(request, response, http.StatusOK, ps) +} + +func (r *tenantResource) createTenant(request *restful.Request, response *restful.Response) { + var pcr v1.TenantCreateRequest + err := request.ReadEntity(&pcr) + if err != nil { + r.sendError(request, response, httperrors.BadRequest(err)) + return + } + + tenant := mapper.ToMdmV1Tenant(&pcr.Tenant) + + mdmv1pcr := &mdmv1.TenantCreateRequest{ + Tenant: tenant, + } + + p, err := r.mdc.Tenant().Create(request.Request.Context(), mdmv1pcr) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + + v1p := mapper.ToV1Tenant(p.Tenant) + pcres := &v1.TenantResponse{ + Tenant: *v1p, + } + + r.send(request, response, http.StatusCreated, pcres) +} + +func (r *tenantResource) deleteTenant(request *restful.Request, response *restful.Response) { + id := request.PathParameter("id") + + pgr := &mdmv1.TenantGetRequest{ + Id: id, + } + p, err := r.mdc.Tenant().Get(request.Request.Context(), pgr) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + + plr, err := r.mdc.Project().Find(request.Request.Context(), &mdmv1.ProjectFindRequest{TenantId: wrapperspb.String(id)}) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + if len(plr.Projects) > 0 { + r.sendError(request, response, httperrors.UnprocessableEntity(errors.New("there are still projects allocated by this tenant"))) + return + } + + pdr := &mdmv1.TenantDeleteRequest{ + Id: p.Tenant.Meta.Id, + } + pdresponse, err := r.mdc.Tenant().Delete(request.Request.Context(), pdr) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + + v1p := mapper.ToV1Tenant(pdresponse.Tenant) + pcres := &v1.TenantResponse{ + Tenant: *v1p, + } + + r.send(request, response, http.StatusOK, pcres) +} + +func (r *tenantResource) updateTenant(request *restful.Request, response *restful.Response) { + var requestPayload v1.TenantUpdateRequest + err := request.ReadEntity(&requestPayload) + if err != nil { + r.sendError(request, response, httperrors.BadRequest(err)) + return + } + + if requestPayload.Tenant.Meta == nil { + r.sendError(request, response, httperrors.BadRequest(errors.New("tenant and tenant.meta must be specified"))) + return + } + + // new data + tenantUpdateData := mapper.ToMdmV1Tenant(&requestPayload.Tenant) + + pur, err := r.mdc.Tenant().Update(request.Request.Context(), &mdmv1.TenantUpdateRequest{ + Tenant: tenantUpdateData, + }) + if err != nil { + r.sendError(request, response, defaultError(err)) + return + } + + v1p := mapper.ToV1Tenant(pur.Tenant) + + r.send(request, response, http.StatusOK, &v1.TenantResponse{ + Tenant: *v1p, + }) +} diff --git a/cmd/metal-api/internal/service/tenant-service_test.go b/cmd/metal-api/internal/service/tenant-service_test.go index 6dcc7dd5e..98fcc0112 100644 --- a/cmd/metal-api/internal/service/tenant-service_test.go +++ b/cmd/metal-api/internal/service/tenant-service_test.go @@ -1,7 +1,6 @@ package service import ( - "context" "fmt" "testing" @@ -12,6 +11,7 @@ import ( mdm "github.com/metal-stack/masterdata-api/pkg/client" "github.com/metal-stack/metal-lib/httperrors" "github.com/metal-stack/security" + testifymock "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) @@ -66,7 +66,7 @@ func Test_tenantResource_getTenant(t *testing.T) { userScenarios: []security.User{*testViewUser}, id: "122", tenantServiceMock: func(mock *mdmv1mock.TenantServiceClient) { - mock.On("Get", context.Background(), &mdmv1.TenantGetRequest{Id: "122"}).Return(&mdmv1.TenantResponse{Tenant: &mdmv1.Tenant{Name: "t122"}}, nil) + mock.On("Get", testifymock.Anything, &mdmv1.TenantGetRequest{Id: "122"}).Return(&mdmv1.TenantResponse{Tenant: &mdmv1.Tenant{Name: "t122"}}, nil) }, want: &v1.TenantResponse{Tenant: v1.Tenant{Name: "t122"}}, wantStatus: 200, @@ -76,7 +76,7 @@ func Test_tenantResource_getTenant(t *testing.T) { name: "entity allowed for user with admin privileges", userScenarios: []security.User{*testAdminUser}, tenantServiceMock: func(mock *mdmv1mock.TenantServiceClient) { - mock.On("Get", context.Background(), &mdmv1.TenantGetRequest{Id: "123"}).Return(&mdmv1.TenantResponse{Tenant: &mdmv1.Tenant{Name: "t123"}}, nil) + mock.On("Get", testifymock.Anything, &mdmv1.TenantGetRequest{Id: "123"}).Return(&mdmv1.TenantResponse{Tenant: &mdmv1.Tenant{Name: "t123"}}, nil) }, id: "123", want: &v1.TenantResponse{Tenant: v1.Tenant{Name: "t123"}}, @@ -128,7 +128,7 @@ func Test_tenantResource_listTenants(t *testing.T) { name: "entity allowed for user with view privileges", userScenarios: []security.User{*testViewUser}, tenantServiceMock: func(mock *mdmv1mock.TenantServiceClient) { - mock.On("Find", context.Background(), &mdmv1.TenantFindRequest{}).Return(&mdmv1.TenantListResponse{Tenants: []*mdmv1.Tenant{{Name: "t121"}, {Name: "t122"}}}, nil) + mock.On("Find", testifymock.Anything, &mdmv1.TenantFindRequest{}).Return(&mdmv1.TenantListResponse{Tenants: []*mdmv1.Tenant{{Name: "t121"}, {Name: "t122"}}}, nil) }, want: []*v1.Tenant{{Name: "t121"}, {Name: "t122"}}, wantStatus: 200, @@ -138,7 +138,7 @@ func Test_tenantResource_listTenants(t *testing.T) { name: "entity allowed for user with admin privileges", userScenarios: []security.User{*testAdminUser}, tenantServiceMock: func(mock *mdmv1mock.TenantServiceClient) { - mock.On("Find", context.Background(), &mdmv1.TenantFindRequest{}).Return(&mdmv1.TenantListResponse{Tenants: []*mdmv1.Tenant{{Name: "t123"}}}, nil) + mock.On("Find", testifymock.Anything, &mdmv1.TenantFindRequest{}).Return(&mdmv1.TenantListResponse{Tenants: []*mdmv1.Tenant{{Name: "t123"}}}, nil) }, want: []*v1.Tenant{{Name: "t123"}}, wantStatus: 200, diff --git a/go.mod b/go.mod index 62b4269a6..5b57d8dbe 100644 --- a/go.mod +++ b/go.mod @@ -8,18 +8,18 @@ require ( github.com/aws/aws-sdk-go v1.44.326 github.com/dustin/go-humanize v1.0.1 github.com/emicklei/go-restful-openapi/v2 v2.9.1 - github.com/emicklei/go-restful/v3 v3.10.2 + github.com/emicklei/go-restful/v3 v3.11.0 github.com/go-openapi/spec v0.20.9 github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/juanfont/headscale v0.22.3 github.com/looplab/fsm v0.3.0 github.com/metal-stack/go-ipam v1.8.5 - github.com/metal-stack/masterdata-api v0.9.0 - github.com/metal-stack/metal-lib v0.13.1 - github.com/metal-stack/security v0.6.6 + github.com/metal-stack/masterdata-api v0.10.0 + github.com/metal-stack/metal-lib v0.13.2 + github.com/metal-stack/security v0.6.7 github.com/metal-stack/v v1.0.3 github.com/nsqio/go-nsq v1.1.0 github.com/prometheus/client_golang v1.16.0 @@ -37,8 +37,6 @@ require ( ) replace ( - // Keep this because v3.10.x breaks image-create - github.com/emicklei/go-restful/v3 => github.com/emicklei/go-restful/v3 v3.9.0 // netipx and x/exp must be replaced for tailscale < 1.48 go4.org/netipx => go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 golang.org/x/exp => golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 @@ -65,7 +63,7 @@ require ( github.com/coreos/go-oidc/v3 v3.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/deckarep/golang-set/v2 v2.3.0 // indirect + github.com/deckarep/golang-set/v2 v2.3.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.5+incompatible // indirect @@ -154,13 +152,13 @@ require ( github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/stretchr/objx v0.5.1 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.48.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect + go.mongodb.org/mongo-driver v1.12.1 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/intern v0.0.0-20230205224052-192e9f60865c // indirect go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect @@ -176,9 +174,9 @@ require ( golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 7a20445af..d62756884 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjI github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= -github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A= +github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= @@ -271,8 +271,9 @@ github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful-openapi/v2 v2.9.1 h1:Of8B1rXdG81il5TTiSY+9Qrh7pYOr8aLdynHIpvo7fM= github.com/emicklei/go-restful-openapi/v2 v2.9.1/go.mod h1:VKNgZyYviM1hnyrjD9RDzP2RuE94xTXxV+u6MGN4v4k= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.7.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -458,8 +459,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -634,12 +635,12 @@ github.com/meilisearch/meilisearch-go v0.25.0 h1:xIp+8YWterHuDvpdYlwQ4Qp7im3JlRH github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/metal-stack/go-ipam v1.8.5 h1:XE1XfaU6Ck1Ucc7svTO25dlT7kEcE1oxOM3lBrWIQmE= github.com/metal-stack/go-ipam v1.8.5/go.mod h1:JgsddJabu8A7lWD+4MJKqbQhmSA/zhBbO+Bp8pLhRZM= -github.com/metal-stack/masterdata-api v0.9.0 h1:bKsUkIYRSckVEQsZQfeG10dY17/N+/SfwkUMCCLniEA= -github.com/metal-stack/masterdata-api v0.9.0/go.mod h1:IBRuTb37nc0q65R7CpNVNjYZ0RHsBfCIg5n4n5w1M2c= -github.com/metal-stack/metal-lib v0.13.1 h1:DxtvFZnV3uyv0C+ZpXSlo9eozDv/hzS+8bfjmar5Z5k= -github.com/metal-stack/metal-lib v0.13.1/go.mod h1:l18VEuS1YkxnVE35iF8AMP6QRxoYjRZ9e2NE3aGxVY0= -github.com/metal-stack/security v0.6.6 h1:KSPNN8YZd2EJEjsJ0xCBcd5o53uU0iFupahHA9Twuh0= -github.com/metal-stack/security v0.6.6/go.mod h1:WchPm3+2Xjj1h7AxM+DsnR9EWgLw+ktoGCl/0gcmgSA= +github.com/metal-stack/masterdata-api v0.10.0 h1:xcB8kd1FK5etmRbcTlAPk2bQXY6i9tTTvAeDsTjmh6E= +github.com/metal-stack/masterdata-api v0.10.0/go.mod h1:xwaMDC9hhNjXep3ppD+Iqeg2OEFM6hwq2zFyBDnlXGc= +github.com/metal-stack/metal-lib v0.13.2 h1:gpsnKUxahT4r3N55QY1MTRBZy10CySTQCQKb9XFCDrA= +github.com/metal-stack/metal-lib v0.13.2/go.mod h1:l18VEuS1YkxnVE35iF8AMP6QRxoYjRZ9e2NE3aGxVY0= +github.com/metal-stack/security v0.6.7 h1:8wstGy0pdUmphVclAlT+9RKQmx9lF+cIGklJZAB5cIc= +github.com/metal-stack/security v0.6.7/go.mod h1:dXyrQ8PYZuUiodWFQ/NwSROxu6tajwRBc5yR/PoK5uE= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= @@ -830,8 +831,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -845,8 +847,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -901,8 +903,8 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1304,12 +1306,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff --git a/spec/metal-api.json b/spec/metal-api.json index 9c75236c0..581a6782c 100644 --- a/spec/metal-api.json +++ b/spec/metal-api.json @@ -3564,6 +3564,18 @@ "used_prefixes" ] }, + "v1.Paging": { + "properties": { + "count": { + "format": "integer", + "type": "integer" + }, + "page": { + "format": "integer", + "type": "integer" + } + } + }, "v1.PartitionBase": { "properties": { "mgmtserviceaddress": { @@ -4649,6 +4661,47 @@ } } }, + "v1.TenantCreateRequest": { + "properties": { + "default_quotas": { + "$ref": "#/definitions/v1.QuotaSet" + }, + "description": { + "type": "string" + }, + "iam_config": { + "$ref": "#/definitions/v1.IAMConfig" + }, + "meta": { + "$ref": "#/definitions/v1.Meta" + }, + "name": { + "type": "string" + }, + "quotas": { + "$ref": "#/definitions/v1.QuotaSet" + } + } + }, + "v1.TenantFindRequest": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "paging": { + "$ref": "#/definitions/v1.Paging" + } + } + }, "v1.TenantResponse": { "properties": { "default_quotas": { @@ -4671,6 +4724,28 @@ } } }, + "v1.TenantUpdateRequest": { + "properties": { + "default_quotas": { + "$ref": "#/definitions/v1.QuotaSet" + }, + "description": { + "type": "string" + }, + "iam_config": { + "$ref": "#/definitions/v1.IAMConfig" + }, + "meta": { + "$ref": "#/definitions/v1.Meta" + }, + "name": { + "type": "string" + }, + "quotas": { + "$ref": "#/definitions/v1.QuotaSet" + } + } + }, "v1.Timestamps": { "properties": { "changed": { @@ -8787,9 +8862,173 @@ "tags": [ "tenant" ] + }, + "post": { + "consumes": [ + "application/json" + ], + "operationId": "updateTenant", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.TenantUpdateRequest" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Updated", + "schema": { + "$ref": "#/definitions/v1.TenantResponse" + } + }, + "412": { + "description": "OptimisticLock", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + }, + "default": { + "description": "Error", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + } + }, + "summary": "update a tenant. optimistic lock error can occur.", + "tags": [ + "tenant" + ] + }, + "put": { + "consumes": [ + "application/json" + ], + "operationId": "createTenant", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.TenantCreateRequest" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/v1.TenantResponse" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + }, + "default": { + "description": "Error", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + } + }, + "summary": "create a tenant. if the given ID already exists a conflict is returned", + "tags": [ + "tenant" + ] + } + }, + "/v1/tenant/find": { + "post": { + "consumes": [ + "application/json" + ], + "operationId": "findTenants", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.TenantFindRequest" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "items": { + "$ref": "#/definitions/v1.TenantResponse" + }, + "type": "array" + } + }, + "default": { + "description": "Error", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + } + }, + "summary": "get all tenants that match given properties", + "tags": [ + "tenant" + ] } }, "/v1/tenant/{id}": { + "delete": { + "consumes": [ + "application/json" + ], + "operationId": "deleteTenant", + "parameters": [ + { + "description": "identifier of the tenant", + "in": "path", + "name": "id", + "required": true, + "type": "string" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.TenantResponse" + } + }, + "default": { + "description": "Error", + "schema": { + "$ref": "#/definitions/httperrors.HTTPErrorResponse" + } + } + }, + "summary": "deletes a tenant and returns the deleted entity", + "tags": [ + "tenant" + ] + }, "get": { "consumes": [ "application/json"