From 0164e5572e698413d8ea92e735ad1ff4ac78e969 Mon Sep 17 00:00:00 2001 From: Paul Lorenz Date: Fri, 3 Dec 2021 16:13:41 -0500 Subject: [PATCH 1/2] Add support for inspect --- controller/api_impl/inspections_api_model.go | 39 ++++ controller/api_impl/inspections_router.go | 55 +++++ controller/handler_mgmt/inspect.go | 176 +++----------- controller/network/controllers.go | 2 + controller/network/inspect.go | 182 +++++++++++++++ controller/network/network.go | 11 + rest_client/inspect/inspect_client.go | 106 +++++++++ rest_client/inspect/inspect_parameters.go | 175 ++++++++++++++ rest_client/inspect/inspect_responses.go | 129 +++++++++++ rest_client/ziti_fabric_client.go | 5 + rest_model/inspect_request.go | 112 +++++++++ rest_model/inspect_response.go | 161 +++++++++++++ rest_model/inspect_response_value.go | 129 +++++++++++ rest_server/configure_ziti_fabric.go | 6 + rest_server/embedded_spec.go | 214 ++++++++++++++++++ rest_server/operations/inspect/inspect.go | 83 +++++++ .../operations/inspect/inspect_parameters.go | 109 +++++++++ .../operations/inspect/inspect_responses.go | 126 +++++++++++ .../operations/inspect/inspect_urlbuilder.go | 111 +++++++++ rest_server/operations/ziti_fabric_api.go | 13 ++ specs/swagger.yml | 85 ++++++- 21 files changed, 1877 insertions(+), 152 deletions(-) create mode 100644 controller/api_impl/inspections_api_model.go create mode 100644 controller/api_impl/inspections_router.go create mode 100644 controller/network/inspect.go create mode 100644 rest_client/inspect/inspect_client.go create mode 100644 rest_client/inspect/inspect_parameters.go create mode 100644 rest_client/inspect/inspect_responses.go create mode 100644 rest_model/inspect_request.go create mode 100644 rest_model/inspect_response.go create mode 100644 rest_model/inspect_response_value.go create mode 100644 rest_server/operations/inspect/inspect.go create mode 100644 rest_server/operations/inspect/inspect_parameters.go create mode 100644 rest_server/operations/inspect/inspect_responses.go create mode 100644 rest_server/operations/inspect/inspect_urlbuilder.go diff --git a/controller/api_impl/inspections_api_model.go b/controller/api_impl/inspections_api_model.go new file mode 100644 index 000000000..c6de03621 --- /dev/null +++ b/controller/api_impl/inspections_api_model.go @@ -0,0 +1,39 @@ +/* + 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. +*/ + +package api_impl + +import ( + "github.com/openziti/fabric/controller/network" + "github.com/openziti/fabric/rest_model" +) + +const EntityNameInspect = "inspections" + +func MapInspectResultToRestModel(inspectResult *network.InspectResult) *rest_model.InspectResponse { + resp := &rest_model.InspectResponse{ + Errors: inspectResult.Errors, + Success: &inspectResult.Success, + } + for _, val := range inspectResult.Results { + resp.Values = append(resp.Values, &rest_model.InspectResponseValue{ + AppID: &val.AppId, + Name: &val.Name, + Value: &val.Value, + }) + } + return resp +} diff --git a/controller/api_impl/inspections_router.go b/controller/api_impl/inspections_router.go new file mode 100644 index 000000000..37355e88f --- /dev/null +++ b/controller/api_impl/inspections_router.go @@ -0,0 +1,55 @@ +/* + 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. +*/ + +package api_impl + +import ( + "github.com/go-openapi/runtime/middleware" + "github.com/openziti/fabric/controller/api" + "github.com/openziti/fabric/controller/network" + "github.com/openziti/fabric/rest_model" + "github.com/openziti/fabric/rest_server/operations" + "github.com/openziti/fabric/rest_server/operations/inspect" + "github.com/openziti/foundation/util/stringz" + "net/http" +) + +func init() { + r := NewInspectRouter() + AddRouter(r) +} + +type InspectRouter struct { + BasePath string +} + +func NewInspectRouter() *InspectRouter { + return &InspectRouter{ + BasePath: "/" + EntityNameInspect, + } +} + +func (r *InspectRouter) Register(fabricApi *operations.ZitiFabricAPI, wrapper RequestWrapper) { + fabricApi.InspectInspectHandler = inspect.InspectHandlerFunc(func(params inspect.InspectParams) middleware.Responder { + return wrapper.WrapRequest(func(n *network.Network, rc api.RequestContext) { r.Inspect(n, rc, params.Request) }, params.HTTPRequest, "", "") + }) +} + +func (r *InspectRouter) Inspect(n *network.Network, rc api.RequestContext, request *rest_model.InspectRequest) { + result := n.Controllers.Inspections.Inspect(stringz.OrEmpty(request.AppRegex), request.RequestedValues) + resp := MapInspectResultToRestModel(result) + rc.Respond(resp, http.StatusOK) +} diff --git a/controller/handler_mgmt/inspect.go b/controller/handler_mgmt/inspect.go index d379d7978..62cfc315b 100644 --- a/controller/handler_mgmt/inspect.go +++ b/controller/handler_mgmt/inspect.go @@ -21,14 +21,8 @@ import ( "github.com/golang/protobuf/proto" "github.com/michaelquigley/pfxlog" "github.com/openziti/fabric/controller/network" - "github.com/openziti/fabric/pb/ctrl_pb" "github.com/openziti/fabric/pb/mgmt_pb" "github.com/openziti/foundation/channel2" - "github.com/openziti/foundation/util/debugz" - "regexp" - "strings" - "sync" - "time" ) type inspectHandler struct { @@ -44,153 +38,35 @@ func (*inspectHandler) ContentType() int32 { } func (handler *inspectHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) { - context := &inspectRequestContext{ - handler: handler, - msg: msg, - ch: ch, - request: &mgmt_pb.InspectRequest{}, - response: &mgmt_pb.InspectResponse{Success: true}, - } - - var err error - if err = proto.Unmarshal(msg.Body, context.request); err != nil { - context.appendError(handler.network.GetAppId(), err.Error()) - } - - context.regex, err = regexp.Compile(context.request.AppRegex) - if err != nil { - context.appendError(handler.network.GetAppId(), err.Error()) - } - - if !context.response.Success { - context.sendResponse() - return - } - - context.processLocal() - context.processRemote() - context.sendResponse() -} - -type inspectRequestContext struct { - handler *inspectHandler - msg *channel2.Message - ch channel2.Channel - request *mgmt_pb.InspectRequest - response *mgmt_pb.InspectResponse - regex *regexp.Regexp -} - -func (context *inspectRequestContext) processLocal() { - if context.regex.MatchString(context.handler.network.GetAppId()) { - for _, requested := range context.request.RequestedValues { - if strings.ToLower(requested) == "stackdump" { - context.appendValue(context.handler.network.GetAppId(), requested, debugz.GenerateStack()) - } - } - } -} - -func (context *inspectRequestContext) processRemote() { - routerRequest := &ctrl_pb.InspectRequest{RequestedValues: context.request.RequestedValues} - body, err := proto.Marshal(routerRequest) - if err != nil { - context.appendError(context.handler.network.GetAppId(), err.Error()) - return - } - - remoteResultChan := make(chan *remoteInspectResult) - waitGroup := &sync.WaitGroup{} - - for _, router := range context.handler.network.AllConnectedRouters() { - if context.regex.MatchString(router.Id) { - msg := channel2.NewMessage(int32(ctrl_pb.ContentType_InspectRequestType), body) - respCh, err := router.Control.SendAndWait(msg) - if err != nil { - context.appendError(router.Id, err.Error()) - } else { - waitGroup.Add(1) - go handleInspectResponse(router.Id, respCh, remoteResultChan, waitGroup) - } - } - } - - // Close chan once all results have been queued go func() { - waitGroup.Wait() - close(remoteResultChan) - }() - - for remoteResult := range remoteResultChan { - for _, err := range remoteResult.result.Errors { - context.appendError(remoteResult.appId, err) - } - for _, val := range remoteResult.result.Values { - context.appendValue(remoteResult.appId, val.Name, val.Value) - } - } -} - -func handleInspectResponse(appId string, respCh <-chan *channel2.Message, msgsCh chan<- *remoteInspectResult, waitGroup *sync.WaitGroup) { - defer waitGroup.Done() - - timeout := time.After(time.Second * 5) - - select { - case response, ok := <-respCh: - if !ok { - routerInspectFailed(appId, msgsCh, "no response from router") - } else if response.ContentType == int32(ctrl_pb.ContentType_InspectResponseType) { - result := &ctrl_pb.InspectResponse{} - if err := proto.Unmarshal(response.Body, result); err != nil { - routerInspectFailed(appId, msgsCh, fmt.Sprintf("Failed to decode response from router: %v", err)) - } else { - msgsCh <- &remoteInspectResult{appId: appId, result: result} - } + response := &mgmt_pb.InspectResponse{} + request := &mgmt_pb.InspectRequest{} + if err := proto.Unmarshal(msg.Body, request); err != nil { + response.Success = false + response.Errors = append(response.Errors, fmt.Sprintf("%v: %v", handler.network.GetAppId(), err)) } else { - msg := fmt.Sprintf("Unexpected response type from router %v: %v\n", appId, response.ContentType) - routerInspectFailed(appId, msgsCh, msg) + result := handler.network.Controllers.Inspections.Inspect(request.AppRegex, request.RequestedValues) + response.Success = result.Success + response.Errors = result.Errors + for _, val := range result.Results { + response.Values = append(response.Values, &mgmt_pb.InspectResponse_InspectValue{ + AppId: val.AppId, + Name: val.Name, + Value: val.Value, + }) + } } - case <-timeout: - routerInspectFailed(appId, msgsCh, "timed out waiting for response from router") - } -} -func routerInspectFailed(appId string, msgsCh chan<- *remoteInspectResult, msg string) { - msgsCh <- &remoteInspectResult{ - appId: appId, - result: &ctrl_pb.InspectResponse{Errors: []string{msg}}, - } -} + body, err := proto.Marshal(response) + if err != nil { + pfxlog.Logger().Errorf("unexpected error serializing InspectResponse (%s)", err) + return + } -func (context *inspectRequestContext) sendResponse() { - body, err := proto.Marshal(context.response) - if err != nil { - pfxlog.Logger().Errorf("unexpected error serializing InspectResponse (%s)", err) - return - } - - responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_InspectResponseType), body) - responseMsg.ReplyTo(context.msg) - if err := context.ch.Send(responseMsg); err != nil { - pfxlog.Logger().Errorf("unexpected error sending InspectResponse (%s)", err) - } -} - -func (context *inspectRequestContext) appendValue(appId string, name string, value string) { - context.response.Values = append(context.response.Values, &mgmt_pb.InspectResponse_InspectValue{ - AppId: appId, - Name: name, - Value: value, - }) -} - -func (context *inspectRequestContext) appendError(appId string, err string) { - context.response.Success = false - context.response.Errors = append(context.response.Errors, fmt.Sprintf("%v: %v", appId, err)) -} - -type remoteInspectResult struct { - appId string - result *ctrl_pb.InspectResponse + responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_InspectResponseType), body) + responseMsg.ReplyTo(msg) + if err := ch.Send(responseMsg); err != nil { + pfxlog.Logger().Errorf("unexpected error sending InspectResponse (%s)", err) + } + }() } diff --git a/controller/network/controllers.go b/controller/network/controllers.go index bedf9852d..b0aac26ec 100644 --- a/controller/network/controllers.go +++ b/controller/network/controllers.go @@ -31,6 +31,7 @@ type Controllers struct { Terminators *TerminatorController Routers *RouterController Services *ServiceController + Inspections *InspectionsController } func (e *Controllers) getDb() boltz.Db { @@ -45,6 +46,7 @@ func NewControllers(db boltz.Db, stores *db.Stores) *Controllers { result.Terminators = newTerminatorController(result) result.Routers = newRouterController(result) result.Services = newServiceController(result) + result.Inspections = &InspectionsController{} return result } diff --git a/controller/network/inspect.go b/controller/network/inspect.go new file mode 100644 index 000000000..dc8eac53c --- /dev/null +++ b/controller/network/inspect.go @@ -0,0 +1,182 @@ +/* + 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. +*/ + +package network + +import ( + "fmt" + "github.com/michaelquigley/pfxlog" + "github.com/openziti/fabric/pb/ctrl_pb" + "github.com/openziti/foundation/util/concurrenz" + "regexp" + "sync" + "time" +) + +type InspectResultValue struct { + AppId string + Name string + Value string +} + +type InspectResult struct { + Success bool + Errors []string + Results []*InspectResultValue +} + +type InspectionsController struct { + network *Network +} + +func (self *InspectionsController) Inspect(appRegex string, values []string) *InspectResult { + ctx := &inspectRequestContext{ + network: self.network, + timeout: time.Second * 10, + requestedValues: values, + waitGroup: concurrenz.NewWaitGroup(), + appRegex: appRegex, + response: InspectResult{Success: true}, + } + + var err error + ctx.regex, err = regexp.Compile(appRegex) + if err != nil { + ctx.appendError(self.network.GetAppId(), err.Error()) + return &ctx.response + } + + return ctx.runInspections() +} + +type inspectRequestContext struct { + network *Network + timeout time.Duration + requestedValues []string + waitGroup concurrenz.WaitGroup + response InspectResult + appRegex string + regex *regexp.Regexp + lock sync.Mutex + complete bool +} + +func (ctx *inspectRequestContext) runInspections() *InspectResult { + log := pfxlog.Logger(). + WithField("appRegex", ctx.appRegex). + WithField("values", ctx.requestedValues). + WithField("timeout", ctx.timeout) + + ctx.inspectLocal() + + for _, router := range ctx.network.AllConnectedRouters() { + ctx.inspectRouter(router) + } + + if !ctx.waitGroup.WaitForDone(ctx.timeout) { + log.Info("inspect timed out, some values may be missing") + } + + ctx.lock.Lock() + defer ctx.lock.Unlock() + + ctx.complete = true + return &ctx.response +} + +func (ctx *inspectRequestContext) inspectLocal() { + log := pfxlog.Logger(). + WithField("appRegex", ctx.appRegex). + WithField("appId", ctx.network.GetAppId()). + WithField("values", ctx.requestedValues). + WithField("timeout", ctx.timeout) + + if ctx.regex.MatchString(ctx.network.GetAppId()) { + log.Debug("inspect matched") + notifier := make(chan struct{}) + ctx.waitGroup.AddNotifier(notifier) + go func() { + for _, requested := range ctx.requestedValues { + result := ctx.network.Inspect(requested) + if result != nil { + ctx.appendValue(ctx.network.GetAppId(), requested, *result) + } + } + close(notifier) + }() + } else { + log.Debug("inspect not matched") + } +} + +func (ctx *inspectRequestContext) inspectRouter(router *Router) { + log := pfxlog.Logger(). + WithField("appRegex", ctx.appRegex). + WithField("appId", router.Id). + WithField("values", ctx.requestedValues). + WithField("timeout", ctx.timeout) + + if ctx.regex.MatchString(router.Id) { + log.Debug("inspect matched") + notifier := make(chan struct{}) + ctx.waitGroup.AddNotifier(notifier) + + go ctx.handleRouterMessaging(router, notifier) + } else { + log.Debug("inspect not matched") + } +} + +func (ctx *inspectRequestContext) handleRouterMessaging(router *Router, notifier chan struct{}) { + defer close(notifier) + + request := &ctrl_pb.InspectRequest{RequestedValues: ctx.requestedValues} + resp := &ctrl_pb.InspectResponse{} + err := router.Control.SendForReplyAndDecode(request, ctx.timeout, resp) + if err != nil { + ctx.appendError(router.Id, err.Error()) + return + } + + for _, err := range resp.Errors { + ctx.appendError(router.Id, err) + } + + for _, val := range resp.Values { + ctx.appendValue(router.Id, val.Name, val.Value) + } +} + +func (ctx *inspectRequestContext) appendValue(appId string, name string, value string) { + ctx.lock.Lock() + defer ctx.lock.Unlock() + if !ctx.complete { + ctx.response.Results = append(ctx.response.Results, &InspectResultValue{ + AppId: appId, + Name: name, + Value: value, + }) + } +} + +func (ctx *inspectRequestContext) appendError(appId string, err string) { + ctx.lock.Lock() + defer ctx.lock.Unlock() + if !ctx.complete { + ctx.response.Success = false + ctx.response.Errors = append(ctx.response.Errors, fmt.Sprintf("%v: %v", appId, err)) + } +} diff --git a/controller/network/network.go b/controller/network/network.go index 9a302494d..7932de059 100644 --- a/controller/network/network.go +++ b/controller/network/network.go @@ -35,6 +35,7 @@ import ( "github.com/openziti/foundation/metrics" "github.com/openziti/foundation/metrics/metrics_pb" "github.com/openziti/foundation/storage/boltz" + "github.com/openziti/foundation/util/debugz" "github.com/openziti/foundation/util/errorz" "github.com/openziti/foundation/util/sequence" "github.com/pkg/errors" @@ -113,6 +114,8 @@ func NewNetwork(nodeId string, options *Options, database boltz.Db, metricsCfg * serviceDialOtherErrorCounter: serviceEventMetrics.IntervalCounter("service.dial.error_other", time.Minute), } + network.Controllers.Inspections.network = network + metrics.Init(metricsCfg) events.AddMetricsEventHandler(network) network.AddCapability("ziti.fabric") @@ -934,6 +937,14 @@ func (network *Network) NotifyRouterRenamed(id, name string) { } } +func (network *Network) Inspect(name string) *string { + if strings.ToLower(name) == "stackdump" { + result := debugz.GenerateStack() + return &result + } + return nil +} + var DbSnapshotTooFrequentError = dbSnapshotTooFrequentError{} type dbSnapshotTooFrequentError struct{} diff --git a/rest_client/inspect/inspect_client.go b/rest_client/inspect/inspect_client.go new file mode 100644 index 000000000..b7560dd2a --- /dev/null +++ b/rest_client/inspect/inspect_client.go @@ -0,0 +1,106 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" +) + +// New creates a new inspect API client. +func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { + return &Client{transport: transport, formats: formats} +} + +/* +Client for inspect API +*/ +type Client struct { + transport runtime.ClientTransport + formats strfmt.Registry +} + +// ClientOption is the option for Client methods +type ClientOption func(*runtime.ClientOperation) + +// ClientService is the interface for Client methods +type ClientService interface { + Inspect(params *InspectParams, opts ...ClientOption) (*InspectOK, error) + + SetTransport(transport runtime.ClientTransport) +} + +/* + Inspect inspects system values + + Requests system information, such as stack dumps or information about capabilities. Requires admin access. + +*/ +func (a *Client) Inspect(params *InspectParams, opts ...ClientOption) (*InspectOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewInspectParams() + } + op := &runtime.ClientOperation{ + ID: "inspect", + Method: "POST", + PathPattern: "/inspections", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"https"}, + Params: params, + Reader: &InspectReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*InspectOK) + if ok { + return success, nil + } + // unexpected success response + // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + msg := fmt.Sprintf("unexpected success response for inspect: API contract not enforced by server. Client expected to get an error, but got: %T", result) + panic(msg) +} + +// SetTransport changes the transport on the client +func (a *Client) SetTransport(transport runtime.ClientTransport) { + a.transport = transport +} diff --git a/rest_client/inspect/inspect_parameters.go b/rest_client/inspect/inspect_parameters.go new file mode 100644 index 000000000..c5a1cde9c --- /dev/null +++ b/rest_client/inspect/inspect_parameters.go @@ -0,0 +1,175 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/openziti/fabric/rest_model" +) + +// NewInspectParams creates a new InspectParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewInspectParams() *InspectParams { + return &InspectParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewInspectParamsWithTimeout creates a new InspectParams object +// with the ability to set a timeout on a request. +func NewInspectParamsWithTimeout(timeout time.Duration) *InspectParams { + return &InspectParams{ + timeout: timeout, + } +} + +// NewInspectParamsWithContext creates a new InspectParams object +// with the ability to set a context for a request. +func NewInspectParamsWithContext(ctx context.Context) *InspectParams { + return &InspectParams{ + Context: ctx, + } +} + +// NewInspectParamsWithHTTPClient creates a new InspectParams object +// with the ability to set a custom HTTPClient for a request. +func NewInspectParamsWithHTTPClient(client *http.Client) *InspectParams { + return &InspectParams{ + HTTPClient: client, + } +} + +/* InspectParams contains all the parameters to send to the API endpoint + for the inspect operation. + + Typically these are written to a http.Request. +*/ +type InspectParams struct { + + /* Request. + + An inspect request + */ + Request *rest_model.InspectRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the inspect params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *InspectParams) WithDefaults() *InspectParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the inspect params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *InspectParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the inspect params +func (o *InspectParams) WithTimeout(timeout time.Duration) *InspectParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the inspect params +func (o *InspectParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the inspect params +func (o *InspectParams) WithContext(ctx context.Context) *InspectParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the inspect params +func (o *InspectParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the inspect params +func (o *InspectParams) WithHTTPClient(client *http.Client) *InspectParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the inspect params +func (o *InspectParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithRequest adds the request to the inspect params +func (o *InspectParams) WithRequest(request *rest_model.InspectRequest) *InspectParams { + o.SetRequest(request) + return o +} + +// SetRequest adds the request to the inspect params +func (o *InspectParams) SetRequest(request *rest_model.InspectRequest) { + o.Request = request +} + +// WriteToRequest writes these params to a swagger request +func (o *InspectParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Request != nil { + if err := r.SetBodyParam(o.Request); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/rest_client/inspect/inspect_responses.go b/rest_client/inspect/inspect_responses.go new file mode 100644 index 000000000..b9ae3994e --- /dev/null +++ b/rest_client/inspect/inspect_responses.go @@ -0,0 +1,129 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/openziti/fabric/rest_model" +) + +// InspectReader is a Reader for the Inspect structure. +type InspectReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *InspectReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewInspectOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 401: + result := NewInspectUnauthorized() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + default: + return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) + } +} + +// NewInspectOK creates a InspectOK with default headers values +func NewInspectOK() *InspectOK { + return &InspectOK{} +} + +/* InspectOK describes a response with status code 200, with default header values. + +A response to an inspect request +*/ +type InspectOK struct { + Payload *rest_model.InspectResponse +} + +func (o *InspectOK) Error() string { + return fmt.Sprintf("[POST /inspections][%d] inspectOK %+v", 200, o.Payload) +} +func (o *InspectOK) GetPayload() *rest_model.InspectResponse { + return o.Payload +} + +func (o *InspectOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.InspectResponse) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewInspectUnauthorized creates a InspectUnauthorized with default headers values +func NewInspectUnauthorized() *InspectUnauthorized { + return &InspectUnauthorized{} +} + +/* InspectUnauthorized describes a response with status code 401, with default header values. + +The currently supplied session does not have the correct access rights to request this resource +*/ +type InspectUnauthorized struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *InspectUnauthorized) Error() string { + return fmt.Sprintf("[POST /inspections][%d] inspectUnauthorized %+v", 401, o.Payload) +} +func (o *InspectUnauthorized) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *InspectUnauthorized) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/rest_client/ziti_fabric_client.go b/rest_client/ziti_fabric_client.go index f1ff140b8..564fe0d58 100644 --- a/rest_client/ziti_fabric_client.go +++ b/rest_client/ziti_fabric_client.go @@ -35,6 +35,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/openziti/fabric/rest_client/circuit" + "github.com/openziti/fabric/rest_client/inspect" "github.com/openziti/fabric/rest_client/link" "github.com/openziti/fabric/rest_client/router" "github.com/openziti/fabric/rest_client/service" @@ -84,6 +85,7 @@ func New(transport runtime.ClientTransport, formats strfmt.Registry) *ZitiFabric cli := new(ZitiFabric) cli.Transport = transport cli.Circuit = circuit.New(transport, formats) + cli.Inspect = inspect.New(transport, formats) cli.Link = link.New(transport, formats) cli.Router = router.New(transport, formats) cli.Service = service.New(transport, formats) @@ -134,6 +136,8 @@ func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig { type ZitiFabric struct { Circuit circuit.ClientService + Inspect inspect.ClientService + Link link.ClientService Router router.ClientService @@ -149,6 +153,7 @@ type ZitiFabric struct { func (c *ZitiFabric) SetTransport(transport runtime.ClientTransport) { c.Transport = transport c.Circuit.SetTransport(transport) + c.Inspect.SetTransport(transport) c.Link.SetTransport(transport) c.Router.SetTransport(transport) c.Service.SetTransport(transport) diff --git a/rest_model/inspect_request.go b/rest_model/inspect_request.go new file mode 100644 index 000000000..966eafef0 --- /dev/null +++ b/rest_model/inspect_request.go @@ -0,0 +1,112 @@ +// 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 ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// InspectRequest inspect request +// +// swagger:model inspectRequest +type InspectRequest struct { + + // app regex + // Required: true + AppRegex *string `json:"appRegex"` + + // requested values + // Required: true + RequestedValues []string `json:"requestedValues"` +} + +// Validate validates this inspect request +func (m *InspectRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAppRegex(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequestedValues(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InspectRequest) validateAppRegex(formats strfmt.Registry) error { + + if err := validate.Required("appRegex", "body", m.AppRegex); err != nil { + return err + } + + return nil +} + +func (m *InspectRequest) validateRequestedValues(formats strfmt.Registry) error { + + if err := validate.Required("requestedValues", "body", m.RequestedValues); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this inspect request based on context it is used +func (m *InspectRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *InspectRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *InspectRequest) UnmarshalBinary(b []byte) error { + var res InspectRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/rest_model/inspect_response.go b/rest_model/inspect_response.go new file mode 100644 index 000000000..67f80587b --- /dev/null +++ b/rest_model/inspect_response.go @@ -0,0 +1,161 @@ +// 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 ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// InspectResponse inspect response +// +// swagger:model inspectResponse +type InspectResponse struct { + + // errors + Errors []string `json:"errors"` + + // success + // Required: true + Success *bool `json:"success"` + + // values + Values []*InspectResponseValue `json:"values"` +} + +// Validate validates this inspect response +func (m *InspectResponse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSuccess(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValues(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InspectResponse) validateSuccess(formats strfmt.Registry) error { + + if err := validate.Required("success", "body", m.Success); err != nil { + return err + } + + return nil +} + +func (m *InspectResponse) validateValues(formats strfmt.Registry) error { + if swag.IsZero(m.Values) { // not required + return nil + } + + for i := 0; i < len(m.Values); i++ { + if swag.IsZero(m.Values[i]) { // not required + continue + } + + if m.Values[i] != nil { + if err := m.Values[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("values" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("values" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this inspect response based on the context it is used +func (m *InspectResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateValues(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InspectResponse) contextValidateValues(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Values); i++ { + + if m.Values[i] != nil { + if err := m.Values[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("values" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("values" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *InspectResponse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *InspectResponse) UnmarshalBinary(b []byte) error { + var res InspectResponse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/rest_model/inspect_response_value.go b/rest_model/inspect_response_value.go new file mode 100644 index 000000000..9b305de2b --- /dev/null +++ b/rest_model/inspect_response_value.go @@ -0,0 +1,129 @@ +// 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 ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// InspectResponseValue inspect response value +// +// swagger:model inspectResponseValue +type InspectResponseValue struct { + + // app Id + // Required: true + AppID *string `json:"appId"` + + // name + // Required: true + Name *string `json:"name"` + + // value + // Required: true + Value *string `json:"value"` +} + +// Validate validates this inspect response value +func (m *InspectResponseValue) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAppID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValue(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InspectResponseValue) validateAppID(formats strfmt.Registry) error { + + if err := validate.Required("appId", "body", m.AppID); err != nil { + return err + } + + return nil +} + +func (m *InspectResponseValue) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +func (m *InspectResponseValue) validateValue(formats strfmt.Registry) error { + + if err := validate.Required("value", "body", m.Value); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this inspect response value based on context it is used +func (m *InspectResponseValue) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *InspectResponseValue) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *InspectResponseValue) UnmarshalBinary(b []byte) error { + var res InspectResponseValue + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/rest_server/configure_ziti_fabric.go b/rest_server/configure_ziti_fabric.go index 14256ebdb..f29861bc2 100644 --- a/rest_server/configure_ziti_fabric.go +++ b/rest_server/configure_ziti_fabric.go @@ -36,6 +36,7 @@ import ( "github.com/openziti/fabric/rest_server/operations" "github.com/openziti/fabric/rest_server/operations/circuit" + "github.com/openziti/fabric/rest_server/operations/inspect" "github.com/openziti/fabric/rest_server/operations/link" "github.com/openziti/fabric/rest_server/operations/router" "github.com/openziti/fabric/rest_server/operations/service" @@ -126,6 +127,11 @@ func configureAPI(api *operations.ZitiFabricAPI) http.Handler { return middleware.NotImplemented("operation terminator.DetailTerminator has not yet been implemented") }) } + if api.InspectInspectHandler == nil { + api.InspectInspectHandler = inspect.InspectHandlerFunc(func(params inspect.InspectParams) middleware.Responder { + return middleware.NotImplemented("operation inspect.Inspect has not yet been implemented") + }) + } if api.CircuitListCircuitsHandler == nil { api.CircuitListCircuitsHandler = circuit.ListCircuitsHandlerFunc(func(params circuit.ListCircuitsParams) middleware.Responder { return middleware.NotImplemented("operation circuit.ListCircuits has not yet been implemented") diff --git a/rest_server/embedded_spec.go b/rest_server/embedded_spec.go index a029f4ce1..1ec539b0e 100644 --- a/rest_server/embedded_spec.go +++ b/rest_server/embedded_spec.go @@ -136,6 +136,35 @@ func init() { } ] }, + "/inspections": { + "post": { + "description": "Requests system information, such as stack dumps or information about capabilities. Requires admin access.\n", + "tags": [ + "Inspect" + ], + "summary": "Inspect system values", + "operationId": "inspect", + "parameters": [ + { + "description": "An inspect request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/inspectRequest" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/inspectResponse" + }, + "401": { + "$ref": "#/responses/unauthorizedResponse" + } + } + } + }, "/links": { "get": { "description": "Retrieves a list of link resources; does not supports filtering, sorting, or pagination. Requires admin access.\n", @@ -1103,6 +1132,66 @@ func init() { } } }, + "inspectRequest": { + "type": "object", + "required": [ + "appRegex", + "requestedValues" + ], + "properties": { + "appRegex": { + "type": "string" + }, + "requestedValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "inspectResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "errors": { + "type": "array", + "items": { + "type": "string" + } + }, + "success": { + "type": "boolean" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/inspectResponseValue" + } + } + } + }, + "inspectResponseValue": { + "type": "object", + "required": [ + "appId", + "name", + "value" + ], + "properties": { + "appId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "link": { "description": "A link to another resource", "type": "object", @@ -1833,6 +1922,12 @@ func init() { "$ref": "#/definitions/empty" } }, + "inspectResponse": { + "description": "A response to an inspect request", + "schema": { + "$ref": "#/definitions/inspectResponse" + } + }, "invalidAuthResponse": { "description": "The authentication request could not be processed as the credentials are invalid", "schema": { @@ -2224,6 +2319,59 @@ func init() { } ] }, + "/inspections": { + "post": { + "description": "Requests system information, such as stack dumps or information about capabilities. Requires admin access.\n", + "tags": [ + "Inspect" + ], + "summary": "Inspect system values", + "operationId": "inspect", + "parameters": [ + { + "description": "An inspect request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/inspectRequest" + } + } + ], + "responses": { + "200": { + "description": "A response to an inspect request", + "schema": { + "$ref": "#/definitions/inspectResponse" + } + }, + "401": { + "description": "The currently supplied session does not have the correct access rights to request this resource", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "cause": "", + "causeMessage": "", + "code": "UNAUTHORIZED", + "message": "The request could not be completed. The session is not authorized or the credentials are invalid", + "requestId": "0bfe7a04-9229-4b7a-812c-9eb3cc0eac0f" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } + } + } + } + }, "/links": { "get": { "description": "Retrieves a list of link resources; does not supports filtering, sorting, or pagination. Requires admin access.\n", @@ -4677,6 +4825,66 @@ func init() { } } }, + "inspectRequest": { + "type": "object", + "required": [ + "appRegex", + "requestedValues" + ], + "properties": { + "appRegex": { + "type": "string" + }, + "requestedValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "inspectResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "errors": { + "type": "array", + "items": { + "type": "string" + } + }, + "success": { + "type": "boolean" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/inspectResponseValue" + } + } + } + }, + "inspectResponseValue": { + "type": "object", + "required": [ + "appId", + "name", + "value" + ], + "properties": { + "appId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "link": { "description": "A link to another resource", "type": "object", @@ -5408,6 +5616,12 @@ func init() { "$ref": "#/definitions/empty" } }, + "inspectResponse": { + "description": "A response to an inspect request", + "schema": { + "$ref": "#/definitions/inspectResponse" + } + }, "invalidAuthResponse": { "description": "The authentication request could not be processed as the credentials are invalid", "schema": { diff --git a/rest_server/operations/inspect/inspect.go b/rest_server/operations/inspect/inspect.go new file mode 100644 index 000000000..c009b665a --- /dev/null +++ b/rest_server/operations/inspect/inspect.go @@ -0,0 +1,83 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// InspectHandlerFunc turns a function with the right signature into a inspect handler +type InspectHandlerFunc func(InspectParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn InspectHandlerFunc) Handle(params InspectParams) middleware.Responder { + return fn(params) +} + +// InspectHandler interface for that can handle valid inspect params +type InspectHandler interface { + Handle(InspectParams) middleware.Responder +} + +// NewInspect creates a new http.Handler for the inspect operation +func NewInspect(ctx *middleware.Context, handler InspectHandler) *Inspect { + return &Inspect{Context: ctx, Handler: handler} +} + +/* Inspect swagger:route POST /inspections Inspect inspect + +Inspect system values + +Requests system information, such as stack dumps or information about capabilities. Requires admin access. + + +*/ +type Inspect struct { + Context *middleware.Context + Handler InspectHandler +} + +func (o *Inspect) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewInspectParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/rest_server/operations/inspect/inspect_parameters.go b/rest_server/operations/inspect/inspect_parameters.go new file mode 100644 index 000000000..6bb8fe7d5 --- /dev/null +++ b/rest_server/operations/inspect/inspect_parameters.go @@ -0,0 +1,109 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "io" + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/validate" + + "github.com/openziti/fabric/rest_model" +) + +// NewInspectParams creates a new InspectParams object +// +// There are no default values defined in the spec. +func NewInspectParams() InspectParams { + + return InspectParams{} +} + +// InspectParams contains all the bound params for the inspect operation +// typically these are obtained from a http.Request +// +// swagger:parameters inspect +type InspectParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /*An inspect request + Required: true + In: body + */ + Request *rest_model.InspectRequest +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewInspectParams() beforehand. +func (o *InspectParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body rest_model.InspectRequest + if err := route.Consumer.Consume(r.Body, &body); err != nil { + if err == io.EOF { + res = append(res, errors.Required("request", "body", "")) + } else { + res = append(res, errors.NewParseError("request", "body", "", err)) + } + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(context.Background()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.Request = &body + } + } + } else { + res = append(res, errors.Required("request", "body", "")) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/rest_server/operations/inspect/inspect_responses.go b/rest_server/operations/inspect/inspect_responses.go new file mode 100644 index 000000000..33b7dfaf2 --- /dev/null +++ b/rest_server/operations/inspect/inspect_responses.go @@ -0,0 +1,126 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/openziti/fabric/rest_model" +) + +// InspectOKCode is the HTTP code returned for type InspectOK +const InspectOKCode int = 200 + +/*InspectOK A response to an inspect request + +swagger:response inspectOK +*/ +type InspectOK struct { + + /* + In: Body + */ + Payload *rest_model.InspectResponse `json:"body,omitempty"` +} + +// NewInspectOK creates InspectOK with default headers values +func NewInspectOK() *InspectOK { + + return &InspectOK{} +} + +// WithPayload adds the payload to the inspect o k response +func (o *InspectOK) WithPayload(payload *rest_model.InspectResponse) *InspectOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the inspect o k response +func (o *InspectOK) SetPayload(payload *rest_model.InspectResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *InspectOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// InspectUnauthorizedCode is the HTTP code returned for type InspectUnauthorized +const InspectUnauthorizedCode int = 401 + +/*InspectUnauthorized The currently supplied session does not have the correct access rights to request this resource + +swagger:response inspectUnauthorized +*/ +type InspectUnauthorized struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewInspectUnauthorized creates InspectUnauthorized with default headers values +func NewInspectUnauthorized() *InspectUnauthorized { + + return &InspectUnauthorized{} +} + +// WithPayload adds the payload to the inspect unauthorized response +func (o *InspectUnauthorized) WithPayload(payload *rest_model.APIErrorEnvelope) *InspectUnauthorized { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the inspect unauthorized response +func (o *InspectUnauthorized) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *InspectUnauthorized) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(401) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/rest_server/operations/inspect/inspect_urlbuilder.go b/rest_server/operations/inspect/inspect_urlbuilder.go new file mode 100644 index 000000000..260c5bce6 --- /dev/null +++ b/rest_server/operations/inspect/inspect_urlbuilder.go @@ -0,0 +1,111 @@ +// 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 inspect + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" +) + +// InspectURL generates an URL for the inspect operation +type InspectURL struct { + _basePath string +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *InspectURL) WithBasePath(bp string) *InspectURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *InspectURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *InspectURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/inspections" + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/fabric/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *InspectURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *InspectURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *InspectURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on InspectURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on InspectURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *InspectURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/rest_server/operations/ziti_fabric_api.go b/rest_server/operations/ziti_fabric_api.go index 91317b802..d3d2a7083 100644 --- a/rest_server/operations/ziti_fabric_api.go +++ b/rest_server/operations/ziti_fabric_api.go @@ -44,6 +44,7 @@ import ( "github.com/go-openapi/swag" "github.com/openziti/fabric/rest_server/operations/circuit" + "github.com/openziti/fabric/rest_server/operations/inspect" "github.com/openziti/fabric/rest_server/operations/link" "github.com/openziti/fabric/rest_server/operations/router" "github.com/openziti/fabric/rest_server/operations/service" @@ -108,6 +109,9 @@ func NewZitiFabricAPI(spec *loads.Document) *ZitiFabricAPI { TerminatorDetailTerminatorHandler: terminator.DetailTerminatorHandlerFunc(func(params terminator.DetailTerminatorParams) middleware.Responder { return middleware.NotImplemented("operation terminator.DetailTerminator has not yet been implemented") }), + InspectInspectHandler: inspect.InspectHandlerFunc(func(params inspect.InspectParams) middleware.Responder { + return middleware.NotImplemented("operation inspect.Inspect has not yet been implemented") + }), CircuitListCircuitsHandler: circuit.ListCircuitsHandlerFunc(func(params circuit.ListCircuitsParams) middleware.Responder { return middleware.NotImplemented("operation circuit.ListCircuits has not yet been implemented") }), @@ -210,6 +214,8 @@ type ZitiFabricAPI struct { ServiceDetailServiceHandler service.DetailServiceHandler // TerminatorDetailTerminatorHandler sets the operation handler for the detail terminator operation TerminatorDetailTerminatorHandler terminator.DetailTerminatorHandler + // InspectInspectHandler sets the operation handler for the inspect operation + InspectInspectHandler inspect.InspectHandler // CircuitListCircuitsHandler sets the operation handler for the list circuits operation CircuitListCircuitsHandler circuit.ListCircuitsHandler // LinkListLinksHandler sets the operation handler for the list links operation @@ -351,6 +357,9 @@ func (o *ZitiFabricAPI) Validate() error { if o.TerminatorDetailTerminatorHandler == nil { unregistered = append(unregistered, "terminator.DetailTerminatorHandler") } + if o.InspectInspectHandler == nil { + unregistered = append(unregistered, "inspect.InspectHandler") + } if o.CircuitListCircuitsHandler == nil { unregistered = append(unregistered, "circuit.ListCircuitsHandler") } @@ -529,6 +538,10 @@ func (o *ZitiFabricAPI) initHandlerCache() { o.handlers["GET"] = make(map[string]http.Handler) } o.handlers["GET"]["/terminators/{id}"] = terminator.NewDetailTerminator(o.context, o.TerminatorDetailTerminatorHandler) + if o.handlers["POST"] == nil { + o.handlers["POST"] = make(map[string]http.Handler) + } + o.handlers["POST"]["/inspections"] = inspect.NewInspect(o.context, o.InspectInspectHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } diff --git a/specs/swagger.yml b/specs/swagger.yml index 03ab59764..7c9614cc0 100644 --- a/specs/swagger.yml +++ b/specs/swagger.yml @@ -523,6 +523,30 @@ paths: '409': $ref: '#/responses/cannotDeleteReferencedResourceResponse' + ################################################################### + # Inspections + ################################################################## + '/inspections': + post: + summary: Inspect system values + description: | + Requests system information, such as stack dumps or information about capabilities. Requires admin access. + tags: + - Inspect + operationId: inspect + parameters: + - name: request + in: body + required: true + description: An inspect request + schema: + $ref: '#/definitions/inspectRequest' + responses: + '200': + $ref: '#/responses/inspectResponse' + '401': + $ref: '#/responses/unauthorizedResponse' + ####################################################################################################################### # # Parameters - Reusable parameters @@ -745,7 +769,7 @@ responses: ################################################################### # Circuits - ################################################################## + ################################################################### listCircuits: description: A list of circuits schema: @@ -755,6 +779,14 @@ responses: schema: $ref: '#/definitions/detailCircuitEnvelope' + ################################################################### + # Inspections + ################################################################### + inspectResponse: + description: A response to an inspect request + schema: + $ref: '#/definitions/inspectResponse' + ####################################################################################################################### # # Definitions - In & Out Models Only @@ -1386,4 +1418,53 @@ definitions: type: object properties: immediate: - type: boolean \ No newline at end of file + type: boolean + + ################################################################### + # Inspections + ################################################################## + inspectRequest: + type: object + required: + - appRegex + - requestedValues + properties: + appRegex: + type: string + requestedValues: + type: array + items: + type: string + inspectResponseValue: + type: object + required: + - appId + - name + - value + properties: + appId: + type: string + name: + type: string + value: + type: string + inspectResponse: + type: object + required: + - success + properties: + success: + type: boolean + errors: + type: array + items: + type: string + values: + type: array + items: + $ref: '#/definitions/inspectResponseValue' + + + + + From cbbd3fee4b8dfaee4aa53e6328fe5f4b07c0109e Mon Sep 17 00:00:00 2001 From: Paul Lorenz Date: Fri, 3 Dec 2021 16:14:51 -0500 Subject: [PATCH 2/2] Add codeowners file --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..5be6e2a4e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# see: +# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners +* @openziti/maintainers +