diff --git a/controller/internal/routes/service_router.go b/controller/internal/routes/service_router.go index f09e7162a..ded245be2 100644 --- a/controller/internal/routes/service_router.go +++ b/controller/internal/routes/service_router.go @@ -92,7 +92,7 @@ func (r *ServiceRouter) Register(ae *env.AppEnv) { }) ae.Api.ServiceListServiceTerminatorsHandler = service.ListServiceTerminatorsHandlerFunc(func(params service.ListServiceTerminatorsParams, i interface{}) middleware.Responder { - return ae.IsAllowed(r.listTerminators, params.HTTPRequest, params.ID, "", permissions.IsAdmin()) + return ae.IsAllowed(r.listTerminators, params.HTTPRequest, params.ID, "", permissions.IsAuthenticated()) }) } @@ -208,7 +208,36 @@ func (r *ServiceRouter) listConfigs(ae *env.AppEnv, rc *response.RequestContext) } func (r *ServiceRouter) listTerminators(ae *env.AppEnv, rc *response.RequestContext) { - r.listAssociations(ae, rc, ae.Handlers.Terminator, MapTerminatorToRestEntity) + if rc.Identity.IsAdmin { + r.listAssociations(ae, rc, ae.Handlers.Terminator, MapTerminatorToRestEntity) + return + } else { + serviceId, err := rc.GetEntityId() + + if err != nil { + rc.RespondWithError(err) + return + } + + svc, err := ae.Handlers.EdgeService.ReadForIdentity(serviceId, rc.Identity.Id, nil) + + if err != nil { + if boltz.IsErrNotFoundErr(err) { + rc.RespondWithNotFound() + } else { + rc.RespondWithError(err) + } + return + } + + if svc == nil { + rc.RespondWithNotFound() + return + } + + r.listAssociations(ae, rc, ae.Handlers.Terminator, MapLimitedTerminatorToRestEntity) + return + } } func (r *ServiceRouter) listAssociations(ae *env.AppEnv, rc *response.RequestContext, associationLoader models.EntityRetriever, mapper ModelToApiMapper) { diff --git a/controller/internal/routes/terminator_api_model.go b/controller/internal/routes/terminator_api_model.go index ee2458116..8d3308c9f 100644 --- a/controller/internal/routes/terminator_api_model.go +++ b/controller/internal/routes/terminator_api_model.go @@ -148,3 +148,41 @@ func MapTerminatorToRestModel(ae *env.AppEnv, terminator *network.Terminator) (* return ret, nil } + +func MapLimitedTerminatorToRestEntity(ae *env.AppEnv, _ *response.RequestContext, e models.Entity) (interface{}, error) { + terminator, ok := e.(*network.Terminator) + + if !ok { + err := fmt.Errorf("entity is not a Terminator \"%s\"", e.GetId()) + log := pfxlog.Logger() + log.Error(err) + return nil, err + } + + restModel, err := MapLimitedTerminatorToRestModel(ae, terminator) + + if err != nil { + err := fmt.Errorf("could not convert to API entity \"%s\": %s", e.GetId(), err) + log := pfxlog.Logger() + log.Error(err) + return nil, err + } + return restModel, nil +} + +func MapLimitedTerminatorToRestModel(ae *env.AppEnv, terminator *network.Terminator) (*rest_model.TerminatorDetailLimited, error) { + service, err := ae.Handlers.EdgeService.Read(terminator.Service) + if err != nil { + return nil, err + } + + ret := &rest_model.TerminatorDetailLimited{ + BaseEntity: BaseEntityToRestModel(terminator, TerminatorLinkFactory), + ServiceID: &terminator.Service, + Service: ToEntityRef(service.Name, service, ServiceLinkFactory), + RouterID: &terminator.Router, + Identity: &terminator.Identity, + } + + return ret, nil +} diff --git a/rest_client/service/service_client.go b/rest_client/service/service_client.go index 4ca262336..da4a6d7a0 100644 --- a/rest_client/service/service_client.go +++ b/rest_client/service/service_client.go @@ -382,7 +382,7 @@ func (a *Client) ListServiceServicePolicies(params *ListServiceServicePoliciesPa /* ListServiceTerminators lists of terminators assigned to a service - Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. Requires admin access. + Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. */ func (a *Client) ListServiceTerminators(params *ListServiceTerminatorsParams, authInfo runtime.ClientAuthInfoWriter) (*ListServiceTerminatorsOK, error) { diff --git a/rest_model/terminator_detail_limited.go b/rest_model/terminator_detail_limited.go new file mode 100644 index 000000000..a1d1648c1 --- /dev/null +++ b/rest_model/terminator_detail_limited.go @@ -0,0 +1,223 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// +// Copyright NetFoundry, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// __ __ _ +// \ \ / / (_) +// \ \ /\ / /_ _ _ __ _ __ _ _ __ __ _ +// \ \/ \/ / _` | '__| '_ \| | '_ \ / _` | +// \ /\ / (_| | | | | | | | | | | (_| | : This file is generated, do not edit it. +// \/ \/ \__,_|_| |_| |_|_|_| |_|\__, | +// __/ | +// |___/ + +package rest_model + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// TerminatorDetailLimited terminator detail limited +// +// swagger:model terminatorDetailLimited +type TerminatorDetailLimited struct { + BaseEntity + + // identity + // Required: true + Identity *string `json:"identity"` + + // router Id + // Required: true + RouterID *string `json:"routerId"` + + // service + // Required: true + Service *EntityRef `json:"service"` + + // service Id + // Required: true + ServiceID *string `json:"serviceId"` +} + +// UnmarshalJSON unmarshals this object from a JSON structure +func (m *TerminatorDetailLimited) UnmarshalJSON(raw []byte) error { + // AO0 + var aO0 BaseEntity + if err := swag.ReadJSON(raw, &aO0); err != nil { + return err + } + m.BaseEntity = aO0 + + // AO1 + var dataAO1 struct { + Identity *string `json:"identity"` + + RouterID *string `json:"routerId"` + + Service *EntityRef `json:"service"` + + ServiceID *string `json:"serviceId"` + } + if err := swag.ReadJSON(raw, &dataAO1); err != nil { + return err + } + + m.Identity = dataAO1.Identity + + m.RouterID = dataAO1.RouterID + + m.Service = dataAO1.Service + + m.ServiceID = dataAO1.ServiceID + + return nil +} + +// MarshalJSON marshals this object to a JSON structure +func (m TerminatorDetailLimited) MarshalJSON() ([]byte, error) { + _parts := make([][]byte, 0, 2) + + aO0, err := swag.WriteJSON(m.BaseEntity) + if err != nil { + return nil, err + } + _parts = append(_parts, aO0) + var dataAO1 struct { + Identity *string `json:"identity"` + + RouterID *string `json:"routerId"` + + Service *EntityRef `json:"service"` + + ServiceID *string `json:"serviceId"` + } + + dataAO1.Identity = m.Identity + + dataAO1.RouterID = m.RouterID + + dataAO1.Service = m.Service + + dataAO1.ServiceID = m.ServiceID + + jsonDataAO1, errAO1 := swag.WriteJSON(dataAO1) + if errAO1 != nil { + return nil, errAO1 + } + _parts = append(_parts, jsonDataAO1) + return swag.ConcatJSON(_parts...), nil +} + +// Validate validates this terminator detail limited +func (m *TerminatorDetailLimited) Validate(formats strfmt.Registry) error { + var res []error + + // validation for a type composition with BaseEntity + if err := m.BaseEntity.Validate(formats); err != nil { + res = append(res, err) + } + + if err := m.validateIdentity(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRouterID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateService(formats); err != nil { + res = append(res, err) + } + + if err := m.validateServiceID(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *TerminatorDetailLimited) validateIdentity(formats strfmt.Registry) error { + + if err := validate.Required("identity", "body", m.Identity); err != nil { + return err + } + + return nil +} + +func (m *TerminatorDetailLimited) validateRouterID(formats strfmt.Registry) error { + + if err := validate.Required("routerId", "body", m.RouterID); err != nil { + return err + } + + return nil +} + +func (m *TerminatorDetailLimited) validateService(formats strfmt.Registry) error { + + if err := validate.Required("service", "body", m.Service); err != nil { + return err + } + + if m.Service != nil { + if err := m.Service.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("service") + } + return err + } + } + + return nil +} + +func (m *TerminatorDetailLimited) validateServiceID(formats strfmt.Registry) error { + + if err := validate.Required("serviceId", "body", m.ServiceID); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *TerminatorDetailLimited) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *TerminatorDetailLimited) UnmarshalBinary(b []byte) error { + var res TerminatorDetailLimited + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/rest_server/embedded_spec.go b/rest_server/embedded_spec.go index ca3325d55..a8a01fb73 100644 --- a/rest_server/embedded_spec.go +++ b/rest_server/embedded_spec.go @@ -4282,7 +4282,7 @@ func init() { "ztSession": [] } ], - "description": "Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. Requires admin access.\n", + "description": "Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination.\n", "tags": [ "Service" ], @@ -8869,6 +8869,37 @@ func init() { } ] }, + "terminatorDetailLimited": { + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/baseEntity" + }, + { + "type": "object", + "required": [ + "serviceId", + "service", + "routerId", + "identity" + ], + "properties": { + "identity": { + "type": "string" + }, + "routerId": { + "type": "string" + }, + "service": { + "$ref": "#/definitions/entityRef" + }, + "serviceId": { + "type": "string" + } + } + } + ] + }, "terminatorList": { "type": "array", "items": { @@ -20817,7 +20848,7 @@ func init() { "ztSession": [] } ], - "description": "Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. Requires admin access.\n", + "description": "Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination.\n", "tags": [ "Service" ], @@ -26545,6 +26576,37 @@ func init() { } ] }, + "terminatorDetailLimited": { + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/baseEntity" + }, + { + "type": "object", + "required": [ + "serviceId", + "service", + "routerId", + "identity" + ], + "properties": { + "identity": { + "type": "string" + }, + "routerId": { + "type": "string" + }, + "service": { + "$ref": "#/definitions/entityRef" + }, + "serviceId": { + "type": "string" + } + } + } + ] + }, "terminatorList": { "type": "array", "items": { diff --git a/rest_server/operations/service/list_service_terminators.go b/rest_server/operations/service/list_service_terminators.go index 723f6dcba..dd5e636ce 100644 --- a/rest_server/operations/service/list_service_terminators.go +++ b/rest_server/operations/service/list_service_terminators.go @@ -57,7 +57,7 @@ func NewListServiceTerminators(ctx *middleware.Context, handler ListServiceTermi List of terminators assigned to a service -Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. Requires admin access. +Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. */ diff --git a/specs/swagger.yml b/specs/swagger.yml index c30437b37..989aeb0f5 100644 --- a/specs/swagger.yml +++ b/specs/swagger.yml @@ -2521,7 +2521,7 @@ paths: get: summary: List of terminators assigned to a service description: | - Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. Requires admin access. + Retrieves a list of terminator resources that are assigned specific service; supports filtering, sorting, and pagination. security: - ztSession: [ ] tags: @@ -5857,6 +5857,25 @@ definitions: $ref: '#/definitions/terminatorPrecedence' dynamicCost: $ref: '#/definitions/terminatorCost' + terminatorDetailLimited: + type: object + allOf: + - $ref: '#/definitions/baseEntity' + - type: object + required: + - serviceId + - service + - routerId + - identity + properties: + serviceId: + type: string + service: + $ref: '#/definitions/entityRef' + routerId: + type: string + identity: + type: string terminatorCreate: type: object