diff --git a/api/Makefile b/api/Makefile index c94b0ad68a9..48f9b69204e 100644 --- a/api/Makefile +++ b/api/Makefile @@ -22,6 +22,7 @@ gen: ## Generate PMM API qan/v1 \ realtimeanalytics/v1 \ platform/v1 \ + om/v1 \ ha/v1beta1"; \ for API in $$SPECS; do \ set -x ; \ @@ -40,7 +41,8 @@ gen: ## Generate PMM API --additional-initialism=realtimeanalytics \ --additional-initialism=rds \ --additional-initialism=sql \ - --additional-initialism=ha ; \ + --additional-initialism=ha \ + --additional-initialism=om ; \ done # generate public API spec, omit agentlocal and inventory (always private), @@ -57,6 +59,7 @@ gen: ## Generate PMM API backup/v1/json/v1.json \ qan/v1/json/v1.json \ realtimeanalytics/v1/json/v1.json \ + om/v1/json/v1.json \ ha/v1beta1/json/v1beta1.json go tool swagger validate swagger/swagger.json @@ -75,6 +78,7 @@ gen: ## Generate PMM API accesscontrol/v1beta1/json/v1beta1.json \ qan/v1/json/v1.json \ realtimeanalytics/v1/json/v1.json \ + om/v1/json/v1.json \ ha/v1beta1/json/v1beta1.json go tool swagger validate swagger/swagger-dev.json @@ -119,6 +123,7 @@ clean: clean-swagger ## Remove generated files qan/v1 \ realtimeanalytics/v1 \ platform/v1 \ + om/v1 \ ha/v1beta1"; \ for API in $$SPECS; do \ rm -fr $$API/json/client $$API/json/models $$API/json/$$(basename $$API).json ; \ diff --git a/api/om/v1/json/client/om_service/delete_inventory_config_override_parameters.go b/api/om/v1/json/client/om_service/delete_inventory_config_override_parameters.go new file mode 100644 index 00000000000..275933033be --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_config_override_parameters.go @@ -0,0 +1,147 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewDeleteInventoryConfigOverrideParams creates a new DeleteInventoryConfigOverrideParams 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 NewDeleteInventoryConfigOverrideParams() *DeleteInventoryConfigOverrideParams { + return &DeleteInventoryConfigOverrideParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteInventoryConfigOverrideParamsWithTimeout creates a new DeleteInventoryConfigOverrideParams object +// with the ability to set a timeout on a request. +func NewDeleteInventoryConfigOverrideParamsWithTimeout(timeout time.Duration) *DeleteInventoryConfigOverrideParams { + return &DeleteInventoryConfigOverrideParams{ + timeout: timeout, + } +} + +// NewDeleteInventoryConfigOverrideParamsWithContext creates a new DeleteInventoryConfigOverrideParams object +// with the ability to set a context for a request. +func NewDeleteInventoryConfigOverrideParamsWithContext(ctx context.Context) *DeleteInventoryConfigOverrideParams { + return &DeleteInventoryConfigOverrideParams{ + Context: ctx, + } +} + +// NewDeleteInventoryConfigOverrideParamsWithHTTPClient creates a new DeleteInventoryConfigOverrideParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteInventoryConfigOverrideParamsWithHTTPClient(client *http.Client) *DeleteInventoryConfigOverrideParams { + return &DeleteInventoryConfigOverrideParams{ + HTTPClient: client, + } +} + +/* +DeleteInventoryConfigOverrideParams contains all the parameters to send to the API endpoint + + for the delete inventory config override operation. + + Typically these are written to a http.Request. +*/ +type DeleteInventoryConfigOverrideParams struct { + /* Key. + + The field whose override to remove, putting it back to its deployed value. Also the + resource ID within the `overrides` collection. + */ + Key string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete inventory config override params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryConfigOverrideParams) WithDefaults() *DeleteInventoryConfigOverrideParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete inventory config override params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryConfigOverrideParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) WithTimeout(timeout time.Duration) *DeleteInventoryConfigOverrideParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) WithContext(ctx context.Context) *DeleteInventoryConfigOverrideParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) WithHTTPClient(client *http.Client) *DeleteInventoryConfigOverrideParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithKey adds the key to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) WithKey(key string) *DeleteInventoryConfigOverrideParams { + o.SetKey(key) + return o +} + +// SetKey adds the key to the delete inventory config override params +func (o *DeleteInventoryConfigOverrideParams) SetKey(key string) { + o.Key = key +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteInventoryConfigOverrideParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param key + if err := r.SetPathParam("key", o.Key); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/delete_inventory_config_override_responses.go b/api/om/v1/json/client/om_service/delete_inventory_config_override_responses.go new file mode 100644 index 00000000000..99756553a98 --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_config_override_responses.go @@ -0,0 +1,411 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DeleteInventoryConfigOverrideReader is a Reader for the DeleteInventoryConfigOverride structure. +type DeleteInventoryConfigOverrideReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteInventoryConfigOverrideReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewDeleteInventoryConfigOverrideOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewDeleteInventoryConfigOverrideDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewDeleteInventoryConfigOverrideOK creates a DeleteInventoryConfigOverrideOK with default headers values +func NewDeleteInventoryConfigOverrideOK() *DeleteInventoryConfigOverrideOK { + return &DeleteInventoryConfigOverrideOK{} +} + +/* +DeleteInventoryConfigOverrideOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type DeleteInventoryConfigOverrideOK struct { + Payload any +} + +// IsSuccess returns true when this delete inventory config override Ok response has a 2xx status code +func (o *DeleteInventoryConfigOverrideOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this delete inventory config override Ok response has a 3xx status code +func (o *DeleteInventoryConfigOverrideOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this delete inventory config override Ok response has a 4xx status code +func (o *DeleteInventoryConfigOverrideOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this delete inventory config override Ok response has a 5xx status code +func (o *DeleteInventoryConfigOverrideOK) IsServerError() bool { + return false +} + +// IsCode returns true when this delete inventory config override Ok response a status code equal to that given +func (o *DeleteInventoryConfigOverrideOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the delete inventory config override Ok response +func (o *DeleteInventoryConfigOverrideOK) Code() int { + return 200 +} + +func (o *DeleteInventoryConfigOverrideOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/config/overrides/{key}][%d] deleteInventoryConfigOverrideOk %s", 200, payload) +} + +func (o *DeleteInventoryConfigOverrideOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/config/overrides/{key}][%d] deleteInventoryConfigOverrideOk %s", 200, payload) +} + +func (o *DeleteInventoryConfigOverrideOK) GetPayload() any { + return o.Payload +} + +func (o *DeleteInventoryConfigOverrideOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewDeleteInventoryConfigOverrideDefault creates a DeleteInventoryConfigOverrideDefault with default headers values +func NewDeleteInventoryConfigOverrideDefault(code int) *DeleteInventoryConfigOverrideDefault { + return &DeleteInventoryConfigOverrideDefault{ + _statusCode: code, + } +} + +/* +DeleteInventoryConfigOverrideDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type DeleteInventoryConfigOverrideDefault struct { + _statusCode int + + Payload *DeleteInventoryConfigOverrideDefaultBody +} + +// IsSuccess returns true when this delete inventory config override default response has a 2xx status code +func (o *DeleteInventoryConfigOverrideDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete inventory config override default response has a 3xx status code +func (o *DeleteInventoryConfigOverrideDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete inventory config override default response has a 4xx status code +func (o *DeleteInventoryConfigOverrideDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete inventory config override default response has a 5xx status code +func (o *DeleteInventoryConfigOverrideDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete inventory config override default response a status code equal to that given +func (o *DeleteInventoryConfigOverrideDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete inventory config override default response +func (o *DeleteInventoryConfigOverrideDefault) Code() int { + return o._statusCode +} + +func (o *DeleteInventoryConfigOverrideDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/config/overrides/{key}][%d] DeleteInventoryConfigOverride default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryConfigOverrideDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/config/overrides/{key}][%d] DeleteInventoryConfigOverride default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryConfigOverrideDefault) GetPayload() *DeleteInventoryConfigOverrideDefaultBody { + return o.Payload +} + +func (o *DeleteInventoryConfigOverrideDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(DeleteInventoryConfigOverrideDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +DeleteInventoryConfigOverrideDefaultBody delete inventory config override default body +swagger:model DeleteInventoryConfigOverrideDefaultBody +*/ +type DeleteInventoryConfigOverrideDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this delete inventory config override default body +func (o *DeleteInventoryConfigOverrideDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryConfigOverrideDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryConfigOverride default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryConfigOverride default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this delete inventory config override default body based on the context it is used +func (o *DeleteInventoryConfigOverrideDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryConfigOverrideDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryConfigOverride default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryConfigOverride default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryConfigOverrideDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryConfigOverrideDefaultBody) UnmarshalBinary(b []byte) error { + var res DeleteInventoryConfigOverrideDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 delete inventory config override default body details items0 +swagger:model DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 +*/ +type DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // delete inventory config override default body details items0 + DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this delete inventory config override default body details items0 +func (o *DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this delete inventory config override default body details items0 based on context it is used +func (o *DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryConfigOverrideDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res DeleteInventoryConfigOverrideDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/delete_inventory_host_parameters.go b/api/om/v1/json/client/om_service/delete_inventory_host_parameters.go new file mode 100644 index 00000000000..2fcab415f7a --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_host_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewDeleteInventoryHostParams creates a new DeleteInventoryHostParams 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 NewDeleteInventoryHostParams() *DeleteInventoryHostParams { + return &DeleteInventoryHostParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteInventoryHostParamsWithTimeout creates a new DeleteInventoryHostParams object +// with the ability to set a timeout on a request. +func NewDeleteInventoryHostParamsWithTimeout(timeout time.Duration) *DeleteInventoryHostParams { + return &DeleteInventoryHostParams{ + timeout: timeout, + } +} + +// NewDeleteInventoryHostParamsWithContext creates a new DeleteInventoryHostParams object +// with the ability to set a context for a request. +func NewDeleteInventoryHostParamsWithContext(ctx context.Context) *DeleteInventoryHostParams { + return &DeleteInventoryHostParams{ + Context: ctx, + } +} + +// NewDeleteInventoryHostParamsWithHTTPClient creates a new DeleteInventoryHostParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteInventoryHostParamsWithHTTPClient(client *http.Client) *DeleteInventoryHostParams { + return &DeleteInventoryHostParams{ + HTTPClient: client, + } +} + +/* +DeleteInventoryHostParams contains all the parameters to send to the API endpoint + + for the delete inventory host operation. + + Typically these are written to a http.Request. +*/ +type DeleteInventoryHostParams struct { + /* NodeID. + + PMM's node ID. + */ + NodeID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete inventory host params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryHostParams) WithDefaults() *DeleteInventoryHostParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete inventory host params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryHostParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete inventory host params +func (o *DeleteInventoryHostParams) WithTimeout(timeout time.Duration) *DeleteInventoryHostParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete inventory host params +func (o *DeleteInventoryHostParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete inventory host params +func (o *DeleteInventoryHostParams) WithContext(ctx context.Context) *DeleteInventoryHostParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete inventory host params +func (o *DeleteInventoryHostParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete inventory host params +func (o *DeleteInventoryHostParams) WithHTTPClient(client *http.Client) *DeleteInventoryHostParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete inventory host params +func (o *DeleteInventoryHostParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithNodeID adds the nodeID to the delete inventory host params +func (o *DeleteInventoryHostParams) WithNodeID(nodeID string) *DeleteInventoryHostParams { + o.SetNodeID(nodeID) + return o +} + +// SetNodeID adds the nodeId to the delete inventory host params +func (o *DeleteInventoryHostParams) SetNodeID(nodeID string) { + o.NodeID = nodeID +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteInventoryHostParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param node_id + if err := r.SetPathParam("node_id", o.NodeID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/delete_inventory_host_responses.go b/api/om/v1/json/client/om_service/delete_inventory_host_responses.go new file mode 100644 index 00000000000..ede6d3f7a1e --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_host_responses.go @@ -0,0 +1,411 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DeleteInventoryHostReader is a Reader for the DeleteInventoryHost structure. +type DeleteInventoryHostReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteInventoryHostReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewDeleteInventoryHostOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewDeleteInventoryHostDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewDeleteInventoryHostOK creates a DeleteInventoryHostOK with default headers values +func NewDeleteInventoryHostOK() *DeleteInventoryHostOK { + return &DeleteInventoryHostOK{} +} + +/* +DeleteInventoryHostOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type DeleteInventoryHostOK struct { + Payload any +} + +// IsSuccess returns true when this delete inventory host Ok response has a 2xx status code +func (o *DeleteInventoryHostOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this delete inventory host Ok response has a 3xx status code +func (o *DeleteInventoryHostOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this delete inventory host Ok response has a 4xx status code +func (o *DeleteInventoryHostOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this delete inventory host Ok response has a 5xx status code +func (o *DeleteInventoryHostOK) IsServerError() bool { + return false +} + +// IsCode returns true when this delete inventory host Ok response a status code equal to that given +func (o *DeleteInventoryHostOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the delete inventory host Ok response +func (o *DeleteInventoryHostOK) Code() int { + return 200 +} + +func (o *DeleteInventoryHostOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/hosts/{node_id}][%d] deleteInventoryHostOk %s", 200, payload) +} + +func (o *DeleteInventoryHostOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/hosts/{node_id}][%d] deleteInventoryHostOk %s", 200, payload) +} + +func (o *DeleteInventoryHostOK) GetPayload() any { + return o.Payload +} + +func (o *DeleteInventoryHostOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewDeleteInventoryHostDefault creates a DeleteInventoryHostDefault with default headers values +func NewDeleteInventoryHostDefault(code int) *DeleteInventoryHostDefault { + return &DeleteInventoryHostDefault{ + _statusCode: code, + } +} + +/* +DeleteInventoryHostDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type DeleteInventoryHostDefault struct { + _statusCode int + + Payload *DeleteInventoryHostDefaultBody +} + +// IsSuccess returns true when this delete inventory host default response has a 2xx status code +func (o *DeleteInventoryHostDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete inventory host default response has a 3xx status code +func (o *DeleteInventoryHostDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete inventory host default response has a 4xx status code +func (o *DeleteInventoryHostDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete inventory host default response has a 5xx status code +func (o *DeleteInventoryHostDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete inventory host default response a status code equal to that given +func (o *DeleteInventoryHostDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete inventory host default response +func (o *DeleteInventoryHostDefault) Code() int { + return o._statusCode +} + +func (o *DeleteInventoryHostDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/hosts/{node_id}][%d] DeleteInventoryHost default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryHostDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/hosts/{node_id}][%d] DeleteInventoryHost default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryHostDefault) GetPayload() *DeleteInventoryHostDefaultBody { + return o.Payload +} + +func (o *DeleteInventoryHostDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(DeleteInventoryHostDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +DeleteInventoryHostDefaultBody delete inventory host default body +swagger:model DeleteInventoryHostDefaultBody +*/ +type DeleteInventoryHostDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*DeleteInventoryHostDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this delete inventory host default body +func (o *DeleteInventoryHostDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryHostDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this delete inventory host default body based on the context it is used +func (o *DeleteInventoryHostDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryHostDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryHostDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryHostDefaultBody) UnmarshalBinary(b []byte) error { + var res DeleteInventoryHostDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +DeleteInventoryHostDefaultBodyDetailsItems0 delete inventory host default body details items0 +swagger:model DeleteInventoryHostDefaultBodyDetailsItems0 +*/ +type DeleteInventoryHostDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // delete inventory host default body details items0 + DeleteInventoryHostDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *DeleteInventoryHostDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv DeleteInventoryHostDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.DeleteInventoryHostDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o DeleteInventoryHostDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.DeleteInventoryHostDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.DeleteInventoryHostDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this delete inventory host default body details items0 +func (o *DeleteInventoryHostDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this delete inventory host default body details items0 based on context it is used +func (o *DeleteInventoryHostDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryHostDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryHostDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res DeleteInventoryHostDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/delete_inventory_service_parameters.go b/api/om/v1/json/client/om_service/delete_inventory_service_parameters.go new file mode 100644 index 00000000000..a830ebbb8e9 --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_service_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewDeleteInventoryServiceParams creates a new DeleteInventoryServiceParams 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 NewDeleteInventoryServiceParams() *DeleteInventoryServiceParams { + return &DeleteInventoryServiceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteInventoryServiceParamsWithTimeout creates a new DeleteInventoryServiceParams object +// with the ability to set a timeout on a request. +func NewDeleteInventoryServiceParamsWithTimeout(timeout time.Duration) *DeleteInventoryServiceParams { + return &DeleteInventoryServiceParams{ + timeout: timeout, + } +} + +// NewDeleteInventoryServiceParamsWithContext creates a new DeleteInventoryServiceParams object +// with the ability to set a context for a request. +func NewDeleteInventoryServiceParamsWithContext(ctx context.Context) *DeleteInventoryServiceParams { + return &DeleteInventoryServiceParams{ + Context: ctx, + } +} + +// NewDeleteInventoryServiceParamsWithHTTPClient creates a new DeleteInventoryServiceParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteInventoryServiceParamsWithHTTPClient(client *http.Client) *DeleteInventoryServiceParams { + return &DeleteInventoryServiceParams{ + HTTPClient: client, + } +} + +/* +DeleteInventoryServiceParams contains all the parameters to send to the API endpoint + + for the delete inventory service operation. + + Typically these are written to a http.Request. +*/ +type DeleteInventoryServiceParams struct { + /* ServiceID. + + PMM's service ID. + */ + ServiceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete inventory service params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryServiceParams) WithDefaults() *DeleteInventoryServiceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete inventory service params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteInventoryServiceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete inventory service params +func (o *DeleteInventoryServiceParams) WithTimeout(timeout time.Duration) *DeleteInventoryServiceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete inventory service params +func (o *DeleteInventoryServiceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete inventory service params +func (o *DeleteInventoryServiceParams) WithContext(ctx context.Context) *DeleteInventoryServiceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete inventory service params +func (o *DeleteInventoryServiceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete inventory service params +func (o *DeleteInventoryServiceParams) WithHTTPClient(client *http.Client) *DeleteInventoryServiceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete inventory service params +func (o *DeleteInventoryServiceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithServiceID adds the serviceID to the delete inventory service params +func (o *DeleteInventoryServiceParams) WithServiceID(serviceID string) *DeleteInventoryServiceParams { + o.SetServiceID(serviceID) + return o +} + +// SetServiceID adds the serviceId to the delete inventory service params +func (o *DeleteInventoryServiceParams) SetServiceID(serviceID string) { + o.ServiceID = serviceID +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteInventoryServiceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param service_id + if err := r.SetPathParam("service_id", o.ServiceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/delete_inventory_service_responses.go b/api/om/v1/json/client/om_service/delete_inventory_service_responses.go new file mode 100644 index 00000000000..970f340b0c5 --- /dev/null +++ b/api/om/v1/json/client/om_service/delete_inventory_service_responses.go @@ -0,0 +1,411 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DeleteInventoryServiceReader is a Reader for the DeleteInventoryService structure. +type DeleteInventoryServiceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteInventoryServiceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewDeleteInventoryServiceOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewDeleteInventoryServiceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewDeleteInventoryServiceOK creates a DeleteInventoryServiceOK with default headers values +func NewDeleteInventoryServiceOK() *DeleteInventoryServiceOK { + return &DeleteInventoryServiceOK{} +} + +/* +DeleteInventoryServiceOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type DeleteInventoryServiceOK struct { + Payload any +} + +// IsSuccess returns true when this delete inventory service Ok response has a 2xx status code +func (o *DeleteInventoryServiceOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this delete inventory service Ok response has a 3xx status code +func (o *DeleteInventoryServiceOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this delete inventory service Ok response has a 4xx status code +func (o *DeleteInventoryServiceOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this delete inventory service Ok response has a 5xx status code +func (o *DeleteInventoryServiceOK) IsServerError() bool { + return false +} + +// IsCode returns true when this delete inventory service Ok response a status code equal to that given +func (o *DeleteInventoryServiceOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the delete inventory service Ok response +func (o *DeleteInventoryServiceOK) Code() int { + return 200 +} + +func (o *DeleteInventoryServiceOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/services/{service_id}][%d] deleteInventoryServiceOk %s", 200, payload) +} + +func (o *DeleteInventoryServiceOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/services/{service_id}][%d] deleteInventoryServiceOk %s", 200, payload) +} + +func (o *DeleteInventoryServiceOK) GetPayload() any { + return o.Payload +} + +func (o *DeleteInventoryServiceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewDeleteInventoryServiceDefault creates a DeleteInventoryServiceDefault with default headers values +func NewDeleteInventoryServiceDefault(code int) *DeleteInventoryServiceDefault { + return &DeleteInventoryServiceDefault{ + _statusCode: code, + } +} + +/* +DeleteInventoryServiceDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type DeleteInventoryServiceDefault struct { + _statusCode int + + Payload *DeleteInventoryServiceDefaultBody +} + +// IsSuccess returns true when this delete inventory service default response has a 2xx status code +func (o *DeleteInventoryServiceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete inventory service default response has a 3xx status code +func (o *DeleteInventoryServiceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete inventory service default response has a 4xx status code +func (o *DeleteInventoryServiceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete inventory service default response has a 5xx status code +func (o *DeleteInventoryServiceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete inventory service default response a status code equal to that given +func (o *DeleteInventoryServiceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete inventory service default response +func (o *DeleteInventoryServiceDefault) Code() int { + return o._statusCode +} + +func (o *DeleteInventoryServiceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/services/{service_id}][%d] DeleteInventoryService default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryServiceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/om/inventory/services/{service_id}][%d] DeleteInventoryService default %s", o._statusCode, payload) +} + +func (o *DeleteInventoryServiceDefault) GetPayload() *DeleteInventoryServiceDefaultBody { + return o.Payload +} + +func (o *DeleteInventoryServiceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(DeleteInventoryServiceDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +DeleteInventoryServiceDefaultBody delete inventory service default body +swagger:model DeleteInventoryServiceDefaultBody +*/ +type DeleteInventoryServiceDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*DeleteInventoryServiceDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this delete inventory service default body +func (o *DeleteInventoryServiceDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryServiceDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this delete inventory service default body based on the context it is used +func (o *DeleteInventoryServiceDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteInventoryServiceDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryServiceDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryServiceDefaultBody) UnmarshalBinary(b []byte) error { + var res DeleteInventoryServiceDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +DeleteInventoryServiceDefaultBodyDetailsItems0 delete inventory service default body details items0 +swagger:model DeleteInventoryServiceDefaultBodyDetailsItems0 +*/ +type DeleteInventoryServiceDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // delete inventory service default body details items0 + DeleteInventoryServiceDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *DeleteInventoryServiceDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv DeleteInventoryServiceDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.DeleteInventoryServiceDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o DeleteInventoryServiceDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.DeleteInventoryServiceDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.DeleteInventoryServiceDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this delete inventory service default body details items0 +func (o *DeleteInventoryServiceDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this delete inventory service default body details items0 based on context it is used +func (o *DeleteInventoryServiceDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteInventoryServiceDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteInventoryServiceDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res DeleteInventoryServiceDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_config_parameters.go b/api/om/v1/json/client/om_service/get_inventory_config_parameters.go new file mode 100644 index 00000000000..fd337fe7c73 --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_config_parameters.go @@ -0,0 +1,124 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetInventoryConfigParams creates a new GetInventoryConfigParams 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 NewGetInventoryConfigParams() *GetInventoryConfigParams { + return &GetInventoryConfigParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetInventoryConfigParamsWithTimeout creates a new GetInventoryConfigParams object +// with the ability to set a timeout on a request. +func NewGetInventoryConfigParamsWithTimeout(timeout time.Duration) *GetInventoryConfigParams { + return &GetInventoryConfigParams{ + timeout: timeout, + } +} + +// NewGetInventoryConfigParamsWithContext creates a new GetInventoryConfigParams object +// with the ability to set a context for a request. +func NewGetInventoryConfigParamsWithContext(ctx context.Context) *GetInventoryConfigParams { + return &GetInventoryConfigParams{ + Context: ctx, + } +} + +// NewGetInventoryConfigParamsWithHTTPClient creates a new GetInventoryConfigParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetInventoryConfigParamsWithHTTPClient(client *http.Client) *GetInventoryConfigParams { + return &GetInventoryConfigParams{ + HTTPClient: client, + } +} + +/* +GetInventoryConfigParams contains all the parameters to send to the API endpoint + + for the get inventory config operation. + + Typically these are written to a http.Request. +*/ +type GetInventoryConfigParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get inventory config params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryConfigParams) WithDefaults() *GetInventoryConfigParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get inventory config params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryConfigParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get inventory config params +func (o *GetInventoryConfigParams) WithTimeout(timeout time.Duration) *GetInventoryConfigParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get inventory config params +func (o *GetInventoryConfigParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get inventory config params +func (o *GetInventoryConfigParams) WithContext(ctx context.Context) *GetInventoryConfigParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get inventory config params +func (o *GetInventoryConfigParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get inventory config params +func (o *GetInventoryConfigParams) WithHTTPClient(client *http.Client) *GetInventoryConfigParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get inventory config params +func (o *GetInventoryConfigParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *GetInventoryConfigParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_config_responses.go b/api/om/v1/json/client/om_service/get_inventory_config_responses.go new file mode 100644 index 00000000000..243976cf6dc --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_config_responses.go @@ -0,0 +1,656 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetInventoryConfigReader is a Reader for the GetInventoryConfig structure. +type GetInventoryConfigReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetInventoryConfigReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetInventoryConfigOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetInventoryConfigDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetInventoryConfigOK creates a GetInventoryConfigOK with default headers values +func NewGetInventoryConfigOK() *GetInventoryConfigOK { + return &GetInventoryConfigOK{} +} + +/* +GetInventoryConfigOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetInventoryConfigOK struct { + Payload *GetInventoryConfigOKBody +} + +// IsSuccess returns true when this get inventory config Ok response has a 2xx status code +func (o *GetInventoryConfigOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get inventory config Ok response has a 3xx status code +func (o *GetInventoryConfigOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get inventory config Ok response has a 4xx status code +func (o *GetInventoryConfigOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get inventory config Ok response has a 5xx status code +func (o *GetInventoryConfigOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get inventory config Ok response a status code equal to that given +func (o *GetInventoryConfigOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get inventory config Ok response +func (o *GetInventoryConfigOK) Code() int { + return 200 +} + +func (o *GetInventoryConfigOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/config][%d] getInventoryConfigOk %s", 200, payload) +} + +func (o *GetInventoryConfigOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/config][%d] getInventoryConfigOk %s", 200, payload) +} + +func (o *GetInventoryConfigOK) GetPayload() *GetInventoryConfigOKBody { + return o.Payload +} + +func (o *GetInventoryConfigOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryConfigOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetInventoryConfigDefault creates a GetInventoryConfigDefault with default headers values +func NewGetInventoryConfigDefault(code int) *GetInventoryConfigDefault { + return &GetInventoryConfigDefault{ + _statusCode: code, + } +} + +/* +GetInventoryConfigDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetInventoryConfigDefault struct { + _statusCode int + + Payload *GetInventoryConfigDefaultBody +} + +// IsSuccess returns true when this get inventory config default response has a 2xx status code +func (o *GetInventoryConfigDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get inventory config default response has a 3xx status code +func (o *GetInventoryConfigDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get inventory config default response has a 4xx status code +func (o *GetInventoryConfigDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get inventory config default response has a 5xx status code +func (o *GetInventoryConfigDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get inventory config default response a status code equal to that given +func (o *GetInventoryConfigDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get inventory config default response +func (o *GetInventoryConfigDefault) Code() int { + return o._statusCode +} + +func (o *GetInventoryConfigDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/config][%d] GetInventoryConfig default %s", o._statusCode, payload) +} + +func (o *GetInventoryConfigDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/config][%d] GetInventoryConfig default %s", o._statusCode, payload) +} + +func (o *GetInventoryConfigDefault) GetPayload() *GetInventoryConfigDefaultBody { + return o.Payload +} + +func (o *GetInventoryConfigDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryConfigDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetInventoryConfigDefaultBody get inventory config default body +swagger:model GetInventoryConfigDefaultBody +*/ +type GetInventoryConfigDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetInventoryConfigDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get inventory config default body +func (o *GetInventoryConfigDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryConfigDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory config default body based on the context it is used +func (o *GetInventoryConfigDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryConfigDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryConfigDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryConfigDefaultBody) UnmarshalBinary(b []byte) error { + var res GetInventoryConfigDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryConfigDefaultBodyDetailsItems0 get inventory config default body details items0 +swagger:model GetInventoryConfigDefaultBodyDetailsItems0 +*/ +type GetInventoryConfigDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get inventory config default body details items0 + GetInventoryConfigDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetInventoryConfigDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetInventoryConfigDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetInventoryConfigDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetInventoryConfigDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetInventoryConfigDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetInventoryConfigDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get inventory config default body details items0 +func (o *GetInventoryConfigDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory config default body details items0 based on context it is used +func (o *GetInventoryConfigDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryConfigDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryConfigDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryConfigDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryConfigOKBody GetInventoryConfigResponse returns the inventory app's configuration. +swagger:model GetInventoryConfigOKBody +*/ +type GetInventoryConfigOKBody struct { + // Every field, whether or not it is overridden. + Settings []*GetInventoryConfigOKBodySettingsItems0 `json:"settings"` +} + +// Validate validates this get inventory config OK body +func (o *GetInventoryConfigOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateSettings(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryConfigOKBody) validateSettings(formats strfmt.Registry) error { + if swag.IsZero(o.Settings) { // not required + return nil + } + + for i := 0; i < len(o.Settings); i++ { + if swag.IsZero(o.Settings[i]) { // not required + continue + } + + if o.Settings[i] != nil { + if err := o.Settings[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory config OK body based on the context it is used +func (o *GetInventoryConfigOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateSettings(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryConfigOKBody) contextValidateSettings(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Settings); i++ { + if o.Settings[i] != nil { + + if swag.IsZero(o.Settings[i]) { // not required + return nil + } + + if err := o.Settings[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryConfigOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryConfigOKBody) UnmarshalBinary(b []byte) error { + var res GetInventoryConfigOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryConfigOKBodySettingsItems0 InventorySetting is one of the inventory app's configuration fields. +swagger:model GetInventoryConfigOKBodySettingsItems0 +*/ +type GetInventoryConfigOKBodySettingsItems0 struct { + // The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every. + Key string `json:"key,omitempty"` + + // The value in effect. + Value any `json:"value,omitempty"` + + // What it would be with no override. + DefaultValue any `json:"default_value,omitempty"` + + // The field's type, for rendering an input. A string because the app's own schema + // names it, so this contract does not get to enumerate the possibilities. + Type string `json:"type,omitempty"` + + // SettingReload is how a configuration field may be overridden, if at all. + // + // Mirrors the app's own three-valued classification rather than collapsing it to + // editable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a + // whole-object write while its children accept one, so a form that read it as + // "not overridable" would refuse to edit a leaf the API would have accepted. + // + // The distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable + // promises a change the API cannot deliver. + // + // - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh. + // - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written + // whole. + // - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources. + // Enum: ["SETTING_RELOAD_UNSPECIFIED","SETTING_RELOAD_HOT","SETTING_RELOAD_NESTED_ONLY","SETTING_RELOAD_NOT_OVERRIDABLE"] + Reload *string `json:"reload,omitempty"` + + // Whether an override is in effect, which is how "why is it set to this" is + // answerable without also reading the deployment's configuration file. + HasOverride bool `json:"has_override,omitempty"` + + // Whether to hide it behind an "advanced" disclosure. + IsAdvanced bool `json:"is_advanced,omitempty"` + + // The field's documentation, where it has any. + Description *string `json:"description,omitempty"` +} + +// Validate validates this get inventory config OK body settings items0 +func (o *GetInventoryConfigOKBodySettingsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateReload(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getInventoryConfigOkBodySettingsItems0TypeReloadPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SETTING_RELOAD_UNSPECIFIED","SETTING_RELOAD_HOT","SETTING_RELOAD_NESTED_ONLY","SETTING_RELOAD_NOT_OVERRIDABLE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getInventoryConfigOkBodySettingsItems0TypeReloadPropEnum = append(getInventoryConfigOkBodySettingsItems0TypeReloadPropEnum, v) + } +} + +const ( + + // GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADUNSPECIFIED captures enum value "SETTING_RELOAD_UNSPECIFIED" + GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADUNSPECIFIED string = "SETTING_RELOAD_UNSPECIFIED" + + // GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADHOT captures enum value "SETTING_RELOAD_HOT" + GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADHOT string = "SETTING_RELOAD_HOT" + + // GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNESTEDONLY captures enum value "SETTING_RELOAD_NESTED_ONLY" + GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNESTEDONLY string = "SETTING_RELOAD_NESTED_ONLY" + + // GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNOTOVERRIDABLE captures enum value "SETTING_RELOAD_NOT_OVERRIDABLE" + GetInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNOTOVERRIDABLE string = "SETTING_RELOAD_NOT_OVERRIDABLE" +) + +// prop value enum +func (o *GetInventoryConfigOKBodySettingsItems0) validateReloadEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getInventoryConfigOkBodySettingsItems0TypeReloadPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetInventoryConfigOKBodySettingsItems0) validateReload(formats strfmt.Registry) error { + if swag.IsZero(o.Reload) { // not required + return nil + } + + // value enum + if err := o.validateReloadEnum("reload", "body", *o.Reload); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get inventory config OK body settings items0 based on context it is used +func (o *GetInventoryConfigOKBodySettingsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryConfigOKBodySettingsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryConfigOKBodySettingsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryConfigOKBodySettingsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_host_parameters.go b/api/om/v1/json/client/om_service/get_inventory_host_parameters.go new file mode 100644 index 00000000000..26b87688e4d --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_host_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetInventoryHostParams creates a new GetInventoryHostParams 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 NewGetInventoryHostParams() *GetInventoryHostParams { + return &GetInventoryHostParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetInventoryHostParamsWithTimeout creates a new GetInventoryHostParams object +// with the ability to set a timeout on a request. +func NewGetInventoryHostParamsWithTimeout(timeout time.Duration) *GetInventoryHostParams { + return &GetInventoryHostParams{ + timeout: timeout, + } +} + +// NewGetInventoryHostParamsWithContext creates a new GetInventoryHostParams object +// with the ability to set a context for a request. +func NewGetInventoryHostParamsWithContext(ctx context.Context) *GetInventoryHostParams { + return &GetInventoryHostParams{ + Context: ctx, + } +} + +// NewGetInventoryHostParamsWithHTTPClient creates a new GetInventoryHostParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetInventoryHostParamsWithHTTPClient(client *http.Client) *GetInventoryHostParams { + return &GetInventoryHostParams{ + HTTPClient: client, + } +} + +/* +GetInventoryHostParams contains all the parameters to send to the API endpoint + + for the get inventory host operation. + + Typically these are written to a http.Request. +*/ +type GetInventoryHostParams struct { + /* NodeID. + + PMM's node ID. + */ + NodeID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get inventory host params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryHostParams) WithDefaults() *GetInventoryHostParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get inventory host params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryHostParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get inventory host params +func (o *GetInventoryHostParams) WithTimeout(timeout time.Duration) *GetInventoryHostParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get inventory host params +func (o *GetInventoryHostParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get inventory host params +func (o *GetInventoryHostParams) WithContext(ctx context.Context) *GetInventoryHostParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get inventory host params +func (o *GetInventoryHostParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get inventory host params +func (o *GetInventoryHostParams) WithHTTPClient(client *http.Client) *GetInventoryHostParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get inventory host params +func (o *GetInventoryHostParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithNodeID adds the nodeID to the get inventory host params +func (o *GetInventoryHostParams) WithNodeID(nodeID string) *GetInventoryHostParams { + o.SetNodeID(nodeID) + return o +} + +// SetNodeID adds the nodeId to the get inventory host params +func (o *GetInventoryHostParams) SetNodeID(nodeID string) { + o.NodeID = nodeID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetInventoryHostParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param node_id + if err := r.SetPathParam("node_id", o.NodeID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_host_responses.go b/api/om/v1/json/client/om_service/get_inventory_host_responses.go new file mode 100644 index 00000000000..84491757e0c --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_host_responses.go @@ -0,0 +1,1361 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetInventoryHostReader is a Reader for the GetInventoryHost structure. +type GetInventoryHostReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetInventoryHostReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetInventoryHostOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetInventoryHostDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetInventoryHostOK creates a GetInventoryHostOK with default headers values +func NewGetInventoryHostOK() *GetInventoryHostOK { + return &GetInventoryHostOK{} +} + +/* +GetInventoryHostOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetInventoryHostOK struct { + Payload *GetInventoryHostOKBody +} + +// IsSuccess returns true when this get inventory host Ok response has a 2xx status code +func (o *GetInventoryHostOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get inventory host Ok response has a 3xx status code +func (o *GetInventoryHostOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get inventory host Ok response has a 4xx status code +func (o *GetInventoryHostOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get inventory host Ok response has a 5xx status code +func (o *GetInventoryHostOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get inventory host Ok response a status code equal to that given +func (o *GetInventoryHostOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get inventory host Ok response +func (o *GetInventoryHostOK) Code() int { + return 200 +} + +func (o *GetInventoryHostOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts/{node_id}][%d] getInventoryHostOk %s", 200, payload) +} + +func (o *GetInventoryHostOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts/{node_id}][%d] getInventoryHostOk %s", 200, payload) +} + +func (o *GetInventoryHostOK) GetPayload() *GetInventoryHostOKBody { + return o.Payload +} + +func (o *GetInventoryHostOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryHostOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetInventoryHostDefault creates a GetInventoryHostDefault with default headers values +func NewGetInventoryHostDefault(code int) *GetInventoryHostDefault { + return &GetInventoryHostDefault{ + _statusCode: code, + } +} + +/* +GetInventoryHostDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetInventoryHostDefault struct { + _statusCode int + + Payload *GetInventoryHostDefaultBody +} + +// IsSuccess returns true when this get inventory host default response has a 2xx status code +func (o *GetInventoryHostDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get inventory host default response has a 3xx status code +func (o *GetInventoryHostDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get inventory host default response has a 4xx status code +func (o *GetInventoryHostDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get inventory host default response has a 5xx status code +func (o *GetInventoryHostDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get inventory host default response a status code equal to that given +func (o *GetInventoryHostDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get inventory host default response +func (o *GetInventoryHostDefault) Code() int { + return o._statusCode +} + +func (o *GetInventoryHostDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts/{node_id}][%d] GetInventoryHost default %s", o._statusCode, payload) +} + +func (o *GetInventoryHostDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts/{node_id}][%d] GetInventoryHost default %s", o._statusCode, payload) +} + +func (o *GetInventoryHostDefault) GetPayload() *GetInventoryHostDefaultBody { + return o.Payload +} + +func (o *GetInventoryHostDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryHostDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetInventoryHostDefaultBody get inventory host default body +swagger:model GetInventoryHostDefaultBody +*/ +type GetInventoryHostDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetInventoryHostDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get inventory host default body +func (o *GetInventoryHostDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory host default body based on the context it is used +func (o *GetInventoryHostDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryHost default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostDefaultBody) UnmarshalBinary(b []byte) error { + var res GetInventoryHostDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostDefaultBodyDetailsItems0 get inventory host default body details items0 +swagger:model GetInventoryHostDefaultBodyDetailsItems0 +*/ +type GetInventoryHostDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get inventory host default body details items0 + GetInventoryHostDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetInventoryHostDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetInventoryHostDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetInventoryHostDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetInventoryHostDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetInventoryHostDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetInventoryHostDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get inventory host default body details items0 +func (o *GetInventoryHostDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory host default body details items0 based on context it is used +func (o *GetInventoryHostDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryHostDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBody GetInventoryHostResponse returns one host. +swagger:model GetInventoryHostOKBody +*/ +type GetInventoryHostOKBody struct { + // host + Host *GetInventoryHostOKBodyHost `json:"host,omitempty"` +} + +// Validate validates this get inventory host OK body +func (o *GetInventoryHostOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateHost(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBody) validateHost(formats strfmt.Registry) error { + if swag.IsZero(o.Host) { // not required + return nil + } + + if o.Host != nil { + if err := o.Host.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory host OK body based on the context it is used +func (o *GetInventoryHostOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateHost(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBody) contextValidateHost(ctx context.Context, formats strfmt.Registry) error { + if o.Host != nil { + + if swag.IsZero(o.Host) { // not required + return nil + } + + if err := o.Host.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBody) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHost InventoryHost is one machine OM knows about, with the services on it. +// +// A host is a row whether or not any MongoDB was found on it. That is what makes +// "which machines have no database" a query rather than an absence, and it is the only +// way a machine that has never run one appears at all - which is the case installing a +// database somewhere later depends on. +swagger:model GetInventoryHostOKBodyHost +*/ +type GetInventoryHostOKBodyHost struct { + // PMM's node ID. Also what a scoped refresh is addressed by. + NodeID string `json:"node_id,omitempty"` + + // The node name PMM registered. + Name string `json:"name,omitempty"` + + // The node address PMM registered. + Address *string `json:"address,omitempty"` + + // The Nomad client that serves it. Unset means nothing can be run there, which is a + // fact about the estate rather than a probe failure. + ExecutorHost *string `json:"executor_host,omitempty"` + + // The operating system, as the host reports it. Worth having from a probe because + // PMM does not know it for some nodes. + Os *string `json:"os,omitempty"` + + // The kernel release. + Kernel *string `json:"kernel,omitempty"` + + // Mongods running that PMM has no service for. + UnregisteredMongods []*GetInventoryHostOKBodyHostUnregisteredMongodsItems0 `json:"unregistered_mongods"` + + // Everything the probe recorded about the host, including attributes with no field + // above. + Observed any `json:"observed,omitempty"` + + // The services on it. Empty is a meaningful answer, not a gap. + Services []*GetInventoryHostOKBodyHostServicesItems0 `json:"services"` + + // executor + Executor *GetInventoryHostOKBodyHostExecutor `json:"executor,omitempty"` + + // freshness + Freshness *GetInventoryHostOKBodyHostFreshness `json:"freshness,omitempty"` +} + +// Validate validates this get inventory host OK body host +func (o *GetInventoryHostOKBodyHost) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateUnregisteredMongods(formats); err != nil { + res = append(res, err) + } + + if err := o.validateServices(formats); err != nil { + res = append(res, err) + } + + if err := o.validateExecutor(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHost) validateUnregisteredMongods(formats strfmt.Registry) error { + if swag.IsZero(o.UnregisteredMongods) { // not required + return nil + } + + for i := 0; i < len(o.UnregisteredMongods); i++ { + if swag.IsZero(o.UnregisteredMongods[i]) { // not required + continue + } + + if o.UnregisteredMongods[i] != nil { + if err := o.UnregisteredMongods[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "unregistered_mongods" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "unregistered_mongods" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) validateServices(formats strfmt.Registry) error { + if swag.IsZero(o.Services) { // not required + return nil + } + + for i := 0; i < len(o.Services); i++ { + if swag.IsZero(o.Services[i]) { // not required + continue + } + + if o.Services[i] != nil { + if err := o.Services[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "services" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) validateExecutor(formats strfmt.Registry) error { + if swag.IsZero(o.Executor) { // not required + return nil + } + + if o.Executor != nil { + if err := o.Executor.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "executor") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "executor") + } + + return err + } + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory host OK body host based on the context it is used +func (o *GetInventoryHostOKBodyHost) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateUnregisteredMongods(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateServices(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateExecutor(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHost) contextValidateUnregisteredMongods(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.UnregisteredMongods); i++ { + if o.UnregisteredMongods[i] != nil { + + if swag.IsZero(o.UnregisteredMongods[i]) { // not required + return nil + } + + if err := o.UnregisteredMongods[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "unregistered_mongods" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "unregistered_mongods" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) contextValidateServices(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Services); i++ { + if o.Services[i] != nil { + + if swag.IsZero(o.Services[i]) { // not required + return nil + } + + if err := o.Services[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "services" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) contextValidateExecutor(ctx context.Context, formats strfmt.Registry) error { + if o.Executor != nil { + + if swag.IsZero(o.Executor) { // not required + return nil + } + + if err := o.Executor.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "executor") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "executor") + } + + return err + } + } + + return nil +} + +func (o *GetInventoryHostOKBodyHost) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryHostOk" + "." + "host" + "." + "freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryHostOk" + "." + "host" + "." + "freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHost) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHost) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHost + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHostExecutor InventoryExecutor reports whether SEP can run anything on a host. +// +// Three flags rather than one, because "orphaned" hid three different problems with +// three different fixes: never onboarded (registered false), onboarded and down +// (reachable false), and up with a broken raw_exec driver (driver_healthy false). This +// is SEP's own knowledge rather than probe output, so it is filled in for every host +// on every sweep, including hosts no probe reached. +swagger:model GetInventoryHostOKBodyHostExecutor +*/ +type GetInventoryHostOKBodyHostExecutor struct { + // Whether the Tasks backend knows this node at all. + Registered bool `json:"registered,omitempty"` + + // Whether it is currently up. + Reachable bool `json:"reachable,omitempty"` + + // Whether its raw_exec driver is healthy, which is what a probe actually needs. + DriverHealthy bool `json:"driver_healthy,omitempty"` + + // Whatever detail the backend gave, when it gave any. + Detail *string `json:"detail,omitempty"` +} + +// Validate validates this get inventory host OK body host executor +func (o *GetInventoryHostOKBodyHostExecutor) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory host OK body host executor based on context it is used +func (o *GetInventoryHostOKBodyHostExecutor) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostExecutor) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostExecutor) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHostExecutor + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHostFreshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model GetInventoryHostOKBodyHostFreshness +*/ +type GetInventoryHostOKBodyHostFreshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this get inventory host OK body host freshness +func (o *GetInventoryHostOKBodyHostFreshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHostFreshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryHostOk"+"."+"host"+"."+"freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostFreshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryHostOk"+"."+"host"+"."+"freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostFreshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryHostOk"+"."+"host"+"."+"freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostFreshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryHostOk"+"."+"host"+"."+"freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get inventory host OK body host freshness based on context it is used +func (o *GetInventoryHostOKBodyHostFreshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostFreshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostFreshness) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHostFreshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHostServicesItems0 InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +swagger:model GetInventoryHostOKBodyHostServicesItems0 +*/ +type GetInventoryHostOKBodyHostServicesItems0 struct { + // PMM's service ID. The join key against the topology document. + ServiceID string `json:"service_id,omitempty"` + + // The node it runs on, as PMM's node ID. + NodeID string `json:"node_id,omitempty"` + + // The service name PMM registered. + Name string `json:"name,omitempty"` + + // The port it listens on, where OM knows it. + Port *int32 `json:"port,omitempty"` + + // PRIMARY, SECONDARY, ARBITER, or unset. + Role *string `json:"role,omitempty"` + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + InstalledVersion *string `json:"installed_version,omitempty"` + + // The version the running server reports. + RunningVersion *string `json:"running_version,omitempty"` + + // The configuration file the running server read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // What the last probe of this service concluded, in the payload's own words. + ProbeStatus *string `json:"probe_status,omitempty"` + + // Whether a server was found running. Unset where no probe has looked. + ServerRunning *bool `json:"server_running,omitempty"` + + // How long it has been up, seconds. + UptimeSeconds *float64 `json:"uptime_seconds,omitempty"` + + // The replica set it belongs to, or unset for a standalone or a router. + ReplicationSet *string `json:"replication_set,omitempty"` + + // Everything the probe recorded, including attributes with no field above. + Observed any `json:"observed,omitempty"` + + // freshness + Freshness *GetInventoryHostOKBodyHostServicesItems0Freshness `json:"freshness,omitempty"` +} + +// Validate validates this get inventory host OK body host services items0 +func (o *GetInventoryHostOKBodyHostServicesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory host OK body host services items0 based on the context it is used +func (o *GetInventoryHostOKBodyHostServicesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostServicesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostServicesItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHostServicesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHostServicesItems0Freshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model GetInventoryHostOKBodyHostServicesItems0Freshness +*/ +type GetInventoryHostOKBodyHostServicesItems0Freshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this get inventory host OK body host services items0 freshness +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get inventory host OK body host services items0 freshness based on context it is used +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostServicesItems0Freshness) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHostServicesItems0Freshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryHostOKBodyHostUnregisteredMongodsItems0 UnregisteredMongod is a mongod found running that PMM has no service for. +// +// The arbiter case, mostly: PMM registers no service for an arbiter, so nothing else +// in OM would report the process at all. Also what stands in the way of installing +// anything over a port that is already taken. +swagger:model GetInventoryHostOKBodyHostUnregisteredMongodsItems0 +*/ +type GetInventoryHostOKBodyHostUnregisteredMongodsItems0 struct { + // The port it is listening on. + Port *int32 `json:"port,omitempty"` + + // The configuration file it read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // The process name, e.g. "mongod". + Program *string `json:"program,omitempty"` + + // Its process ID at the time of the probe. + Pid *int32 `json:"pid,omitempty"` +} + +// Validate validates this get inventory host OK body host unregistered mongods items0 +func (o *GetInventoryHostOKBodyHostUnregisteredMongodsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory host OK body host unregistered mongods items0 based on context it is used +func (o *GetInventoryHostOKBodyHostUnregisteredMongodsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostUnregisteredMongodsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryHostOKBodyHostUnregisteredMongodsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryHostOKBodyHostUnregisteredMongodsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_run_parameters.go b/api/om/v1/json/client/om_service/get_inventory_run_parameters.go new file mode 100644 index 00000000000..d64e0ac0bed --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_run_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetInventoryRunParams creates a new GetInventoryRunParams 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 NewGetInventoryRunParams() *GetInventoryRunParams { + return &GetInventoryRunParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetInventoryRunParamsWithTimeout creates a new GetInventoryRunParams object +// with the ability to set a timeout on a request. +func NewGetInventoryRunParamsWithTimeout(timeout time.Duration) *GetInventoryRunParams { + return &GetInventoryRunParams{ + timeout: timeout, + } +} + +// NewGetInventoryRunParamsWithContext creates a new GetInventoryRunParams object +// with the ability to set a context for a request. +func NewGetInventoryRunParamsWithContext(ctx context.Context) *GetInventoryRunParams { + return &GetInventoryRunParams{ + Context: ctx, + } +} + +// NewGetInventoryRunParamsWithHTTPClient creates a new GetInventoryRunParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetInventoryRunParamsWithHTTPClient(client *http.Client) *GetInventoryRunParams { + return &GetInventoryRunParams{ + HTTPClient: client, + } +} + +/* +GetInventoryRunParams contains all the parameters to send to the API endpoint + + for the get inventory run operation. + + Typically these are written to a http.Request. +*/ +type GetInventoryRunParams struct { + /* RunID. + + The run's ID. + */ + RunID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get inventory run params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryRunParams) WithDefaults() *GetInventoryRunParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get inventory run params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryRunParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get inventory run params +func (o *GetInventoryRunParams) WithTimeout(timeout time.Duration) *GetInventoryRunParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get inventory run params +func (o *GetInventoryRunParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get inventory run params +func (o *GetInventoryRunParams) WithContext(ctx context.Context) *GetInventoryRunParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get inventory run params +func (o *GetInventoryRunParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get inventory run params +func (o *GetInventoryRunParams) WithHTTPClient(client *http.Client) *GetInventoryRunParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get inventory run params +func (o *GetInventoryRunParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithRunID adds the runID to the get inventory run params +func (o *GetInventoryRunParams) WithRunID(runID string) *GetInventoryRunParams { + o.SetRunID(runID) + return o +} + +// SetRunID adds the runId to the get inventory run params +func (o *GetInventoryRunParams) SetRunID(runID string) { + o.RunID = runID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetInventoryRunParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param run_id + if err := r.SetPathParam("run_id", o.RunID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_run_responses.go b/api/om/v1/json/client/om_service/get_inventory_run_responses.go new file mode 100644 index 00000000000..bc2340ed0c7 --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_run_responses.go @@ -0,0 +1,1138 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetInventoryRunReader is a Reader for the GetInventoryRun structure. +type GetInventoryRunReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetInventoryRunReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetInventoryRunOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetInventoryRunDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetInventoryRunOK creates a GetInventoryRunOK with default headers values +func NewGetInventoryRunOK() *GetInventoryRunOK { + return &GetInventoryRunOK{} +} + +/* +GetInventoryRunOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetInventoryRunOK struct { + Payload *GetInventoryRunOKBody +} + +// IsSuccess returns true when this get inventory run Ok response has a 2xx status code +func (o *GetInventoryRunOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get inventory run Ok response has a 3xx status code +func (o *GetInventoryRunOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get inventory run Ok response has a 4xx status code +func (o *GetInventoryRunOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get inventory run Ok response has a 5xx status code +func (o *GetInventoryRunOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get inventory run Ok response a status code equal to that given +func (o *GetInventoryRunOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get inventory run Ok response +func (o *GetInventoryRunOK) Code() int { + return 200 +} + +func (o *GetInventoryRunOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs/{run_id}][%d] getInventoryRunOk %s", 200, payload) +} + +func (o *GetInventoryRunOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs/{run_id}][%d] getInventoryRunOk %s", 200, payload) +} + +func (o *GetInventoryRunOK) GetPayload() *GetInventoryRunOKBody { + return o.Payload +} + +func (o *GetInventoryRunOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryRunOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetInventoryRunDefault creates a GetInventoryRunDefault with default headers values +func NewGetInventoryRunDefault(code int) *GetInventoryRunDefault { + return &GetInventoryRunDefault{ + _statusCode: code, + } +} + +/* +GetInventoryRunDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetInventoryRunDefault struct { + _statusCode int + + Payload *GetInventoryRunDefaultBody +} + +// IsSuccess returns true when this get inventory run default response has a 2xx status code +func (o *GetInventoryRunDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get inventory run default response has a 3xx status code +func (o *GetInventoryRunDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get inventory run default response has a 4xx status code +func (o *GetInventoryRunDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get inventory run default response has a 5xx status code +func (o *GetInventoryRunDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get inventory run default response a status code equal to that given +func (o *GetInventoryRunDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get inventory run default response +func (o *GetInventoryRunDefault) Code() int { + return o._statusCode +} + +func (o *GetInventoryRunDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs/{run_id}][%d] GetInventoryRun default %s", o._statusCode, payload) +} + +func (o *GetInventoryRunDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs/{run_id}][%d] GetInventoryRun default %s", o._statusCode, payload) +} + +func (o *GetInventoryRunDefault) GetPayload() *GetInventoryRunDefaultBody { + return o.Payload +} + +func (o *GetInventoryRunDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryRunDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetInventoryRunDefaultBody get inventory run default body +swagger:model GetInventoryRunDefaultBody +*/ +type GetInventoryRunDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetInventoryRunDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get inventory run default body +func (o *GetInventoryRunDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory run default body based on the context it is used +func (o *GetInventoryRunDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunDefaultBody) UnmarshalBinary(b []byte) error { + var res GetInventoryRunDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunDefaultBodyDetailsItems0 get inventory run default body details items0 +swagger:model GetInventoryRunDefaultBodyDetailsItems0 +*/ +type GetInventoryRunDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get inventory run default body details items0 + GetInventoryRunDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetInventoryRunDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetInventoryRunDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetInventoryRunDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetInventoryRunDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetInventoryRunDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetInventoryRunDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get inventory run default body details items0 +func (o *GetInventoryRunDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory run default body details items0 based on context it is used +func (o *GetInventoryRunDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryRunDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunOKBody GetInventoryRunResponse returns one refresh, with the rows behind its counters. +swagger:model GetInventoryRunOKBody +*/ +type GetInventoryRunOKBody struct { + // What it attempted, one entry per entity. + // + // Only on the detail response, never on the list: a refresh of a real estate has a + // row per service, and a history of twenty-five would carry the lot to render a + // page that shows one at a time. + Entities []*GetInventoryRunOKBodyEntitiesItems0 `json:"entities"` + + // run + Run *GetInventoryRunOKBodyRun `json:"run,omitempty"` +} + +// Validate validates this get inventory run OK body +func (o *GetInventoryRunOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateEntities(formats); err != nil { + res = append(res, err) + } + + if err := o.validateRun(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunOKBody) validateEntities(formats strfmt.Registry) error { + if swag.IsZero(o.Entities) { // not required + return nil + } + + for i := 0; i < len(o.Entities); i++ { + if swag.IsZero(o.Entities[i]) { // not required + continue + } + + if o.Entities[i] != nil { + if err := o.Entities[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "entities" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "entities" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetInventoryRunOKBody) validateRun(formats strfmt.Registry) error { + if swag.IsZero(o.Run) { // not required + return nil + } + + if o.Run != nil { + if err := o.Run.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "run") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "run") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory run OK body based on the context it is used +func (o *GetInventoryRunOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateEntities(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateRun(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunOKBody) contextValidateEntities(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Entities); i++ { + if o.Entities[i] != nil { + + if swag.IsZero(o.Entities[i]) { // not required + return nil + } + + if err := o.Entities[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "entities" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "entities" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetInventoryRunOKBody) contextValidateRun(ctx context.Context, formats strfmt.Registry) error { + if o.Run != nil { + + if swag.IsZero(o.Run) { // not required + return nil + } + + if err := o.Run.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "run") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "run") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunOKBody) UnmarshalBinary(b []byte) error { + var res GetInventoryRunOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunOKBodyEntitiesItems0 InventoryRunEntity is one host a refresh attempted, and what came of it. +// +// Host-oriented, because a refresh attempts hosts. A flat list of services - which +// this was - cannot show a machine carrying a PMM client and no database, however +// many times it is probed, and that machine is the case OM most exists to describe: +// it is where a database can be installed. +// +// One dispatch covers every service on a host, so the host owns the timing and the +// failure and its services carry only what is theirs. Previously the duration was +// copied onto each service, which read as several measurements when it was one. +// +// Deliberately outcomes and not observations. What the probe *found* lives on the +// estate, where it is upserted and stays current; a receipt that also carried the +// attributes would be a second copy that goes stale the moment the next refresh runs. +swagger:model GetInventoryRunOKBodyEntitiesItems0 +*/ +type GetInventoryRunOKBodyEntitiesItems0 struct { + // PMM's node ID, the key OM holds this host under. + NodeID string `json:"node_id,omitempty"` + + // The node's registered name. + HostName *string `json:"host_name,omitempty"` + + // The client its probe ran on. Unset when none matched. + ExecutorHost *string `json:"executor_host,omitempty"` + + // ExecutorResolution is how a host was matched to the client its probe ran on. + // + // ORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact + // about onboarding. NAME and ADDRESS record *which* of the two joins matched, because a + // host reachable only by address is a different estate problem from one matched by name. + // + // - EXECUTOR_RESOLUTION_NAME: Matched on the node's registered name. + // - EXECUTOR_RESOLUTION_ADDRESS: Matched on the node's address. + // - EXECUTOR_RESOLUTION_ORPHANED: Not matched, so nothing was dispatched. + // Enum: ["EXECUTOR_RESOLUTION_UNSPECIFIED","EXECUTOR_RESOLUTION_NAME","EXECUTOR_RESOLUTION_ADDRESS","EXECUTOR_RESOLUTION_ORPHANED"] + Resolution *string `json:"resolution,omitempty"` + + // Whether the *host* answered. A different question from whether its services did: + // a host with no database answers perfectly well and has no services at all. + Answered bool `json:"answered,omitempty"` + + // The host's wall clock, dispatch to collected output. + DurationSeconds *float64 `json:"duration_seconds,omitempty"` + + // The host-level failure, when its probe failed. + Error *string `json:"error,omitempty"` + + // The services on it. Empty is a meaningful answer, not a gap. + Services []*GetInventoryRunOKBodyEntitiesItems0ServicesItems0 `json:"services"` + + // The task history id of the dispatch, so a reader can open the probe's own log. + // Unset when the dispatch never got one. + TaskHistoryID *string `json:"task_history_id,omitempty"` +} + +// Validate validates this get inventory run OK body entities items0 +func (o *GetInventoryRunOKBodyEntitiesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateResolution(formats); err != nil { + res = append(res, err) + } + + if err := o.validateServices(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getInventoryRunOkBodyEntitiesItems0TypeResolutionPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["EXECUTOR_RESOLUTION_UNSPECIFIED","EXECUTOR_RESOLUTION_NAME","EXECUTOR_RESOLUTION_ADDRESS","EXECUTOR_RESOLUTION_ORPHANED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getInventoryRunOkBodyEntitiesItems0TypeResolutionPropEnum = append(getInventoryRunOkBodyEntitiesItems0TypeResolutionPropEnum, v) + } +} + +const ( + + // GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONUNSPECIFIED captures enum value "EXECUTOR_RESOLUTION_UNSPECIFIED" + GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONUNSPECIFIED string = "EXECUTOR_RESOLUTION_UNSPECIFIED" + + // GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONNAME captures enum value "EXECUTOR_RESOLUTION_NAME" + GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONNAME string = "EXECUTOR_RESOLUTION_NAME" + + // GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONADDRESS captures enum value "EXECUTOR_RESOLUTION_ADDRESS" + GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONADDRESS string = "EXECUTOR_RESOLUTION_ADDRESS" + + // GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONORPHANED captures enum value "EXECUTOR_RESOLUTION_ORPHANED" + GetInventoryRunOKBodyEntitiesItems0ResolutionEXECUTORRESOLUTIONORPHANED string = "EXECUTOR_RESOLUTION_ORPHANED" +) + +// prop value enum +func (o *GetInventoryRunOKBodyEntitiesItems0) validateResolutionEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getInventoryRunOkBodyEntitiesItems0TypeResolutionPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetInventoryRunOKBodyEntitiesItems0) validateResolution(formats strfmt.Registry) error { + if swag.IsZero(o.Resolution) { // not required + return nil + } + + // value enum + if err := o.validateResolutionEnum("resolution", "body", *o.Resolution); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryRunOKBodyEntitiesItems0) validateServices(formats strfmt.Registry) error { + if swag.IsZero(o.Services) { // not required + return nil + } + + for i := 0; i < len(o.Services); i++ { + if swag.IsZero(o.Services[i]) { // not required + continue + } + + if o.Services[i] != nil { + if err := o.Services[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory run OK body entities items0 based on the context it is used +func (o *GetInventoryRunOKBodyEntitiesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateServices(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunOKBodyEntitiesItems0) contextValidateServices(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Services); i++ { + if o.Services[i] != nil { + + if swag.IsZero(o.Services[i]) { // not required + return nil + } + + if err := o.Services[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunOKBodyEntitiesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunOKBodyEntitiesItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryRunOKBodyEntitiesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunOKBodyEntitiesItems0ServicesItems0 InventoryRunEntityService is one service on a host, as a refresh saw it. +swagger:model GetInventoryRunOKBodyEntitiesItems0ServicesItems0 +*/ +type GetInventoryRunOKBodyEntitiesItems0ServicesItems0 struct { + // PMM's service ID, when OM could key one. + ServiceID *string `json:"service_id,omitempty"` + + // Its name, so a reader is not left joining UUIDs by hand. + ServiceName *string `json:"service_name,omitempty"` + + // Whether the host returned a usable record for it. + Answered bool `json:"answered,omitempty"` + + // Why it did not, when it did not. + Error *string `json:"error,omitempty"` +} + +// Validate validates this get inventory run OK body entities items0 services items0 +func (o *GetInventoryRunOKBodyEntitiesItems0ServicesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory run OK body entities items0 services items0 based on context it is used +func (o *GetInventoryRunOKBodyEntitiesItems0ServicesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunOKBodyEntitiesItems0ServicesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunOKBodyEntitiesItems0ServicesItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryRunOKBodyEntitiesItems0ServicesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunOKBodyRun InventoryRun is one refresh of the estate. +swagger:model GetInventoryRunOKBodyRun +*/ +type GetInventoryRunOKBodyRun struct { + // The run's ID. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When it began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` + + // When it stopped. Unset while it is still going. + // Format: date-time + EndTime strfmt.DateTime `json:"end_time,omitempty"` + + // The hosts it was limited to. Empty means it refreshed the whole estate, which is + // what the scheduled sweep does. + Scope []string `json:"scope"` + + // What went wrong, when something did. + Error *string `json:"error,omitempty"` + + // counts + Counts *GetInventoryRunOKBodyRunCounts `json:"counts,omitempty"` +} + +// Validate validates this get inventory run OK body run +func (o *GetInventoryRunOKBodyRun) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateEndTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateCounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getInventoryRunOkBodyRunTypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getInventoryRunOkBodyRunTypeStatusPropEnum = append(getInventoryRunOkBodyRunTypeStatusPropEnum, v) + } +} + +const ( + + // GetInventoryRunOKBodyRunStatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + GetInventoryRunOKBodyRunStatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // GetInventoryRunOKBodyRunStatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + GetInventoryRunOKBodyRunStatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // GetInventoryRunOKBodyRunStatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + GetInventoryRunOKBodyRunStatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // GetInventoryRunOKBodyRunStatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + GetInventoryRunOKBodyRunStatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // GetInventoryRunOKBodyRunStatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + GetInventoryRunOKBodyRunStatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // GetInventoryRunOKBodyRunStatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + GetInventoryRunOKBodyRunStatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *GetInventoryRunOKBodyRun) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getInventoryRunOkBodyRunTypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetInventoryRunOKBodyRun) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("getInventoryRunOk"+"."+"run"+"."+"status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryRunOKBodyRun) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryRunOk"+"."+"run"+"."+"start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryRunOKBodyRun) validateEndTime(formats strfmt.Registry) error { + if swag.IsZero(o.EndTime) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryRunOk"+"."+"run"+"."+"end_time", "body", "date-time", o.EndTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryRunOKBodyRun) validateCounts(formats strfmt.Registry) error { + if swag.IsZero(o.Counts) { // not required + return nil + } + + if o.Counts != nil { + if err := o.Counts.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "run" + "." + "counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "run" + "." + "counts") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory run OK body run based on the context it is used +func (o *GetInventoryRunOKBodyRun) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryRunOKBodyRun) contextValidateCounts(ctx context.Context, formats strfmt.Registry) error { + if o.Counts != nil { + + if swag.IsZero(o.Counts) { // not required + return nil + } + + if err := o.Counts.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryRunOk" + "." + "run" + "." + "counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryRunOk" + "." + "run" + "." + "counts") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunOKBodyRun) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunOKBodyRun) UnmarshalBinary(b []byte) error { + var res GetInventoryRunOKBodyRun + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryRunOKBodyRunCounts InventoryRunCounts is what one refresh saw. +swagger:model GetInventoryRunOKBodyRunCounts +*/ +type GetInventoryRunOKBodyRunCounts struct { + // Services enumeration found. + TotalServices int32 `json:"total_services,omitempty"` + + // ...of which matched a host something could be run on. + ResolvedServices int32 `json:"resolved_services,omitempty"` + + // ...of which did not. Not an error. + OrphanedServices int32 `json:"orphaned_services,omitempty"` + + // Services that answered a probe. + AnsweredServices int32 `json:"answered_services,omitempty"` + + // Hosts in scope this run, service or no service. + // + // A refresh attempts hosts as well as the services on them, so counting only + // services makes a refresh of a host with no database read as "0 of 0" - which is + // exactly what a run that did nothing looks like, on the one kind of host OM most + // exists to describe. + TotalHosts int32 `json:"total_hosts,omitempty"` + + // ...of which had somewhere to run a probe. The gap is the estate nothing can be + // dispatched to, which is a fact about onboarding rather than a failed run. + ProbeableHosts int32 `json:"probeable_hosts,omitempty"` + + // Hosts that answered. + AnsweredHosts int32 `json:"answered_hosts,omitempty"` +} + +// Validate validates this get inventory run OK body run counts +func (o *GetInventoryRunOKBodyRunCounts) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory run OK body run counts based on context it is used +func (o *GetInventoryRunOKBodyRunCounts) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryRunOKBodyRunCounts) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryRunOKBodyRunCounts) UnmarshalBinary(b []byte) error { + var res GetInventoryRunOKBodyRunCounts + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_service_parameters.go b/api/om/v1/json/client/om_service/get_inventory_service_parameters.go new file mode 100644 index 00000000000..595f6f9bbfe --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_service_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetInventoryServiceParams creates a new GetInventoryServiceParams 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 NewGetInventoryServiceParams() *GetInventoryServiceParams { + return &GetInventoryServiceParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetInventoryServiceParamsWithTimeout creates a new GetInventoryServiceParams object +// with the ability to set a timeout on a request. +func NewGetInventoryServiceParamsWithTimeout(timeout time.Duration) *GetInventoryServiceParams { + return &GetInventoryServiceParams{ + timeout: timeout, + } +} + +// NewGetInventoryServiceParamsWithContext creates a new GetInventoryServiceParams object +// with the ability to set a context for a request. +func NewGetInventoryServiceParamsWithContext(ctx context.Context) *GetInventoryServiceParams { + return &GetInventoryServiceParams{ + Context: ctx, + } +} + +// NewGetInventoryServiceParamsWithHTTPClient creates a new GetInventoryServiceParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetInventoryServiceParamsWithHTTPClient(client *http.Client) *GetInventoryServiceParams { + return &GetInventoryServiceParams{ + HTTPClient: client, + } +} + +/* +GetInventoryServiceParams contains all the parameters to send to the API endpoint + + for the get inventory service operation. + + Typically these are written to a http.Request. +*/ +type GetInventoryServiceParams struct { + /* ServiceID. + + PMM's service ID. + */ + ServiceID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get inventory service params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryServiceParams) WithDefaults() *GetInventoryServiceParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get inventory service params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetInventoryServiceParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get inventory service params +func (o *GetInventoryServiceParams) WithTimeout(timeout time.Duration) *GetInventoryServiceParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get inventory service params +func (o *GetInventoryServiceParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get inventory service params +func (o *GetInventoryServiceParams) WithContext(ctx context.Context) *GetInventoryServiceParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get inventory service params +func (o *GetInventoryServiceParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get inventory service params +func (o *GetInventoryServiceParams) WithHTTPClient(client *http.Client) *GetInventoryServiceParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get inventory service params +func (o *GetInventoryServiceParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithServiceID adds the serviceID to the get inventory service params +func (o *GetInventoryServiceParams) WithServiceID(serviceID string) *GetInventoryServiceParams { + o.SetServiceID(serviceID) + return o +} + +// SetServiceID adds the serviceId to the get inventory service params +func (o *GetInventoryServiceParams) SetServiceID(serviceID string) { + o.ServiceID = serviceID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetInventoryServiceParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param service_id + if err := r.SetPathParam("service_id", o.ServiceID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_inventory_service_responses.go b/api/om/v1/json/client/om_service/get_inventory_service_responses.go new file mode 100644 index 00000000000..cdddaa9d74a --- /dev/null +++ b/api/om/v1/json/client/om_service/get_inventory_service_responses.go @@ -0,0 +1,801 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetInventoryServiceReader is a Reader for the GetInventoryService structure. +type GetInventoryServiceReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetInventoryServiceReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetInventoryServiceOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetInventoryServiceDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetInventoryServiceOK creates a GetInventoryServiceOK with default headers values +func NewGetInventoryServiceOK() *GetInventoryServiceOK { + return &GetInventoryServiceOK{} +} + +/* +GetInventoryServiceOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetInventoryServiceOK struct { + Payload *GetInventoryServiceOKBody +} + +// IsSuccess returns true when this get inventory service Ok response has a 2xx status code +func (o *GetInventoryServiceOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get inventory service Ok response has a 3xx status code +func (o *GetInventoryServiceOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get inventory service Ok response has a 4xx status code +func (o *GetInventoryServiceOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get inventory service Ok response has a 5xx status code +func (o *GetInventoryServiceOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get inventory service Ok response a status code equal to that given +func (o *GetInventoryServiceOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get inventory service Ok response +func (o *GetInventoryServiceOK) Code() int { + return 200 +} + +func (o *GetInventoryServiceOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services/{service_id}][%d] getInventoryServiceOk %s", 200, payload) +} + +func (o *GetInventoryServiceOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services/{service_id}][%d] getInventoryServiceOk %s", 200, payload) +} + +func (o *GetInventoryServiceOK) GetPayload() *GetInventoryServiceOKBody { + return o.Payload +} + +func (o *GetInventoryServiceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryServiceOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetInventoryServiceDefault creates a GetInventoryServiceDefault with default headers values +func NewGetInventoryServiceDefault(code int) *GetInventoryServiceDefault { + return &GetInventoryServiceDefault{ + _statusCode: code, + } +} + +/* +GetInventoryServiceDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetInventoryServiceDefault struct { + _statusCode int + + Payload *GetInventoryServiceDefaultBody +} + +// IsSuccess returns true when this get inventory service default response has a 2xx status code +func (o *GetInventoryServiceDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get inventory service default response has a 3xx status code +func (o *GetInventoryServiceDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get inventory service default response has a 4xx status code +func (o *GetInventoryServiceDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get inventory service default response has a 5xx status code +func (o *GetInventoryServiceDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get inventory service default response a status code equal to that given +func (o *GetInventoryServiceDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get inventory service default response +func (o *GetInventoryServiceDefault) Code() int { + return o._statusCode +} + +func (o *GetInventoryServiceDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services/{service_id}][%d] GetInventoryService default %s", o._statusCode, payload) +} + +func (o *GetInventoryServiceDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services/{service_id}][%d] GetInventoryService default %s", o._statusCode, payload) +} + +func (o *GetInventoryServiceDefault) GetPayload() *GetInventoryServiceDefaultBody { + return o.Payload +} + +func (o *GetInventoryServiceDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetInventoryServiceDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetInventoryServiceDefaultBody get inventory service default body +swagger:model GetInventoryServiceDefaultBody +*/ +type GetInventoryServiceDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetInventoryServiceDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get inventory service default body +func (o *GetInventoryServiceDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get inventory service default body based on the context it is used +func (o *GetInventoryServiceDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetInventoryService default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryServiceDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryServiceDefaultBody) UnmarshalBinary(b []byte) error { + var res GetInventoryServiceDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryServiceDefaultBodyDetailsItems0 get inventory service default body details items0 +swagger:model GetInventoryServiceDefaultBodyDetailsItems0 +*/ +type GetInventoryServiceDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get inventory service default body details items0 + GetInventoryServiceDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetInventoryServiceDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetInventoryServiceDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetInventoryServiceDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetInventoryServiceDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetInventoryServiceDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetInventoryServiceDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get inventory service default body details items0 +func (o *GetInventoryServiceDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get inventory service default body details items0 based on context it is used +func (o *GetInventoryServiceDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryServiceDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryServiceDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetInventoryServiceDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryServiceOKBody GetInventoryServiceResponse returns one service. +swagger:model GetInventoryServiceOKBody +*/ +type GetInventoryServiceOKBody struct { + // service + Service *GetInventoryServiceOKBodyService `json:"service,omitempty"` +} + +// Validate validates this get inventory service OK body +func (o *GetInventoryServiceOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateService(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceOKBody) validateService(formats strfmt.Registry) error { + if swag.IsZero(o.Service) { // not required + return nil + } + + if o.Service != nil { + if err := o.Service.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryServiceOk" + "." + "service") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryServiceOk" + "." + "service") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory service OK body based on the context it is used +func (o *GetInventoryServiceOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateService(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceOKBody) contextValidateService(ctx context.Context, formats strfmt.Registry) error { + if o.Service != nil { + + if swag.IsZero(o.Service) { // not required + return nil + } + + if err := o.Service.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryServiceOk" + "." + "service") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryServiceOk" + "." + "service") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryServiceOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryServiceOKBody) UnmarshalBinary(b []byte) error { + var res GetInventoryServiceOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryServiceOKBodyService InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +swagger:model GetInventoryServiceOKBodyService +*/ +type GetInventoryServiceOKBodyService struct { + // PMM's service ID. The join key against the topology document. + ServiceID string `json:"service_id,omitempty"` + + // The node it runs on, as PMM's node ID. + NodeID string `json:"node_id,omitempty"` + + // The service name PMM registered. + Name string `json:"name,omitempty"` + + // The port it listens on, where OM knows it. + Port *int32 `json:"port,omitempty"` + + // PRIMARY, SECONDARY, ARBITER, or unset. + Role *string `json:"role,omitempty"` + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + InstalledVersion *string `json:"installed_version,omitempty"` + + // The version the running server reports. + RunningVersion *string `json:"running_version,omitempty"` + + // The configuration file the running server read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // What the last probe of this service concluded, in the payload's own words. + ProbeStatus *string `json:"probe_status,omitempty"` + + // Whether a server was found running. Unset where no probe has looked. + ServerRunning *bool `json:"server_running,omitempty"` + + // How long it has been up, seconds. + UptimeSeconds *float64 `json:"uptime_seconds,omitempty"` + + // The replica set it belongs to, or unset for a standalone or a router. + ReplicationSet *string `json:"replication_set,omitempty"` + + // Everything the probe recorded, including attributes with no field above. + Observed any `json:"observed,omitempty"` + + // freshness + Freshness *GetInventoryServiceOKBodyServiceFreshness `json:"freshness,omitempty"` +} + +// Validate validates this get inventory service OK body service +func (o *GetInventoryServiceOKBodyService) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceOKBodyService) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryServiceOk" + "." + "service" + "." + "freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryServiceOk" + "." + "service" + "." + "freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get inventory service OK body service based on the context it is used +func (o *GetInventoryServiceOKBodyService) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceOKBodyService) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getInventoryServiceOk" + "." + "service" + "." + "freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getInventoryServiceOk" + "." + "service" + "." + "freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryServiceOKBodyService) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryServiceOKBodyService) UnmarshalBinary(b []byte) error { + var res GetInventoryServiceOKBodyService + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetInventoryServiceOKBodyServiceFreshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model GetInventoryServiceOKBodyServiceFreshness +*/ +type GetInventoryServiceOKBodyServiceFreshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this get inventory service OK body service freshness +func (o *GetInventoryServiceOKBodyServiceFreshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetInventoryServiceOKBodyServiceFreshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryServiceOk"+"."+"service"+"."+"freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryServiceOKBodyServiceFreshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryServiceOk"+"."+"service"+"."+"freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryServiceOKBodyServiceFreshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryServiceOk"+"."+"service"+"."+"freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetInventoryServiceOKBodyServiceFreshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("getInventoryServiceOk"+"."+"service"+"."+"freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get inventory service OK body service freshness based on context it is used +func (o *GetInventoryServiceOKBodyServiceFreshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetInventoryServiceOKBodyServiceFreshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetInventoryServiceOKBodyServiceFreshness) UnmarshalBinary(b []byte) error { + var res GetInventoryServiceOKBodyServiceFreshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_topology_parameters.go b/api/om/v1/json/client/om_service/get_topology_parameters.go new file mode 100644 index 00000000000..8feca3f74c4 --- /dev/null +++ b/api/om/v1/json/client/om_service/get_topology_parameters.go @@ -0,0 +1,124 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetTopologyParams creates a new GetTopologyParams 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 NewGetTopologyParams() *GetTopologyParams { + return &GetTopologyParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetTopologyParamsWithTimeout creates a new GetTopologyParams object +// with the ability to set a timeout on a request. +func NewGetTopologyParamsWithTimeout(timeout time.Duration) *GetTopologyParams { + return &GetTopologyParams{ + timeout: timeout, + } +} + +// NewGetTopologyParamsWithContext creates a new GetTopologyParams object +// with the ability to set a context for a request. +func NewGetTopologyParamsWithContext(ctx context.Context) *GetTopologyParams { + return &GetTopologyParams{ + Context: ctx, + } +} + +// NewGetTopologyParamsWithHTTPClient creates a new GetTopologyParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetTopologyParamsWithHTTPClient(client *http.Client) *GetTopologyParams { + return &GetTopologyParams{ + HTTPClient: client, + } +} + +/* +GetTopologyParams contains all the parameters to send to the API endpoint + + for the get topology operation. + + Typically these are written to a http.Request. +*/ +type GetTopologyParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get topology params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetTopologyParams) WithDefaults() *GetTopologyParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get topology params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetTopologyParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get topology params +func (o *GetTopologyParams) WithTimeout(timeout time.Duration) *GetTopologyParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get topology params +func (o *GetTopologyParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get topology params +func (o *GetTopologyParams) WithContext(ctx context.Context) *GetTopologyParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get topology params +func (o *GetTopologyParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get topology params +func (o *GetTopologyParams) WithHTTPClient(client *http.Client) *GetTopologyParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get topology params +func (o *GetTopologyParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *GetTopologyParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_topology_responses.go b/api/om/v1/json/client/om_service/get_topology_responses.go new file mode 100644 index 00000000000..e89049ccdeb --- /dev/null +++ b/api/om/v1/json/client/om_service/get_topology_responses.go @@ -0,0 +1,1405 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetTopologyReader is a Reader for the GetTopology structure. +type GetTopologyReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetTopologyReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetTopologyOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetTopologyDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetTopologyOK creates a GetTopologyOK with default headers values +func NewGetTopologyOK() *GetTopologyOK { + return &GetTopologyOK{} +} + +/* +GetTopologyOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetTopologyOK struct { + Payload *GetTopologyOKBody +} + +// IsSuccess returns true when this get topology Ok response has a 2xx status code +func (o *GetTopologyOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get topology Ok response has a 3xx status code +func (o *GetTopologyOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get topology Ok response has a 4xx status code +func (o *GetTopologyOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get topology Ok response has a 5xx status code +func (o *GetTopologyOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get topology Ok response a status code equal to that given +func (o *GetTopologyOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get topology Ok response +func (o *GetTopologyOK) Code() int { + return 200 +} + +func (o *GetTopologyOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology][%d] getTopologyOk %s", 200, payload) +} + +func (o *GetTopologyOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology][%d] getTopologyOk %s", 200, payload) +} + +func (o *GetTopologyOK) GetPayload() *GetTopologyOKBody { + return o.Payload +} + +func (o *GetTopologyOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetTopologyOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetTopologyDefault creates a GetTopologyDefault with default headers values +func NewGetTopologyDefault(code int) *GetTopologyDefault { + return &GetTopologyDefault{ + _statusCode: code, + } +} + +/* +GetTopologyDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetTopologyDefault struct { + _statusCode int + + Payload *GetTopologyDefaultBody +} + +// IsSuccess returns true when this get topology default response has a 2xx status code +func (o *GetTopologyDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get topology default response has a 3xx status code +func (o *GetTopologyDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get topology default response has a 4xx status code +func (o *GetTopologyDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get topology default response has a 5xx status code +func (o *GetTopologyDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get topology default response a status code equal to that given +func (o *GetTopologyDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get topology default response +func (o *GetTopologyDefault) Code() int { + return o._statusCode +} + +func (o *GetTopologyDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology][%d] GetTopology default %s", o._statusCode, payload) +} + +func (o *GetTopologyDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology][%d] GetTopology default %s", o._statusCode, payload) +} + +func (o *GetTopologyDefault) GetPayload() *GetTopologyDefaultBody { + return o.Payload +} + +func (o *GetTopologyDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetTopologyDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetTopologyDefaultBody get topology default body +swagger:model GetTopologyDefaultBody +*/ +type GetTopologyDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetTopologyDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get topology default body +func (o *GetTopologyDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetTopology default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetTopology default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get topology default body based on the context it is used +func (o *GetTopologyDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetTopology default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetTopology default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyDefaultBody) UnmarshalBinary(b []byte) error { + var res GetTopologyDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyDefaultBodyDetailsItems0 get topology default body details items0 +swagger:model GetTopologyDefaultBodyDetailsItems0 +*/ +type GetTopologyDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get topology default body details items0 + GetTopologyDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetTopologyDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetTopologyDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetTopologyDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetTopologyDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetTopologyDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetTopologyDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get topology default body details items0 +func (o *GetTopologyDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get topology default body details items0 based on context it is used +func (o *GetTopologyDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBody GetTopologyResponse is the whole topology document plus the provenance of the run +// behind it. +swagger:model GetTopologyOKBody +*/ +type GetTopologyOKBody struct { + // The PMM node the document was assembled on. + OriginNode *string `json:"origin_node,omitempty"` + + // The VictoriaMetrics queries the document was derived from. + SourceQueries []string `json:"source_queries"` + + // The estate, grouped environment then cluster. + Environments []*GetTopologyOKBodyEnvironmentsItems0 `json:"environments"` + + // snapshot + Snapshot *GetTopologyOKBodySnapshot `json:"snapshot,omitempty"` + + // summary + Summary *GetTopologyOKBodySummary `json:"summary,omitempty"` +} + +// Validate validates this get topology OK body +func (o *GetTopologyOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateEnvironments(formats); err != nil { + res = append(res, err) + } + + if err := o.validateSnapshot(formats); err != nil { + res = append(res, err) + } + + if err := o.validateSummary(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBody) validateEnvironments(formats strfmt.Registry) error { + if swag.IsZero(o.Environments) { // not required + return nil + } + + for i := 0; i < len(o.Environments); i++ { + if swag.IsZero(o.Environments[i]) { // not required + continue + } + + if o.Environments[i] != nil { + if err := o.Environments[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "environments" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "environments" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetTopologyOKBody) validateSnapshot(formats strfmt.Registry) error { + if swag.IsZero(o.Snapshot) { // not required + return nil + } + + if o.Snapshot != nil { + if err := o.Snapshot.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "snapshot") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "snapshot") + } + + return err + } + } + + return nil +} + +func (o *GetTopologyOKBody) validateSummary(formats strfmt.Registry) error { + if swag.IsZero(o.Summary) { // not required + return nil + } + + if o.Summary != nil { + if err := o.Summary.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "summary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "summary") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get topology OK body based on the context it is used +func (o *GetTopologyOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateEnvironments(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateSnapshot(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateSummary(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBody) contextValidateEnvironments(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Environments); i++ { + if o.Environments[i] != nil { + + if swag.IsZero(o.Environments[i]) { // not required + return nil + } + + if err := o.Environments[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "environments" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "environments" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetTopologyOKBody) contextValidateSnapshot(ctx context.Context, formats strfmt.Registry) error { + if o.Snapshot != nil { + + if swag.IsZero(o.Snapshot) { // not required + return nil + } + + if err := o.Snapshot.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "snapshot") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "snapshot") + } + + return err + } + } + + return nil +} + +func (o *GetTopologyOKBody) contextValidateSummary(ctx context.Context, formats strfmt.Registry) error { + if o.Summary != nil { + + if swag.IsZero(o.Summary) { // not required + return nil + } + + if err := o.Summary.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyOk" + "." + "summary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyOk" + "." + "summary") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBody) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBodyEnvironmentsItems0 Environment represents one monitoring environment. +swagger:model GetTopologyOKBodyEnvironmentsItems0 +*/ +type GetTopologyOKBodyEnvironmentsItems0 struct { + // Environment label, unset when its services carry none. + EnvName *string `json:"env_name,omitempty"` + + // Its clusters, ordered by name. + Clusters []*GetTopologyOKBodyEnvironmentsItems0ClustersItems0 `json:"clusters"` +} + +// Validate validates this get topology OK body environments items0 +func (o *GetTopologyOKBodyEnvironmentsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateClusters(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0) validateClusters(formats strfmt.Registry) error { + if swag.IsZero(o.Clusters) { // not required + return nil + } + + for i := 0; i < len(o.Clusters); i++ { + if swag.IsZero(o.Clusters[i]) { // not required + continue + } + + if o.Clusters[i] != nil { + if err := o.Clusters[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("clusters" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("clusters" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get topology OK body environments items0 based on the context it is used +func (o *GetTopologyOKBodyEnvironmentsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateClusters(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0) contextValidateClusters(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Clusters); i++ { + if o.Clusters[i] != nil { + + if swag.IsZero(o.Clusters[i]) { // not required + return nil + } + + if err := o.Clusters[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("clusters" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("clusters" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBodyEnvironmentsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBodyEnvironmentsItems0ClustersItems0 Cluster represents one grouped service inventory: every service PMM's inventory +// labelled with the same (environment, cluster) or (environment, replication_set), not a +// reconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat +// list of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for +// the one thing inferred about that shape, and the package comment for what is +// deliberately not. +swagger:model GetTopologyOKBodyEnvironmentsItems0ClustersItems0 +*/ +type GetTopologyOKBodyEnvironmentsItems0ClustersItems0 struct { + // Cluster label, unset when its services carry none. Not a stable identity: two + // clusters can share this label (a second generation of a sandbox reusing a name), and + // `id` is what tells them apart. + Name *string `json:"name,omitempty"` + + // Its services, ordered by name. + Services []*GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0 `json:"services"` + + // Opaque, server-issued, stable across a rename of `name`. Derived from + // (environment, cluster, replication_set) so the same estate group always gets the + // same id -- clients must not parse it or assume a derivation. + ID string `json:"id,omitempty"` + + // ClusterType is the shape buildDocument inferred for one grouped service inventory. + // + // Inferred, not reconstructed: this package groups services by label and infers a shape + // from what is in the group, it does not walk a replica set's own config to build a + // member list. See the package comment. + // + // - CLUSTER_TYPE_REPLICA_SET: Exactly one replication_set label under this cluster, and no mongos. + // - CLUSTER_TYPE_SHARDED: A mongos is present, or more than one replication_set label shares this cluster + // label. + // - CLUSTER_TYPE_STANDALONE: Neither: services grouped under one label with no replica-set identity at all. + // Enum: ["CLUSTER_TYPE_UNSPECIFIED","CLUSTER_TYPE_REPLICA_SET","CLUSTER_TYPE_SHARDED","CLUSTER_TYPE_STANDALONE"] + Type *string `json:"type,omitempty"` + + // ClusterHealth is a reserved verdict slot, not yet computed by anything. + // + // UNSPECIFIED is the only value that exists today. It is declared now, alongside the + // applyHealth seam in the collector, so a rollup status has a field to land in without a + // later schema change -- see the om package's health-pipeline comment. + // Enum: ["CLUSTER_HEALTH_UNSPECIFIED"] + Health *string `json:"health,omitempty"` +} + +// Validate validates this get topology OK body environments items0 clusters items0 +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateServices(formats); err != nil { + res = append(res, err) + } + + if err := o.validateType(formats); err != nil { + res = append(res, err) + } + + if err := o.validateHealth(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) validateServices(formats strfmt.Registry) error { + if swag.IsZero(o.Services) { // not required + return nil + } + + for i := 0; i < len(o.Services); i++ { + if swag.IsZero(o.Services[i]) { // not required + continue + } + + if o.Services[i] != nil { + if err := o.Services[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +var getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeTypePropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["CLUSTER_TYPE_UNSPECIFIED","CLUSTER_TYPE_REPLICA_SET","CLUSTER_TYPE_SHARDED","CLUSTER_TYPE_STANDALONE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeTypePropEnum = append(getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeTypePropEnum, v) + } +} + +const ( + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPEUNSPECIFIED captures enum value "CLUSTER_TYPE_UNSPECIFIED" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPEUNSPECIFIED string = "CLUSTER_TYPE_UNSPECIFIED" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPEREPLICASET captures enum value "CLUSTER_TYPE_REPLICA_SET" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPEREPLICASET string = "CLUSTER_TYPE_REPLICA_SET" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPESHARDED captures enum value "CLUSTER_TYPE_SHARDED" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPESHARDED string = "CLUSTER_TYPE_SHARDED" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPESTANDALONE captures enum value "CLUSTER_TYPE_STANDALONE" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0TypeCLUSTERTYPESTANDALONE string = "CLUSTER_TYPE_STANDALONE" +) + +// prop value enum +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) validateTypeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeTypePropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) validateType(formats strfmt.Registry) error { + if swag.IsZero(o.Type) { // not required + return nil + } + + // value enum + if err := o.validateTypeEnum("type", "body", *o.Type); err != nil { + return err + } + + return nil +} + +var getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeHealthPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["CLUSTER_HEALTH_UNSPECIFIED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeHealthPropEnum = append(getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeHealthPropEnum, v) + } +} + +const ( + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0HealthCLUSTERHEALTHUNSPECIFIED captures enum value "CLUSTER_HEALTH_UNSPECIFIED" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0HealthCLUSTERHEALTHUNSPECIFIED string = "CLUSTER_HEALTH_UNSPECIFIED" +) + +// prop value enum +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) validateHealthEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyOkBodyEnvironmentsItems0ClustersItems0TypeHealthPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) validateHealth(formats strfmt.Registry) error { + if swag.IsZero(o.Health) { // not required + return nil + } + + // value enum + if err := o.validateHealthEnum("health", "body", *o.Health); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this get topology OK body environments items0 clusters items0 based on the context it is used +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateServices(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) contextValidateServices(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Services); i++ { + if o.Services[i] != nil { + + if swag.IsZero(o.Services[i]) { // not required + return nil + } + + if err := o.Services[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBodyEnvironmentsItems0ClustersItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0 TopologyService represents one monitored MongoDB service as the topology document +// records it. +// +// Two conventions for "no value", and they differ on purpose. cpu_usage_percent and +// connections_free_percent are -1 when not measured, never absent and never 0, because +// zero CPU is a legitimate reading and a numeric column must keep "idle" and "unknown" +// apart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is +// absent when they do not apply -- a router and a standalone have no replica-set oplog -- +// which is a different statement from -1's "we could not measure it". +// +// The optional fields were wrapper messages until the REST contract was checked: +// protoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema +// and the generated Go client both collapsed to a value type and lost the distinction +// entirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting +// the key rather than emitting an explicit null. +swagger:model GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0 +*/ +type GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0 struct { + // Service name as PMM inventory registered it. + ServiceName string `json:"service_name,omitempty"` + + // Node the service runs on. + Host *string `json:"host,omitempty"` + + // host:port as the replica set itself addresses the member. + Endpoint *string `json:"endpoint,omitempty"` + + // PMM's service ID. The join key against VictoriaMetrics. + ServiceID *string `json:"service_id,omitempty"` + + // Always "mongodb" today. + ServiceType *string `json:"service_type,omitempty"` + + // Running server version. + Version *string `json:"version,omitempty"` + + // MongoDB or Percona. + Vendor *string `json:"vendor,omitempty"` + + // Community or Enterprise. + Edition *string `json:"edition,omitempty"` + + // Replica set, or unset for a router or a standalone. + ReplicationSet *string `json:"replication_set,omitempty"` + + // PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state. + State *string `json:"state,omitempty"` + + // ServiceStatus is whether the exporter reached a service. + // + // Two values and no third: this is the exporter's reachability, not the server's health. + // "we did not look" is UNSPECIFIED, which the collector never emits. + // + // - SERVICE_STATUS_UP: The exporter reached the service. + // - SERVICE_STATUS_DOWN: It did not. + // Enum: ["SERVICE_STATUS_UNSPECIFIED","SERVICE_STATUS_UP","SERVICE_STATUS_DOWN"] + Status *string `json:"status,omitempty"` + + // CPU percentage, or -1 when not measured. + CPUUsagePercent float64 `json:"cpu_usage_percent,omitempty"` + + // Percentage of free connections, or -1 when not measured. + ConnectionsFreePercent float64 `json:"connections_free_percent,omitempty"` + + // ProcessRole is what a mongod or mongos is doing in the deployment. + // + // Not the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This + // is the role the process was started in, which is a property of the deployment's shape. + // + // - PROCESS_ROLE_MONGOD: A standalone or replica-set member with no sharding role. + // - PROCESS_ROLE_MONGOS: A router. + // - PROCESS_ROLE_CONFIGSVR: A config-server member. + // - PROCESS_ROLE_SHARDSVR: A shard member. + // Enum: ["PROCESS_ROLE_UNSPECIFIED","PROCESS_ROLE_MONGOD","PROCESS_ROLE_MONGOS","PROCESS_ROLE_CONFIGSVR","PROCESS_ROLE_SHARDSVR"] + ProcessRole *string `json:"process_role,omitempty"` + + // Seconds this member trails the primary; unset where there is no primary to trail. + ReplicationLagSeconds *float64 `json:"replication_lag_seconds,omitempty"` + + // Seconds of history the oplog holds; unset where there is no replica-set oplog. + OplogWindowSeconds *float64 `json:"oplog_window_seconds,omitempty"` + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from `version` is the upgraded-but-not-restarted case. Only + // an on-host probe can see it, so this is unset wherever one has not run. + InstalledVersion *string `json:"installed_version,omitempty"` + + // The configuration file the running server read. Probe-only. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line the running server was started with. Probe-only. + Argv *string `json:"argv,omitempty"` + + // When the newest *live* field on this row was observed, unset when every field on it + // is either absent or not time-bounded (inventory only, no metric and no probe ever + // seen). This is the row's own provenance -- Snapshot.observed_at is the newest across + // the whole estate, which cannot tell "this row is current" from "this row is the one + // that made the snapshot look fresh". A field's own MergedField.ObservedAt exists + // internally; this is the first one exposed on the wire. + // Format: date-time + ObservedAt *strfmt.DateTime `json:"observed_at,omitempty"` +} + +// Validate validates this get topology OK body environments items0 clusters items0 services items0 +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateProcessRole(formats); err != nil { + res = append(res, err) + } + + if err := o.validateObservedAt(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SERVICE_STATUS_UNSPECIFIED","SERVICE_STATUS_UP","SERVICE_STATUS_DOWN"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeStatusPropEnum = append(getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeStatusPropEnum, v) + } +} + +const ( + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSUNSPECIFIED captures enum value "SERVICE_STATUS_UNSPECIFIED" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSUNSPECIFIED string = "SERVICE_STATUS_UNSPECIFIED" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSUP captures enum value "SERVICE_STATUS_UP" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSUP string = "SERVICE_STATUS_UP" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSDOWN captures enum value "SERVICE_STATUS_DOWN" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0StatusSERVICESTATUSDOWN string = "SERVICE_STATUS_DOWN" +) + +// prop value enum +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +var getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeProcessRolePropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["PROCESS_ROLE_UNSPECIFIED","PROCESS_ROLE_MONGOD","PROCESS_ROLE_MONGOS","PROCESS_ROLE_CONFIGSVR","PROCESS_ROLE_SHARDSVR"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeProcessRolePropEnum = append(getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeProcessRolePropEnum, v) + } +} + +const ( + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEUNSPECIFIED captures enum value "PROCESS_ROLE_UNSPECIFIED" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEUNSPECIFIED string = "PROCESS_ROLE_UNSPECIFIED" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEMONGOD captures enum value "PROCESS_ROLE_MONGOD" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEMONGOD string = "PROCESS_ROLE_MONGOD" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEMONGOS captures enum value "PROCESS_ROLE_MONGOS" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLEMONGOS string = "PROCESS_ROLE_MONGOS" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLECONFIGSVR captures enum value "PROCESS_ROLE_CONFIGSVR" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLECONFIGSVR string = "PROCESS_ROLE_CONFIGSVR" + + // GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLESHARDSVR captures enum value "PROCESS_ROLE_SHARDSVR" + GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0ProcessRolePROCESSROLESHARDSVR string = "PROCESS_ROLE_SHARDSVR" +) + +// prop value enum +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) validateProcessRoleEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyOkBodyEnvironmentsItems0ClustersItems0ServicesItems0TypeProcessRolePropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) validateProcessRole(formats strfmt.Registry) error { + if swag.IsZero(o.ProcessRole) { // not required + return nil + } + + // value enum + if err := o.validateProcessRoleEnum("process_role", "body", *o.ProcessRole); err != nil { + return err + } + + return nil +} + +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) validateObservedAt(formats strfmt.Registry) error { + if swag.IsZero(o.ObservedAt) { // not required + return nil + } + + if err := validate.FormatOf("observed_at", "body", "date-time", o.ObservedAt.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get topology OK body environments items0 clusters items0 services items0 based on context it is used +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBodyEnvironmentsItems0ClustersItems0ServicesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBodySnapshot Snapshot carries the provenance every snapshot-backed response repeats. +swagger:model GetTopologyOKBodySnapshot +*/ +type GetTopologyOKBodySnapshot struct { + // When the document was assembled. + // Format: date-time + GeneratedAt strfmt.DateTime `json:"generated_at,omitempty"` + + // The newest observation in it, unset when nothing was observed at all. + // Format: date-time + ObservedAt strfmt.DateTime `json:"observed_at,omitempty"` + + // Whether the document is older than the staleness grace period. Also true, with + // observed_at unset and every environment empty, on a genuinely cold estate -- no + // collection has completed anywhere yet. That is a startup state, not a statement that + // the estate itself is empty; a reader should render it as "collecting" rather than as + // an empty result. + Stale bool `json:"stale,omitempty"` + + // The document schema version. + SchemaVersion int32 `json:"schema_version,omitempty"` + + // The collection run that produced it. + RunID string `json:"run_id,omitempty"` +} + +// Validate validates this get topology OK body snapshot +func (o *GetTopologyOKBodySnapshot) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateGeneratedAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateObservedAt(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyOKBodySnapshot) validateGeneratedAt(formats strfmt.Registry) error { + if swag.IsZero(o.GeneratedAt) { // not required + return nil + } + + if err := validate.FormatOf("getTopologyOk"+"."+"snapshot"+"."+"generated_at", "body", "date-time", o.GeneratedAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetTopologyOKBodySnapshot) validateObservedAt(formats strfmt.Registry) error { + if swag.IsZero(o.ObservedAt) { // not required + return nil + } + + if err := validate.FormatOf("getTopologyOk"+"."+"snapshot"+"."+"observed_at", "body", "date-time", o.ObservedAt.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get topology OK body snapshot based on context it is used +func (o *GetTopologyOKBodySnapshot) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBodySnapshot) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBodySnapshot) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBodySnapshot + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyOKBodySummary Summary carries the fleet-level counts, so a caller need not re-derive them. +swagger:model GetTopologyOKBodySummary +*/ +type GetTopologyOKBodySummary struct { + // Environments in the document. + Environments int32 `json:"environments,omitempty"` + + // Clusters across all of them. + Clusters int32 `json:"clusters,omitempty"` + + // Services in the document. + TotalServices int32 `json:"total_services,omitempty"` + + // Services the exporter reached. + UpServices int32 `json:"up_services,omitempty"` + + // Services it did not. + DownServices int32 `json:"down_services,omitempty"` + + // Service counts per process role, keyed by the ProcessRole enum's name. + ProcessRoleCounts map[string]int32 `json:"process_role_counts,omitempty"` +} + +// Validate validates this get topology OK body summary +func (o *GetTopologyOKBodySummary) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get topology OK body summary based on context it is used +func (o *GetTopologyOKBodySummary) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyOKBodySummary) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyOKBodySummary) UnmarshalBinary(b []byte) error { + var res GetTopologyOKBodySummary + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/get_topology_run_parameters.go b/api/om/v1/json/client/om_service/get_topology_run_parameters.go new file mode 100644 index 00000000000..f2679856c16 --- /dev/null +++ b/api/om/v1/json/client/om_service/get_topology_run_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewGetTopologyRunParams creates a new GetTopologyRunParams 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 NewGetTopologyRunParams() *GetTopologyRunParams { + return &GetTopologyRunParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetTopologyRunParamsWithTimeout creates a new GetTopologyRunParams object +// with the ability to set a timeout on a request. +func NewGetTopologyRunParamsWithTimeout(timeout time.Duration) *GetTopologyRunParams { + return &GetTopologyRunParams{ + timeout: timeout, + } +} + +// NewGetTopologyRunParamsWithContext creates a new GetTopologyRunParams object +// with the ability to set a context for a request. +func NewGetTopologyRunParamsWithContext(ctx context.Context) *GetTopologyRunParams { + return &GetTopologyRunParams{ + Context: ctx, + } +} + +// NewGetTopologyRunParamsWithHTTPClient creates a new GetTopologyRunParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetTopologyRunParamsWithHTTPClient(client *http.Client) *GetTopologyRunParams { + return &GetTopologyRunParams{ + HTTPClient: client, + } +} + +/* +GetTopologyRunParams contains all the parameters to send to the API endpoint + + for the get topology run operation. + + Typically these are written to a http.Request. +*/ +type GetTopologyRunParams struct { + /* RunID. + + The run to return. + */ + RunID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get topology run params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetTopologyRunParams) WithDefaults() *GetTopologyRunParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get topology run params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetTopologyRunParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get topology run params +func (o *GetTopologyRunParams) WithTimeout(timeout time.Duration) *GetTopologyRunParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get topology run params +func (o *GetTopologyRunParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get topology run params +func (o *GetTopologyRunParams) WithContext(ctx context.Context) *GetTopologyRunParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get topology run params +func (o *GetTopologyRunParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get topology run params +func (o *GetTopologyRunParams) WithHTTPClient(client *http.Client) *GetTopologyRunParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get topology run params +func (o *GetTopologyRunParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithRunID adds the runID to the get topology run params +func (o *GetTopologyRunParams) WithRunID(runID string) *GetTopologyRunParams { + o.SetRunID(runID) + return o +} + +// SetRunID adds the runId to the get topology run params +func (o *GetTopologyRunParams) SetRunID(runID string) { + o.RunID = runID +} + +// WriteToRequest writes these params to a swagger request +func (o *GetTopologyRunParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param run_id + if err := r.SetPathParam("run_id", o.RunID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/get_topology_run_responses.go b/api/om/v1/json/client/om_service/get_topology_run_responses.go new file mode 100644 index 00000000000..8076b736e3c --- /dev/null +++ b/api/om/v1/json/client/om_service/get_topology_run_responses.go @@ -0,0 +1,1093 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetTopologyRunReader is a Reader for the GetTopologyRun structure. +type GetTopologyRunReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetTopologyRunReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetTopologyRunOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetTopologyRunDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetTopologyRunOK creates a GetTopologyRunOK with default headers values +func NewGetTopologyRunOK() *GetTopologyRunOK { + return &GetTopologyRunOK{} +} + +/* +GetTopologyRunOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetTopologyRunOK struct { + Payload *GetTopologyRunOKBody +} + +// IsSuccess returns true when this get topology run Ok response has a 2xx status code +func (o *GetTopologyRunOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get topology run Ok response has a 3xx status code +func (o *GetTopologyRunOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get topology run Ok response has a 4xx status code +func (o *GetTopologyRunOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get topology run Ok response has a 5xx status code +func (o *GetTopologyRunOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get topology run Ok response a status code equal to that given +func (o *GetTopologyRunOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get topology run Ok response +func (o *GetTopologyRunOK) Code() int { + return 200 +} + +func (o *GetTopologyRunOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs/{run_id}][%d] getTopologyRunOk %s", 200, payload) +} + +func (o *GetTopologyRunOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs/{run_id}][%d] getTopologyRunOk %s", 200, payload) +} + +func (o *GetTopologyRunOK) GetPayload() *GetTopologyRunOKBody { + return o.Payload +} + +func (o *GetTopologyRunOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetTopologyRunOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetTopologyRunDefault creates a GetTopologyRunDefault with default headers values +func NewGetTopologyRunDefault(code int) *GetTopologyRunDefault { + return &GetTopologyRunDefault{ + _statusCode: code, + } +} + +/* +GetTopologyRunDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetTopologyRunDefault struct { + _statusCode int + + Payload *GetTopologyRunDefaultBody +} + +// IsSuccess returns true when this get topology run default response has a 2xx status code +func (o *GetTopologyRunDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get topology run default response has a 3xx status code +func (o *GetTopologyRunDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get topology run default response has a 4xx status code +func (o *GetTopologyRunDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get topology run default response has a 5xx status code +func (o *GetTopologyRunDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get topology run default response a status code equal to that given +func (o *GetTopologyRunDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get topology run default response +func (o *GetTopologyRunDefault) Code() int { + return o._statusCode +} + +func (o *GetTopologyRunDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs/{run_id}][%d] GetTopologyRun default %s", o._statusCode, payload) +} + +func (o *GetTopologyRunDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs/{run_id}][%d] GetTopologyRun default %s", o._statusCode, payload) +} + +func (o *GetTopologyRunDefault) GetPayload() *GetTopologyRunDefaultBody { + return o.Payload +} + +func (o *GetTopologyRunDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetTopologyRunDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetTopologyRunDefaultBody get topology run default body +swagger:model GetTopologyRunDefaultBody +*/ +type GetTopologyRunDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetTopologyRunDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get topology run default body +func (o *GetTopologyRunDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyRunDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetTopologyRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetTopologyRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get topology run default body based on the context it is used +func (o *GetTopologyRunDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyRunDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetTopologyRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetTopologyRun default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunDefaultBody) UnmarshalBinary(b []byte) error { + var res GetTopologyRunDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunDefaultBodyDetailsItems0 get topology run default body details items0 +swagger:model GetTopologyRunDefaultBodyDetailsItems0 +*/ +type GetTopologyRunDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get topology run default body details items0 + GetTopologyRunDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetTopologyRunDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetTopologyRunDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetTopologyRunDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetTopologyRunDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetTopologyRunDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetTopologyRunDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get topology run default body details items0 +func (o *GetTopologyRunDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get topology run default body details items0 based on context it is used +func (o *GetTopologyRunDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyRunDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunOKBody GetTopologyRunResponse returns one collection run. +swagger:model GetTopologyRunOKBody +*/ +type GetTopologyRunOKBody struct { + // run + Run *GetTopologyRunOKBodyRun `json:"run,omitempty"` +} + +// Validate validates this get topology run OK body +func (o *GetTopologyRunOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateRun(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyRunOKBody) validateRun(formats strfmt.Registry) error { + if swag.IsZero(o.Run) { // not required + return nil + } + + if o.Run != nil { + if err := o.Run.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get topology run OK body based on the context it is used +func (o *GetTopologyRunOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateRun(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyRunOKBody) contextValidateRun(ctx context.Context, formats strfmt.Registry) error { + if o.Run != nil { + + if swag.IsZero(o.Run) { // not required + return nil + } + + if err := o.Run.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunOKBody) UnmarshalBinary(b []byte) error { + var res GetTopologyRunOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunOKBodyRun TopologyRun represents one collection run. +swagger:model GetTopologyRunOKBodyRun +*/ +type GetTopologyRunOKBodyRun struct { + // The run's ID, also the snapshot key. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When the run began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` + + // When it reached a terminal status; unset while running. + // Format: date-time + EndTime strfmt.DateTime `json:"end_time,omitempty"` + + // Query-level, service-level and run-level failures. + Errors []*GetTopologyRunOKBodyRunErrorsItems0 `json:"errors"` + + // How completely each collection source answered. + Sources []*GetTopologyRunOKBodyRunSourcesItems0 `json:"sources"` + + // counts + Counts *GetTopologyRunOKBodyRunCounts `json:"counts,omitempty"` +} + +// Validate validates this get topology run OK body run +func (o *GetTopologyRunOKBodyRun) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateEndTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateErrors(formats); err != nil { + res = append(res, err) + } + + if err := o.validateSources(formats); err != nil { + res = append(res, err) + } + + if err := o.validateCounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getTopologyRunOkBodyRunTypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyRunOkBodyRunTypeStatusPropEnum = append(getTopologyRunOkBodyRunTypeStatusPropEnum, v) + } +} + +const ( + + // GetTopologyRunOKBodyRunStatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + GetTopologyRunOKBodyRunStatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // GetTopologyRunOKBodyRunStatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + GetTopologyRunOKBodyRunStatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // GetTopologyRunOKBodyRunStatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + GetTopologyRunOKBodyRunStatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // GetTopologyRunOKBodyRunStatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + GetTopologyRunOKBodyRunStatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // GetTopologyRunOKBodyRunStatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + GetTopologyRunOKBodyRunStatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // GetTopologyRunOKBodyRunStatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + GetTopologyRunOKBodyRunStatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *GetTopologyRunOKBodyRun) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyRunOkBodyRunTypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("getTopologyRunOk"+"."+"run"+"."+"status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("getTopologyRunOk"+"."+"run"+"."+"start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateEndTime(formats strfmt.Registry) error { + if swag.IsZero(o.EndTime) { // not required + return nil + } + + if err := validate.FormatOf("getTopologyRunOk"+"."+"run"+"."+"end_time", "body", "date-time", o.EndTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateErrors(formats strfmt.Registry) error { + if swag.IsZero(o.Errors) { // not required + return nil + } + + for i := 0; i < len(o.Errors); i++ { + if swag.IsZero(o.Errors[i]) { // not required + continue + } + + if o.Errors[i] != nil { + if err := o.Errors[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "errors" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "errors" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateSources(formats strfmt.Registry) error { + if swag.IsZero(o.Sources) { // not required + return nil + } + + for i := 0; i < len(o.Sources); i++ { + if swag.IsZero(o.Sources[i]) { // not required + continue + } + + if o.Sources[i] != nil { + if err := o.Sources[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) validateCounts(formats strfmt.Registry) error { + if swag.IsZero(o.Counts) { // not required + return nil + } + + if o.Counts != nil { + if err := o.Counts.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "counts") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get topology run OK body run based on the context it is used +func (o *GetTopologyRunOKBodyRun) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateErrors(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateSources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateCounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetTopologyRunOKBodyRun) contextValidateErrors(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Errors); i++ { + if o.Errors[i] != nil { + + if swag.IsZero(o.Errors[i]) { // not required + return nil + } + + if err := o.Errors[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "errors" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "errors" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) contextValidateSources(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Sources); i++ { + if o.Sources[i] != nil { + + if swag.IsZero(o.Sources[i]) { // not required + return nil + } + + if err := o.Sources[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *GetTopologyRunOKBodyRun) contextValidateCounts(ctx context.Context, formats strfmt.Registry) error { + if o.Counts != nil { + + if swag.IsZero(o.Counts) { // not required + return nil + } + + if err := o.Counts.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getTopologyRunOk" + "." + "run" + "." + "counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getTopologyRunOk" + "." + "run" + "." + "counts") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRun) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRun) UnmarshalBinary(b []byte) error { + var res GetTopologyRunOKBodyRun + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunOKBodyRunCounts TopologyRunCounts counts what one collection run saw. +swagger:model GetTopologyRunOKBodyRunCounts +*/ +type GetTopologyRunOKBodyRunCounts struct { + // MongoDB services inventory reported. + TotalServices int32 `json:"total_services,omitempty"` + + // ...of which carried a service ID to join metrics on. + ResolvedServices int32 `json:"resolved_services,omitempty"` + + // ...of which did not. Not an error. + OrphanedServices int32 `json:"orphaned_services,omitempty"` + + // Services metrics actually observed as reachable. + SuccessfulProbes int32 `json:"successful_probes,omitempty"` + + // Services carrying at least one volatile fact too old to read as current. + StaleServices int32 `json:"stale_services,omitempty"` +} + +// Validate validates this get topology run OK body run counts +func (o *GetTopologyRunOKBodyRunCounts) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get topology run OK body run counts based on context it is used +func (o *GetTopologyRunOKBodyRunCounts) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunCounts) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunCounts) UnmarshalBinary(b []byte) error { + var res GetTopologyRunOKBodyRunCounts + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunOKBodyRunErrorsItems0 TopologyRunError describes one thing that went wrong during a collection run. +swagger:model GetTopologyRunOKBodyRunErrorsItems0 +*/ +type GetTopologyRunOKBodyRunErrorsItems0 struct { + // What the error is about, e.g. "run" or "query". + Scope string `json:"scope,omitempty"` + + // The service it concerns, when scoped to one. + ServiceName *string `json:"service_name,omitempty"` + + // A machine-readable cause. + Code string `json:"code,omitempty"` + + // The human-readable detail. + Message string `json:"message,omitempty"` +} + +// Validate validates this get topology run OK body run errors items0 +func (o *GetTopologyRunOKBodyRunErrorsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get topology run OK body run errors items0 based on context it is used +func (o *GetTopologyRunOKBodyRunErrorsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunErrorsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunErrorsItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyRunOKBodyRunErrorsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetTopologyRunOKBodyRunSourcesItems0 SourceReport says how completely one collection source answered, and what it saw. +// +// Recorded per source so a thin document is legible rather than merely thin: a snapshot +// assembled with metrics=ok and probe=failed is still correct about every version and +// honest about reachability. +swagger:model GetTopologyRunOKBodyRunSourcesItems0 +*/ +type GetTopologyRunOKBodyRunSourcesItems0 struct { + // The source key, e.g. "inventory", "metrics" or "probe". An open set on purpose: a + // source is named by whatever produced it, so this stays a string where the statuses + // beside it are enums. + Source string `json:"source,omitempty"` + + // SourceStatus is how completely one collection source answered. + // + // Separate from RunStatus because it carries DISABLED, which a run cannot be: a source + // switched off in configuration is a deliberate state, not a degraded one. + // + // - SOURCE_STATUS_OK: Answered everything asked of it. + // - SOURCE_STATUS_PARTIAL: Answered some of it. + // - SOURCE_STATUS_FAILED: Did not answer. + // - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked. + // Enum: ["SOURCE_STATUS_UNSPECIFIED","SOURCE_STATUS_OK","SOURCE_STATUS_PARTIAL","SOURCE_STATUS_FAILED","SOURCE_STATUS_DISABLED"] + Status *string `json:"status,omitempty"` + + // How many facts it produced. + Facts int32 `json:"facts,omitempty"` + + // Source-specific counters, rendered as strings so a source can report whatever it has + // without this contract naming every counter. + Detail map[string]string `json:"detail,omitempty"` +} + +// Validate validates this get topology run OK body run sources items0 +func (o *GetTopologyRunOKBodyRunSourcesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getTopologyRunOkBodyRunSourcesItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SOURCE_STATUS_UNSPECIFIED","SOURCE_STATUS_OK","SOURCE_STATUS_PARTIAL","SOURCE_STATUS_FAILED","SOURCE_STATUS_DISABLED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getTopologyRunOkBodyRunSourcesItems0TypeStatusPropEnum = append(getTopologyRunOkBodyRunSourcesItems0TypeStatusPropEnum, v) + } +} + +const ( + + // GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSUNSPECIFIED captures enum value "SOURCE_STATUS_UNSPECIFIED" + GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSUNSPECIFIED string = "SOURCE_STATUS_UNSPECIFIED" + + // GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSOK captures enum value "SOURCE_STATUS_OK" + GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSOK string = "SOURCE_STATUS_OK" + + // GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSPARTIAL captures enum value "SOURCE_STATUS_PARTIAL" + GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSPARTIAL string = "SOURCE_STATUS_PARTIAL" + + // GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSFAILED captures enum value "SOURCE_STATUS_FAILED" + GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSFAILED string = "SOURCE_STATUS_FAILED" + + // GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSDISABLED captures enum value "SOURCE_STATUS_DISABLED" + GetTopologyRunOKBodyRunSourcesItems0StatusSOURCESTATUSDISABLED string = "SOURCE_STATUS_DISABLED" +) + +// prop value enum +func (o *GetTopologyRunOKBodyRunSourcesItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getTopologyRunOkBodyRunSourcesItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetTopologyRunOKBodyRunSourcesItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this get topology run OK body run sources items0 based on context it is used +func (o *GetTopologyRunOKBodyRunSourcesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunSourcesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetTopologyRunOKBodyRunSourcesItems0) UnmarshalBinary(b []byte) error { + var res GetTopologyRunOKBodyRunSourcesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_hosts_parameters.go b/api/om/v1/json/client/om_service/list_inventory_hosts_parameters.go new file mode 100644 index 00000000000..bc1222ea17b --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_hosts_parameters.go @@ -0,0 +1,227 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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/go-openapi/swag" +) + +// NewListInventoryHostsParams creates a new ListInventoryHostsParams 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 NewListInventoryHostsParams() *ListInventoryHostsParams { + return &ListInventoryHostsParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListInventoryHostsParamsWithTimeout creates a new ListInventoryHostsParams object +// with the ability to set a timeout on a request. +func NewListInventoryHostsParamsWithTimeout(timeout time.Duration) *ListInventoryHostsParams { + return &ListInventoryHostsParams{ + timeout: timeout, + } +} + +// NewListInventoryHostsParamsWithContext creates a new ListInventoryHostsParams object +// with the ability to set a context for a request. +func NewListInventoryHostsParamsWithContext(ctx context.Context) *ListInventoryHostsParams { + return &ListInventoryHostsParams{ + Context: ctx, + } +} + +// NewListInventoryHostsParamsWithHTTPClient creates a new ListInventoryHostsParams object +// with the ability to set a custom HTTPClient for a request. +func NewListInventoryHostsParamsWithHTTPClient(client *http.Client) *ListInventoryHostsParams { + return &ListInventoryHostsParams{ + HTTPClient: client, + } +} + +/* +ListInventoryHostsParams contains all the parameters to send to the API endpoint + + for the list inventory hosts operation. + + Typically these are written to a http.Request. +*/ +type ListInventoryHostsParams struct { + /* Executor. + + When set, return only hosts that do (or do not) have an executor to run a probe + on. Not a client name: the app filters on whether one is matched at all, and + "which machines can nothing be dispatched to" is the question worth asking. + */ + Executor *bool + + /* Failing. + + When true, return only hosts currently failing. + */ + Failing *bool + + /* HasService. + + When set, return only hosts that do (or do not) carry a registered service. + Unset returns both, which is the ordinary listing. + */ + HasService *bool + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list inventory hosts params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryHostsParams) WithDefaults() *ListInventoryHostsParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list inventory hosts params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryHostsParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list inventory hosts params +func (o *ListInventoryHostsParams) WithTimeout(timeout time.Duration) *ListInventoryHostsParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list inventory hosts params +func (o *ListInventoryHostsParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list inventory hosts params +func (o *ListInventoryHostsParams) WithContext(ctx context.Context) *ListInventoryHostsParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list inventory hosts params +func (o *ListInventoryHostsParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list inventory hosts params +func (o *ListInventoryHostsParams) WithHTTPClient(client *http.Client) *ListInventoryHostsParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list inventory hosts params +func (o *ListInventoryHostsParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithExecutor adds the executor to the list inventory hosts params +func (o *ListInventoryHostsParams) WithExecutor(executor *bool) *ListInventoryHostsParams { + o.SetExecutor(executor) + return o +} + +// SetExecutor adds the executor to the list inventory hosts params +func (o *ListInventoryHostsParams) SetExecutor(executor *bool) { + o.Executor = executor +} + +// WithFailing adds the failing to the list inventory hosts params +func (o *ListInventoryHostsParams) WithFailing(failing *bool) *ListInventoryHostsParams { + o.SetFailing(failing) + return o +} + +// SetFailing adds the failing to the list inventory hosts params +func (o *ListInventoryHostsParams) SetFailing(failing *bool) { + o.Failing = failing +} + +// WithHasService adds the hasService to the list inventory hosts params +func (o *ListInventoryHostsParams) WithHasService(hasService *bool) *ListInventoryHostsParams { + o.SetHasService(hasService) + return o +} + +// SetHasService adds the hasService to the list inventory hosts params +func (o *ListInventoryHostsParams) SetHasService(hasService *bool) { + o.HasService = hasService +} + +// WriteToRequest writes these params to a swagger request +func (o *ListInventoryHostsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Executor != nil { + + // query param executor + var qrExecutor bool + + if o.Executor != nil { + qrExecutor = *o.Executor + } + qExecutor := swag.FormatBool(qrExecutor) + if qExecutor != "" { + if err := r.SetQueryParam("executor", qExecutor); err != nil { + return err + } + } + } + + if o.Failing != nil { + + // query param failing + var qrFailing bool + + if o.Failing != nil { + qrFailing = *o.Failing + } + qFailing := swag.FormatBool(qrFailing) + if qFailing != "" { + if err := r.SetQueryParam("failing", qFailing); err != nil { + return err + } + } + } + + if o.HasService != nil { + + // query param has_service + var qrHasService bool + + if o.HasService != nil { + qrHasService = *o.HasService + } + qHasService := swag.FormatBool(qrHasService) + if qHasService != "" { + if err := r.SetQueryParam("has_service", qHasService); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_hosts_responses.go b/api/om/v1/json/client/om_service/list_inventory_hosts_responses.go new file mode 100644 index 00000000000..9dd32270a48 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_hosts_responses.go @@ -0,0 +1,1370 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListInventoryHostsReader is a Reader for the ListInventoryHosts structure. +type ListInventoryHostsReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListInventoryHostsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListInventoryHostsOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListInventoryHostsDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListInventoryHostsOK creates a ListInventoryHostsOK with default headers values +func NewListInventoryHostsOK() *ListInventoryHostsOK { + return &ListInventoryHostsOK{} +} + +/* +ListInventoryHostsOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListInventoryHostsOK struct { + Payload *ListInventoryHostsOKBody +} + +// IsSuccess returns true when this list inventory hosts Ok response has a 2xx status code +func (o *ListInventoryHostsOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list inventory hosts Ok response has a 3xx status code +func (o *ListInventoryHostsOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list inventory hosts Ok response has a 4xx status code +func (o *ListInventoryHostsOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list inventory hosts Ok response has a 5xx status code +func (o *ListInventoryHostsOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list inventory hosts Ok response a status code equal to that given +func (o *ListInventoryHostsOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list inventory hosts Ok response +func (o *ListInventoryHostsOK) Code() int { + return 200 +} + +func (o *ListInventoryHostsOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts][%d] listInventoryHostsOk %s", 200, payload) +} + +func (o *ListInventoryHostsOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts][%d] listInventoryHostsOk %s", 200, payload) +} + +func (o *ListInventoryHostsOK) GetPayload() *ListInventoryHostsOKBody { + return o.Payload +} + +func (o *ListInventoryHostsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryHostsOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListInventoryHostsDefault creates a ListInventoryHostsDefault with default headers values +func NewListInventoryHostsDefault(code int) *ListInventoryHostsDefault { + return &ListInventoryHostsDefault{ + _statusCode: code, + } +} + +/* +ListInventoryHostsDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListInventoryHostsDefault struct { + _statusCode int + + Payload *ListInventoryHostsDefaultBody +} + +// IsSuccess returns true when this list inventory hosts default response has a 2xx status code +func (o *ListInventoryHostsDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list inventory hosts default response has a 3xx status code +func (o *ListInventoryHostsDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list inventory hosts default response has a 4xx status code +func (o *ListInventoryHostsDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list inventory hosts default response has a 5xx status code +func (o *ListInventoryHostsDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list inventory hosts default response a status code equal to that given +func (o *ListInventoryHostsDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list inventory hosts default response +func (o *ListInventoryHostsDefault) Code() int { + return o._statusCode +} + +func (o *ListInventoryHostsDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts][%d] ListInventoryHosts default %s", o._statusCode, payload) +} + +func (o *ListInventoryHostsDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/hosts][%d] ListInventoryHosts default %s", o._statusCode, payload) +} + +func (o *ListInventoryHostsDefault) GetPayload() *ListInventoryHostsDefaultBody { + return o.Payload +} + +func (o *ListInventoryHostsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryHostsDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListInventoryHostsDefaultBody list inventory hosts default body +swagger:model ListInventoryHostsDefaultBody +*/ +type ListInventoryHostsDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListInventoryHostsDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list inventory hosts default body +func (o *ListInventoryHostsDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryHosts default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryHosts default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory hosts default body based on the context it is used +func (o *ListInventoryHostsDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryHosts default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryHosts default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsDefaultBody) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsDefaultBodyDetailsItems0 list inventory hosts default body details items0 +swagger:model ListInventoryHostsDefaultBodyDetailsItems0 +*/ +type ListInventoryHostsDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list inventory hosts default body details items0 + ListInventoryHostsDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListInventoryHostsDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListInventoryHostsDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListInventoryHostsDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListInventoryHostsDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListInventoryHostsDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListInventoryHostsDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list inventory hosts default body details items0 +func (o *ListInventoryHostsDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory hosts default body details items0 based on context it is used +func (o *ListInventoryHostsDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBody ListInventoryHostsResponse returns the hosts OM knows about. +swagger:model ListInventoryHostsOKBody +*/ +type ListInventoryHostsOKBody struct { + // The hosts. + Hosts []*ListInventoryHostsOKBodyHostsItems0 `json:"hosts"` +} + +// Validate validates this list inventory hosts OK body +func (o *ListInventoryHostsOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateHosts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBody) validateHosts(formats strfmt.Registry) error { + if swag.IsZero(o.Hosts) { // not required + return nil + } + + for i := 0; i < len(o.Hosts); i++ { + if swag.IsZero(o.Hosts[i]) { // not required + continue + } + + if o.Hosts[i] != nil { + if err := o.Hosts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryHostsOk" + "." + "hosts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryHostsOk" + "." + "hosts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory hosts OK body based on the context it is used +func (o *ListInventoryHostsOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateHosts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBody) contextValidateHosts(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Hosts); i++ { + if o.Hosts[i] != nil { + + if swag.IsZero(o.Hosts[i]) { // not required + return nil + } + + if err := o.Hosts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryHostsOk" + "." + "hosts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryHostsOk" + "." + "hosts" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBody) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0 InventoryHost is one machine OM knows about, with the services on it. +// +// A host is a row whether or not any MongoDB was found on it. That is what makes +// "which machines have no database" a query rather than an absence, and it is the only +// way a machine that has never run one appears at all - which is the case installing a +// database somewhere later depends on. +swagger:model ListInventoryHostsOKBodyHostsItems0 +*/ +type ListInventoryHostsOKBodyHostsItems0 struct { + // PMM's node ID. Also what a scoped refresh is addressed by. + NodeID string `json:"node_id,omitempty"` + + // The node name PMM registered. + Name string `json:"name,omitempty"` + + // The node address PMM registered. + Address *string `json:"address,omitempty"` + + // The Nomad client that serves it. Unset means nothing can be run there, which is a + // fact about the estate rather than a probe failure. + ExecutorHost *string `json:"executor_host,omitempty"` + + // The operating system, as the host reports it. Worth having from a probe because + // PMM does not know it for some nodes. + Os *string `json:"os,omitempty"` + + // The kernel release. + Kernel *string `json:"kernel,omitempty"` + + // Mongods running that PMM has no service for. + UnregisteredMongods []*ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0 `json:"unregistered_mongods"` + + // Everything the probe recorded about the host, including attributes with no field + // above. + Observed any `json:"observed,omitempty"` + + // The services on it. Empty is a meaningful answer, not a gap. + Services []*ListInventoryHostsOKBodyHostsItems0ServicesItems0 `json:"services"` + + // executor + Executor *ListInventoryHostsOKBodyHostsItems0Executor `json:"executor,omitempty"` + + // freshness + Freshness *ListInventoryHostsOKBodyHostsItems0Freshness `json:"freshness,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 +func (o *ListInventoryHostsOKBodyHostsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateUnregisteredMongods(formats); err != nil { + res = append(res, err) + } + + if err := o.validateServices(formats); err != nil { + res = append(res, err) + } + + if err := o.validateExecutor(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) validateUnregisteredMongods(formats strfmt.Registry) error { + if swag.IsZero(o.UnregisteredMongods) { // not required + return nil + } + + for i := 0; i < len(o.UnregisteredMongods); i++ { + if swag.IsZero(o.UnregisteredMongods[i]) { // not required + continue + } + + if o.UnregisteredMongods[i] != nil { + if err := o.UnregisteredMongods[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("unregistered_mongods" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("unregistered_mongods" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) validateServices(formats strfmt.Registry) error { + if swag.IsZero(o.Services) { // not required + return nil + } + + for i := 0; i < len(o.Services); i++ { + if swag.IsZero(o.Services[i]) { // not required + continue + } + + if o.Services[i] != nil { + if err := o.Services[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) validateExecutor(formats strfmt.Registry) error { + if swag.IsZero(o.Executor) { // not required + return nil + } + + if o.Executor != nil { + if err := o.Executor.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("executor") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("executor") + } + + return err + } + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this list inventory hosts OK body hosts items0 based on the context it is used +func (o *ListInventoryHostsOKBodyHostsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateUnregisteredMongods(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateServices(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateExecutor(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) contextValidateUnregisteredMongods(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.UnregisteredMongods); i++ { + if o.UnregisteredMongods[i] != nil { + + if swag.IsZero(o.UnregisteredMongods[i]) { // not required + return nil + } + + if err := o.UnregisteredMongods[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("unregistered_mongods" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("unregistered_mongods" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) contextValidateServices(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Services); i++ { + if o.Services[i] != nil { + + if swag.IsZero(o.Services[i]) { // not required + return nil + } + + if err := o.Services[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("services" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) contextValidateExecutor(ctx context.Context, formats strfmt.Registry) error { + if o.Executor != nil { + + if swag.IsZero(o.Executor) { // not required + return nil + } + + if err := o.Executor.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("executor") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("executor") + } + + return err + } + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0Executor InventoryExecutor reports whether SEP can run anything on a host. +// +// Three flags rather than one, because "orphaned" hid three different problems with +// three different fixes: never onboarded (registered false), onboarded and down +// (reachable false), and up with a broken raw_exec driver (driver_healthy false). This +// is SEP's own knowledge rather than probe output, so it is filled in for every host +// on every sweep, including hosts no probe reached. +swagger:model ListInventoryHostsOKBodyHostsItems0Executor +*/ +type ListInventoryHostsOKBodyHostsItems0Executor struct { + // Whether the Tasks backend knows this node at all. + Registered bool `json:"registered,omitempty"` + + // Whether it is currently up. + Reachable bool `json:"reachable,omitempty"` + + // Whether its raw_exec driver is healthy, which is what a probe actually needs. + DriverHealthy bool `json:"driver_healthy,omitempty"` + + // Whatever detail the backend gave, when it gave any. + Detail *string `json:"detail,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 executor +func (o *ListInventoryHostsOKBodyHostsItems0Executor) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory hosts OK body hosts items0 executor based on context it is used +func (o *ListInventoryHostsOKBodyHostsItems0Executor) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0Executor) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0Executor) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0Executor + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0Freshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model ListInventoryHostsOKBodyHostsItems0Freshness +*/ +type ListInventoryHostsOKBodyHostsItems0Freshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 freshness +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list inventory hosts OK body hosts items0 freshness based on context it is used +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0Freshness) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0Freshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0ServicesItems0 InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +swagger:model ListInventoryHostsOKBodyHostsItems0ServicesItems0 +*/ +type ListInventoryHostsOKBodyHostsItems0ServicesItems0 struct { + // PMM's service ID. The join key against the topology document. + ServiceID string `json:"service_id,omitempty"` + + // The node it runs on, as PMM's node ID. + NodeID string `json:"node_id,omitempty"` + + // The service name PMM registered. + Name string `json:"name,omitempty"` + + // The port it listens on, where OM knows it. + Port *int32 `json:"port,omitempty"` + + // PRIMARY, SECONDARY, ARBITER, or unset. + Role *string `json:"role,omitempty"` + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + InstalledVersion *string `json:"installed_version,omitempty"` + + // The version the running server reports. + RunningVersion *string `json:"running_version,omitempty"` + + // The configuration file the running server read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // What the last probe of this service concluded, in the payload's own words. + ProbeStatus *string `json:"probe_status,omitempty"` + + // Whether a server was found running. Unset where no probe has looked. + ServerRunning *bool `json:"server_running,omitempty"` + + // How long it has been up, seconds. + UptimeSeconds *float64 `json:"uptime_seconds,omitempty"` + + // The replica set it belongs to, or unset for a standalone or a router. + ReplicationSet *string `json:"replication_set,omitempty"` + + // Everything the probe recorded, including attributes with no field above. + Observed any `json:"observed,omitempty"` + + // freshness + Freshness *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness `json:"freshness,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 services items0 +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this list inventory hosts OK body hosts items0 services items0 based on the context it is used +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0ServicesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness +*/ +type ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 services items0 freshness +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list inventory hosts OK body hosts items0 services items0 freshness based on context it is used +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0ServicesItems0Freshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0 UnregisteredMongod is a mongod found running that PMM has no service for. +// +// The arbiter case, mostly: PMM registers no service for an arbiter, so nothing else +// in OM would report the process at all. Also what stands in the way of installing +// anything over a port that is already taken. +swagger:model ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0 +*/ +type ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0 struct { + // The port it is listening on. + Port *int32 `json:"port,omitempty"` + + // The configuration file it read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // The process name, e.g. "mongod". + Program *string `json:"program,omitempty"` + + // Its process ID at the time of the probe. + Pid *int32 `json:"pid,omitempty"` +} + +// Validate validates this list inventory hosts OK body hosts items0 unregistered mongods items0 +func (o *ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory hosts OK body hosts items0 unregistered mongods items0 based on context it is used +func (o *ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryHostsOKBodyHostsItems0UnregisteredMongodsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_runs_parameters.go b/api/om/v1/json/client/om_service/list_inventory_runs_parameters.go new file mode 100644 index 00000000000..418c89ab626 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_runs_parameters.go @@ -0,0 +1,233 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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/go-openapi/swag" +) + +// NewListInventoryRunsParams creates a new ListInventoryRunsParams 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 NewListInventoryRunsParams() *ListInventoryRunsParams { + return &ListInventoryRunsParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListInventoryRunsParamsWithTimeout creates a new ListInventoryRunsParams object +// with the ability to set a timeout on a request. +func NewListInventoryRunsParamsWithTimeout(timeout time.Duration) *ListInventoryRunsParams { + return &ListInventoryRunsParams{ + timeout: timeout, + } +} + +// NewListInventoryRunsParamsWithContext creates a new ListInventoryRunsParams object +// with the ability to set a context for a request. +func NewListInventoryRunsParamsWithContext(ctx context.Context) *ListInventoryRunsParams { + return &ListInventoryRunsParams{ + Context: ctx, + } +} + +// NewListInventoryRunsParamsWithHTTPClient creates a new ListInventoryRunsParams object +// with the ability to set a custom HTTPClient for a request. +func NewListInventoryRunsParamsWithHTTPClient(client *http.Client) *ListInventoryRunsParams { + return &ListInventoryRunsParams{ + HTTPClient: client, + } +} + +/* +ListInventoryRunsParams contains all the parameters to send to the API endpoint + + for the list inventory runs operation. + + Typically these are written to a http.Request. +*/ +type ListInventoryRunsParams struct { + /* Limit. + + How many to return, newest first. Defaults to 20, capped at 100. + + Format: int32 + */ + Limit *int32 + + /* Since. + + Inclusive lower bound on start_time. Unset means no lower bound. + + Applied before limit, so a week window is the newest runs *in that week*, + not the newest overall then those that happen to fall in it. + + Format: date-time + */ + Since *strfmt.DateTime + + /* Until. + + Inclusive upper bound on start_time. Unset means no upper bound. + + Format: date-time + */ + Until *strfmt.DateTime + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list inventory runs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryRunsParams) WithDefaults() *ListInventoryRunsParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list inventory runs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryRunsParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list inventory runs params +func (o *ListInventoryRunsParams) WithTimeout(timeout time.Duration) *ListInventoryRunsParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list inventory runs params +func (o *ListInventoryRunsParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list inventory runs params +func (o *ListInventoryRunsParams) WithContext(ctx context.Context) *ListInventoryRunsParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list inventory runs params +func (o *ListInventoryRunsParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list inventory runs params +func (o *ListInventoryRunsParams) WithHTTPClient(client *http.Client) *ListInventoryRunsParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list inventory runs params +func (o *ListInventoryRunsParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithLimit adds the limit to the list inventory runs params +func (o *ListInventoryRunsParams) WithLimit(limit *int32) *ListInventoryRunsParams { + o.SetLimit(limit) + return o +} + +// SetLimit adds the limit to the list inventory runs params +func (o *ListInventoryRunsParams) SetLimit(limit *int32) { + o.Limit = limit +} + +// WithSince adds the since to the list inventory runs params +func (o *ListInventoryRunsParams) WithSince(since *strfmt.DateTime) *ListInventoryRunsParams { + o.SetSince(since) + return o +} + +// SetSince adds the since to the list inventory runs params +func (o *ListInventoryRunsParams) SetSince(since *strfmt.DateTime) { + o.Since = since +} + +// WithUntil adds the until to the list inventory runs params +func (o *ListInventoryRunsParams) WithUntil(until *strfmt.DateTime) *ListInventoryRunsParams { + o.SetUntil(until) + return o +} + +// SetUntil adds the until to the list inventory runs params +func (o *ListInventoryRunsParams) SetUntil(until *strfmt.DateTime) { + o.Until = until +} + +// WriteToRequest writes these params to a swagger request +func (o *ListInventoryRunsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Limit != nil { + + // query param limit + var qrLimit int32 + + if o.Limit != nil { + qrLimit = *o.Limit + } + qLimit := swag.FormatInt32(qrLimit) + if qLimit != "" { + if err := r.SetQueryParam("limit", qLimit); err != nil { + return err + } + } + } + + if o.Since != nil { + + // query param since + var qrSince strfmt.DateTime + + if o.Since != nil { + qrSince = *o.Since + } + qSince := qrSince.String() + if qSince != "" { + if err := r.SetQueryParam("since", qSince); err != nil { + return err + } + } + } + + if o.Until != nil { + + // query param until + var qrUntil strfmt.DateTime + + if o.Until != nil { + qrUntil = *o.Until + } + qUntil := qrUntil.String() + if qUntil != "" { + if err := r.SetQueryParam("until", qUntil); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_runs_responses.go b/api/om/v1/json/client/om_service/list_inventory_runs_responses.go new file mode 100644 index 00000000000..66aa9560c6f --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_runs_responses.go @@ -0,0 +1,819 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListInventoryRunsReader is a Reader for the ListInventoryRuns structure. +type ListInventoryRunsReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListInventoryRunsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListInventoryRunsOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListInventoryRunsDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListInventoryRunsOK creates a ListInventoryRunsOK with default headers values +func NewListInventoryRunsOK() *ListInventoryRunsOK { + return &ListInventoryRunsOK{} +} + +/* +ListInventoryRunsOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListInventoryRunsOK struct { + Payload *ListInventoryRunsOKBody +} + +// IsSuccess returns true when this list inventory runs Ok response has a 2xx status code +func (o *ListInventoryRunsOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list inventory runs Ok response has a 3xx status code +func (o *ListInventoryRunsOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list inventory runs Ok response has a 4xx status code +func (o *ListInventoryRunsOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list inventory runs Ok response has a 5xx status code +func (o *ListInventoryRunsOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list inventory runs Ok response a status code equal to that given +func (o *ListInventoryRunsOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list inventory runs Ok response +func (o *ListInventoryRunsOK) Code() int { + return 200 +} + +func (o *ListInventoryRunsOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs][%d] listInventoryRunsOk %s", 200, payload) +} + +func (o *ListInventoryRunsOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs][%d] listInventoryRunsOk %s", 200, payload) +} + +func (o *ListInventoryRunsOK) GetPayload() *ListInventoryRunsOKBody { + return o.Payload +} + +func (o *ListInventoryRunsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryRunsOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListInventoryRunsDefault creates a ListInventoryRunsDefault with default headers values +func NewListInventoryRunsDefault(code int) *ListInventoryRunsDefault { + return &ListInventoryRunsDefault{ + _statusCode: code, + } +} + +/* +ListInventoryRunsDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListInventoryRunsDefault struct { + _statusCode int + + Payload *ListInventoryRunsDefaultBody +} + +// IsSuccess returns true when this list inventory runs default response has a 2xx status code +func (o *ListInventoryRunsDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list inventory runs default response has a 3xx status code +func (o *ListInventoryRunsDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list inventory runs default response has a 4xx status code +func (o *ListInventoryRunsDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list inventory runs default response has a 5xx status code +func (o *ListInventoryRunsDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list inventory runs default response a status code equal to that given +func (o *ListInventoryRunsDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list inventory runs default response +func (o *ListInventoryRunsDefault) Code() int { + return o._statusCode +} + +func (o *ListInventoryRunsDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs][%d] ListInventoryRuns default %s", o._statusCode, payload) +} + +func (o *ListInventoryRunsDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/runs][%d] ListInventoryRuns default %s", o._statusCode, payload) +} + +func (o *ListInventoryRunsDefault) GetPayload() *ListInventoryRunsDefaultBody { + return o.Payload +} + +func (o *ListInventoryRunsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryRunsDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListInventoryRunsDefaultBody list inventory runs default body +swagger:model ListInventoryRunsDefaultBody +*/ +type ListInventoryRunsDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListInventoryRunsDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list inventory runs default body +func (o *ListInventoryRunsDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryRunsDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory runs default body based on the context it is used +func (o *ListInventoryRunsDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryRunsDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryRunsDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryRunsDefaultBody) UnmarshalBinary(b []byte) error { + var res ListInventoryRunsDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryRunsDefaultBodyDetailsItems0 list inventory runs default body details items0 +swagger:model ListInventoryRunsDefaultBodyDetailsItems0 +*/ +type ListInventoryRunsDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list inventory runs default body details items0 + ListInventoryRunsDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListInventoryRunsDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListInventoryRunsDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListInventoryRunsDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListInventoryRunsDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListInventoryRunsDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListInventoryRunsDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list inventory runs default body details items0 +func (o *ListInventoryRunsDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory runs default body details items0 based on context it is used +func (o *ListInventoryRunsDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryRunsDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryRunsDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryRunsDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryRunsOKBody ListInventoryRunsResponse returns the refresh history, newest first. +swagger:model ListInventoryRunsOKBody +*/ +type ListInventoryRunsOKBody struct { + // The runs. + Runs []*ListInventoryRunsOKBodyRunsItems0 `json:"runs"` +} + +// Validate validates this list inventory runs OK body +func (o *ListInventoryRunsOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateRuns(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryRunsOKBody) validateRuns(formats strfmt.Registry) error { + if swag.IsZero(o.Runs) { // not required + return nil + } + + for i := 0; i < len(o.Runs); i++ { + if swag.IsZero(o.Runs[i]) { // not required + continue + } + + if o.Runs[i] != nil { + if err := o.Runs[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory runs OK body based on the context it is used +func (o *ListInventoryRunsOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateRuns(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryRunsOKBody) contextValidateRuns(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Runs); i++ { + if o.Runs[i] != nil { + + if swag.IsZero(o.Runs[i]) { // not required + return nil + } + + if err := o.Runs[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryRunsOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryRunsOKBody) UnmarshalBinary(b []byte) error { + var res ListInventoryRunsOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryRunsOKBodyRunsItems0 InventoryRun is one refresh of the estate. +swagger:model ListInventoryRunsOKBodyRunsItems0 +*/ +type ListInventoryRunsOKBodyRunsItems0 struct { + // The run's ID. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When it began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` + + // When it stopped. Unset while it is still going. + // Format: date-time + EndTime strfmt.DateTime `json:"end_time,omitempty"` + + // The hosts it was limited to. Empty means it refreshed the whole estate, which is + // what the scheduled sweep does. + Scope []string `json:"scope"` + + // What went wrong, when something did. + Error *string `json:"error,omitempty"` + + // counts + Counts *ListInventoryRunsOKBodyRunsItems0Counts `json:"counts,omitempty"` +} + +// Validate validates this list inventory runs OK body runs items0 +func (o *ListInventoryRunsOKBodyRunsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateEndTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateCounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var listInventoryRunsOkBodyRunsItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listInventoryRunsOkBodyRunsItems0TypeStatusPropEnum = append(listInventoryRunsOkBodyRunsItems0TypeStatusPropEnum, v) + } +} + +const ( + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + ListInventoryRunsOKBodyRunsItems0StatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *ListInventoryRunsOKBodyRunsItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listInventoryRunsOkBodyRunsItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListInventoryRunsOKBodyRunsItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryRunsOKBodyRunsItems0) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryRunsOKBodyRunsItems0) validateEndTime(formats strfmt.Registry) error { + if swag.IsZero(o.EndTime) { // not required + return nil + } + + if err := validate.FormatOf("end_time", "body", "date-time", o.EndTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryRunsOKBodyRunsItems0) validateCounts(formats strfmt.Registry) error { + if swag.IsZero(o.Counts) { // not required + return nil + } + + if o.Counts != nil { + if err := o.Counts.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("counts") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this list inventory runs OK body runs items0 based on the context it is used +func (o *ListInventoryRunsOKBodyRunsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryRunsOKBodyRunsItems0) contextValidateCounts(ctx context.Context, formats strfmt.Registry) error { + if o.Counts != nil { + + if swag.IsZero(o.Counts) { // not required + return nil + } + + if err := o.Counts.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("counts") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryRunsOKBodyRunsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryRunsOKBodyRunsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryRunsOKBodyRunsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryRunsOKBodyRunsItems0Counts InventoryRunCounts is what one refresh saw. +swagger:model ListInventoryRunsOKBodyRunsItems0Counts +*/ +type ListInventoryRunsOKBodyRunsItems0Counts struct { + // Services enumeration found. + TotalServices int32 `json:"total_services,omitempty"` + + // ...of which matched a host something could be run on. + ResolvedServices int32 `json:"resolved_services,omitempty"` + + // ...of which did not. Not an error. + OrphanedServices int32 `json:"orphaned_services,omitempty"` + + // Services that answered a probe. + AnsweredServices int32 `json:"answered_services,omitempty"` + + // Hosts in scope this run, service or no service. + // + // A refresh attempts hosts as well as the services on them, so counting only + // services makes a refresh of a host with no database read as "0 of 0" - which is + // exactly what a run that did nothing looks like, on the one kind of host OM most + // exists to describe. + TotalHosts int32 `json:"total_hosts,omitempty"` + + // ...of which had somewhere to run a probe. The gap is the estate nothing can be + // dispatched to, which is a fact about onboarding rather than a failed run. + ProbeableHosts int32 `json:"probeable_hosts,omitempty"` + + // Hosts that answered. + AnsweredHosts int32 `json:"answered_hosts,omitempty"` +} + +// Validate validates this list inventory runs OK body runs items0 counts +func (o *ListInventoryRunsOKBodyRunsItems0Counts) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory runs OK body runs items0 counts based on context it is used +func (o *ListInventoryRunsOKBodyRunsItems0Counts) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryRunsOKBodyRunsItems0Counts) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryRunsOKBodyRunsItems0Counts) UnmarshalBinary(b []byte) error { + var res ListInventoryRunsOKBodyRunsItems0Counts + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_services_parameters.go b/api/om/v1/json/client/om_service/list_inventory_services_parameters.go new file mode 100644 index 00000000000..c67bae946f9 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_services_parameters.go @@ -0,0 +1,191 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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/go-openapi/swag" +) + +// NewListInventoryServicesParams creates a new ListInventoryServicesParams 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 NewListInventoryServicesParams() *ListInventoryServicesParams { + return &ListInventoryServicesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListInventoryServicesParamsWithTimeout creates a new ListInventoryServicesParams object +// with the ability to set a timeout on a request. +func NewListInventoryServicesParamsWithTimeout(timeout time.Duration) *ListInventoryServicesParams { + return &ListInventoryServicesParams{ + timeout: timeout, + } +} + +// NewListInventoryServicesParamsWithContext creates a new ListInventoryServicesParams object +// with the ability to set a context for a request. +func NewListInventoryServicesParamsWithContext(ctx context.Context) *ListInventoryServicesParams { + return &ListInventoryServicesParams{ + Context: ctx, + } +} + +// NewListInventoryServicesParamsWithHTTPClient creates a new ListInventoryServicesParams object +// with the ability to set a custom HTTPClient for a request. +func NewListInventoryServicesParamsWithHTTPClient(client *http.Client) *ListInventoryServicesParams { + return &ListInventoryServicesParams{ + HTTPClient: client, + } +} + +/* +ListInventoryServicesParams contains all the parameters to send to the API endpoint + + for the list inventory services operation. + + Typically these are written to a http.Request. +*/ +type ListInventoryServicesParams struct { + /* Failing. + + When true, return only services currently failing. + */ + Failing *bool + + /* NodeID. + + When set, return only the services on this host. + */ + NodeID *string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list inventory services params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryServicesParams) WithDefaults() *ListInventoryServicesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list inventory services params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListInventoryServicesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list inventory services params +func (o *ListInventoryServicesParams) WithTimeout(timeout time.Duration) *ListInventoryServicesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list inventory services params +func (o *ListInventoryServicesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list inventory services params +func (o *ListInventoryServicesParams) WithContext(ctx context.Context) *ListInventoryServicesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list inventory services params +func (o *ListInventoryServicesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list inventory services params +func (o *ListInventoryServicesParams) WithHTTPClient(client *http.Client) *ListInventoryServicesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list inventory services params +func (o *ListInventoryServicesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithFailing adds the failing to the list inventory services params +func (o *ListInventoryServicesParams) WithFailing(failing *bool) *ListInventoryServicesParams { + o.SetFailing(failing) + return o +} + +// SetFailing adds the failing to the list inventory services params +func (o *ListInventoryServicesParams) SetFailing(failing *bool) { + o.Failing = failing +} + +// WithNodeID adds the nodeID to the list inventory services params +func (o *ListInventoryServicesParams) WithNodeID(nodeID *string) *ListInventoryServicesParams { + o.SetNodeID(nodeID) + return o +} + +// SetNodeID adds the nodeId to the list inventory services params +func (o *ListInventoryServicesParams) SetNodeID(nodeID *string) { + o.NodeID = nodeID +} + +// WriteToRequest writes these params to a swagger request +func (o *ListInventoryServicesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Failing != nil { + + // query param failing + var qrFailing bool + + if o.Failing != nil { + qrFailing = *o.Failing + } + qFailing := swag.FormatBool(qrFailing) + if qFailing != "" { + if err := r.SetQueryParam("failing", qFailing); err != nil { + return err + } + } + } + + if o.NodeID != nil { + + // query param node_id + var qrNodeID string + + if o.NodeID != nil { + qrNodeID = *o.NodeID + } + qNodeID := qrNodeID + if qNodeID != "" { + if err := r.SetQueryParam("node_id", qNodeID); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/list_inventory_services_responses.go b/api/om/v1/json/client/om_service/list_inventory_services_responses.go new file mode 100644 index 00000000000..cfc625eca04 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_inventory_services_responses.go @@ -0,0 +1,810 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListInventoryServicesReader is a Reader for the ListInventoryServices structure. +type ListInventoryServicesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListInventoryServicesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListInventoryServicesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListInventoryServicesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListInventoryServicesOK creates a ListInventoryServicesOK with default headers values +func NewListInventoryServicesOK() *ListInventoryServicesOK { + return &ListInventoryServicesOK{} +} + +/* +ListInventoryServicesOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListInventoryServicesOK struct { + Payload *ListInventoryServicesOKBody +} + +// IsSuccess returns true when this list inventory services Ok response has a 2xx status code +func (o *ListInventoryServicesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list inventory services Ok response has a 3xx status code +func (o *ListInventoryServicesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list inventory services Ok response has a 4xx status code +func (o *ListInventoryServicesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list inventory services Ok response has a 5xx status code +func (o *ListInventoryServicesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list inventory services Ok response a status code equal to that given +func (o *ListInventoryServicesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list inventory services Ok response +func (o *ListInventoryServicesOK) Code() int { + return 200 +} + +func (o *ListInventoryServicesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services][%d] listInventoryServicesOk %s", 200, payload) +} + +func (o *ListInventoryServicesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services][%d] listInventoryServicesOk %s", 200, payload) +} + +func (o *ListInventoryServicesOK) GetPayload() *ListInventoryServicesOKBody { + return o.Payload +} + +func (o *ListInventoryServicesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryServicesOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListInventoryServicesDefault creates a ListInventoryServicesDefault with default headers values +func NewListInventoryServicesDefault(code int) *ListInventoryServicesDefault { + return &ListInventoryServicesDefault{ + _statusCode: code, + } +} + +/* +ListInventoryServicesDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListInventoryServicesDefault struct { + _statusCode int + + Payload *ListInventoryServicesDefaultBody +} + +// IsSuccess returns true when this list inventory services default response has a 2xx status code +func (o *ListInventoryServicesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list inventory services default response has a 3xx status code +func (o *ListInventoryServicesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list inventory services default response has a 4xx status code +func (o *ListInventoryServicesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list inventory services default response has a 5xx status code +func (o *ListInventoryServicesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list inventory services default response a status code equal to that given +func (o *ListInventoryServicesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list inventory services default response +func (o *ListInventoryServicesDefault) Code() int { + return o._statusCode +} + +func (o *ListInventoryServicesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services][%d] ListInventoryServices default %s", o._statusCode, payload) +} + +func (o *ListInventoryServicesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/inventory/services][%d] ListInventoryServices default %s", o._statusCode, payload) +} + +func (o *ListInventoryServicesDefault) GetPayload() *ListInventoryServicesDefaultBody { + return o.Payload +} + +func (o *ListInventoryServicesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListInventoryServicesDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListInventoryServicesDefaultBody list inventory services default body +swagger:model ListInventoryServicesDefaultBody +*/ +type ListInventoryServicesDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListInventoryServicesDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list inventory services default body +func (o *ListInventoryServicesDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryServices default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryServices default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory services default body based on the context it is used +func (o *ListInventoryServicesDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListInventoryServices default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListInventoryServices default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryServicesDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryServicesDefaultBody) UnmarshalBinary(b []byte) error { + var res ListInventoryServicesDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryServicesDefaultBodyDetailsItems0 list inventory services default body details items0 +swagger:model ListInventoryServicesDefaultBodyDetailsItems0 +*/ +type ListInventoryServicesDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list inventory services default body details items0 + ListInventoryServicesDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListInventoryServicesDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListInventoryServicesDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListInventoryServicesDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListInventoryServicesDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListInventoryServicesDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListInventoryServicesDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list inventory services default body details items0 +func (o *ListInventoryServicesDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list inventory services default body details items0 based on context it is used +func (o *ListInventoryServicesDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryServicesDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryServicesDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryServicesDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryServicesOKBody ListInventoryServicesResponse returns the services OM knows about, flat. +swagger:model ListInventoryServicesOKBody +*/ +type ListInventoryServicesOKBody struct { + // The services. + Services []*ListInventoryServicesOKBodyServicesItems0 `json:"services"` +} + +// Validate validates this list inventory services OK body +func (o *ListInventoryServicesOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateServices(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesOKBody) validateServices(formats strfmt.Registry) error { + if swag.IsZero(o.Services) { // not required + return nil + } + + for i := 0; i < len(o.Services); i++ { + if swag.IsZero(o.Services[i]) { // not required + continue + } + + if o.Services[i] != nil { + if err := o.Services[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryServicesOk" + "." + "services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryServicesOk" + "." + "services" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list inventory services OK body based on the context it is used +func (o *ListInventoryServicesOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateServices(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesOKBody) contextValidateServices(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Services); i++ { + if o.Services[i] != nil { + + if swag.IsZero(o.Services[i]) { // not required + return nil + } + + if err := o.Services[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listInventoryServicesOk" + "." + "services" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listInventoryServicesOk" + "." + "services" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryServicesOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryServicesOKBody) UnmarshalBinary(b []byte) error { + var res ListInventoryServicesOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryServicesOKBodyServicesItems0 InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +swagger:model ListInventoryServicesOKBodyServicesItems0 +*/ +type ListInventoryServicesOKBodyServicesItems0 struct { + // PMM's service ID. The join key against the topology document. + ServiceID string `json:"service_id,omitempty"` + + // The node it runs on, as PMM's node ID. + NodeID string `json:"node_id,omitempty"` + + // The service name PMM registered. + Name string `json:"name,omitempty"` + + // The port it listens on, where OM knows it. + Port *int32 `json:"port,omitempty"` + + // PRIMARY, SECONDARY, ARBITER, or unset. + Role *string `json:"role,omitempty"` + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + InstalledVersion *string `json:"installed_version,omitempty"` + + // The version the running server reports. + RunningVersion *string `json:"running_version,omitempty"` + + // The configuration file the running server read. + ConfigPath *string `json:"config_path,omitempty"` + + // The command line it was started with. + Argv *string `json:"argv,omitempty"` + + // What the last probe of this service concluded, in the payload's own words. + ProbeStatus *string `json:"probe_status,omitempty"` + + // Whether a server was found running. Unset where no probe has looked. + ServerRunning *bool `json:"server_running,omitempty"` + + // How long it has been up, seconds. + UptimeSeconds *float64 `json:"uptime_seconds,omitempty"` + + // The replica set it belongs to, or unset for a standalone or a router. + ReplicationSet *string `json:"replication_set,omitempty"` + + // Everything the probe recorded, including attributes with no field above. + Observed any `json:"observed,omitempty"` + + // freshness + Freshness *ListInventoryServicesOKBodyServicesItems0Freshness `json:"freshness,omitempty"` +} + +// Validate validates this list inventory services OK body services items0 +func (o *ListInventoryServicesOKBodyServicesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFreshness(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0) validateFreshness(formats strfmt.Registry) error { + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if o.Freshness != nil { + if err := o.Freshness.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this list inventory services OK body services items0 based on the context it is used +func (o *ListInventoryServicesOKBodyServicesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateFreshness(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0) contextValidateFreshness(ctx context.Context, formats strfmt.Registry) error { + if o.Freshness != nil { + + if swag.IsZero(o.Freshness) { // not required + return nil + } + + if err := o.Freshness.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freshness") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freshness") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryServicesOKBodyServicesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryServicesOKBodyServicesItems0) UnmarshalBinary(b []byte) error { + var res ListInventoryServicesOKBodyServicesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListInventoryServicesOKBodyServicesItems0Freshness InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +swagger:model ListInventoryServicesOKBodyServicesItems0Freshness +*/ +type ListInventoryServicesOKBodyServicesItems0Freshness struct { + // When OM first wrote a row for this entity. + // Format: date-time + FirstSeenAt strfmt.DateTime `json:"first_seen_at,omitempty"` + + // When a refresh last tried it. + // Format: date-time + LastAttemptAt strfmt.DateTime `json:"last_attempt_at,omitempty"` + + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + // Format: date-time + LastSuccessAt strfmt.DateTime `json:"last_success_at,omitempty"` + + // The first failure after the last success. Unset means it is not failing. + // Format: date-time + FailingSince strfmt.DateTime `json:"failing_since,omitempty"` + + // Failures since the last success. + ConsecutiveFailures int32 `json:"consecutive_failures,omitempty"` + + // The most recent failure detail. + LastError *string `json:"last_error,omitempty"` +} + +// Validate validates this list inventory services OK body services items0 freshness +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateFirstSeenAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastAttemptAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastSuccessAt(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFailingSince(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) validateFirstSeenAt(formats strfmt.Registry) error { + if swag.IsZero(o.FirstSeenAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"first_seen_at", "body", "date-time", o.FirstSeenAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) validateLastAttemptAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastAttemptAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_attempt_at", "body", "date-time", o.LastAttemptAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) validateLastSuccessAt(formats strfmt.Registry) error { + if swag.IsZero(o.LastSuccessAt) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"last_success_at", "body", "date-time", o.LastSuccessAt.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) validateFailingSince(formats strfmt.Registry) error { + if swag.IsZero(o.FailingSince) { // not required + return nil + } + + if err := validate.FormatOf("freshness"+"."+"failing_since", "body", "date-time", o.FailingSince.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list inventory services OK body services items0 freshness based on context it is used +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListInventoryServicesOKBodyServicesItems0Freshness) UnmarshalBinary(b []byte) error { + var res ListInventoryServicesOKBodyServicesItems0Freshness + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/list_topology_runs_parameters.go b/api/om/v1/json/client/om_service/list_topology_runs_parameters.go new file mode 100644 index 00000000000..09dc196c575 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_topology_runs_parameters.go @@ -0,0 +1,160 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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/go-openapi/swag" +) + +// NewListTopologyRunsParams creates a new ListTopologyRunsParams 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 NewListTopologyRunsParams() *ListTopologyRunsParams { + return &ListTopologyRunsParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListTopologyRunsParamsWithTimeout creates a new ListTopologyRunsParams object +// with the ability to set a timeout on a request. +func NewListTopologyRunsParamsWithTimeout(timeout time.Duration) *ListTopologyRunsParams { + return &ListTopologyRunsParams{ + timeout: timeout, + } +} + +// NewListTopologyRunsParamsWithContext creates a new ListTopologyRunsParams object +// with the ability to set a context for a request. +func NewListTopologyRunsParamsWithContext(ctx context.Context) *ListTopologyRunsParams { + return &ListTopologyRunsParams{ + Context: ctx, + } +} + +// NewListTopologyRunsParamsWithHTTPClient creates a new ListTopologyRunsParams object +// with the ability to set a custom HTTPClient for a request. +func NewListTopologyRunsParamsWithHTTPClient(client *http.Client) *ListTopologyRunsParams { + return &ListTopologyRunsParams{ + HTTPClient: client, + } +} + +/* +ListTopologyRunsParams contains all the parameters to send to the API endpoint + + for the list topology runs operation. + + Typically these are written to a http.Request. +*/ +type ListTopologyRunsParams struct { + /* Limit. + + How many runs to return, newest first. Defaults to 25, capped at 100. + + Format: int32 + */ + Limit *int32 + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list topology runs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListTopologyRunsParams) WithDefaults() *ListTopologyRunsParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list topology runs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListTopologyRunsParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list topology runs params +func (o *ListTopologyRunsParams) WithTimeout(timeout time.Duration) *ListTopologyRunsParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list topology runs params +func (o *ListTopologyRunsParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list topology runs params +func (o *ListTopologyRunsParams) WithContext(ctx context.Context) *ListTopologyRunsParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list topology runs params +func (o *ListTopologyRunsParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list topology runs params +func (o *ListTopologyRunsParams) WithHTTPClient(client *http.Client) *ListTopologyRunsParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list topology runs params +func (o *ListTopologyRunsParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithLimit adds the limit to the list topology runs params +func (o *ListTopologyRunsParams) WithLimit(limit *int32) *ListTopologyRunsParams { + o.SetLimit(limit) + return o +} + +// SetLimit adds the limit to the list topology runs params +func (o *ListTopologyRunsParams) SetLimit(limit *int32) { + o.Limit = limit +} + +// WriteToRequest writes these params to a swagger request +func (o *ListTopologyRunsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Limit != nil { + + // query param limit + var qrLimit int32 + + if o.Limit != nil { + qrLimit = *o.Limit + } + qLimit := swag.FormatInt32(qrLimit) + if qLimit != "" { + if err := r.SetQueryParam("limit", qLimit); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/list_topology_runs_responses.go b/api/om/v1/json/client/om_service/list_topology_runs_responses.go new file mode 100644 index 00000000000..8b31f4d5532 --- /dev/null +++ b/api/om/v1/json/client/om_service/list_topology_runs_responses.go @@ -0,0 +1,1102 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListTopologyRunsReader is a Reader for the ListTopologyRuns structure. +type ListTopologyRunsReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListTopologyRunsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListTopologyRunsOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListTopologyRunsDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListTopologyRunsOK creates a ListTopologyRunsOK with default headers values +func NewListTopologyRunsOK() *ListTopologyRunsOK { + return &ListTopologyRunsOK{} +} + +/* +ListTopologyRunsOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListTopologyRunsOK struct { + Payload *ListTopologyRunsOKBody +} + +// IsSuccess returns true when this list topology runs Ok response has a 2xx status code +func (o *ListTopologyRunsOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list topology runs Ok response has a 3xx status code +func (o *ListTopologyRunsOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list topology runs Ok response has a 4xx status code +func (o *ListTopologyRunsOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list topology runs Ok response has a 5xx status code +func (o *ListTopologyRunsOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list topology runs Ok response a status code equal to that given +func (o *ListTopologyRunsOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list topology runs Ok response +func (o *ListTopologyRunsOK) Code() int { + return 200 +} + +func (o *ListTopologyRunsOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs][%d] listTopologyRunsOk %s", 200, payload) +} + +func (o *ListTopologyRunsOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs][%d] listTopologyRunsOk %s", 200, payload) +} + +func (o *ListTopologyRunsOK) GetPayload() *ListTopologyRunsOKBody { + return o.Payload +} + +func (o *ListTopologyRunsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListTopologyRunsOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListTopologyRunsDefault creates a ListTopologyRunsDefault with default headers values +func NewListTopologyRunsDefault(code int) *ListTopologyRunsDefault { + return &ListTopologyRunsDefault{ + _statusCode: code, + } +} + +/* +ListTopologyRunsDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListTopologyRunsDefault struct { + _statusCode int + + Payload *ListTopologyRunsDefaultBody +} + +// IsSuccess returns true when this list topology runs default response has a 2xx status code +func (o *ListTopologyRunsDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list topology runs default response has a 3xx status code +func (o *ListTopologyRunsDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list topology runs default response has a 4xx status code +func (o *ListTopologyRunsDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list topology runs default response has a 5xx status code +func (o *ListTopologyRunsDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list topology runs default response a status code equal to that given +func (o *ListTopologyRunsDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list topology runs default response +func (o *ListTopologyRunsDefault) Code() int { + return o._statusCode +} + +func (o *ListTopologyRunsDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs][%d] ListTopologyRuns default %s", o._statusCode, payload) +} + +func (o *ListTopologyRunsDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/om/topology/runs][%d] ListTopologyRuns default %s", o._statusCode, payload) +} + +func (o *ListTopologyRunsDefault) GetPayload() *ListTopologyRunsDefaultBody { + return o.Payload +} + +func (o *ListTopologyRunsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListTopologyRunsDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListTopologyRunsDefaultBody list topology runs default body +swagger:model ListTopologyRunsDefaultBody +*/ +type ListTopologyRunsDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListTopologyRunsDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list topology runs default body +func (o *ListTopologyRunsDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListTopologyRunsDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListTopologyRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListTopologyRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list topology runs default body based on the context it is used +func (o *ListTopologyRunsDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListTopologyRunsDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListTopologyRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListTopologyRuns default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsDefaultBody) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsDefaultBodyDetailsItems0 list topology runs default body details items0 +swagger:model ListTopologyRunsDefaultBodyDetailsItems0 +*/ +type ListTopologyRunsDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list topology runs default body details items0 + ListTopologyRunsDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListTopologyRunsDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListTopologyRunsDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListTopologyRunsDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListTopologyRunsDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListTopologyRunsDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListTopologyRunsDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list topology runs default body details items0 +func (o *ListTopologyRunsDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list topology runs default body details items0 based on context it is used +func (o *ListTopologyRunsDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsOKBody ListTopologyRunsResponse returns the run history, newest first. +swagger:model ListTopologyRunsOKBody +*/ +type ListTopologyRunsOKBody struct { + // The runs. + Runs []*ListTopologyRunsOKBodyRunsItems0 `json:"runs"` +} + +// Validate validates this list topology runs OK body +func (o *ListTopologyRunsOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateRuns(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListTopologyRunsOKBody) validateRuns(formats strfmt.Registry) error { + if swag.IsZero(o.Runs) { // not required + return nil + } + + for i := 0; i < len(o.Runs); i++ { + if swag.IsZero(o.Runs[i]) { // not required + continue + } + + if o.Runs[i] != nil { + if err := o.Runs[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listTopologyRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listTopologyRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list topology runs OK body based on the context it is used +func (o *ListTopologyRunsOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateRuns(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListTopologyRunsOKBody) contextValidateRuns(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Runs); i++ { + if o.Runs[i] != nil { + + if swag.IsZero(o.Runs[i]) { // not required + return nil + } + + if err := o.Runs[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listTopologyRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listTopologyRunsOk" + "." + "runs" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsOKBody) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsOKBodyRunsItems0 TopologyRun represents one collection run. +swagger:model ListTopologyRunsOKBodyRunsItems0 +*/ +type ListTopologyRunsOKBodyRunsItems0 struct { + // The run's ID, also the snapshot key. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When the run began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` + + // When it reached a terminal status; unset while running. + // Format: date-time + EndTime strfmt.DateTime `json:"end_time,omitempty"` + + // Query-level, service-level and run-level failures. + Errors []*ListTopologyRunsOKBodyRunsItems0ErrorsItems0 `json:"errors"` + + // How completely each collection source answered. + Sources []*ListTopologyRunsOKBodyRunsItems0SourcesItems0 `json:"sources"` + + // counts + Counts *ListTopologyRunsOKBodyRunsItems0Counts `json:"counts,omitempty"` +} + +// Validate validates this list topology runs OK body runs items0 +func (o *ListTopologyRunsOKBodyRunsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateEndTime(formats); err != nil { + res = append(res, err) + } + + if err := o.validateErrors(formats); err != nil { + res = append(res, err) + } + + if err := o.validateSources(formats); err != nil { + res = append(res, err) + } + + if err := o.validateCounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var listTopologyRunsOkBodyRunsItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listTopologyRunsOkBodyRunsItems0TypeStatusPropEnum = append(listTopologyRunsOkBodyRunsItems0TypeStatusPropEnum, v) + } +} + +const ( + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + ListTopologyRunsOKBodyRunsItems0StatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *ListTopologyRunsOKBodyRunsItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listTopologyRunsOkBodyRunsItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateEndTime(formats strfmt.Registry) error { + if swag.IsZero(o.EndTime) { // not required + return nil + } + + if err := validate.FormatOf("end_time", "body", "date-time", o.EndTime.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateErrors(formats strfmt.Registry) error { + if swag.IsZero(o.Errors) { // not required + return nil + } + + for i := 0; i < len(o.Errors); i++ { + if swag.IsZero(o.Errors[i]) { // not required + continue + } + + if o.Errors[i] != nil { + if err := o.Errors[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("errors" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("errors" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateSources(formats strfmt.Registry) error { + if swag.IsZero(o.Sources) { // not required + return nil + } + + for i := 0; i < len(o.Sources); i++ { + if swag.IsZero(o.Sources[i]) { // not required + continue + } + + if o.Sources[i] != nil { + if err := o.Sources[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) validateCounts(formats strfmt.Registry) error { + if swag.IsZero(o.Counts) { // not required + return nil + } + + if o.Counts != nil { + if err := o.Counts.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("counts") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this list topology runs OK body runs items0 based on the context it is used +func (o *ListTopologyRunsOKBodyRunsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateErrors(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateSources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := o.contextValidateCounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) contextValidateErrors(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Errors); i++ { + if o.Errors[i] != nil { + + if swag.IsZero(o.Errors[i]) { // not required + return nil + } + + if err := o.Errors[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("errors" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("errors" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) contextValidateSources(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Sources); i++ { + if o.Sources[i] != nil { + + if swag.IsZero(o.Sources[i]) { // not required + return nil + } + + if err := o.Sources[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0) contextValidateCounts(ctx context.Context, formats strfmt.Registry) error { + if o.Counts != nil { + + if swag.IsZero(o.Counts) { // not required + return nil + } + + if err := o.Counts.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("counts") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("counts") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsOKBodyRunsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsOKBodyRunsItems0Counts TopologyRunCounts counts what one collection run saw. +swagger:model ListTopologyRunsOKBodyRunsItems0Counts +*/ +type ListTopologyRunsOKBodyRunsItems0Counts struct { + // MongoDB services inventory reported. + TotalServices int32 `json:"total_services,omitempty"` + + // ...of which carried a service ID to join metrics on. + ResolvedServices int32 `json:"resolved_services,omitempty"` + + // ...of which did not. Not an error. + OrphanedServices int32 `json:"orphaned_services,omitempty"` + + // Services metrics actually observed as reachable. + SuccessfulProbes int32 `json:"successful_probes,omitempty"` + + // Services carrying at least one volatile fact too old to read as current. + StaleServices int32 `json:"stale_services,omitempty"` +} + +// Validate validates this list topology runs OK body runs items0 counts +func (o *ListTopologyRunsOKBodyRunsItems0Counts) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list topology runs OK body runs items0 counts based on context it is used +func (o *ListTopologyRunsOKBodyRunsItems0Counts) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0Counts) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0Counts) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsOKBodyRunsItems0Counts + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsOKBodyRunsItems0ErrorsItems0 TopologyRunError describes one thing that went wrong during a collection run. +swagger:model ListTopologyRunsOKBodyRunsItems0ErrorsItems0 +*/ +type ListTopologyRunsOKBodyRunsItems0ErrorsItems0 struct { + // What the error is about, e.g. "run" or "query". + Scope string `json:"scope,omitempty"` + + // The service it concerns, when scoped to one. + ServiceName *string `json:"service_name,omitempty"` + + // A machine-readable cause. + Code string `json:"code,omitempty"` + + // The human-readable detail. + Message string `json:"message,omitempty"` +} + +// Validate validates this list topology runs OK body runs items0 errors items0 +func (o *ListTopologyRunsOKBodyRunsItems0ErrorsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list topology runs OK body runs items0 errors items0 based on context it is used +func (o *ListTopologyRunsOKBodyRunsItems0ErrorsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0ErrorsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0ErrorsItems0) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsOKBodyRunsItems0ErrorsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListTopologyRunsOKBodyRunsItems0SourcesItems0 SourceReport says how completely one collection source answered, and what it saw. +// +// Recorded per source so a thin document is legible rather than merely thin: a snapshot +// assembled with metrics=ok and probe=failed is still correct about every version and +// honest about reachability. +swagger:model ListTopologyRunsOKBodyRunsItems0SourcesItems0 +*/ +type ListTopologyRunsOKBodyRunsItems0SourcesItems0 struct { + // The source key, e.g. "inventory", "metrics" or "probe". An open set on purpose: a + // source is named by whatever produced it, so this stays a string where the statuses + // beside it are enums. + Source string `json:"source,omitempty"` + + // SourceStatus is how completely one collection source answered. + // + // Separate from RunStatus because it carries DISABLED, which a run cannot be: a source + // switched off in configuration is a deliberate state, not a degraded one. + // + // - SOURCE_STATUS_OK: Answered everything asked of it. + // - SOURCE_STATUS_PARTIAL: Answered some of it. + // - SOURCE_STATUS_FAILED: Did not answer. + // - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked. + // Enum: ["SOURCE_STATUS_UNSPECIFIED","SOURCE_STATUS_OK","SOURCE_STATUS_PARTIAL","SOURCE_STATUS_FAILED","SOURCE_STATUS_DISABLED"] + Status *string `json:"status,omitempty"` + + // How many facts it produced. + Facts int32 `json:"facts,omitempty"` + + // Source-specific counters, rendered as strings so a source can report whatever it has + // without this contract naming every counter. + Detail map[string]string `json:"detail,omitempty"` +} + +// Validate validates this list topology runs OK body runs items0 sources items0 +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var listTopologyRunsOkBodyRunsItems0SourcesItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SOURCE_STATUS_UNSPECIFIED","SOURCE_STATUS_OK","SOURCE_STATUS_PARTIAL","SOURCE_STATUS_FAILED","SOURCE_STATUS_DISABLED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listTopologyRunsOkBodyRunsItems0SourcesItems0TypeStatusPropEnum = append(listTopologyRunsOkBodyRunsItems0SourcesItems0TypeStatusPropEnum, v) + } +} + +const ( + + // ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSUNSPECIFIED captures enum value "SOURCE_STATUS_UNSPECIFIED" + ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSUNSPECIFIED string = "SOURCE_STATUS_UNSPECIFIED" + + // ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSOK captures enum value "SOURCE_STATUS_OK" + ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSOK string = "SOURCE_STATUS_OK" + + // ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSPARTIAL captures enum value "SOURCE_STATUS_PARTIAL" + ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSPARTIAL string = "SOURCE_STATUS_PARTIAL" + + // ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSFAILED captures enum value "SOURCE_STATUS_FAILED" + ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSFAILED string = "SOURCE_STATUS_FAILED" + + // ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSDISABLED captures enum value "SOURCE_STATUS_DISABLED" + ListTopologyRunsOKBodyRunsItems0SourcesItems0StatusSOURCESTATUSDISABLED string = "SOURCE_STATUS_DISABLED" +) + +// prop value enum +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listTopologyRunsOkBodyRunsItems0SourcesItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list topology runs OK body runs items0 sources items0 based on context it is used +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListTopologyRunsOKBodyRunsItems0SourcesItems0) UnmarshalBinary(b []byte) error { + var res ListTopologyRunsOKBodyRunsItems0SourcesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/om_service_client.go b/api/om/v1/json/client/om_service/om_service_client.go new file mode 100644 index 00000000000..88209f7f905 --- /dev/null +++ b/api/om/v1/json/client/om_service/om_service_client.go @@ -0,0 +1,796 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "github.com/go-openapi/runtime" + httptransport "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// New creates a new om service API client. +func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { + return &Client{transport: transport, formats: formats} +} + +// New creates a new om service API client with basic auth credentials. +// It takes the following parameters: +// - host: http host (github.com). +// - basePath: any base path for the API client ("/v1", "/v3"). +// - scheme: http scheme ("http", "https"). +// - user: user for basic authentication header. +// - password: password for basic authentication header. +func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService { + transport := httptransport.New(host, basePath, []string{scheme}) + transport.DefaultAuthentication = httptransport.BasicAuth(user, password) + return &Client{transport: transport, formats: strfmt.Default} +} + +// New creates a new om service API client with a bearer token for authentication. +// It takes the following parameters: +// - host: http host (github.com). +// - basePath: any base path for the API client ("/v1", "/v3"). +// - scheme: http scheme ("http", "https"). +// - bearerToken: bearer token for Bearer authentication header. +func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService { + transport := httptransport.New(host, basePath, []string{scheme}) + transport.DefaultAuthentication = httptransport.BearerToken(bearerToken) + return &Client{transport: transport, formats: strfmt.Default} +} + +/* +Client for om service API +*/ +type Client struct { + transport runtime.ClientTransport + formats strfmt.Registry +} + +// ClientOption may be used to customize the behavior of Client methods. +type ClientOption func(*runtime.ClientOperation) + +// ClientService is the interface for Client methods +type ClientService interface { + DeleteInventoryConfigOverride(params *DeleteInventoryConfigOverrideParams, opts ...ClientOption) (*DeleteInventoryConfigOverrideOK, error) + + DeleteInventoryHost(params *DeleteInventoryHostParams, opts ...ClientOption) (*DeleteInventoryHostOK, error) + + DeleteInventoryService(params *DeleteInventoryServiceParams, opts ...ClientOption) (*DeleteInventoryServiceOK, error) + + GetInventoryConfig(params *GetInventoryConfigParams, opts ...ClientOption) (*GetInventoryConfigOK, error) + + GetInventoryHost(params *GetInventoryHostParams, opts ...ClientOption) (*GetInventoryHostOK, error) + + GetInventoryRun(params *GetInventoryRunParams, opts ...ClientOption) (*GetInventoryRunOK, error) + + GetInventoryService(params *GetInventoryServiceParams, opts ...ClientOption) (*GetInventoryServiceOK, error) + + GetTopology(params *GetTopologyParams, opts ...ClientOption) (*GetTopologyOK, error) + + GetTopologyRun(params *GetTopologyRunParams, opts ...ClientOption) (*GetTopologyRunOK, error) + + ListInventoryHosts(params *ListInventoryHostsParams, opts ...ClientOption) (*ListInventoryHostsOK, error) + + ListInventoryRuns(params *ListInventoryRunsParams, opts ...ClientOption) (*ListInventoryRunsOK, error) + + ListInventoryServices(params *ListInventoryServicesParams, opts ...ClientOption) (*ListInventoryServicesOK, error) + + ListTopologyRuns(params *ListTopologyRunsParams, opts ...ClientOption) (*ListTopologyRunsOK, error) + + TriggerInventoryRefresh(params *TriggerInventoryRefreshParams, opts ...ClientOption) (*TriggerInventoryRefreshOK, error) + + TriggerTopologyCollection(params *TriggerTopologyCollectionParams, opts ...ClientOption) (*TriggerTopologyCollectionOK, error) + + UpdateInventoryConfig(params *UpdateInventoryConfigParams, opts ...ClientOption) (*UpdateInventoryConfigOK, error) + + SetTransport(transport runtime.ClientTransport) +} + +/* +DeleteInventoryConfigOverride reverts an inventory configuration field + +Removes the override for one field so it returns to whatever the deployment configured. Idempotent. +*/ +func (a *Client) DeleteInventoryConfigOverride(params *DeleteInventoryConfigOverrideParams, opts ...ClientOption) (*DeleteInventoryConfigOverrideOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteInventoryConfigOverrideParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteInventoryConfigOverride", + Method: "DELETE", + PathPattern: "/v1/om/inventory/config/overrides/{key}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &DeleteInventoryConfigOverrideReader{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 + } + + // only one success response has to be checked + success, ok := result.(*DeleteInventoryConfigOverrideOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*DeleteInventoryConfigOverrideDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +DeleteInventoryHost forgets an inventory host + +Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID. +*/ +func (a *Client) DeleteInventoryHost(params *DeleteInventoryHostParams, opts ...ClientOption) (*DeleteInventoryHostOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteInventoryHostParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteInventoryHost", + Method: "DELETE", + PathPattern: "/v1/om/inventory/hosts/{node_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &DeleteInventoryHostReader{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 + } + + // only one success response has to be checked + success, ok := result.(*DeleteInventoryHostOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*DeleteInventoryHostDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +DeleteInventoryService forgets an inventory service + +Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh. +*/ +func (a *Client) DeleteInventoryService(params *DeleteInventoryServiceParams, opts ...ClientOption) (*DeleteInventoryServiceOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteInventoryServiceParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteInventoryService", + Method: "DELETE", + PathPattern: "/v1/om/inventory/services/{service_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &DeleteInventoryServiceReader{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 + } + + // only one success response has to be checked + success, ok := result.(*DeleteInventoryServiceOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*DeleteInventoryServiceDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetInventoryConfig gets the inventory configuration + +Returns every configuration field of the inventory app, its effective value, and whether an override is in effect. +*/ +func (a *Client) GetInventoryConfig(params *GetInventoryConfigParams, opts ...ClientOption) (*GetInventoryConfigOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetInventoryConfigParams() + } + op := &runtime.ClientOperation{ + ID: "GetInventoryConfig", + Method: "GET", + PathPattern: "/v1/om/inventory/config", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetInventoryConfigReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetInventoryConfigOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetInventoryConfigDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetInventoryHost gets an inventory host + +Returns one host by PMM node ID, with the services on it. +*/ +func (a *Client) GetInventoryHost(params *GetInventoryHostParams, opts ...ClientOption) (*GetInventoryHostOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetInventoryHostParams() + } + op := &runtime.ClientOperation{ + ID: "GetInventoryHost", + Method: "GET", + PathPattern: "/v1/om/inventory/hosts/{node_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetInventoryHostReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetInventoryHostOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetInventoryHostDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetInventoryRun gets an inventory refresh + +Returns one refresh by ID, with what it saw and which hosts it covered. +*/ +func (a *Client) GetInventoryRun(params *GetInventoryRunParams, opts ...ClientOption) (*GetInventoryRunOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetInventoryRunParams() + } + op := &runtime.ClientOperation{ + ID: "GetInventoryRun", + Method: "GET", + PathPattern: "/v1/om/inventory/runs/{run_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetInventoryRunReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetInventoryRunOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetInventoryRunDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetInventoryService gets an inventory service + +Returns one service by PMM service ID. +*/ +func (a *Client) GetInventoryService(params *GetInventoryServiceParams, opts ...ClientOption) (*GetInventoryServiceOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetInventoryServiceParams() + } + op := &runtime.ClientOperation{ + ID: "GetInventoryService", + Method: "GET", + PathPattern: "/v1/om/inventory/services/{service_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetInventoryServiceReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetInventoryServiceOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetInventoryServiceDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetTopology gets the mongo DB topology + +Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load. +*/ +func (a *Client) GetTopology(params *GetTopologyParams, opts ...ClientOption) (*GetTopologyOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetTopologyParams() + } + op := &runtime.ClientOperation{ + ID: "GetTopology", + Method: "GET", + PathPattern: "/v1/om/topology", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetTopologyReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetTopologyOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetTopologyDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetTopologyRun gets a collection run + +Returns one recorded collection run, with what it saw, how each source answered, and any errors it hit. +*/ +func (a *Client) GetTopologyRun(params *GetTopologyRunParams, opts ...ClientOption) (*GetTopologyRunOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetTopologyRunParams() + } + op := &runtime.ClientOperation{ + ID: "GetTopologyRun", + Method: "GET", + PathPattern: "/v1/om/topology/runs/{run_id}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetTopologyRunReader{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 + } + + // only one success response has to be checked + success, ok := result.(*GetTopologyRunOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetTopologyRunDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListInventoryHosts lists inventory hosts + +Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are. +*/ +func (a *Client) ListInventoryHosts(params *ListInventoryHostsParams, opts ...ClientOption) (*ListInventoryHostsOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListInventoryHostsParams() + } + op := &runtime.ClientOperation{ + ID: "ListInventoryHosts", + Method: "GET", + PathPattern: "/v1/om/inventory/hosts", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListInventoryHostsReader{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 + } + + // only one success response has to be checked + success, ok := result.(*ListInventoryHostsOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListInventoryHostsDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListInventoryRuns lists inventory refreshes + +Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host. +*/ +func (a *Client) ListInventoryRuns(params *ListInventoryRunsParams, opts ...ClientOption) (*ListInventoryRunsOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListInventoryRunsParams() + } + op := &runtime.ClientOperation{ + ID: "ListInventoryRuns", + Method: "GET", + PathPattern: "/v1/om/inventory/runs", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListInventoryRunsReader{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 + } + + // only one success response has to be checked + success, ok := result.(*ListInventoryRunsOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListInventoryRunsDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListInventoryServices lists inventory services + +Returns every MongoDB service the inventory app has a row for, with what each last reported and when. +*/ +func (a *Client) ListInventoryServices(params *ListInventoryServicesParams, opts ...ClientOption) (*ListInventoryServicesOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListInventoryServicesParams() + } + op := &runtime.ClientOperation{ + ID: "ListInventoryServices", + Method: "GET", + PathPattern: "/v1/om/inventory/services", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListInventoryServicesReader{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 + } + + // only one success response has to be checked + success, ok := result.(*ListInventoryServicesOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListInventoryServicesDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ListTopologyRuns lists collection runs + +Returns the recorded collection runs, newest first, with what each one saw and any errors it hit. +*/ +func (a *Client) ListTopologyRuns(params *ListTopologyRunsParams, opts ...ClientOption) (*ListTopologyRunsOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListTopologyRunsParams() + } + op := &runtime.ClientOperation{ + ID: "ListTopologyRuns", + Method: "GET", + PathPattern: "/v1/om/topology/runs", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListTopologyRunsReader{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 + } + + // only one success response has to be checked + success, ok := result.(*ListTopologyRunsOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListTopologyRunsDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +TriggerInventoryRefresh refreshes the inventory + +Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them. +*/ +func (a *Client) TriggerInventoryRefresh(params *TriggerInventoryRefreshParams, opts ...ClientOption) (*TriggerInventoryRefreshOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewTriggerInventoryRefreshParams() + } + op := &runtime.ClientOperation{ + ID: "TriggerInventoryRefresh", + Method: "POST", + PathPattern: "/v1/om/inventory/runs:trigger", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &TriggerInventoryRefreshReader{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 + } + + // only one success response has to be checked + success, ok := result.(*TriggerInventoryRefreshOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*TriggerInventoryRefreshDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +TriggerTopologyCollection triggers a collection run + +Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run. +*/ +func (a *Client) TriggerTopologyCollection(params *TriggerTopologyCollectionParams, opts ...ClientOption) (*TriggerTopologyCollectionOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewTriggerTopologyCollectionParams() + } + op := &runtime.ClientOperation{ + ID: "TriggerTopologyCollection", + Method: "POST", + PathPattern: "/v1/om/topology/runs:collect", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &TriggerTopologyCollectionReader{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 + } + + // only one success response has to be checked + success, ok := result.(*TriggerTopologyCollectionOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*TriggerTopologyCollectionDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +UpdateInventoryConfig changes the inventory configuration + +Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted. +*/ +func (a *Client) UpdateInventoryConfig(params *UpdateInventoryConfigParams, opts ...ClientOption) (*UpdateInventoryConfigOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUpdateInventoryConfigParams() + } + op := &runtime.ClientOperation{ + ID: "UpdateInventoryConfig", + Method: "PUT", + PathPattern: "/v1/om/inventory/config", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &UpdateInventoryConfigReader{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 + } + + // only one success response has to be checked + success, ok := result.(*UpdateInventoryConfigOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*UpdateInventoryConfigDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +// SetTransport changes the transport on the client +func (a *Client) SetTransport(transport runtime.ClientTransport) { + a.transport = transport +} diff --git a/api/om/v1/json/client/om_service/trigger_inventory_refresh_parameters.go b/api/om/v1/json/client/om_service/trigger_inventory_refresh_parameters.go new file mode 100644 index 00000000000..c61661fc7dc --- /dev/null +++ b/api/om/v1/json/client/om_service/trigger_inventory_refresh_parameters.go @@ -0,0 +1,144 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewTriggerInventoryRefreshParams creates a new TriggerInventoryRefreshParams 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 NewTriggerInventoryRefreshParams() *TriggerInventoryRefreshParams { + return &TriggerInventoryRefreshParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewTriggerInventoryRefreshParamsWithTimeout creates a new TriggerInventoryRefreshParams object +// with the ability to set a timeout on a request. +func NewTriggerInventoryRefreshParamsWithTimeout(timeout time.Duration) *TriggerInventoryRefreshParams { + return &TriggerInventoryRefreshParams{ + timeout: timeout, + } +} + +// NewTriggerInventoryRefreshParamsWithContext creates a new TriggerInventoryRefreshParams object +// with the ability to set a context for a request. +func NewTriggerInventoryRefreshParamsWithContext(ctx context.Context) *TriggerInventoryRefreshParams { + return &TriggerInventoryRefreshParams{ + Context: ctx, + } +} + +// NewTriggerInventoryRefreshParamsWithHTTPClient creates a new TriggerInventoryRefreshParams object +// with the ability to set a custom HTTPClient for a request. +func NewTriggerInventoryRefreshParamsWithHTTPClient(client *http.Client) *TriggerInventoryRefreshParams { + return &TriggerInventoryRefreshParams{ + HTTPClient: client, + } +} + +/* +TriggerInventoryRefreshParams contains all the parameters to send to the API endpoint + + for the trigger inventory refresh operation. + + Typically these are written to a http.Request. +*/ +type TriggerInventoryRefreshParams struct { + /* Body. + + TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh. + */ + Body TriggerInventoryRefreshBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the trigger inventory refresh params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *TriggerInventoryRefreshParams) WithDefaults() *TriggerInventoryRefreshParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the trigger inventory refresh params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *TriggerInventoryRefreshParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) WithTimeout(timeout time.Duration) *TriggerInventoryRefreshParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) WithContext(ctx context.Context) *TriggerInventoryRefreshParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) WithHTTPClient(client *http.Client) *TriggerInventoryRefreshParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) WithBody(body TriggerInventoryRefreshBody) *TriggerInventoryRefreshParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the trigger inventory refresh params +func (o *TriggerInventoryRefreshParams) SetBody(body TriggerInventoryRefreshBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *TriggerInventoryRefreshParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/trigger_inventory_refresh_responses.go b/api/om/v1/json/client/om_service/trigger_inventory_refresh_responses.go new file mode 100644 index 00000000000..65cbb551fad --- /dev/null +++ b/api/om/v1/json/client/om_service/trigger_inventory_refresh_responses.go @@ -0,0 +1,610 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// TriggerInventoryRefreshReader is a Reader for the TriggerInventoryRefresh structure. +type TriggerInventoryRefreshReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *TriggerInventoryRefreshReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewTriggerInventoryRefreshOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewTriggerInventoryRefreshDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewTriggerInventoryRefreshOK creates a TriggerInventoryRefreshOK with default headers values +func NewTriggerInventoryRefreshOK() *TriggerInventoryRefreshOK { + return &TriggerInventoryRefreshOK{} +} + +/* +TriggerInventoryRefreshOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type TriggerInventoryRefreshOK struct { + Payload *TriggerInventoryRefreshOKBody +} + +// IsSuccess returns true when this trigger inventory refresh Ok response has a 2xx status code +func (o *TriggerInventoryRefreshOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this trigger inventory refresh Ok response has a 3xx status code +func (o *TriggerInventoryRefreshOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this trigger inventory refresh Ok response has a 4xx status code +func (o *TriggerInventoryRefreshOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this trigger inventory refresh Ok response has a 5xx status code +func (o *TriggerInventoryRefreshOK) IsServerError() bool { + return false +} + +// IsCode returns true when this trigger inventory refresh Ok response a status code equal to that given +func (o *TriggerInventoryRefreshOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the trigger inventory refresh Ok response +func (o *TriggerInventoryRefreshOK) Code() int { + return 200 +} + +func (o *TriggerInventoryRefreshOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/inventory/runs:trigger][%d] triggerInventoryRefreshOk %s", 200, payload) +} + +func (o *TriggerInventoryRefreshOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/inventory/runs:trigger][%d] triggerInventoryRefreshOk %s", 200, payload) +} + +func (o *TriggerInventoryRefreshOK) GetPayload() *TriggerInventoryRefreshOKBody { + return o.Payload +} + +func (o *TriggerInventoryRefreshOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(TriggerInventoryRefreshOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewTriggerInventoryRefreshDefault creates a TriggerInventoryRefreshDefault with default headers values +func NewTriggerInventoryRefreshDefault(code int) *TriggerInventoryRefreshDefault { + return &TriggerInventoryRefreshDefault{ + _statusCode: code, + } +} + +/* +TriggerInventoryRefreshDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type TriggerInventoryRefreshDefault struct { + _statusCode int + + Payload *TriggerInventoryRefreshDefaultBody +} + +// IsSuccess returns true when this trigger inventory refresh default response has a 2xx status code +func (o *TriggerInventoryRefreshDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this trigger inventory refresh default response has a 3xx status code +func (o *TriggerInventoryRefreshDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this trigger inventory refresh default response has a 4xx status code +func (o *TriggerInventoryRefreshDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this trigger inventory refresh default response has a 5xx status code +func (o *TriggerInventoryRefreshDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this trigger inventory refresh default response a status code equal to that given +func (o *TriggerInventoryRefreshDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the trigger inventory refresh default response +func (o *TriggerInventoryRefreshDefault) Code() int { + return o._statusCode +} + +func (o *TriggerInventoryRefreshDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/inventory/runs:trigger][%d] TriggerInventoryRefresh default %s", o._statusCode, payload) +} + +func (o *TriggerInventoryRefreshDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/inventory/runs:trigger][%d] TriggerInventoryRefresh default %s", o._statusCode, payload) +} + +func (o *TriggerInventoryRefreshDefault) GetPayload() *TriggerInventoryRefreshDefaultBody { + return o.Payload +} + +func (o *TriggerInventoryRefreshDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(TriggerInventoryRefreshDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +TriggerInventoryRefreshBody TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh. +swagger:model TriggerInventoryRefreshBody +*/ +type TriggerInventoryRefreshBody struct { + // The hosts to refresh, by PMM node ID. Empty refreshes the whole estate. + // + // Plural on purpose: PMM's node ID is also OM's key, so ids pass through + // untranslated, and one host is a list of one. A surface taking a single id where + // the app takes a list would be a translation step in disguise. + // + // Bounded because a refresh dispatches a Nomad job per host: the empty list already + // means "the whole estate", so a caller naming hosts individually is naming a few, + // and an unbounded list is only reachable by accident. An empty string is rejected + // rather than forwarded, where it would read as a node ID that matches nothing. + NodeIds []string `json:"node_ids"` +} + +// Validate validates this trigger inventory refresh body +func (o *TriggerInventoryRefreshBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this trigger inventory refresh body based on context it is used +func (o *TriggerInventoryRefreshBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerInventoryRefreshBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerInventoryRefreshBody) UnmarshalBinary(b []byte) error { + var res TriggerInventoryRefreshBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +TriggerInventoryRefreshDefaultBody trigger inventory refresh default body +swagger:model TriggerInventoryRefreshDefaultBody +*/ +type TriggerInventoryRefreshDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*TriggerInventoryRefreshDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this trigger inventory refresh default body +func (o *TriggerInventoryRefreshDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *TriggerInventoryRefreshDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("TriggerInventoryRefresh default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("TriggerInventoryRefresh default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this trigger inventory refresh default body based on the context it is used +func (o *TriggerInventoryRefreshDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *TriggerInventoryRefreshDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("TriggerInventoryRefresh default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("TriggerInventoryRefresh default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerInventoryRefreshDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerInventoryRefreshDefaultBody) UnmarshalBinary(b []byte) error { + var res TriggerInventoryRefreshDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +TriggerInventoryRefreshDefaultBodyDetailsItems0 trigger inventory refresh default body details items0 +swagger:model TriggerInventoryRefreshDefaultBodyDetailsItems0 +*/ +type TriggerInventoryRefreshDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // trigger inventory refresh default body details items0 + TriggerInventoryRefreshDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *TriggerInventoryRefreshDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv TriggerInventoryRefreshDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.TriggerInventoryRefreshDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o TriggerInventoryRefreshDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.TriggerInventoryRefreshDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.TriggerInventoryRefreshDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this trigger inventory refresh default body details items0 +func (o *TriggerInventoryRefreshDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this trigger inventory refresh default body details items0 based on context it is used +func (o *TriggerInventoryRefreshDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerInventoryRefreshDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerInventoryRefreshDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res TriggerInventoryRefreshDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +TriggerInventoryRefreshOKBody TriggerInventoryRefreshResponse acknowledges an accepted refresh. +// +// Accepted, not finished. A refresh dispatches a Nomad job per host and takes tens of +// seconds, unlike PMM's own collection pass, which never probes and completes in +// milliseconds. Two triggers that different must not look alike to a caller. +swagger:model TriggerInventoryRefreshOKBody +*/ +type TriggerInventoryRefreshOKBody struct { + // The run's ID, to follow with GetInventoryRun. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When it began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` + + // The hosts it will refresh. Empty means the whole estate. + Scope []string `json:"scope"` +} + +// Validate validates this trigger inventory refresh OK body +func (o *TriggerInventoryRefreshOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var triggerInventoryRefreshOkBodyTypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + triggerInventoryRefreshOkBodyTypeStatusPropEnum = append(triggerInventoryRefreshOkBodyTypeStatusPropEnum, v) + } +} + +const ( + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // TriggerInventoryRefreshOKBodyStatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + TriggerInventoryRefreshOKBodyStatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *TriggerInventoryRefreshOKBody) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, triggerInventoryRefreshOkBodyTypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *TriggerInventoryRefreshOKBody) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("triggerInventoryRefreshOk"+"."+"status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *TriggerInventoryRefreshOKBody) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("triggerInventoryRefreshOk"+"."+"start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this trigger inventory refresh OK body based on context it is used +func (o *TriggerInventoryRefreshOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerInventoryRefreshOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerInventoryRefreshOKBody) UnmarshalBinary(b []byte) error { + var res TriggerInventoryRefreshOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/trigger_topology_collection_parameters.go b/api/om/v1/json/client/om_service/trigger_topology_collection_parameters.go new file mode 100644 index 00000000000..0d71f78090a --- /dev/null +++ b/api/om/v1/json/client/om_service/trigger_topology_collection_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewTriggerTopologyCollectionParams creates a new TriggerTopologyCollectionParams 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 NewTriggerTopologyCollectionParams() *TriggerTopologyCollectionParams { + return &TriggerTopologyCollectionParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewTriggerTopologyCollectionParamsWithTimeout creates a new TriggerTopologyCollectionParams object +// with the ability to set a timeout on a request. +func NewTriggerTopologyCollectionParamsWithTimeout(timeout time.Duration) *TriggerTopologyCollectionParams { + return &TriggerTopologyCollectionParams{ + timeout: timeout, + } +} + +// NewTriggerTopologyCollectionParamsWithContext creates a new TriggerTopologyCollectionParams object +// with the ability to set a context for a request. +func NewTriggerTopologyCollectionParamsWithContext(ctx context.Context) *TriggerTopologyCollectionParams { + return &TriggerTopologyCollectionParams{ + Context: ctx, + } +} + +// NewTriggerTopologyCollectionParamsWithHTTPClient creates a new TriggerTopologyCollectionParams object +// with the ability to set a custom HTTPClient for a request. +func NewTriggerTopologyCollectionParamsWithHTTPClient(client *http.Client) *TriggerTopologyCollectionParams { + return &TriggerTopologyCollectionParams{ + HTTPClient: client, + } +} + +/* +TriggerTopologyCollectionParams contains all the parameters to send to the API endpoint + + for the trigger topology collection operation. + + Typically these are written to a http.Request. +*/ +type TriggerTopologyCollectionParams struct { + /* Body. + + TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection. + */ + Body any + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the trigger topology collection params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *TriggerTopologyCollectionParams) WithDefaults() *TriggerTopologyCollectionParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the trigger topology collection params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *TriggerTopologyCollectionParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) WithTimeout(timeout time.Duration) *TriggerTopologyCollectionParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) WithContext(ctx context.Context) *TriggerTopologyCollectionParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) WithHTTPClient(client *http.Client) *TriggerTopologyCollectionParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) WithBody(body any) *TriggerTopologyCollectionParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the trigger topology collection params +func (o *TriggerTopologyCollectionParams) SetBody(body any) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *TriggerTopologyCollectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/trigger_topology_collection_responses.go b/api/om/v1/json/client/om_service/trigger_topology_collection_responses.go new file mode 100644 index 00000000000..a861e63675c --- /dev/null +++ b/api/om/v1/json/client/om_service/trigger_topology_collection_responses.go @@ -0,0 +1,557 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// TriggerTopologyCollectionReader is a Reader for the TriggerTopologyCollection structure. +type TriggerTopologyCollectionReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *TriggerTopologyCollectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewTriggerTopologyCollectionOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewTriggerTopologyCollectionDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewTriggerTopologyCollectionOK creates a TriggerTopologyCollectionOK with default headers values +func NewTriggerTopologyCollectionOK() *TriggerTopologyCollectionOK { + return &TriggerTopologyCollectionOK{} +} + +/* +TriggerTopologyCollectionOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type TriggerTopologyCollectionOK struct { + Payload *TriggerTopologyCollectionOKBody +} + +// IsSuccess returns true when this trigger topology collection Ok response has a 2xx status code +func (o *TriggerTopologyCollectionOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this trigger topology collection Ok response has a 3xx status code +func (o *TriggerTopologyCollectionOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this trigger topology collection Ok response has a 4xx status code +func (o *TriggerTopologyCollectionOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this trigger topology collection Ok response has a 5xx status code +func (o *TriggerTopologyCollectionOK) IsServerError() bool { + return false +} + +// IsCode returns true when this trigger topology collection Ok response a status code equal to that given +func (o *TriggerTopologyCollectionOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the trigger topology collection Ok response +func (o *TriggerTopologyCollectionOK) Code() int { + return 200 +} + +func (o *TriggerTopologyCollectionOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/topology/runs:collect][%d] triggerTopologyCollectionOk %s", 200, payload) +} + +func (o *TriggerTopologyCollectionOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/topology/runs:collect][%d] triggerTopologyCollectionOk %s", 200, payload) +} + +func (o *TriggerTopologyCollectionOK) GetPayload() *TriggerTopologyCollectionOKBody { + return o.Payload +} + +func (o *TriggerTopologyCollectionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(TriggerTopologyCollectionOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewTriggerTopologyCollectionDefault creates a TriggerTopologyCollectionDefault with default headers values +func NewTriggerTopologyCollectionDefault(code int) *TriggerTopologyCollectionDefault { + return &TriggerTopologyCollectionDefault{ + _statusCode: code, + } +} + +/* +TriggerTopologyCollectionDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type TriggerTopologyCollectionDefault struct { + _statusCode int + + Payload *TriggerTopologyCollectionDefaultBody +} + +// IsSuccess returns true when this trigger topology collection default response has a 2xx status code +func (o *TriggerTopologyCollectionDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this trigger topology collection default response has a 3xx status code +func (o *TriggerTopologyCollectionDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this trigger topology collection default response has a 4xx status code +func (o *TriggerTopologyCollectionDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this trigger topology collection default response has a 5xx status code +func (o *TriggerTopologyCollectionDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this trigger topology collection default response a status code equal to that given +func (o *TriggerTopologyCollectionDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the trigger topology collection default response +func (o *TriggerTopologyCollectionDefault) Code() int { + return o._statusCode +} + +func (o *TriggerTopologyCollectionDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/topology/runs:collect][%d] TriggerTopologyCollection default %s", o._statusCode, payload) +} + +func (o *TriggerTopologyCollectionDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/om/topology/runs:collect][%d] TriggerTopologyCollection default %s", o._statusCode, payload) +} + +func (o *TriggerTopologyCollectionDefault) GetPayload() *TriggerTopologyCollectionDefaultBody { + return o.Payload +} + +func (o *TriggerTopologyCollectionDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(TriggerTopologyCollectionDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +TriggerTopologyCollectionDefaultBody trigger topology collection default body +swagger:model TriggerTopologyCollectionDefaultBody +*/ +type TriggerTopologyCollectionDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*TriggerTopologyCollectionDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this trigger topology collection default body +func (o *TriggerTopologyCollectionDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *TriggerTopologyCollectionDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("TriggerTopologyCollection default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("TriggerTopologyCollection default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this trigger topology collection default body based on the context it is used +func (o *TriggerTopologyCollectionDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *TriggerTopologyCollectionDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("TriggerTopologyCollection default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("TriggerTopologyCollection default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerTopologyCollectionDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerTopologyCollectionDefaultBody) UnmarshalBinary(b []byte) error { + var res TriggerTopologyCollectionDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +TriggerTopologyCollectionDefaultBodyDetailsItems0 trigger topology collection default body details items0 +swagger:model TriggerTopologyCollectionDefaultBodyDetailsItems0 +*/ +type TriggerTopologyCollectionDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // trigger topology collection default body details items0 + TriggerTopologyCollectionDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *TriggerTopologyCollectionDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv TriggerTopologyCollectionDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.TriggerTopologyCollectionDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o TriggerTopologyCollectionDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.TriggerTopologyCollectionDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.TriggerTopologyCollectionDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this trigger topology collection default body details items0 +func (o *TriggerTopologyCollectionDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this trigger topology collection default body details items0 based on context it is used +func (o *TriggerTopologyCollectionDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerTopologyCollectionDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerTopologyCollectionDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res TriggerTopologyCollectionDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +TriggerTopologyCollectionOKBody TriggerTopologyCollectionResponse acknowledges a completed collection run. +swagger:model TriggerTopologyCollectionOKBody +*/ +type TriggerTopologyCollectionOKBody struct { + // The run's ID. + RunID string `json:"run_id,omitempty"` + + // RunStatus is how a run ended, for both kinds of run. + // + // Shared by the topology collection pass and the inventory refresh deliberately: the two + // runs differ in what they do, not in how they finish, and two identical enums would + // invite them to drift apart for no reason. + // + // - RUN_STATUS_RUNNING: Still going. Not a terminal status. + // - RUN_STATUS_SUCCESS: Everything it attempted answered. + // - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + // - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing. + // - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + // Enum: ["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"] + Status *string `json:"status,omitempty"` + + // When the run began. + // Format: date-time + StartTime strfmt.DateTime `json:"start_time,omitempty"` +} + +// Validate validates this trigger topology collection OK body +func (o *TriggerTopologyCollectionOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStartTime(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var triggerTopologyCollectionOkBodyTypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["RUN_STATUS_UNSPECIFIED","RUN_STATUS_RUNNING","RUN_STATUS_SUCCESS","RUN_STATUS_PARTIAL","RUN_STATUS_FAILED","RUN_STATUS_SKIPPED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + triggerTopologyCollectionOkBodyTypeStatusPropEnum = append(triggerTopologyCollectionOkBodyTypeStatusPropEnum, v) + } +} + +const ( + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSUNSPECIFIED captures enum value "RUN_STATUS_UNSPECIFIED" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSUNSPECIFIED string = "RUN_STATUS_UNSPECIFIED" + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSRUNNING captures enum value "RUN_STATUS_RUNNING" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSRUNNING string = "RUN_STATUS_RUNNING" + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSSUCCESS captures enum value "RUN_STATUS_SUCCESS" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSSUCCESS string = "RUN_STATUS_SUCCESS" + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSPARTIAL captures enum value "RUN_STATUS_PARTIAL" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSPARTIAL string = "RUN_STATUS_PARTIAL" + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSFAILED captures enum value "RUN_STATUS_FAILED" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSFAILED string = "RUN_STATUS_FAILED" + + // TriggerTopologyCollectionOKBodyStatusRUNSTATUSSKIPPED captures enum value "RUN_STATUS_SKIPPED" + TriggerTopologyCollectionOKBodyStatusRUNSTATUSSKIPPED string = "RUN_STATUS_SKIPPED" +) + +// prop value enum +func (o *TriggerTopologyCollectionOKBody) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, triggerTopologyCollectionOkBodyTypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *TriggerTopologyCollectionOKBody) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("triggerTopologyCollectionOk"+"."+"status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +func (o *TriggerTopologyCollectionOKBody) validateStartTime(formats strfmt.Registry) error { + if swag.IsZero(o.StartTime) { // not required + return nil + } + + if err := validate.FormatOf("triggerTopologyCollectionOk"+"."+"start_time", "body", "date-time", o.StartTime.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this trigger topology collection OK body based on context it is used +func (o *TriggerTopologyCollectionOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *TriggerTopologyCollectionOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *TriggerTopologyCollectionOKBody) UnmarshalBinary(b []byte) error { + var res TriggerTopologyCollectionOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/om_service/update_inventory_config_parameters.go b/api/om/v1/json/client/om_service/update_inventory_config_parameters.go new file mode 100644 index 00000000000..4de0b33e4cb --- /dev/null +++ b/api/om/v1/json/client/om_service/update_inventory_config_parameters.go @@ -0,0 +1,160 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +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" +) + +// NewUpdateInventoryConfigParams creates a new UpdateInventoryConfigParams 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 NewUpdateInventoryConfigParams() *UpdateInventoryConfigParams { + return &UpdateInventoryConfigParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUpdateInventoryConfigParamsWithTimeout creates a new UpdateInventoryConfigParams object +// with the ability to set a timeout on a request. +func NewUpdateInventoryConfigParamsWithTimeout(timeout time.Duration) *UpdateInventoryConfigParams { + return &UpdateInventoryConfigParams{ + timeout: timeout, + } +} + +// NewUpdateInventoryConfigParamsWithContext creates a new UpdateInventoryConfigParams object +// with the ability to set a context for a request. +func NewUpdateInventoryConfigParamsWithContext(ctx context.Context) *UpdateInventoryConfigParams { + return &UpdateInventoryConfigParams{ + Context: ctx, + } +} + +// NewUpdateInventoryConfigParamsWithHTTPClient creates a new UpdateInventoryConfigParams object +// with the ability to set a custom HTTPClient for a request. +func NewUpdateInventoryConfigParamsWithHTTPClient(client *http.Client) *UpdateInventoryConfigParams { + return &UpdateInventoryConfigParams{ + HTTPClient: client, + } +} + +/* +UpdateInventoryConfigParams contains all the parameters to send to the API endpoint + + for the update inventory config operation. + + Typically these are written to a http.Request. +*/ +type UpdateInventoryConfigParams struct { + /* Values. + + The fields to change, as `{key: value}`. + + A map of arbitrary JSON rather than named fields, because the app owns which + fields exist and what they are typed as; mirroring them here would mean a proto + change and a `make gen` every time it grows a setting. The app validates and + rejects the batch as a whole. + + Bound to the HTTP body directly (`body: "values"`, not `body: "*"`), so the request + this endpoint takes is the same object it forwards. The alternative wraps it as + `{"values": {...}}`, which would make the proxy's shape differ from the shape of the + thing being proxied for no gain to anyone reading either. + + A `Struct` carries no field rules, so "name at least one field" is enforced in the + handler rather than declared here -- the only precondition on this surface that a + generated validator does not express. + */ + Values any + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the update inventory config params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateInventoryConfigParams) WithDefaults() *UpdateInventoryConfigParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the update inventory config params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateInventoryConfigParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the update inventory config params +func (o *UpdateInventoryConfigParams) WithTimeout(timeout time.Duration) *UpdateInventoryConfigParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the update inventory config params +func (o *UpdateInventoryConfigParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the update inventory config params +func (o *UpdateInventoryConfigParams) WithContext(ctx context.Context) *UpdateInventoryConfigParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the update inventory config params +func (o *UpdateInventoryConfigParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the update inventory config params +func (o *UpdateInventoryConfigParams) WithHTTPClient(client *http.Client) *UpdateInventoryConfigParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the update inventory config params +func (o *UpdateInventoryConfigParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithValues adds the values to the update inventory config params +func (o *UpdateInventoryConfigParams) WithValues(values any) *UpdateInventoryConfigParams { + o.SetValues(values) + return o +} + +// SetValues adds the values to the update inventory config params +func (o *UpdateInventoryConfigParams) SetValues(values any) { + o.Values = values +} + +// WriteToRequest writes these params to a swagger request +func (o *UpdateInventoryConfigParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Values != nil { + if err := r.SetBodyParam(o.Values); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/om/v1/json/client/om_service/update_inventory_config_responses.go b/api/om/v1/json/client/om_service/update_inventory_config_responses.go new file mode 100644 index 00000000000..4affc70ce59 --- /dev/null +++ b/api/om/v1/json/client/om_service/update_inventory_config_responses.go @@ -0,0 +1,661 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package om_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// UpdateInventoryConfigReader is a Reader for the UpdateInventoryConfig structure. +type UpdateInventoryConfigReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UpdateInventoryConfigReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewUpdateInventoryConfigOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUpdateInventoryConfigDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUpdateInventoryConfigOK creates a UpdateInventoryConfigOK with default headers values +func NewUpdateInventoryConfigOK() *UpdateInventoryConfigOK { + return &UpdateInventoryConfigOK{} +} + +/* +UpdateInventoryConfigOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type UpdateInventoryConfigOK struct { + Payload *UpdateInventoryConfigOKBody +} + +// IsSuccess returns true when this update inventory config Ok response has a 2xx status code +func (o *UpdateInventoryConfigOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this update inventory config Ok response has a 3xx status code +func (o *UpdateInventoryConfigOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this update inventory config Ok response has a 4xx status code +func (o *UpdateInventoryConfigOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this update inventory config Ok response has a 5xx status code +func (o *UpdateInventoryConfigOK) IsServerError() bool { + return false +} + +// IsCode returns true when this update inventory config Ok response a status code equal to that given +func (o *UpdateInventoryConfigOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the update inventory config Ok response +func (o *UpdateInventoryConfigOK) Code() int { + return 200 +} + +func (o *UpdateInventoryConfigOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/om/inventory/config][%d] updateInventoryConfigOk %s", 200, payload) +} + +func (o *UpdateInventoryConfigOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/om/inventory/config][%d] updateInventoryConfigOk %s", 200, payload) +} + +func (o *UpdateInventoryConfigOK) GetPayload() *UpdateInventoryConfigOKBody { + return o.Payload +} + +func (o *UpdateInventoryConfigOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateInventoryConfigOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewUpdateInventoryConfigDefault creates a UpdateInventoryConfigDefault with default headers values +func NewUpdateInventoryConfigDefault(code int) *UpdateInventoryConfigDefault { + return &UpdateInventoryConfigDefault{ + _statusCode: code, + } +} + +/* +UpdateInventoryConfigDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type UpdateInventoryConfigDefault struct { + _statusCode int + + Payload *UpdateInventoryConfigDefaultBody +} + +// IsSuccess returns true when this update inventory config default response has a 2xx status code +func (o *UpdateInventoryConfigDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this update inventory config default response has a 3xx status code +func (o *UpdateInventoryConfigDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this update inventory config default response has a 4xx status code +func (o *UpdateInventoryConfigDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this update inventory config default response has a 5xx status code +func (o *UpdateInventoryConfigDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this update inventory config default response a status code equal to that given +func (o *UpdateInventoryConfigDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the update inventory config default response +func (o *UpdateInventoryConfigDefault) Code() int { + return o._statusCode +} + +func (o *UpdateInventoryConfigDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/om/inventory/config][%d] UpdateInventoryConfig default %s", o._statusCode, payload) +} + +func (o *UpdateInventoryConfigDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/om/inventory/config][%d] UpdateInventoryConfig default %s", o._statusCode, payload) +} + +func (o *UpdateInventoryConfigDefault) GetPayload() *UpdateInventoryConfigDefaultBody { + return o.Payload +} + +func (o *UpdateInventoryConfigDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateInventoryConfigDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +UpdateInventoryConfigDefaultBody update inventory config default body +swagger:model UpdateInventoryConfigDefaultBody +*/ +type UpdateInventoryConfigDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*UpdateInventoryConfigDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this update inventory config default body +func (o *UpdateInventoryConfigDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateInventoryConfigDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("UpdateInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update inventory config default body based on the context it is used +func (o *UpdateInventoryConfigDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateInventoryConfigDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("UpdateInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateInventoryConfig default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateInventoryConfigDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateInventoryConfigDefaultBody) UnmarshalBinary(b []byte) error { + var res UpdateInventoryConfigDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateInventoryConfigDefaultBodyDetailsItems0 update inventory config default body details items0 +swagger:model UpdateInventoryConfigDefaultBodyDetailsItems0 +*/ +type UpdateInventoryConfigDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // update inventory config default body details items0 + UpdateInventoryConfigDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *UpdateInventoryConfigDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv UpdateInventoryConfigDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.UpdateInventoryConfigDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o UpdateInventoryConfigDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.UpdateInventoryConfigDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.UpdateInventoryConfigDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this update inventory config default body details items0 +func (o *UpdateInventoryConfigDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update inventory config default body details items0 based on context it is used +func (o *UpdateInventoryConfigDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateInventoryConfigDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateInventoryConfigDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res UpdateInventoryConfigDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateInventoryConfigOKBody UpdateInventoryConfigResponse returns the configuration as it now stands. +swagger:model UpdateInventoryConfigOKBody +*/ +type UpdateInventoryConfigOKBody struct { + // Every field, not only the ones the request named. + // + // The whole resource, because an Update answers with the resource. It is also the only + // honest answer for a nested write: overriding a parent object changes what its + // children effectively resolve to, and a response scoped to the submitted keys would + // report the parent and leave a stale child beside it. + Settings []*UpdateInventoryConfigOKBodySettingsItems0 `json:"settings"` +} + +// Validate validates this update inventory config OK body +func (o *UpdateInventoryConfigOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateSettings(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateInventoryConfigOKBody) validateSettings(formats strfmt.Registry) error { + if swag.IsZero(o.Settings) { // not required + return nil + } + + for i := 0; i < len(o.Settings); i++ { + if swag.IsZero(o.Settings[i]) { // not required + continue + } + + if o.Settings[i] != nil { + if err := o.Settings[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update inventory config OK body based on the context it is used +func (o *UpdateInventoryConfigOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateSettings(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateInventoryConfigOKBody) contextValidateSettings(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Settings); i++ { + if o.Settings[i] != nil { + + if swag.IsZero(o.Settings[i]) { // not required + return nil + } + + if err := o.Settings[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateInventoryConfigOk" + "." + "settings" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateInventoryConfigOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateInventoryConfigOKBody) UnmarshalBinary(b []byte) error { + var res UpdateInventoryConfigOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateInventoryConfigOKBodySettingsItems0 InventorySetting is one of the inventory app's configuration fields. +swagger:model UpdateInventoryConfigOKBodySettingsItems0 +*/ +type UpdateInventoryConfigOKBodySettingsItems0 struct { + // The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every. + Key string `json:"key,omitempty"` + + // The value in effect. + Value any `json:"value,omitempty"` + + // What it would be with no override. + DefaultValue any `json:"default_value,omitempty"` + + // The field's type, for rendering an input. A string because the app's own schema + // names it, so this contract does not get to enumerate the possibilities. + Type string `json:"type,omitempty"` + + // SettingReload is how a configuration field may be overridden, if at all. + // + // Mirrors the app's own three-valued classification rather than collapsing it to + // editable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a + // whole-object write while its children accept one, so a form that read it as + // "not overridable" would refuse to edit a leaf the API would have accepted. + // + // The distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable + // promises a change the API cannot deliver. + // + // - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh. + // - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written + // whole. + // - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources. + // Enum: ["SETTING_RELOAD_UNSPECIFIED","SETTING_RELOAD_HOT","SETTING_RELOAD_NESTED_ONLY","SETTING_RELOAD_NOT_OVERRIDABLE"] + Reload *string `json:"reload,omitempty"` + + // Whether an override is in effect, which is how "why is it set to this" is + // answerable without also reading the deployment's configuration file. + HasOverride bool `json:"has_override,omitempty"` + + // Whether to hide it behind an "advanced" disclosure. + IsAdvanced bool `json:"is_advanced,omitempty"` + + // The field's documentation, where it has any. + Description *string `json:"description,omitempty"` +} + +// Validate validates this update inventory config OK body settings items0 +func (o *UpdateInventoryConfigOKBodySettingsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateReload(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var updateInventoryConfigOkBodySettingsItems0TypeReloadPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SETTING_RELOAD_UNSPECIFIED","SETTING_RELOAD_HOT","SETTING_RELOAD_NESTED_ONLY","SETTING_RELOAD_NOT_OVERRIDABLE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + updateInventoryConfigOkBodySettingsItems0TypeReloadPropEnum = append(updateInventoryConfigOkBodySettingsItems0TypeReloadPropEnum, v) + } +} + +const ( + + // UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADUNSPECIFIED captures enum value "SETTING_RELOAD_UNSPECIFIED" + UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADUNSPECIFIED string = "SETTING_RELOAD_UNSPECIFIED" + + // UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADHOT captures enum value "SETTING_RELOAD_HOT" + UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADHOT string = "SETTING_RELOAD_HOT" + + // UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNESTEDONLY captures enum value "SETTING_RELOAD_NESTED_ONLY" + UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNESTEDONLY string = "SETTING_RELOAD_NESTED_ONLY" + + // UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNOTOVERRIDABLE captures enum value "SETTING_RELOAD_NOT_OVERRIDABLE" + UpdateInventoryConfigOKBodySettingsItems0ReloadSETTINGRELOADNOTOVERRIDABLE string = "SETTING_RELOAD_NOT_OVERRIDABLE" +) + +// prop value enum +func (o *UpdateInventoryConfigOKBodySettingsItems0) validateReloadEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, updateInventoryConfigOkBodySettingsItems0TypeReloadPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *UpdateInventoryConfigOKBodySettingsItems0) validateReload(formats strfmt.Registry) error { + if swag.IsZero(o.Reload) { // not required + return nil + } + + // value enum + if err := o.validateReloadEnum("reload", "body", *o.Reload); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this update inventory config OK body settings items0 based on context it is used +func (o *UpdateInventoryConfigOKBodySettingsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateInventoryConfigOKBodySettingsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateInventoryConfigOKBodySettingsItems0) UnmarshalBinary(b []byte) error { + var res UpdateInventoryConfigOKBodySettingsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/om/v1/json/client/pmm_om_api_client.go b/api/om/v1/json/client/pmm_om_api_client.go new file mode 100644 index 00000000000..b0645ed9f88 --- /dev/null +++ b/api/om/v1/json/client/pmm_om_api_client.go @@ -0,0 +1,109 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package client + +import ( + "github.com/go-openapi/runtime" + httptransport "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/percona/pmm/api/om/v1/json/client/om_service" +) + +// Default PMM OM API HTTP client. +var Default = NewHTTPClient(nil) + +const ( + // DefaultHost is the default Host + // found in Meta (info) section of spec file + DefaultHost string = "localhost" + // DefaultBasePath is the default BasePath + // found in Meta (info) section of spec file + DefaultBasePath string = "/" +) + +// DefaultSchemes are the default schemes found in Meta (info) section of spec file +var DefaultSchemes = []string{"http", "https"} + +// NewHTTPClient creates a new PMM OM API HTTP client. +func NewHTTPClient(formats strfmt.Registry) *PMMOMAPI { + return NewHTTPClientWithConfig(formats, nil) +} + +// NewHTTPClientWithConfig creates a new PMM OM API HTTP client, +// using a customizable transport config. +func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *PMMOMAPI { + // ensure nullable parameters have default + if cfg == nil { + cfg = DefaultTransportConfig() + } + + // create transport and client + transport := httptransport.New(cfg.Host, cfg.BasePath, cfg.Schemes) + return New(transport, formats) +} + +// New creates a new PMM OM API client +func New(transport runtime.ClientTransport, formats strfmt.Registry) *PMMOMAPI { + // ensure nullable parameters have default + if formats == nil { + formats = strfmt.Default + } + + cli := new(PMMOMAPI) + cli.Transport = transport + cli.OMService = om_service.New(transport, formats) + return cli +} + +// DefaultTransportConfig creates a TransportConfig with the +// default settings taken from the meta section of the spec file. +func DefaultTransportConfig() *TransportConfig { + return &TransportConfig{ + Host: DefaultHost, + BasePath: DefaultBasePath, + Schemes: DefaultSchemes, + } +} + +// TransportConfig contains the transport related info, +// found in the meta section of the spec file. +type TransportConfig struct { + Host string + BasePath string + Schemes []string +} + +// WithHost overrides the default host, +// provided by the meta section of the spec file. +func (cfg *TransportConfig) WithHost(host string) *TransportConfig { + cfg.Host = host + return cfg +} + +// WithBasePath overrides the default basePath, +// provided by the meta section of the spec file. +func (cfg *TransportConfig) WithBasePath(basePath string) *TransportConfig { + cfg.BasePath = basePath + return cfg +} + +// WithSchemes overrides the default schemes, +// provided by the meta section of the spec file. +func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig { + cfg.Schemes = schemes + return cfg +} + +// PMMOMAPI is a client for PMM OM API +type PMMOMAPI struct { + OMService om_service.ClientService + + Transport runtime.ClientTransport +} + +// SetTransport changes the transport on the client and all its subresources +func (c *PMMOMAPI) SetTransport(transport runtime.ClientTransport) { + c.Transport = transport + c.OMService.SetTransport(transport) +} diff --git a/api/om/v1/json/header.json b/api/om/v1/json/header.json new file mode 100644 index 00000000000..6f8b111cc0f --- /dev/null +++ b/api/om/v1/json/header.json @@ -0,0 +1,11 @@ +{ + "swagger": "2.0", + "info": { + "title": "PMM OM API", + "version": "v1" + }, + "schemes": [ + "https", + "http" + ] +} diff --git a/api/om/v1/json/v1.json b/api/om/v1/json/v1.json new file mode 100644 index 00000000000..3d338eb5099 --- /dev/null +++ b/api/om/v1/json/v1.json @@ -0,0 +1,2964 @@ +{ + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "schemes": [ + "https", + "http" + ], + "swagger": "2.0", + "info": { + "title": "PMM OM API", + "version": "v1" + }, + "paths": { + "/v1/om/inventory/config": { + "get": { + "description": "Returns every configuration field of the inventory app, its effective value, and whether an override is in effect.", + "tags": [ + "OmService" + ], + "summary": "Get the inventory configuration", + "operationId": "GetInventoryConfig", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryConfigResponse returns the inventory app's configuration.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, whether or not it is overridden.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "put": { + "description": "Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted.", + "tags": [ + "OmService" + ], + "summary": "Change the inventory configuration", + "operationId": "UpdateInventoryConfig", + "parameters": [ + { + "description": "The fields to change, as `{key: value}`.\n\nA map of arbitrary JSON rather than named fields, because the app owns which\nfields exist and what they are typed as; mirroring them here would mean a proto\nchange and a `make gen` every time it grows a setting. The app validates and\nrejects the batch as a whole.\n\nBound to the HTTP body directly (`body: \"values\"`, not `body: \"*\"`), so the request\nthis endpoint takes is the same object it forwards. The alternative wraps it as\n`{\"values\": {...}}`, which would make the proxy's shape differ from the shape of the\nthing being proxied for no gain to anyone reading either.\n\nA `Struct` carries no field rules, so \"name at least one field\" is enforced in the\nhandler rather than declared here -- the only precondition on this surface that a\ngenerated validator does not express.", + "name": "values", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "UpdateInventoryConfigResponse returns the configuration as it now stands.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, not only the ones the request named.\n\nThe whole resource, because an Update answers with the resource. It is also the only\nhonest answer for a nested write: overriding a parent object changes what its\nchildren effectively resolve to, and a response scoped to the submitted keys would\nreport the parent and leave a stale child beside it.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/config/overrides/{key}": { + "delete": { + "description": "Removes the override for one field so it returns to whatever the deployment configured. Idempotent.", + "tags": [ + "OmService" + ], + "summary": "Revert an inventory configuration field", + "operationId": "DeleteInventoryConfigOverride", + "parameters": [ + { + "type": "string", + "description": "The field whose override to remove, putting it back to its deployed value. Also the\nresource ID within the `overrides` collection.", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryConfigOverrideResponse acknowledges the revert.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts": { + "get": { + "description": "Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are.", + "tags": [ + "OmService" + ], + "summary": "List inventory hosts", + "operationId": "ListInventoryHosts", + "parameters": [ + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) carry a registered service.\nUnset returns both, which is the ordinary listing.", + "name": "has_service", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only hosts currently failing.", + "name": "failing", + "in": "query" + }, + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) have an executor to run a probe\non. Not a client name: the app filters on whether one is matched at all, and\n\"which machines can nothing be dispatched to\" is the question worth asking.", + "name": "executor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryHostsResponse returns the hosts OM knows about.", + "type": "object", + "properties": { + "hosts": { + "description": "The hosts.", + "type": "array", + "items": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts/{node_id}": { + "get": { + "description": "Returns one host by PMM node ID, with the services on it.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory host", + "operationId": "GetInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryHostResponse returns one host.", + "type": "object", + "properties": { + "host": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory host", + "operationId": "DeleteInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryHostResponse acknowledges forgetting a host.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs": { + "get": { + "description": "Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host.", + "tags": [ + "OmService" + ], + "summary": "List inventory refreshes", + "operationId": "ListInventoryRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many to return, newest first. Defaults to 20, capped at 100.", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive lower bound on start_time. Unset means no lower bound.\n\nApplied before limit, so a week window is the newest runs *in that week*,\nnot the newest overall then those that happen to fall in it.", + "name": "since", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive upper bound on start_time. Unset means no upper bound.", + "name": "until", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryRunsResponse returns the refresh history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs/{run_id}": { + "get": { + "description": "Returns one refresh by ID, with what it saw and which hosts it covered.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory refresh", + "operationId": "GetInventoryRun", + "parameters": [ + { + "type": "string", + "description": "The run's ID.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryRunResponse returns one refresh, with the rows behind its counters.", + "type": "object", + "properties": { + "run": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + }, + "x-order": 0 + }, + "entities": { + "description": "What it attempted, one entry per entity.\n\nOnly on the detail response, never on the list: a refresh of a real estate has a\nrow per service, and a history of twenty-five would carry the lot to render a\npage that shows one at a time.", + "type": "array", + "items": { + "description": "InventoryRunEntity is one host a refresh attempted, and what came of it.\n\nHost-oriented, because a refresh attempts hosts. A flat list of services - which\nthis was - cannot show a machine carrying a PMM client and no database, however\nmany times it is probed, and that machine is the case OM most exists to describe:\nit is where a database can be installed.\n\nOne dispatch covers every service on a host, so the host owns the timing and the\nfailure and its services carry only what is theirs. Previously the duration was\ncopied onto each service, which read as several measurements when it was one.\n\nDeliberately outcomes and not observations. What the probe *found* lives on the\nestate, where it is upserted and stays current; a receipt that also carried the\nattributes would be a second copy that goes stale the moment the next refresh runs.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID, the key OM holds this host under.", + "type": "string", + "x-order": 0 + }, + "host_name": { + "description": "The node's registered name.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "executor_host": { + "description": "The client its probe ran on. Unset when none matched.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "resolution": { + "description": "ExecutorResolution is how a host was matched to the client its probe ran on.\n\nORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact\nabout onboarding. NAME and ADDRESS record *which* of the two joins matched, because a\nhost reachable only by address is a different estate problem from one matched by name.\n\n - EXECUTOR_RESOLUTION_NAME: Matched on the node's registered name.\n - EXECUTOR_RESOLUTION_ADDRESS: Matched on the node's address.\n - EXECUTOR_RESOLUTION_ORPHANED: Not matched, so nothing was dispatched.", + "type": "string", + "default": "EXECUTOR_RESOLUTION_UNSPECIFIED", + "enum": [ + "EXECUTOR_RESOLUTION_UNSPECIFIED", + "EXECUTOR_RESOLUTION_NAME", + "EXECUTOR_RESOLUTION_ADDRESS", + "EXECUTOR_RESOLUTION_ORPHANED" + ], + "x-order": 3 + }, + "answered": { + "description": "Whether the *host* answered. A different question from whether its services did:\na host with no database answers perfectly well and has no services at all.", + "type": "boolean", + "x-order": 4 + }, + "duration_seconds": { + "description": "The host's wall clock, dispatch to collected output.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 5 + }, + "error": { + "description": "The host-level failure, when its probe failed.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryRunEntityService is one service on a host, as a refresh saw it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID, when OM could key one.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "service_name": { + "description": "Its name, so a reader is not left joining UUIDs by hand.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "answered": { + "description": "Whether the host returned a usable record for it.", + "type": "boolean", + "x-order": 2 + }, + "error": { + "description": "Why it did not, when it did not.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + } + }, + "x-order": 7 + }, + "task_history_id": { + "description": "The task history id of the dispatch, so a reader can open the probe's own log.\nUnset when the dispatch never got one.", + "type": "string", + "format": "int64", + "x-nullable": true, + "x-order": 8 + } + } + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs:trigger": { + "post": { + "description": "Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them.", + "tags": [ + "OmService" + ], + "summary": "Refresh the inventory", + "operationId": "TriggerInventoryRefresh", + "parameters": [ + { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "type": "object", + "properties": { + "node_ids": { + "description": "The hosts to refresh, by PMM node ID. Empty refreshes the whole estate.\n\nPlural on purpose: PMM's node ID is also OM's key, so ids pass through\nuntranslated, and one host is a list of one. A surface taking a single id where\nthe app takes a list would be a translation step in disguise.\n\nBounded because a refresh dispatches a Nomad job per host: the empty list already\nmeans \"the whole estate\", so a caller naming hosts individually is naming a few,\nand an unbounded list is only reachable by accident. An empty string is rejected\nrather than forwarded, where it would read as a node ID that matches nothing.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerInventoryRefreshResponse acknowledges an accepted refresh.\n\nAccepted, not finished. A refresh dispatches a Nomad job per host and takes tens of\nseconds, unlike PMM's own collection pass, which never probes and completes in\nmilliseconds. Two triggers that different must not look alike to a caller.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, to follow with GetInventoryRun.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "scope": { + "description": "The hosts it will refresh. Empty means the whole estate.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 3 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services": { + "get": { + "description": "Returns every MongoDB service the inventory app has a row for, with what each last reported and when.", + "tags": [ + "OmService" + ], + "summary": "List inventory services", + "operationId": "ListInventoryServices", + "parameters": [ + { + "type": "string", + "description": "When set, return only the services on this host.", + "name": "node_id", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only services currently failing.", + "name": "failing", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryServicesResponse returns the services OM knows about, flat.", + "type": "object", + "properties": { + "services": { + "description": "The services.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services/{service_id}": { + "get": { + "description": "Returns one service by PMM service ID.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory service", + "operationId": "GetInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryServiceResponse returns one service.", + "type": "object", + "properties": { + "service": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory service", + "operationId": "DeleteInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryServiceResponse acknowledges forgetting a service.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology": { + "get": { + "description": "Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load.", + "tags": [ + "OmService" + ], + "summary": "Get the MongoDB topology", + "operationId": "GetTopology", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyResponse is the whole topology document plus the provenance of the run\nbehind it.", + "type": "object", + "properties": { + "snapshot": { + "description": "Snapshot carries the provenance every snapshot-backed response repeats.", + "type": "object", + "properties": { + "generated_at": { + "description": "When the document was assembled.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "observed_at": { + "description": "The newest observation in it, unset when nothing was observed at all.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "stale": { + "description": "Whether the document is older than the staleness grace period. Also true, with\nobserved_at unset and every environment empty, on a genuinely cold estate -- no\ncollection has completed anywhere yet. That is a startup state, not a statement that\nthe estate itself is empty; a reader should render it as \"collecting\" rather than as\nan empty result.", + "type": "boolean", + "x-order": 2 + }, + "schema_version": { + "description": "The document schema version.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "run_id": { + "description": "The collection run that produced it.", + "type": "string", + "x-order": 4 + } + }, + "x-order": 0 + }, + "origin_node": { + "description": "The PMM node the document was assembled on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "source_queries": { + "description": "The VictoriaMetrics queries the document was derived from.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 2 + }, + "summary": { + "description": "Summary carries the fleet-level counts, so a caller need not re-derive them.", + "type": "object", + "properties": { + "environments": { + "description": "Environments in the document.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "clusters": { + "description": "Clusters across all of them.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "total_services": { + "description": "Services in the document.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "up_services": { + "description": "Services the exporter reached.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "down_services": { + "description": "Services it did not.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "process_role_counts": { + "description": "Service counts per process role, keyed by the ProcessRole enum's name.", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + }, + "x-order": 5 + } + }, + "x-order": 3 + }, + "environments": { + "description": "The estate, grouped environment then cluster.", + "type": "array", + "items": { + "description": "Environment represents one monitoring environment.", + "type": "object", + "properties": { + "env_name": { + "description": "Environment label, unset when its services carry none.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "clusters": { + "description": "Its clusters, ordered by name.", + "type": "array", + "items": { + "description": "Cluster represents one grouped service inventory: every service PMM's inventory\nlabelled with the same (environment, cluster) or (environment, replication_set), not a\nreconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat\nlist of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for\nthe one thing inferred about that shape, and the package comment for what is\ndeliberately not.", + "type": "object", + "properties": { + "name": { + "description": "Cluster label, unset when its services carry none. Not a stable identity: two\nclusters can share this label (a second generation of a sandbox reusing a name), and\n`id` is what tells them apart.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "services": { + "description": "Its services, ordered by name.", + "type": "array", + "items": { + "description": "TopologyService represents one monitored MongoDB service as the topology document\nrecords it.\n\nTwo conventions for \"no value\", and they differ on purpose. cpu_usage_percent and\nconnections_free_percent are -1 when not measured, never absent and never 0, because\nzero CPU is a legitimate reading and a numeric column must keep \"idle\" and \"unknown\"\napart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is\nabsent when they do not apply -- a router and a standalone have no replica-set oplog --\nwhich is a different statement from -1's \"we could not measure it\".\n\nThe optional fields were wrapper messages until the REST contract was checked:\nprotoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema\nand the generated Go client both collapsed to a value type and lost the distinction\nentirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting\nthe key rather than emitting an explicit null.", + "type": "object", + "properties": { + "service_name": { + "description": "Service name as PMM inventory registered it.", + "type": "string", + "x-order": 0 + }, + "host": { + "description": "Node the service runs on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "endpoint": { + "description": "host:port as the replica set itself addresses the member.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "service_id": { + "description": "PMM's service ID. The join key against VictoriaMetrics.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "service_type": { + "description": "Always \"mongodb\" today.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "version": { + "description": "Running server version.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "vendor": { + "description": "MongoDB or Percona.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "edition": { + "description": "Community or Enterprise.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "replication_set": { + "description": "Replica set, or unset for a router or a standalone.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "state": { + "description": "PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "status": { + "description": "ServiceStatus is whether the exporter reached a service.\n\nTwo values and no third: this is the exporter's reachability, not the server's health.\n\"we did not look\" is UNSPECIFIED, which the collector never emits.\n\n - SERVICE_STATUS_UP: The exporter reached the service.\n - SERVICE_STATUS_DOWN: It did not.", + "type": "string", + "default": "SERVICE_STATUS_UNSPECIFIED", + "enum": [ + "SERVICE_STATUS_UNSPECIFIED", + "SERVICE_STATUS_UP", + "SERVICE_STATUS_DOWN" + ], + "x-order": 10 + }, + "cpu_usage_percent": { + "description": "CPU percentage, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 11 + }, + "connections_free_percent": { + "description": "Percentage of free connections, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 12 + }, + "process_role": { + "description": "ProcessRole is what a mongod or mongos is doing in the deployment.\n\nNot the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This\nis the role the process was started in, which is a property of the deployment's shape.\n\n - PROCESS_ROLE_MONGOD: A standalone or replica-set member with no sharding role.\n - PROCESS_ROLE_MONGOS: A router.\n - PROCESS_ROLE_CONFIGSVR: A config-server member.\n - PROCESS_ROLE_SHARDSVR: A shard member.", + "type": "string", + "default": "PROCESS_ROLE_UNSPECIFIED", + "enum": [ + "PROCESS_ROLE_UNSPECIFIED", + "PROCESS_ROLE_MONGOD", + "PROCESS_ROLE_MONGOS", + "PROCESS_ROLE_CONFIGSVR", + "PROCESS_ROLE_SHARDSVR" + ], + "x-order": 13 + }, + "replication_lag_seconds": { + "description": "Seconds this member trails the primary; unset where there is no primary to trail.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 14 + }, + "oplog_window_seconds": { + "description": "Seconds of history the oplog holds; unset where there is no replica-set oplog.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 15 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from `version` is the upgraded-but-not-restarted case. Only\nan on-host probe can see it, so this is unset wherever one has not run.", + "type": "string", + "x-nullable": true, + "x-order": 16 + }, + "config_path": { + "description": "The configuration file the running server read. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 17 + }, + "argv": { + "description": "The command line the running server was started with. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 18 + }, + "observed_at": { + "description": "When the newest *live* field on this row was observed, unset when every field on it\nis either absent or not time-bounded (inventory only, no metric and no probe ever\nseen). This is the row's own provenance -- Snapshot.observed_at is the newest across\nthe whole estate, which cannot tell \"this row is current\" from \"this row is the one\nthat made the snapshot look fresh\". A field's own MergedField.ObservedAt exists\ninternally; this is the first one exposed on the wire.", + "type": "string", + "format": "date-time", + "x-nullable": true, + "x-order": 19 + } + } + }, + "x-order": 1 + }, + "id": { + "description": "Opaque, server-issued, stable across a rename of `name`. Derived from\n(environment, cluster, replication_set) so the same estate group always gets the\nsame id -- clients must not parse it or assume a derivation.", + "type": "string", + "x-order": 2 + }, + "type": { + "description": "ClusterType is the shape buildDocument inferred for one grouped service inventory.\n\nInferred, not reconstructed: this package groups services by label and infers a shape\nfrom what is in the group, it does not walk a replica set's own config to build a\nmember list. See the package comment.\n\n - CLUSTER_TYPE_REPLICA_SET: Exactly one replication_set label under this cluster, and no mongos.\n - CLUSTER_TYPE_SHARDED: A mongos is present, or more than one replication_set label shares this cluster\nlabel.\n - CLUSTER_TYPE_STANDALONE: Neither: services grouped under one label with no replica-set identity at all.", + "type": "string", + "default": "CLUSTER_TYPE_UNSPECIFIED", + "enum": [ + "CLUSTER_TYPE_UNSPECIFIED", + "CLUSTER_TYPE_REPLICA_SET", + "CLUSTER_TYPE_SHARDED", + "CLUSTER_TYPE_STANDALONE" + ], + "x-order": 3 + }, + "health": { + "description": "ClusterHealth is a reserved verdict slot, not yet computed by anything.\n\nUNSPECIFIED is the only value that exists today. It is declared now, alongside the\napplyHealth seam in the collector, so a rollup status has a field to land in without a\nlater schema change -- see the om package's health-pipeline comment.", + "type": "string", + "default": "CLUSTER_HEALTH_UNSPECIFIED", + "enum": [ + "CLUSTER_HEALTH_UNSPECIFIED" + ], + "x-order": 4 + } + } + }, + "x-order": 1 + } + } + }, + "x-order": 4 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs": { + "get": { + "description": "Returns the recorded collection runs, newest first, with what each one saw and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "List collection runs", + "operationId": "ListTopologyRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many runs to return, newest first. Defaults to 25, capped at 100.", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListTopologyRunsResponse returns the run history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs/{run_id}": { + "get": { + "description": "Returns one recorded collection run, with what it saw, how each source answered, and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "Get a collection run", + "operationId": "GetTopologyRun", + "parameters": [ + { + "type": "string", + "description": "The run to return.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyRunResponse returns one collection run.", + "type": "object", + "properties": { + "run": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs:collect": { + "post": { + "description": "Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run.", + "tags": [ + "OmService" + ], + "summary": "Trigger a collection run", + "operationId": "TriggerTopologyCollection", + "parameters": [ + { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerTopologyCollectionResponse acknowledges a completed collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + } + }, + "tags": [ + { + "description": "OmService provides the OpenManager topology and health API.", + "name": "OmService" + } + ] +} \ No newline at end of file diff --git a/api/om/v1/om.pb.go b/api/om/v1/om.pb.go new file mode 100644 index 00000000000..3c00258be19 --- /dev/null +++ b/api/om/v1/om.pb.go @@ -0,0 +1,4738 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: om/v1/om.proto + +package omv1 + +import ( + reflect "reflect" + sync "sync" + unsafe "unsafe" + + _ "github.com/envoyproxy/protoc-gen-validate/validate" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + _ "google.golang.org/protobuf/types/known/wrapperspb" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// ServiceStatus is whether the exporter reached a service. +// +// Two values and no third: this is the exporter's reachability, not the server's health. +// "we did not look" is UNSPECIFIED, which the collector never emits. +type ServiceStatus int32 + +const ( + ServiceStatus_SERVICE_STATUS_UNSPECIFIED ServiceStatus = 0 + // The exporter reached the service. + ServiceStatus_SERVICE_STATUS_UP ServiceStatus = 1 + // It did not. + ServiceStatus_SERVICE_STATUS_DOWN ServiceStatus = 2 +) + +// Enum value maps for ServiceStatus. +var ( + ServiceStatus_name = map[int32]string{ + 0: "SERVICE_STATUS_UNSPECIFIED", + 1: "SERVICE_STATUS_UP", + 2: "SERVICE_STATUS_DOWN", + } + ServiceStatus_value = map[string]int32{ + "SERVICE_STATUS_UNSPECIFIED": 0, + "SERVICE_STATUS_UP": 1, + "SERVICE_STATUS_DOWN": 2, + } +) + +func (x ServiceStatus) Enum() *ServiceStatus { + p := new(ServiceStatus) + *p = x + return p +} + +func (x ServiceStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServiceStatus) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[0].Descriptor() +} + +func (ServiceStatus) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[0] +} + +func (x ServiceStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServiceStatus.Descriptor instead. +func (ServiceStatus) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{0} +} + +// ProcessRole is what a mongod or mongos is doing in the deployment. +// +// Not the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This +// is the role the process was started in, which is a property of the deployment's shape. +type ProcessRole int32 + +const ( + ProcessRole_PROCESS_ROLE_UNSPECIFIED ProcessRole = 0 + // A standalone or replica-set member with no sharding role. + ProcessRole_PROCESS_ROLE_MONGOD ProcessRole = 1 + // A router. + ProcessRole_PROCESS_ROLE_MONGOS ProcessRole = 2 + // A config-server member. + ProcessRole_PROCESS_ROLE_CONFIGSVR ProcessRole = 3 + // A shard member. + ProcessRole_PROCESS_ROLE_SHARDSVR ProcessRole = 4 +) + +// Enum value maps for ProcessRole. +var ( + ProcessRole_name = map[int32]string{ + 0: "PROCESS_ROLE_UNSPECIFIED", + 1: "PROCESS_ROLE_MONGOD", + 2: "PROCESS_ROLE_MONGOS", + 3: "PROCESS_ROLE_CONFIGSVR", + 4: "PROCESS_ROLE_SHARDSVR", + } + ProcessRole_value = map[string]int32{ + "PROCESS_ROLE_UNSPECIFIED": 0, + "PROCESS_ROLE_MONGOD": 1, + "PROCESS_ROLE_MONGOS": 2, + "PROCESS_ROLE_CONFIGSVR": 3, + "PROCESS_ROLE_SHARDSVR": 4, + } +) + +func (x ProcessRole) Enum() *ProcessRole { + p := new(ProcessRole) + *p = x + return p +} + +func (x ProcessRole) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ProcessRole) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[1].Descriptor() +} + +func (ProcessRole) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[1] +} + +func (x ProcessRole) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ProcessRole.Descriptor instead. +func (ProcessRole) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{1} +} + +// RunStatus is how a run ended, for both kinds of run. +// +// Shared by the topology collection pass and the inventory refresh deliberately: the two +// runs differ in what they do, not in how they finish, and two identical enums would +// invite them to drift apart for no reason. +type RunStatus int32 + +const ( + RunStatus_RUN_STATUS_UNSPECIFIED RunStatus = 0 + // Still going. Not a terminal status. + RunStatus_RUN_STATUS_RUNNING RunStatus = 1 + // Everything it attempted answered. + RunStatus_RUN_STATUS_SUCCESS RunStatus = 2 + // Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + RunStatus_RUN_STATUS_PARTIAL RunStatus = 3 + // The run itself failed, as opposed to the things it was probing. + RunStatus_RUN_STATUS_FAILED RunStatus = 4 + // Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + RunStatus_RUN_STATUS_SKIPPED RunStatus = 5 +) + +// Enum value maps for RunStatus. +var ( + RunStatus_name = map[int32]string{ + 0: "RUN_STATUS_UNSPECIFIED", + 1: "RUN_STATUS_RUNNING", + 2: "RUN_STATUS_SUCCESS", + 3: "RUN_STATUS_PARTIAL", + 4: "RUN_STATUS_FAILED", + 5: "RUN_STATUS_SKIPPED", + } + RunStatus_value = map[string]int32{ + "RUN_STATUS_UNSPECIFIED": 0, + "RUN_STATUS_RUNNING": 1, + "RUN_STATUS_SUCCESS": 2, + "RUN_STATUS_PARTIAL": 3, + "RUN_STATUS_FAILED": 4, + "RUN_STATUS_SKIPPED": 5, + } +) + +func (x RunStatus) Enum() *RunStatus { + p := new(RunStatus) + *p = x + return p +} + +func (x RunStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RunStatus) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[2].Descriptor() +} + +func (RunStatus) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[2] +} + +func (x RunStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RunStatus.Descriptor instead. +func (RunStatus) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{2} +} + +// SourceStatus is how completely one collection source answered. +// +// Separate from RunStatus because it carries DISABLED, which a run cannot be: a source +// switched off in configuration is a deliberate state, not a degraded one. +type SourceStatus int32 + +const ( + SourceStatus_SOURCE_STATUS_UNSPECIFIED SourceStatus = 0 + // Answered everything asked of it. + SourceStatus_SOURCE_STATUS_OK SourceStatus = 1 + // Answered some of it. + SourceStatus_SOURCE_STATUS_PARTIAL SourceStatus = 2 + // Did not answer. + SourceStatus_SOURCE_STATUS_FAILED SourceStatus = 3 + // Switched off in configuration, so it was never asked. + SourceStatus_SOURCE_STATUS_DISABLED SourceStatus = 4 +) + +// Enum value maps for SourceStatus. +var ( + SourceStatus_name = map[int32]string{ + 0: "SOURCE_STATUS_UNSPECIFIED", + 1: "SOURCE_STATUS_OK", + 2: "SOURCE_STATUS_PARTIAL", + 3: "SOURCE_STATUS_FAILED", + 4: "SOURCE_STATUS_DISABLED", + } + SourceStatus_value = map[string]int32{ + "SOURCE_STATUS_UNSPECIFIED": 0, + "SOURCE_STATUS_OK": 1, + "SOURCE_STATUS_PARTIAL": 2, + "SOURCE_STATUS_FAILED": 3, + "SOURCE_STATUS_DISABLED": 4, + } +) + +func (x SourceStatus) Enum() *SourceStatus { + p := new(SourceStatus) + *p = x + return p +} + +func (x SourceStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SourceStatus) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[3].Descriptor() +} + +func (SourceStatus) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[3] +} + +func (x SourceStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SourceStatus.Descriptor instead. +func (SourceStatus) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{3} +} + +// ClusterType is the shape buildDocument inferred for one grouped service inventory. +// +// Inferred, not reconstructed: this package groups services by label and infers a shape +// from what is in the group, it does not walk a replica set's own config to build a +// member list. See the package comment. +type ClusterType int32 + +const ( + ClusterType_CLUSTER_TYPE_UNSPECIFIED ClusterType = 0 + // Exactly one replication_set label under this cluster, and no mongos. + ClusterType_CLUSTER_TYPE_REPLICA_SET ClusterType = 1 + // A mongos is present, or more than one replication_set label shares this cluster + // label. + ClusterType_CLUSTER_TYPE_SHARDED ClusterType = 2 + // Neither: services grouped under one label with no replica-set identity at all. + ClusterType_CLUSTER_TYPE_STANDALONE ClusterType = 3 +) + +// Enum value maps for ClusterType. +var ( + ClusterType_name = map[int32]string{ + 0: "CLUSTER_TYPE_UNSPECIFIED", + 1: "CLUSTER_TYPE_REPLICA_SET", + 2: "CLUSTER_TYPE_SHARDED", + 3: "CLUSTER_TYPE_STANDALONE", + } + ClusterType_value = map[string]int32{ + "CLUSTER_TYPE_UNSPECIFIED": 0, + "CLUSTER_TYPE_REPLICA_SET": 1, + "CLUSTER_TYPE_SHARDED": 2, + "CLUSTER_TYPE_STANDALONE": 3, + } +) + +func (x ClusterType) Enum() *ClusterType { + p := new(ClusterType) + *p = x + return p +} + +func (x ClusterType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClusterType) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[4].Descriptor() +} + +func (ClusterType) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[4] +} + +func (x ClusterType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClusterType.Descriptor instead. +func (ClusterType) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{4} +} + +// ClusterHealth is a reserved verdict slot, not yet computed by anything. +// +// UNSPECIFIED is the only value that exists today. It is declared now, alongside the +// applyHealth seam in the collector, so a rollup status has a field to land in without a +// later schema change -- see the om package's health-pipeline comment. +type ClusterHealth int32 + +const ( + ClusterHealth_CLUSTER_HEALTH_UNSPECIFIED ClusterHealth = 0 +) + +// Enum value maps for ClusterHealth. +var ( + ClusterHealth_name = map[int32]string{ + 0: "CLUSTER_HEALTH_UNSPECIFIED", + } + ClusterHealth_value = map[string]int32{ + "CLUSTER_HEALTH_UNSPECIFIED": 0, + } +) + +func (x ClusterHealth) Enum() *ClusterHealth { + p := new(ClusterHealth) + *p = x + return p +} + +func (x ClusterHealth) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClusterHealth) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[5].Descriptor() +} + +func (ClusterHealth) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[5] +} + +func (x ClusterHealth) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClusterHealth.Descriptor instead. +func (ClusterHealth) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{5} +} + +// ExecutorResolution is how a host was matched to the client its probe ran on. +// +// ORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact +// about onboarding. NAME and ADDRESS record *which* of the two joins matched, because a +// host reachable only by address is a different estate problem from one matched by name. +type ExecutorResolution int32 + +const ( + ExecutorResolution_EXECUTOR_RESOLUTION_UNSPECIFIED ExecutorResolution = 0 + // Matched on the node's registered name. + ExecutorResolution_EXECUTOR_RESOLUTION_NAME ExecutorResolution = 1 + // Matched on the node's address. + ExecutorResolution_EXECUTOR_RESOLUTION_ADDRESS ExecutorResolution = 2 + // Not matched, so nothing was dispatched. + ExecutorResolution_EXECUTOR_RESOLUTION_ORPHANED ExecutorResolution = 3 +) + +// Enum value maps for ExecutorResolution. +var ( + ExecutorResolution_name = map[int32]string{ + 0: "EXECUTOR_RESOLUTION_UNSPECIFIED", + 1: "EXECUTOR_RESOLUTION_NAME", + 2: "EXECUTOR_RESOLUTION_ADDRESS", + 3: "EXECUTOR_RESOLUTION_ORPHANED", + } + ExecutorResolution_value = map[string]int32{ + "EXECUTOR_RESOLUTION_UNSPECIFIED": 0, + "EXECUTOR_RESOLUTION_NAME": 1, + "EXECUTOR_RESOLUTION_ADDRESS": 2, + "EXECUTOR_RESOLUTION_ORPHANED": 3, + } +) + +func (x ExecutorResolution) Enum() *ExecutorResolution { + p := new(ExecutorResolution) + *p = x + return p +} + +func (x ExecutorResolution) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ExecutorResolution) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[6].Descriptor() +} + +func (ExecutorResolution) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[6] +} + +func (x ExecutorResolution) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ExecutorResolution.Descriptor instead. +func (ExecutorResolution) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{6} +} + +// SettingReload is how a configuration field may be overridden, if at all. +// +// Mirrors the app's own three-valued classification rather than collapsing it to +// editable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a +// whole-object write while its children accept one, so a form that read it as +// "not overridable" would refuse to edit a leaf the API would have accepted. +// +// The distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable +// promises a change the API cannot deliver. +type SettingReload int32 + +const ( + SettingReload_SETTING_RELOAD_UNSPECIFIED SettingReload = 0 + // Overridable at runtime; the new value takes effect on the next snapshot refresh. + SettingReload_SETTING_RELOAD_HOT SettingReload = 1 + // A nested object whose children are overridable, but which rejects being written + // whole. + SettingReload_SETTING_RELOAD_NESTED_ONLY SettingReload = 2 + // Not overridable at all: YAML and environment variables remain the only sources. + SettingReload_SETTING_RELOAD_NOT_OVERRIDABLE SettingReload = 3 +) + +// Enum value maps for SettingReload. +var ( + SettingReload_name = map[int32]string{ + 0: "SETTING_RELOAD_UNSPECIFIED", + 1: "SETTING_RELOAD_HOT", + 2: "SETTING_RELOAD_NESTED_ONLY", + 3: "SETTING_RELOAD_NOT_OVERRIDABLE", + } + SettingReload_value = map[string]int32{ + "SETTING_RELOAD_UNSPECIFIED": 0, + "SETTING_RELOAD_HOT": 1, + "SETTING_RELOAD_NESTED_ONLY": 2, + "SETTING_RELOAD_NOT_OVERRIDABLE": 3, + } +) + +func (x SettingReload) Enum() *SettingReload { + p := new(SettingReload) + *p = x + return p +} + +func (x SettingReload) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SettingReload) Descriptor() protoreflect.EnumDescriptor { + return file_om_v1_om_proto_enumTypes[7].Descriptor() +} + +func (SettingReload) Type() protoreflect.EnumType { + return &file_om_v1_om_proto_enumTypes[7] +} + +func (x SettingReload) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SettingReload.Descriptor instead. +func (SettingReload) EnumDescriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{7} +} + +// TopologyService represents one monitored MongoDB service as the topology document +// records it. +// +// Two conventions for "no value", and they differ on purpose. cpu_usage_percent and +// connections_free_percent are -1 when not measured, never absent and never 0, because +// zero CPU is a legitimate reading and a numeric column must keep "idle" and "unknown" +// apart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is +// absent when they do not apply -- a router and a standalone have no replica-set oplog -- +// which is a different statement from -1's "we could not measure it". +// +// The optional fields were wrapper messages until the REST contract was checked: +// protoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema +// and the generated Go client both collapsed to a value type and lost the distinction +// entirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting +// the key rather than emitting an explicit null. +type TopologyService struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Service name as PMM inventory registered it. + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // Node the service runs on. + Host *string `protobuf:"bytes,2,opt,name=host,proto3,oneof" json:"host,omitempty"` + // host:port as the replica set itself addresses the member. + Endpoint *string `protobuf:"bytes,3,opt,name=endpoint,proto3,oneof" json:"endpoint,omitempty"` + // PMM's service ID. The join key against VictoriaMetrics. + ServiceId *string `protobuf:"bytes,4,opt,name=service_id,json=serviceId,proto3,oneof" json:"service_id,omitempty"` + // Always "mongodb" today. + ServiceType *string `protobuf:"bytes,5,opt,name=service_type,json=serviceType,proto3,oneof" json:"service_type,omitempty"` + // Running server version. + Version *string `protobuf:"bytes,6,opt,name=version,proto3,oneof" json:"version,omitempty"` + // MongoDB or Percona. + Vendor *string `protobuf:"bytes,7,opt,name=vendor,proto3,oneof" json:"vendor,omitempty"` + // Community or Enterprise. + Edition *string `protobuf:"bytes,8,opt,name=edition,proto3,oneof" json:"edition,omitempty"` + // Replica set, or unset for a router or a standalone. + ReplicationSet *string `protobuf:"bytes,9,opt,name=replication_set,json=replicationSet,proto3,oneof" json:"replication_set,omitempty"` + // PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state. + State *string `protobuf:"bytes,10,opt,name=state,proto3,oneof" json:"state,omitempty"` + // Whether the exporter reached the service. + Status ServiceStatus `protobuf:"varint,11,opt,name=status,proto3,enum=om.v1.ServiceStatus" json:"status,omitempty"` + // CPU percentage, or -1 when not measured. + CpuUsagePercent float64 `protobuf:"fixed64,12,opt,name=cpu_usage_percent,json=cpuUsagePercent,proto3" json:"cpu_usage_percent,omitempty"` + // Percentage of free connections, or -1 when not measured. + ConnectionsFreePercent float64 `protobuf:"fixed64,13,opt,name=connections_free_percent,json=connectionsFreePercent,proto3" json:"connections_free_percent,omitempty"` + // What this process is doing in the deployment. + ProcessRole ProcessRole `protobuf:"varint,14,opt,name=process_role,json=processRole,proto3,enum=om.v1.ProcessRole" json:"process_role,omitempty"` + // Seconds this member trails the primary; unset where there is no primary to trail. + ReplicationLagSeconds *float64 `protobuf:"fixed64,15,opt,name=replication_lag_seconds,json=replicationLagSeconds,proto3,oneof" json:"replication_lag_seconds,omitempty"` + // Seconds of history the oplog holds; unset where there is no replica-set oplog. + OplogWindowSeconds *float64 `protobuf:"fixed64,16,opt,name=oplog_window_seconds,json=oplogWindowSeconds,proto3,oneof" json:"oplog_window_seconds,omitempty"` + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from `version` is the upgraded-but-not-restarted case. Only + // an on-host probe can see it, so this is unset wherever one has not run. + InstalledVersion *string `protobuf:"bytes,17,opt,name=installed_version,json=installedVersion,proto3,oneof" json:"installed_version,omitempty"` + // The configuration file the running server read. Probe-only. + ConfigPath *string `protobuf:"bytes,18,opt,name=config_path,json=configPath,proto3,oneof" json:"config_path,omitempty"` + // The command line the running server was started with. Probe-only. + Argv *string `protobuf:"bytes,19,opt,name=argv,proto3,oneof" json:"argv,omitempty"` + // When the newest *live* field on this row was observed, unset when every field on it + // is either absent or not time-bounded (inventory only, no metric and no probe ever + // seen). This is the row's own provenance -- Snapshot.observed_at is the newest across + // the whole estate, which cannot tell "this row is current" from "this row is the one + // that made the snapshot look fresh". A field's own MergedField.ObservedAt exists + // internally; this is the first one exposed on the wire. + ObservedAt *timestamppb.Timestamp `protobuf:"bytes,20,opt,name=observed_at,json=observedAt,proto3,oneof" json:"observed_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyService) Reset() { + *x = TopologyService{} + mi := &file_om_v1_om_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyService) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyService) ProtoMessage() {} + +func (x *TopologyService) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyService.ProtoReflect.Descriptor instead. +func (*TopologyService) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{0} +} + +func (x *TopologyService) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *TopologyService) GetHost() string { + if x != nil && x.Host != nil { + return *x.Host + } + return "" +} + +func (x *TopologyService) GetEndpoint() string { + if x != nil && x.Endpoint != nil { + return *x.Endpoint + } + return "" +} + +func (x *TopologyService) GetServiceId() string { + if x != nil && x.ServiceId != nil { + return *x.ServiceId + } + return "" +} + +func (x *TopologyService) GetServiceType() string { + if x != nil && x.ServiceType != nil { + return *x.ServiceType + } + return "" +} + +func (x *TopologyService) GetVersion() string { + if x != nil && x.Version != nil { + return *x.Version + } + return "" +} + +func (x *TopologyService) GetVendor() string { + if x != nil && x.Vendor != nil { + return *x.Vendor + } + return "" +} + +func (x *TopologyService) GetEdition() string { + if x != nil && x.Edition != nil { + return *x.Edition + } + return "" +} + +func (x *TopologyService) GetReplicationSet() string { + if x != nil && x.ReplicationSet != nil { + return *x.ReplicationSet + } + return "" +} + +func (x *TopologyService) GetState() string { + if x != nil && x.State != nil { + return *x.State + } + return "" +} + +func (x *TopologyService) GetStatus() ServiceStatus { + if x != nil { + return x.Status + } + return ServiceStatus_SERVICE_STATUS_UNSPECIFIED +} + +func (x *TopologyService) GetCpuUsagePercent() float64 { + if x != nil { + return x.CpuUsagePercent + } + return 0 +} + +func (x *TopologyService) GetConnectionsFreePercent() float64 { + if x != nil { + return x.ConnectionsFreePercent + } + return 0 +} + +func (x *TopologyService) GetProcessRole() ProcessRole { + if x != nil { + return x.ProcessRole + } + return ProcessRole_PROCESS_ROLE_UNSPECIFIED +} + +func (x *TopologyService) GetReplicationLagSeconds() float64 { + if x != nil && x.ReplicationLagSeconds != nil { + return *x.ReplicationLagSeconds + } + return 0 +} + +func (x *TopologyService) GetOplogWindowSeconds() float64 { + if x != nil && x.OplogWindowSeconds != nil { + return *x.OplogWindowSeconds + } + return 0 +} + +func (x *TopologyService) GetInstalledVersion() string { + if x != nil && x.InstalledVersion != nil { + return *x.InstalledVersion + } + return "" +} + +func (x *TopologyService) GetConfigPath() string { + if x != nil && x.ConfigPath != nil { + return *x.ConfigPath + } + return "" +} + +func (x *TopologyService) GetArgv() string { + if x != nil && x.Argv != nil { + return *x.Argv + } + return "" +} + +func (x *TopologyService) GetObservedAt() *timestamppb.Timestamp { + if x != nil { + return x.ObservedAt + } + return nil +} + +// Cluster represents one grouped service inventory: every service PMM's inventory +// labelled with the same (environment, cluster) or (environment, replication_set), not a +// reconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat +// list of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for +// the one thing inferred about that shape, and the package comment for what is +// deliberately not. +type Cluster struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Cluster label, unset when its services carry none. Not a stable identity: two + // clusters can share this label (a second generation of a sandbox reusing a name), and + // `id` is what tells them apart. + Name *string `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"` + // Its services, ordered by name. + Services []*TopologyService `protobuf:"bytes,2,rep,name=services,proto3" json:"services,omitempty"` + // Opaque, server-issued, stable across a rename of `name`. Derived from + // (environment, cluster, replication_set) so the same estate group always gets the + // same id -- clients must not parse it or assume a derivation. + Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` + // What buildDocument inferred about this group's shape. + Type ClusterType `protobuf:"varint,4,opt,name=type,proto3,enum=om.v1.ClusterType" json:"type,omitempty"` + // Reserved for the health pipeline. Always UNSPECIFIED today. + Health ClusterHealth `protobuf:"varint,5,opt,name=health,proto3,enum=om.v1.ClusterHealth" json:"health,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Cluster) Reset() { + *x = Cluster{} + mi := &file_om_v1_om_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Cluster) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cluster) ProtoMessage() {} + +func (x *Cluster) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cluster.ProtoReflect.Descriptor instead. +func (*Cluster) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{1} +} + +func (x *Cluster) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *Cluster) GetServices() []*TopologyService { + if x != nil { + return x.Services + } + return nil +} + +func (x *Cluster) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Cluster) GetType() ClusterType { + if x != nil { + return x.Type + } + return ClusterType_CLUSTER_TYPE_UNSPECIFIED +} + +func (x *Cluster) GetHealth() ClusterHealth { + if x != nil { + return x.Health + } + return ClusterHealth_CLUSTER_HEALTH_UNSPECIFIED +} + +// Environment represents one monitoring environment. +type Environment struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Environment label, unset when its services carry none. + EnvName *string `protobuf:"bytes,1,opt,name=env_name,json=envName,proto3,oneof" json:"env_name,omitempty"` + // Its clusters, ordered by name. + Clusters []*Cluster `protobuf:"bytes,2,rep,name=clusters,proto3" json:"clusters,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Environment) Reset() { + *x = Environment{} + mi := &file_om_v1_om_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Environment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Environment) ProtoMessage() {} + +func (x *Environment) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Environment.ProtoReflect.Descriptor instead. +func (*Environment) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{2} +} + +func (x *Environment) GetEnvName() string { + if x != nil && x.EnvName != nil { + return *x.EnvName + } + return "" +} + +func (x *Environment) GetClusters() []*Cluster { + if x != nil { + return x.Clusters + } + return nil +} + +// Summary carries the fleet-level counts, so a caller need not re-derive them. +type Summary struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Environments in the document. + Environments int32 `protobuf:"varint,1,opt,name=environments,proto3" json:"environments,omitempty"` + // Clusters across all of them. + Clusters int32 `protobuf:"varint,2,opt,name=clusters,proto3" json:"clusters,omitempty"` + // Services in the document. + TotalServices int32 `protobuf:"varint,3,opt,name=total_services,json=totalServices,proto3" json:"total_services,omitempty"` + // Services the exporter reached. + UpServices int32 `protobuf:"varint,4,opt,name=up_services,json=upServices,proto3" json:"up_services,omitempty"` + // Services it did not. + DownServices int32 `protobuf:"varint,5,opt,name=down_services,json=downServices,proto3" json:"down_services,omitempty"` + // Service counts per process role, keyed by the ProcessRole enum's name. + ProcessRoleCounts map[string]int32 `protobuf:"bytes,6,rep,name=process_role_counts,json=processRoleCounts,proto3" json:"process_role_counts,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Summary) Reset() { + *x = Summary{} + mi := &file_om_v1_om_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Summary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Summary) ProtoMessage() {} + +func (x *Summary) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Summary.ProtoReflect.Descriptor instead. +func (*Summary) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{3} +} + +func (x *Summary) GetEnvironments() int32 { + if x != nil { + return x.Environments + } + return 0 +} + +func (x *Summary) GetClusters() int32 { + if x != nil { + return x.Clusters + } + return 0 +} + +func (x *Summary) GetTotalServices() int32 { + if x != nil { + return x.TotalServices + } + return 0 +} + +func (x *Summary) GetUpServices() int32 { + if x != nil { + return x.UpServices + } + return 0 +} + +func (x *Summary) GetDownServices() int32 { + if x != nil { + return x.DownServices + } + return 0 +} + +func (x *Summary) GetProcessRoleCounts() map[string]int32 { + if x != nil { + return x.ProcessRoleCounts + } + return nil +} + +// Snapshot carries the provenance every snapshot-backed response repeats. +type Snapshot struct { + state protoimpl.MessageState `protogen:"open.v1"` + // When the document was assembled. + GeneratedAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=generated_at,json=generatedAt,proto3" json:"generated_at,omitempty"` + // The newest observation in it, unset when nothing was observed at all. + ObservedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=observed_at,json=observedAt,proto3" json:"observed_at,omitempty"` + // Whether the document is older than the staleness grace period. Also true, with + // observed_at unset and every environment empty, on a genuinely cold estate -- no + // collection has completed anywhere yet. That is a startup state, not a statement that + // the estate itself is empty; a reader should render it as "collecting" rather than as + // an empty result. + Stale bool `protobuf:"varint,3,opt,name=stale,proto3" json:"stale,omitempty"` + // The document schema version. + SchemaVersion int32 `protobuf:"varint,4,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"` + // The collection run that produced it. + RunId string `protobuf:"bytes,5,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Snapshot) Reset() { + *x = Snapshot{} + mi := &file_om_v1_om_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Snapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Snapshot) ProtoMessage() {} + +func (x *Snapshot) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Snapshot.ProtoReflect.Descriptor instead. +func (*Snapshot) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{4} +} + +func (x *Snapshot) GetGeneratedAt() *timestamppb.Timestamp { + if x != nil { + return x.GeneratedAt + } + return nil +} + +func (x *Snapshot) GetObservedAt() *timestamppb.Timestamp { + if x != nil { + return x.ObservedAt + } + return nil +} + +func (x *Snapshot) GetStale() bool { + if x != nil { + return x.Stale + } + return false +} + +func (x *Snapshot) GetSchemaVersion() int32 { + if x != nil { + return x.SchemaVersion + } + return 0 +} + +func (x *Snapshot) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +// GetTopologyRequest is the request for GetTopology. It takes no parameters: the +// document describes the whole estate, and filtering it is the caller's business. +type GetTopologyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopologyRequest) Reset() { + *x = GetTopologyRequest{} + mi := &file_om_v1_om_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopologyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopologyRequest) ProtoMessage() {} + +func (x *GetTopologyRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopologyRequest.ProtoReflect.Descriptor instead. +func (*GetTopologyRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{5} +} + +// GetTopologyResponse is the whole topology document plus the provenance of the run +// behind it. +type GetTopologyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Which run produced this, when, and whether it is stale. + Snapshot *Snapshot `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + // The PMM node the document was assembled on. + OriginNode *string `protobuf:"bytes,2,opt,name=origin_node,json=originNode,proto3,oneof" json:"origin_node,omitempty"` + // The VictoriaMetrics queries the document was derived from. + SourceQueries []string `protobuf:"bytes,3,rep,name=source_queries,json=sourceQueries,proto3" json:"source_queries,omitempty"` + // Fleet-level counts. + Summary *Summary `protobuf:"bytes,4,opt,name=summary,proto3" json:"summary,omitempty"` + // The estate, grouped environment then cluster. + Environments []*Environment `protobuf:"bytes,5,rep,name=environments,proto3" json:"environments,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopologyResponse) Reset() { + *x = GetTopologyResponse{} + mi := &file_om_v1_om_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopologyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopologyResponse) ProtoMessage() {} + +func (x *GetTopologyResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopologyResponse.ProtoReflect.Descriptor instead. +func (*GetTopologyResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{6} +} + +func (x *GetTopologyResponse) GetSnapshot() *Snapshot { + if x != nil { + return x.Snapshot + } + return nil +} + +func (x *GetTopologyResponse) GetOriginNode() string { + if x != nil && x.OriginNode != nil { + return *x.OriginNode + } + return "" +} + +func (x *GetTopologyResponse) GetSourceQueries() []string { + if x != nil { + return x.SourceQueries + } + return nil +} + +func (x *GetTopologyResponse) GetSummary() *Summary { + if x != nil { + return x.Summary + } + return nil +} + +func (x *GetTopologyResponse) GetEnvironments() []*Environment { + if x != nil { + return x.Environments + } + return nil +} + +// TopologyRunCounts counts what one collection run saw. +type TopologyRunCounts struct { + state protoimpl.MessageState `protogen:"open.v1"` + // MongoDB services inventory reported. + TotalServices int32 `protobuf:"varint,1,opt,name=total_services,json=totalServices,proto3" json:"total_services,omitempty"` + // ...of which carried a service ID to join metrics on. + ResolvedServices int32 `protobuf:"varint,2,opt,name=resolved_services,json=resolvedServices,proto3" json:"resolved_services,omitempty"` + // ...of which did not. Not an error. + OrphanedServices int32 `protobuf:"varint,3,opt,name=orphaned_services,json=orphanedServices,proto3" json:"orphaned_services,omitempty"` + // Services metrics actually observed as reachable. + SuccessfulProbes int32 `protobuf:"varint,4,opt,name=successful_probes,json=successfulProbes,proto3" json:"successful_probes,omitempty"` + // Services carrying at least one volatile fact too old to read as current. + StaleServices int32 `protobuf:"varint,5,opt,name=stale_services,json=staleServices,proto3" json:"stale_services,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyRunCounts) Reset() { + *x = TopologyRunCounts{} + mi := &file_om_v1_om_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyRunCounts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyRunCounts) ProtoMessage() {} + +func (x *TopologyRunCounts) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyRunCounts.ProtoReflect.Descriptor instead. +func (*TopologyRunCounts) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{7} +} + +func (x *TopologyRunCounts) GetTotalServices() int32 { + if x != nil { + return x.TotalServices + } + return 0 +} + +func (x *TopologyRunCounts) GetResolvedServices() int32 { + if x != nil { + return x.ResolvedServices + } + return 0 +} + +func (x *TopologyRunCounts) GetOrphanedServices() int32 { + if x != nil { + return x.OrphanedServices + } + return 0 +} + +func (x *TopologyRunCounts) GetSuccessfulProbes() int32 { + if x != nil { + return x.SuccessfulProbes + } + return 0 +} + +func (x *TopologyRunCounts) GetStaleServices() int32 { + if x != nil { + return x.StaleServices + } + return 0 +} + +// SourceReport says how completely one collection source answered, and what it saw. +// +// Recorded per source so a thin document is legible rather than merely thin: a snapshot +// assembled with metrics=ok and probe=failed is still correct about every version and +// honest about reachability. +type SourceReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The source key, e.g. "inventory", "metrics" or "probe". An open set on purpose: a + // source is named by whatever produced it, so this stays a string where the statuses + // beside it are enums. + Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + // How completely it answered. + Status SourceStatus `protobuf:"varint,2,opt,name=status,proto3,enum=om.v1.SourceStatus" json:"status,omitempty"` + // How many facts it produced. + Facts int32 `protobuf:"varint,3,opt,name=facts,proto3" json:"facts,omitempty"` + // Source-specific counters, rendered as strings so a source can report whatever it has + // without this contract naming every counter. + Detail map[string]string `protobuf:"bytes,4,rep,name=detail,proto3" json:"detail,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SourceReport) Reset() { + *x = SourceReport{} + mi := &file_om_v1_om_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SourceReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SourceReport) ProtoMessage() {} + +func (x *SourceReport) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SourceReport.ProtoReflect.Descriptor instead. +func (*SourceReport) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{8} +} + +func (x *SourceReport) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *SourceReport) GetStatus() SourceStatus { + if x != nil { + return x.Status + } + return SourceStatus_SOURCE_STATUS_UNSPECIFIED +} + +func (x *SourceReport) GetFacts() int32 { + if x != nil { + return x.Facts + } + return 0 +} + +func (x *SourceReport) GetDetail() map[string]string { + if x != nil { + return x.Detail + } + return nil +} + +// TopologyRunError describes one thing that went wrong during a collection run. +type TopologyRunError struct { + state protoimpl.MessageState `protogen:"open.v1"` + // What the error is about, e.g. "run" or "query". + Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` + // The service it concerns, when scoped to one. + ServiceName *string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3,oneof" json:"service_name,omitempty"` + // A machine-readable cause. + Code string `protobuf:"bytes,3,opt,name=code,proto3" json:"code,omitempty"` + // The human-readable detail. + Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyRunError) Reset() { + *x = TopologyRunError{} + mi := &file_om_v1_om_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyRunError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyRunError) ProtoMessage() {} + +func (x *TopologyRunError) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyRunError.ProtoReflect.Descriptor instead. +func (*TopologyRunError) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{9} +} + +func (x *TopologyRunError) GetScope() string { + if x != nil { + return x.Scope + } + return "" +} + +func (x *TopologyRunError) GetServiceName() string { + if x != nil && x.ServiceName != nil { + return *x.ServiceName + } + return "" +} + +func (x *TopologyRunError) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *TopologyRunError) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// TopologyRun represents one collection run. +type TopologyRun struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run's ID, also the snapshot key. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // How it ended. + Status RunStatus `protobuf:"varint,2,opt,name=status,proto3,enum=om.v1.RunStatus" json:"status,omitempty"` + // When the run began. + StartTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + // When it reached a terminal status; unset while running. + EndTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + // What it saw. + Counts *TopologyRunCounts `protobuf:"bytes,5,opt,name=counts,proto3" json:"counts,omitempty"` + // Query-level, service-level and run-level failures. + Errors []*TopologyRunError `protobuf:"bytes,6,rep,name=errors,proto3" json:"errors,omitempty"` + // How completely each collection source answered. + Sources []*SourceReport `protobuf:"bytes,7,rep,name=sources,proto3" json:"sources,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyRun) Reset() { + *x = TopologyRun{} + mi := &file_om_v1_om_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyRun) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyRun) ProtoMessage() {} + +func (x *TopologyRun) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyRun.ProtoReflect.Descriptor instead. +func (*TopologyRun) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{10} +} + +func (x *TopologyRun) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +func (x *TopologyRun) GetStatus() RunStatus { + if x != nil { + return x.Status + } + return RunStatus_RUN_STATUS_UNSPECIFIED +} + +func (x *TopologyRun) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *TopologyRun) GetEndTime() *timestamppb.Timestamp { + if x != nil { + return x.EndTime + } + return nil +} + +func (x *TopologyRun) GetCounts() *TopologyRunCounts { + if x != nil { + return x.Counts + } + return nil +} + +func (x *TopologyRun) GetErrors() []*TopologyRunError { + if x != nil { + return x.Errors + } + return nil +} + +func (x *TopologyRun) GetSources() []*SourceReport { + if x != nil { + return x.Sources + } + return nil +} + +// GetTopologyRunRequest is the request for GetTopologyRun. +type GetTopologyRunRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run to return. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopologyRunRequest) Reset() { + *x = GetTopologyRunRequest{} + mi := &file_om_v1_om_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopologyRunRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopologyRunRequest) ProtoMessage() {} + +func (x *GetTopologyRunRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopologyRunRequest.ProtoReflect.Descriptor instead. +func (*GetTopologyRunRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{11} +} + +func (x *GetTopologyRunRequest) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +// GetTopologyRunResponse returns one collection run. +type GetTopologyRunResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run. + Run *TopologyRun `protobuf:"bytes,1,opt,name=run,proto3" json:"run,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopologyRunResponse) Reset() { + *x = GetTopologyRunResponse{} + mi := &file_om_v1_om_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopologyRunResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopologyRunResponse) ProtoMessage() {} + +func (x *GetTopologyRunResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopologyRunResponse.ProtoReflect.Descriptor instead. +func (*GetTopologyRunResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{12} +} + +func (x *GetTopologyRunResponse) GetRun() *TopologyRun { + if x != nil { + return x.Run + } + return nil +} + +// ListTopologyRunsRequest is the request for ListTopologyRuns. +type ListTopologyRunsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // How many runs to return, newest first. Defaults to 25, capped at 100. + Limit int32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListTopologyRunsRequest) Reset() { + *x = ListTopologyRunsRequest{} + mi := &file_om_v1_om_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListTopologyRunsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTopologyRunsRequest) ProtoMessage() {} + +func (x *ListTopologyRunsRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTopologyRunsRequest.ProtoReflect.Descriptor instead. +func (*ListTopologyRunsRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{13} +} + +func (x *ListTopologyRunsRequest) GetLimit() int32 { + if x != nil { + return x.Limit + } + return 0 +} + +// ListTopologyRunsResponse returns the run history, newest first. +type ListTopologyRunsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The runs. + Runs []*TopologyRun `protobuf:"bytes,1,rep,name=runs,proto3" json:"runs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListTopologyRunsResponse) Reset() { + *x = ListTopologyRunsResponse{} + mi := &file_om_v1_om_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListTopologyRunsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTopologyRunsResponse) ProtoMessage() {} + +func (x *ListTopologyRunsResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTopologyRunsResponse.ProtoReflect.Descriptor instead. +func (*ListTopologyRunsResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{14} +} + +func (x *ListTopologyRunsResponse) GetRuns() []*TopologyRun { + if x != nil { + return x.Runs + } + return nil +} + +// TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection. +type TriggerTopologyCollectionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TriggerTopologyCollectionRequest) Reset() { + *x = TriggerTopologyCollectionRequest{} + mi := &file_om_v1_om_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TriggerTopologyCollectionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerTopologyCollectionRequest) ProtoMessage() {} + +func (x *TriggerTopologyCollectionRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerTopologyCollectionRequest.ProtoReflect.Descriptor instead. +func (*TriggerTopologyCollectionRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{15} +} + +// TriggerTopologyCollectionResponse acknowledges a completed collection run. +type TriggerTopologyCollectionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run's ID. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // The run's terminal status. + Status RunStatus `protobuf:"varint,2,opt,name=status,proto3,enum=om.v1.RunStatus" json:"status,omitempty"` + // When the run began. + StartTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TriggerTopologyCollectionResponse) Reset() { + *x = TriggerTopologyCollectionResponse{} + mi := &file_om_v1_om_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TriggerTopologyCollectionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerTopologyCollectionResponse) ProtoMessage() {} + +func (x *TriggerTopologyCollectionResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerTopologyCollectionResponse.ProtoReflect.Descriptor instead. +func (*TriggerTopologyCollectionResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{16} +} + +func (x *TriggerTopologyCollectionResponse) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +func (x *TriggerTopologyCollectionResponse) GetStatus() RunStatus { + if x != nil { + return x.Status + } + return RunStatus_RUN_STATUS_UNSPECIFIED +} + +func (x *TriggerTopologyCollectionResponse) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +// InventoryExecutor reports whether SEP can run anything on a host. +// +// Three flags rather than one, because "orphaned" hid three different problems with +// three different fixes: never onboarded (registered false), onboarded and down +// (reachable false), and up with a broken raw_exec driver (driver_healthy false). This +// is SEP's own knowledge rather than probe output, so it is filled in for every host +// on every sweep, including hosts no probe reached. +type InventoryExecutor struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Whether the Tasks backend knows this node at all. + Registered bool `protobuf:"varint,1,opt,name=registered,proto3" json:"registered,omitempty"` + // Whether it is currently up. + Reachable bool `protobuf:"varint,2,opt,name=reachable,proto3" json:"reachable,omitempty"` + // Whether its raw_exec driver is healthy, which is what a probe actually needs. + DriverHealthy bool `protobuf:"varint,3,opt,name=driver_healthy,json=driverHealthy,proto3" json:"driver_healthy,omitempty"` + // Whatever detail the backend gave, when it gave any. + Detail *string `protobuf:"bytes,4,opt,name=detail,proto3,oneof" json:"detail,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryExecutor) Reset() { + *x = InventoryExecutor{} + mi := &file_om_v1_om_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryExecutor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryExecutor) ProtoMessage() {} + +func (x *InventoryExecutor) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryExecutor.ProtoReflect.Descriptor instead. +func (*InventoryExecutor) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{17} +} + +func (x *InventoryExecutor) GetRegistered() bool { + if x != nil { + return x.Registered + } + return false +} + +func (x *InventoryExecutor) GetReachable() bool { + if x != nil { + return x.Reachable + } + return false +} + +func (x *InventoryExecutor) GetDriverHealthy() bool { + if x != nil { + return x.DriverHealthy + } + return false +} + +func (x *InventoryExecutor) GetDetail() string { + if x != nil && x.Detail != nil { + return *x.Detail + } + return "" +} + +// UnregisteredMongod is a mongod found running that PMM has no service for. +// +// The arbiter case, mostly: PMM registers no service for an arbiter, so nothing else +// in OM would report the process at all. Also what stands in the way of installing +// anything over a port that is already taken. +type UnregisteredMongod struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The port it is listening on. + Port *int32 `protobuf:"varint,1,opt,name=port,proto3,oneof" json:"port,omitempty"` + // The configuration file it read. + ConfigPath *string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3,oneof" json:"config_path,omitempty"` + // The command line it was started with. + Argv *string `protobuf:"bytes,3,opt,name=argv,proto3,oneof" json:"argv,omitempty"` + // The process name, e.g. "mongod". + Program *string `protobuf:"bytes,4,opt,name=program,proto3,oneof" json:"program,omitempty"` + // Its process ID at the time of the probe. + Pid *int32 `protobuf:"varint,5,opt,name=pid,proto3,oneof" json:"pid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UnregisteredMongod) Reset() { + *x = UnregisteredMongod{} + mi := &file_om_v1_om_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UnregisteredMongod) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnregisteredMongod) ProtoMessage() {} + +func (x *UnregisteredMongod) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnregisteredMongod.ProtoReflect.Descriptor instead. +func (*UnregisteredMongod) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{18} +} + +func (x *UnregisteredMongod) GetPort() int32 { + if x != nil && x.Port != nil { + return *x.Port + } + return 0 +} + +func (x *UnregisteredMongod) GetConfigPath() string { + if x != nil && x.ConfigPath != nil { + return *x.ConfigPath + } + return "" +} + +func (x *UnregisteredMongod) GetArgv() string { + if x != nil && x.Argv != nil { + return *x.Argv + } + return "" +} + +func (x *UnregisteredMongod) GetProgram() string { + if x != nil && x.Program != nil { + return *x.Program + } + return "" +} + +func (x *UnregisteredMongod) GetPid() int32 { + if x != nil && x.Pid != nil { + return *x.Pid + } + return 0 +} + +// InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +type InventoryFreshness struct { + state protoimpl.MessageState `protogen:"open.v1"` + // When OM first wrote a row for this entity. + FirstSeenAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=first_seen_at,json=firstSeenAt,proto3" json:"first_seen_at,omitempty"` + // When a refresh last tried it. + LastAttemptAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=last_attempt_at,json=lastAttemptAt,proto3" json:"last_attempt_at,omitempty"` + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + LastSuccessAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_success_at,json=lastSuccessAt,proto3" json:"last_success_at,omitempty"` + // The first failure after the last success. Unset means it is not failing. + FailingSince *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=failing_since,json=failingSince,proto3" json:"failing_since,omitempty"` + // Failures since the last success. + ConsecutiveFailures int32 `protobuf:"varint,5,opt,name=consecutive_failures,json=consecutiveFailures,proto3" json:"consecutive_failures,omitempty"` + // The most recent failure detail. + LastError *string `protobuf:"bytes,6,opt,name=last_error,json=lastError,proto3,oneof" json:"last_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryFreshness) Reset() { + *x = InventoryFreshness{} + mi := &file_om_v1_om_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryFreshness) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryFreshness) ProtoMessage() {} + +func (x *InventoryFreshness) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryFreshness.ProtoReflect.Descriptor instead. +func (*InventoryFreshness) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{19} +} + +func (x *InventoryFreshness) GetFirstSeenAt() *timestamppb.Timestamp { + if x != nil { + return x.FirstSeenAt + } + return nil +} + +func (x *InventoryFreshness) GetLastAttemptAt() *timestamppb.Timestamp { + if x != nil { + return x.LastAttemptAt + } + return nil +} + +func (x *InventoryFreshness) GetLastSuccessAt() *timestamppb.Timestamp { + if x != nil { + return x.LastSuccessAt + } + return nil +} + +func (x *InventoryFreshness) GetFailingSince() *timestamppb.Timestamp { + if x != nil { + return x.FailingSince + } + return nil +} + +func (x *InventoryFreshness) GetConsecutiveFailures() int32 { + if x != nil { + return x.ConsecutiveFailures + } + return 0 +} + +func (x *InventoryFreshness) GetLastError() string { + if x != nil && x.LastError != nil { + return *x.LastError + } + return "" +} + +// InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +type InventoryService struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's service ID. The join key against the topology document. + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // The node it runs on, as PMM's node ID. + NodeId string `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The service name PMM registered. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // The port it listens on, where OM knows it. + Port *int32 `protobuf:"varint,4,opt,name=port,proto3,oneof" json:"port,omitempty"` + // PRIMARY, SECONDARY, ARBITER, or unset. + Role *string `protobuf:"bytes,5,opt,name=role,proto3,oneof" json:"role,omitempty"` + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + InstalledVersion *string `protobuf:"bytes,6,opt,name=installed_version,json=installedVersion,proto3,oneof" json:"installed_version,omitempty"` + // The version the running server reports. + RunningVersion *string `protobuf:"bytes,7,opt,name=running_version,json=runningVersion,proto3,oneof" json:"running_version,omitempty"` + // The configuration file the running server read. + ConfigPath *string `protobuf:"bytes,8,opt,name=config_path,json=configPath,proto3,oneof" json:"config_path,omitempty"` + // The command line it was started with. + Argv *string `protobuf:"bytes,9,opt,name=argv,proto3,oneof" json:"argv,omitempty"` + // What the last probe of this service concluded, in the payload's own words. + ProbeStatus *string `protobuf:"bytes,10,opt,name=probe_status,json=probeStatus,proto3,oneof" json:"probe_status,omitempty"` + // Whether a server was found running. Unset where no probe has looked. + ServerRunning *bool `protobuf:"varint,11,opt,name=server_running,json=serverRunning,proto3,oneof" json:"server_running,omitempty"` + // How long it has been up, seconds. + UptimeSeconds *float64 `protobuf:"fixed64,12,opt,name=uptime_seconds,json=uptimeSeconds,proto3,oneof" json:"uptime_seconds,omitempty"` + // The replica set it belongs to, or unset for a standalone or a router. + ReplicationSet *string `protobuf:"bytes,13,opt,name=replication_set,json=replicationSet,proto3,oneof" json:"replication_set,omitempty"` + // Everything the probe recorded, including attributes with no field above. + Observed *structpb.Struct `protobuf:"bytes,14,opt,name=observed,proto3" json:"observed,omitempty"` + // How current the above is, and how it is failing. + Freshness *InventoryFreshness `protobuf:"bytes,15,opt,name=freshness,proto3" json:"freshness,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryService) Reset() { + *x = InventoryService{} + mi := &file_om_v1_om_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryService) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryService) ProtoMessage() {} + +func (x *InventoryService) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryService.ProtoReflect.Descriptor instead. +func (*InventoryService) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{20} +} + +func (x *InventoryService) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *InventoryService) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *InventoryService) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *InventoryService) GetPort() int32 { + if x != nil && x.Port != nil { + return *x.Port + } + return 0 +} + +func (x *InventoryService) GetRole() string { + if x != nil && x.Role != nil { + return *x.Role + } + return "" +} + +func (x *InventoryService) GetInstalledVersion() string { + if x != nil && x.InstalledVersion != nil { + return *x.InstalledVersion + } + return "" +} + +func (x *InventoryService) GetRunningVersion() string { + if x != nil && x.RunningVersion != nil { + return *x.RunningVersion + } + return "" +} + +func (x *InventoryService) GetConfigPath() string { + if x != nil && x.ConfigPath != nil { + return *x.ConfigPath + } + return "" +} + +func (x *InventoryService) GetArgv() string { + if x != nil && x.Argv != nil { + return *x.Argv + } + return "" +} + +func (x *InventoryService) GetProbeStatus() string { + if x != nil && x.ProbeStatus != nil { + return *x.ProbeStatus + } + return "" +} + +func (x *InventoryService) GetServerRunning() bool { + if x != nil && x.ServerRunning != nil { + return *x.ServerRunning + } + return false +} + +func (x *InventoryService) GetUptimeSeconds() float64 { + if x != nil && x.UptimeSeconds != nil { + return *x.UptimeSeconds + } + return 0 +} + +func (x *InventoryService) GetReplicationSet() string { + if x != nil && x.ReplicationSet != nil { + return *x.ReplicationSet + } + return "" +} + +func (x *InventoryService) GetObserved() *structpb.Struct { + if x != nil { + return x.Observed + } + return nil +} + +func (x *InventoryService) GetFreshness() *InventoryFreshness { + if x != nil { + return x.Freshness + } + return nil +} + +// InventoryHost is one machine OM knows about, with the services on it. +// +// A host is a row whether or not any MongoDB was found on it. That is what makes +// "which machines have no database" a query rather than an absence, and it is the only +// way a machine that has never run one appears at all - which is the case installing a +// database somewhere later depends on. +type InventoryHost struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's node ID. Also what a scoped refresh is addressed by. + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The node name PMM registered. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // The node address PMM registered. + Address *string `protobuf:"bytes,3,opt,name=address,proto3,oneof" json:"address,omitempty"` + // The Nomad client that serves it. Unset means nothing can be run there, which is a + // fact about the estate rather than a probe failure. + ExecutorHost *string `protobuf:"bytes,4,opt,name=executor_host,json=executorHost,proto3,oneof" json:"executor_host,omitempty"` + // The operating system, as the host reports it. Worth having from a probe because + // PMM does not know it for some nodes. + Os *string `protobuf:"bytes,5,opt,name=os,proto3,oneof" json:"os,omitempty"` + // The kernel release. + Kernel *string `protobuf:"bytes,6,opt,name=kernel,proto3,oneof" json:"kernel,omitempty"` + // Whether anything can be run here, in three parts. + Executor *InventoryExecutor `protobuf:"bytes,7,opt,name=executor,proto3" json:"executor,omitempty"` + // Mongods running that PMM has no service for. + UnregisteredMongods []*UnregisteredMongod `protobuf:"bytes,8,rep,name=unregistered_mongods,json=unregisteredMongods,proto3" json:"unregistered_mongods,omitempty"` + // Everything the probe recorded about the host, including attributes with no field + // above. + Observed *structpb.Struct `protobuf:"bytes,9,opt,name=observed,proto3" json:"observed,omitempty"` + // How current the above is, and how it is failing. + Freshness *InventoryFreshness `protobuf:"bytes,10,opt,name=freshness,proto3" json:"freshness,omitempty"` + // The services on it. Empty is a meaningful answer, not a gap. + Services []*InventoryService `protobuf:"bytes,11,rep,name=services,proto3" json:"services,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryHost) Reset() { + *x = InventoryHost{} + mi := &file_om_v1_om_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryHost) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryHost) ProtoMessage() {} + +func (x *InventoryHost) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryHost.ProtoReflect.Descriptor instead. +func (*InventoryHost) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{21} +} + +func (x *InventoryHost) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *InventoryHost) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *InventoryHost) GetAddress() string { + if x != nil && x.Address != nil { + return *x.Address + } + return "" +} + +func (x *InventoryHost) GetExecutorHost() string { + if x != nil && x.ExecutorHost != nil { + return *x.ExecutorHost + } + return "" +} + +func (x *InventoryHost) GetOs() string { + if x != nil && x.Os != nil { + return *x.Os + } + return "" +} + +func (x *InventoryHost) GetKernel() string { + if x != nil && x.Kernel != nil { + return *x.Kernel + } + return "" +} + +func (x *InventoryHost) GetExecutor() *InventoryExecutor { + if x != nil { + return x.Executor + } + return nil +} + +func (x *InventoryHost) GetUnregisteredMongods() []*UnregisteredMongod { + if x != nil { + return x.UnregisteredMongods + } + return nil +} + +func (x *InventoryHost) GetObserved() *structpb.Struct { + if x != nil { + return x.Observed + } + return nil +} + +func (x *InventoryHost) GetFreshness() *InventoryFreshness { + if x != nil { + return x.Freshness + } + return nil +} + +func (x *InventoryHost) GetServices() []*InventoryService { + if x != nil { + return x.Services + } + return nil +} + +// InventoryRunCounts is what one refresh saw. +type InventoryRunCounts struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Services enumeration found. + TotalServices int32 `protobuf:"varint,1,opt,name=total_services,json=totalServices,proto3" json:"total_services,omitempty"` + // ...of which matched a host something could be run on. + ResolvedServices int32 `protobuf:"varint,2,opt,name=resolved_services,json=resolvedServices,proto3" json:"resolved_services,omitempty"` + // ...of which did not. Not an error. + OrphanedServices int32 `protobuf:"varint,3,opt,name=orphaned_services,json=orphanedServices,proto3" json:"orphaned_services,omitempty"` + // Services that answered a probe. + AnsweredServices int32 `protobuf:"varint,4,opt,name=answered_services,json=answeredServices,proto3" json:"answered_services,omitempty"` + // Hosts in scope this run, service or no service. + // + // A refresh attempts hosts as well as the services on them, so counting only + // services makes a refresh of a host with no database read as "0 of 0" - which is + // exactly what a run that did nothing looks like, on the one kind of host OM most + // exists to describe. + TotalHosts int32 `protobuf:"varint,5,opt,name=total_hosts,json=totalHosts,proto3" json:"total_hosts,omitempty"` + // ...of which had somewhere to run a probe. The gap is the estate nothing can be + // dispatched to, which is a fact about onboarding rather than a failed run. + ProbeableHosts int32 `protobuf:"varint,6,opt,name=probeable_hosts,json=probeableHosts,proto3" json:"probeable_hosts,omitempty"` + // Hosts that answered. + AnsweredHosts int32 `protobuf:"varint,7,opt,name=answered_hosts,json=answeredHosts,proto3" json:"answered_hosts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryRunCounts) Reset() { + *x = InventoryRunCounts{} + mi := &file_om_v1_om_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryRunCounts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryRunCounts) ProtoMessage() {} + +func (x *InventoryRunCounts) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryRunCounts.ProtoReflect.Descriptor instead. +func (*InventoryRunCounts) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{22} +} + +func (x *InventoryRunCounts) GetTotalServices() int32 { + if x != nil { + return x.TotalServices + } + return 0 +} + +func (x *InventoryRunCounts) GetResolvedServices() int32 { + if x != nil { + return x.ResolvedServices + } + return 0 +} + +func (x *InventoryRunCounts) GetOrphanedServices() int32 { + if x != nil { + return x.OrphanedServices + } + return 0 +} + +func (x *InventoryRunCounts) GetAnsweredServices() int32 { + if x != nil { + return x.AnsweredServices + } + return 0 +} + +func (x *InventoryRunCounts) GetTotalHosts() int32 { + if x != nil { + return x.TotalHosts + } + return 0 +} + +func (x *InventoryRunCounts) GetProbeableHosts() int32 { + if x != nil { + return x.ProbeableHosts + } + return 0 +} + +func (x *InventoryRunCounts) GetAnsweredHosts() int32 { + if x != nil { + return x.AnsweredHosts + } + return 0 +} + +// InventoryRunEntityService is one service on a host, as a refresh saw it. +type InventoryRunEntityService struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's service ID, when OM could key one. + ServiceId *string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3,oneof" json:"service_id,omitempty"` + // Its name, so a reader is not left joining UUIDs by hand. + ServiceName *string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3,oneof" json:"service_name,omitempty"` + // Whether the host returned a usable record for it. + Answered bool `protobuf:"varint,3,opt,name=answered,proto3" json:"answered,omitempty"` + // Why it did not, when it did not. + Error *string `protobuf:"bytes,4,opt,name=error,proto3,oneof" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryRunEntityService) Reset() { + *x = InventoryRunEntityService{} + mi := &file_om_v1_om_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryRunEntityService) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryRunEntityService) ProtoMessage() {} + +func (x *InventoryRunEntityService) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryRunEntityService.ProtoReflect.Descriptor instead. +func (*InventoryRunEntityService) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{23} +} + +func (x *InventoryRunEntityService) GetServiceId() string { + if x != nil && x.ServiceId != nil { + return *x.ServiceId + } + return "" +} + +func (x *InventoryRunEntityService) GetServiceName() string { + if x != nil && x.ServiceName != nil { + return *x.ServiceName + } + return "" +} + +func (x *InventoryRunEntityService) GetAnswered() bool { + if x != nil { + return x.Answered + } + return false +} + +func (x *InventoryRunEntityService) GetError() string { + if x != nil && x.Error != nil { + return *x.Error + } + return "" +} + +// InventoryRunEntity is one host a refresh attempted, and what came of it. +// +// Host-oriented, because a refresh attempts hosts. A flat list of services - which +// this was - cannot show a machine carrying a PMM client and no database, however +// many times it is probed, and that machine is the case OM most exists to describe: +// it is where a database can be installed. +// +// One dispatch covers every service on a host, so the host owns the timing and the +// failure and its services carry only what is theirs. Previously the duration was +// copied onto each service, which read as several measurements when it was one. +// +// Deliberately outcomes and not observations. What the probe *found* lives on the +// estate, where it is upserted and stays current; a receipt that also carried the +// attributes would be a second copy that goes stale the moment the next refresh runs. +type InventoryRunEntity struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's node ID, the key OM holds this host under. + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The node's registered name. + HostName *string `protobuf:"bytes,2,opt,name=host_name,json=hostName,proto3,oneof" json:"host_name,omitempty"` + // The client its probe ran on. Unset when none matched. + ExecutorHost *string `protobuf:"bytes,3,opt,name=executor_host,json=executorHost,proto3,oneof" json:"executor_host,omitempty"` + // How that client was matched, or that it was not. + Resolution ExecutorResolution `protobuf:"varint,4,opt,name=resolution,proto3,enum=om.v1.ExecutorResolution" json:"resolution,omitempty"` + // Whether the *host* answered. A different question from whether its services did: + // a host with no database answers perfectly well and has no services at all. + Answered bool `protobuf:"varint,5,opt,name=answered,proto3" json:"answered,omitempty"` + // The host's wall clock, dispatch to collected output. + DurationSeconds *float64 `protobuf:"fixed64,6,opt,name=duration_seconds,json=durationSeconds,proto3,oneof" json:"duration_seconds,omitempty"` + // The host-level failure, when its probe failed. + Error *string `protobuf:"bytes,7,opt,name=error,proto3,oneof" json:"error,omitempty"` + // The services on it. Empty is a meaningful answer, not a gap. + Services []*InventoryRunEntityService `protobuf:"bytes,8,rep,name=services,proto3" json:"services,omitempty"` + // The task history id of the dispatch, so a reader can open the probe's own log. + // Unset when the dispatch never got one. + TaskHistoryId *int64 `protobuf:"varint,9,opt,name=task_history_id,json=taskHistoryId,proto3,oneof" json:"task_history_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryRunEntity) Reset() { + *x = InventoryRunEntity{} + mi := &file_om_v1_om_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryRunEntity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryRunEntity) ProtoMessage() {} + +func (x *InventoryRunEntity) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryRunEntity.ProtoReflect.Descriptor instead. +func (*InventoryRunEntity) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{24} +} + +func (x *InventoryRunEntity) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *InventoryRunEntity) GetHostName() string { + if x != nil && x.HostName != nil { + return *x.HostName + } + return "" +} + +func (x *InventoryRunEntity) GetExecutorHost() string { + if x != nil && x.ExecutorHost != nil { + return *x.ExecutorHost + } + return "" +} + +func (x *InventoryRunEntity) GetResolution() ExecutorResolution { + if x != nil { + return x.Resolution + } + return ExecutorResolution_EXECUTOR_RESOLUTION_UNSPECIFIED +} + +func (x *InventoryRunEntity) GetAnswered() bool { + if x != nil { + return x.Answered + } + return false +} + +func (x *InventoryRunEntity) GetDurationSeconds() float64 { + if x != nil && x.DurationSeconds != nil { + return *x.DurationSeconds + } + return 0 +} + +func (x *InventoryRunEntity) GetError() string { + if x != nil && x.Error != nil { + return *x.Error + } + return "" +} + +func (x *InventoryRunEntity) GetServices() []*InventoryRunEntityService { + if x != nil { + return x.Services + } + return nil +} + +func (x *InventoryRunEntity) GetTaskHistoryId() int64 { + if x != nil && x.TaskHistoryId != nil { + return *x.TaskHistoryId + } + return 0 +} + +// InventoryRun is one refresh of the estate. +type InventoryRun struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run's ID. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // How it ended. + Status RunStatus `protobuf:"varint,2,opt,name=status,proto3,enum=om.v1.RunStatus" json:"status,omitempty"` + // When it began. + StartTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + // When it stopped. Unset while it is still going. + EndTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + // What it saw. + Counts *InventoryRunCounts `protobuf:"bytes,5,opt,name=counts,proto3" json:"counts,omitempty"` + // The hosts it was limited to. Empty means it refreshed the whole estate, which is + // what the scheduled sweep does. + Scope []string `protobuf:"bytes,6,rep,name=scope,proto3" json:"scope,omitempty"` + // What went wrong, when something did. + Error *string `protobuf:"bytes,7,opt,name=error,proto3,oneof" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventoryRun) Reset() { + *x = InventoryRun{} + mi := &file_om_v1_om_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventoryRun) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventoryRun) ProtoMessage() {} + +func (x *InventoryRun) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventoryRun.ProtoReflect.Descriptor instead. +func (*InventoryRun) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{25} +} + +func (x *InventoryRun) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +func (x *InventoryRun) GetStatus() RunStatus { + if x != nil { + return x.Status + } + return RunStatus_RUN_STATUS_UNSPECIFIED +} + +func (x *InventoryRun) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *InventoryRun) GetEndTime() *timestamppb.Timestamp { + if x != nil { + return x.EndTime + } + return nil +} + +func (x *InventoryRun) GetCounts() *InventoryRunCounts { + if x != nil { + return x.Counts + } + return nil +} + +func (x *InventoryRun) GetScope() []string { + if x != nil { + return x.Scope + } + return nil +} + +func (x *InventoryRun) GetError() string { + if x != nil && x.Error != nil { + return *x.Error + } + return "" +} + +// InventorySetting is one of the inventory app's configuration fields. +type InventorySetting struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every. + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // The value in effect. + Value *structpb.Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + // What it would be with no override. + DefaultValue *structpb.Value `protobuf:"bytes,3,opt,name=default_value,json=defaultValue,proto3" json:"default_value,omitempty"` + // The field's type, for rendering an input. A string because the app's own schema + // names it, so this contract does not get to enumerate the possibilities. + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` + // Whether it can be changed at runtime. + Reload SettingReload `protobuf:"varint,5,opt,name=reload,proto3,enum=om.v1.SettingReload" json:"reload,omitempty"` + // Whether an override is in effect, which is how "why is it set to this" is + // answerable without also reading the deployment's configuration file. + HasOverride bool `protobuf:"varint,6,opt,name=has_override,json=hasOverride,proto3" json:"has_override,omitempty"` + // Whether to hide it behind an "advanced" disclosure. + IsAdvanced bool `protobuf:"varint,7,opt,name=is_advanced,json=isAdvanced,proto3" json:"is_advanced,omitempty"` + // The field's documentation, where it has any. + Description *string `protobuf:"bytes,8,opt,name=description,proto3,oneof" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InventorySetting) Reset() { + *x = InventorySetting{} + mi := &file_om_v1_om_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InventorySetting) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InventorySetting) ProtoMessage() {} + +func (x *InventorySetting) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InventorySetting.ProtoReflect.Descriptor instead. +func (*InventorySetting) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{26} +} + +func (x *InventorySetting) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *InventorySetting) GetValue() *structpb.Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *InventorySetting) GetDefaultValue() *structpb.Value { + if x != nil { + return x.DefaultValue + } + return nil +} + +func (x *InventorySetting) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *InventorySetting) GetReload() SettingReload { + if x != nil { + return x.Reload + } + return SettingReload_SETTING_RELOAD_UNSPECIFIED +} + +func (x *InventorySetting) GetHasOverride() bool { + if x != nil { + return x.HasOverride + } + return false +} + +func (x *InventorySetting) GetIsAdvanced() bool { + if x != nil { + return x.IsAdvanced + } + return false +} + +func (x *InventorySetting) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +// ListInventoryHostsRequest is the request for ListInventoryHosts. +type ListInventoryHostsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // When set, return only hosts that do (or do not) carry a registered service. + // Unset returns both, which is the ordinary listing. + HasService *bool `protobuf:"varint,1,opt,name=has_service,json=hasService,proto3,oneof" json:"has_service,omitempty"` + // When true, return only hosts currently failing. + Failing *bool `protobuf:"varint,2,opt,name=failing,proto3,oneof" json:"failing,omitempty"` + // When set, return only hosts that do (or do not) have an executor to run a probe + // on. Not a client name: the app filters on whether one is matched at all, and + // "which machines can nothing be dispatched to" is the question worth asking. + Executor *bool `protobuf:"varint,3,opt,name=executor,proto3,oneof" json:"executor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryHostsRequest) Reset() { + *x = ListInventoryHostsRequest{} + mi := &file_om_v1_om_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryHostsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryHostsRequest) ProtoMessage() {} + +func (x *ListInventoryHostsRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryHostsRequest.ProtoReflect.Descriptor instead. +func (*ListInventoryHostsRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{27} +} + +func (x *ListInventoryHostsRequest) GetHasService() bool { + if x != nil && x.HasService != nil { + return *x.HasService + } + return false +} + +func (x *ListInventoryHostsRequest) GetFailing() bool { + if x != nil && x.Failing != nil { + return *x.Failing + } + return false +} + +func (x *ListInventoryHostsRequest) GetExecutor() bool { + if x != nil && x.Executor != nil { + return *x.Executor + } + return false +} + +// ListInventoryHostsResponse returns the hosts OM knows about. +type ListInventoryHostsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The hosts. + Hosts []*InventoryHost `protobuf:"bytes,1,rep,name=hosts,proto3" json:"hosts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryHostsResponse) Reset() { + *x = ListInventoryHostsResponse{} + mi := &file_om_v1_om_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryHostsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryHostsResponse) ProtoMessage() {} + +func (x *ListInventoryHostsResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryHostsResponse.ProtoReflect.Descriptor instead. +func (*ListInventoryHostsResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{28} +} + +func (x *ListInventoryHostsResponse) GetHosts() []*InventoryHost { + if x != nil { + return x.Hosts + } + return nil +} + +// GetInventoryHostRequest is the request for GetInventoryHost. +type GetInventoryHostRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's node ID. + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryHostRequest) Reset() { + *x = GetInventoryHostRequest{} + mi := &file_om_v1_om_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryHostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryHostRequest) ProtoMessage() {} + +func (x *GetInventoryHostRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryHostRequest.ProtoReflect.Descriptor instead. +func (*GetInventoryHostRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{29} +} + +func (x *GetInventoryHostRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +// GetInventoryHostResponse returns one host. +type GetInventoryHostResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The host. + Host *InventoryHost `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryHostResponse) Reset() { + *x = GetInventoryHostResponse{} + mi := &file_om_v1_om_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryHostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryHostResponse) ProtoMessage() {} + +func (x *GetInventoryHostResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryHostResponse.ProtoReflect.Descriptor instead. +func (*GetInventoryHostResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{30} +} + +func (x *GetInventoryHostResponse) GetHost() *InventoryHost { + if x != nil { + return x.Host + } + return nil +} + +// DeleteInventoryHostRequest is the request for DeleteInventoryHost. +type DeleteInventoryHostRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's node ID. + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryHostRequest) Reset() { + *x = DeleteInventoryHostRequest{} + mi := &file_om_v1_om_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryHostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryHostRequest) ProtoMessage() {} + +func (x *DeleteInventoryHostRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryHostRequest.ProtoReflect.Descriptor instead. +func (*DeleteInventoryHostRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{31} +} + +func (x *DeleteInventoryHostRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +// DeleteInventoryHostResponse acknowledges forgetting a host. +type DeleteInventoryHostResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryHostResponse) Reset() { + *x = DeleteInventoryHostResponse{} + mi := &file_om_v1_om_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryHostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryHostResponse) ProtoMessage() {} + +func (x *DeleteInventoryHostResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryHostResponse.ProtoReflect.Descriptor instead. +func (*DeleteInventoryHostResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{32} +} + +// ListInventoryServicesRequest is the request for ListInventoryServices. +type ListInventoryServicesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // When set, return only the services on this host. + NodeId *string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3,oneof" json:"node_id,omitempty"` + // When true, return only services currently failing. + Failing *bool `protobuf:"varint,2,opt,name=failing,proto3,oneof" json:"failing,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryServicesRequest) Reset() { + *x = ListInventoryServicesRequest{} + mi := &file_om_v1_om_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryServicesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryServicesRequest) ProtoMessage() {} + +func (x *ListInventoryServicesRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryServicesRequest.ProtoReflect.Descriptor instead. +func (*ListInventoryServicesRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{33} +} + +func (x *ListInventoryServicesRequest) GetNodeId() string { + if x != nil && x.NodeId != nil { + return *x.NodeId + } + return "" +} + +func (x *ListInventoryServicesRequest) GetFailing() bool { + if x != nil && x.Failing != nil { + return *x.Failing + } + return false +} + +// ListInventoryServicesResponse returns the services OM knows about, flat. +type ListInventoryServicesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The services. + Services []*InventoryService `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryServicesResponse) Reset() { + *x = ListInventoryServicesResponse{} + mi := &file_om_v1_om_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryServicesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryServicesResponse) ProtoMessage() {} + +func (x *ListInventoryServicesResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryServicesResponse.ProtoReflect.Descriptor instead. +func (*ListInventoryServicesResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{34} +} + +func (x *ListInventoryServicesResponse) GetServices() []*InventoryService { + if x != nil { + return x.Services + } + return nil +} + +// GetInventoryServiceRequest is the request for GetInventoryService. +type GetInventoryServiceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's service ID. + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryServiceRequest) Reset() { + *x = GetInventoryServiceRequest{} + mi := &file_om_v1_om_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryServiceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryServiceRequest) ProtoMessage() {} + +func (x *GetInventoryServiceRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryServiceRequest.ProtoReflect.Descriptor instead. +func (*GetInventoryServiceRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{35} +} + +func (x *GetInventoryServiceRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +// GetInventoryServiceResponse returns one service. +type GetInventoryServiceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The service. + Service *InventoryService `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryServiceResponse) Reset() { + *x = GetInventoryServiceResponse{} + mi := &file_om_v1_om_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryServiceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryServiceResponse) ProtoMessage() {} + +func (x *GetInventoryServiceResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryServiceResponse.ProtoReflect.Descriptor instead. +func (*GetInventoryServiceResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{36} +} + +func (x *GetInventoryServiceResponse) GetService() *InventoryService { + if x != nil { + return x.Service + } + return nil +} + +// DeleteInventoryServiceRequest is the request for DeleteInventoryService. +type DeleteInventoryServiceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // PMM's service ID. + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryServiceRequest) Reset() { + *x = DeleteInventoryServiceRequest{} + mi := &file_om_v1_om_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryServiceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryServiceRequest) ProtoMessage() {} + +func (x *DeleteInventoryServiceRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryServiceRequest.ProtoReflect.Descriptor instead. +func (*DeleteInventoryServiceRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{37} +} + +func (x *DeleteInventoryServiceRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +// DeleteInventoryServiceResponse acknowledges forgetting a service. +type DeleteInventoryServiceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryServiceResponse) Reset() { + *x = DeleteInventoryServiceResponse{} + mi := &file_om_v1_om_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryServiceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryServiceResponse) ProtoMessage() {} + +func (x *DeleteInventoryServiceResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryServiceResponse.ProtoReflect.Descriptor instead. +func (*DeleteInventoryServiceResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{38} +} + +// ListInventoryRunsRequest is the request for ListInventoryRuns. +type ListInventoryRunsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // How many to return, newest first. Defaults to 20, capped at 100. + Limit int32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + // Inclusive lower bound on start_time. Unset means no lower bound. + // + // Applied before limit, so a week window is the newest runs *in that week*, + // not the newest overall then those that happen to fall in it. + Since *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=since,proto3" json:"since,omitempty"` + // Inclusive upper bound on start_time. Unset means no upper bound. + Until *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=until,proto3" json:"until,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryRunsRequest) Reset() { + *x = ListInventoryRunsRequest{} + mi := &file_om_v1_om_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryRunsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryRunsRequest) ProtoMessage() {} + +func (x *ListInventoryRunsRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryRunsRequest.ProtoReflect.Descriptor instead. +func (*ListInventoryRunsRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{39} +} + +func (x *ListInventoryRunsRequest) GetLimit() int32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListInventoryRunsRequest) GetSince() *timestamppb.Timestamp { + if x != nil { + return x.Since + } + return nil +} + +func (x *ListInventoryRunsRequest) GetUntil() *timestamppb.Timestamp { + if x != nil { + return x.Until + } + return nil +} + +// ListInventoryRunsResponse returns the refresh history, newest first. +type ListInventoryRunsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The runs. + Runs []*InventoryRun `protobuf:"bytes,1,rep,name=runs,proto3" json:"runs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListInventoryRunsResponse) Reset() { + *x = ListInventoryRunsResponse{} + mi := &file_om_v1_om_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInventoryRunsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInventoryRunsResponse) ProtoMessage() {} + +func (x *ListInventoryRunsResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[40] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListInventoryRunsResponse.ProtoReflect.Descriptor instead. +func (*ListInventoryRunsResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{40} +} + +func (x *ListInventoryRunsResponse) GetRuns() []*InventoryRun { + if x != nil { + return x.Runs + } + return nil +} + +// GetInventoryRunRequest is the request for GetInventoryRun. +type GetInventoryRunRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run's ID. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryRunRequest) Reset() { + *x = GetInventoryRunRequest{} + mi := &file_om_v1_om_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryRunRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryRunRequest) ProtoMessage() {} + +func (x *GetInventoryRunRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryRunRequest.ProtoReflect.Descriptor instead. +func (*GetInventoryRunRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{41} +} + +func (x *GetInventoryRunRequest) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +// GetInventoryRunResponse returns one refresh, with the rows behind its counters. +type GetInventoryRunResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run. + Run *InventoryRun `protobuf:"bytes,1,opt,name=run,proto3" json:"run,omitempty"` + // What it attempted, one entry per entity. + // + // Only on the detail response, never on the list: a refresh of a real estate has a + // row per service, and a history of twenty-five would carry the lot to render a + // page that shows one at a time. + Entities []*InventoryRunEntity `protobuf:"bytes,2,rep,name=entities,proto3" json:"entities,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryRunResponse) Reset() { + *x = GetInventoryRunResponse{} + mi := &file_om_v1_om_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryRunResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryRunResponse) ProtoMessage() {} + +func (x *GetInventoryRunResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[42] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryRunResponse.ProtoReflect.Descriptor instead. +func (*GetInventoryRunResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{42} +} + +func (x *GetInventoryRunResponse) GetRun() *InventoryRun { + if x != nil { + return x.Run + } + return nil +} + +func (x *GetInventoryRunResponse) GetEntities() []*InventoryRunEntity { + if x != nil { + return x.Entities + } + return nil +} + +// TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh. +type TriggerInventoryRefreshRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The hosts to refresh, by PMM node ID. Empty refreshes the whole estate. + // + // Plural on purpose: PMM's node ID is also OM's key, so ids pass through + // untranslated, and one host is a list of one. A surface taking a single id where + // the app takes a list would be a translation step in disguise. + // + // Bounded because a refresh dispatches a Nomad job per host: the empty list already + // means "the whole estate", so a caller naming hosts individually is naming a few, + // and an unbounded list is only reachable by accident. An empty string is rejected + // rather than forwarded, where it would read as a node ID that matches nothing. + NodeIds []string `protobuf:"bytes,1,rep,name=node_ids,json=nodeIds,proto3" json:"node_ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TriggerInventoryRefreshRequest) Reset() { + *x = TriggerInventoryRefreshRequest{} + mi := &file_om_v1_om_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TriggerInventoryRefreshRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerInventoryRefreshRequest) ProtoMessage() {} + +func (x *TriggerInventoryRefreshRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[43] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerInventoryRefreshRequest.ProtoReflect.Descriptor instead. +func (*TriggerInventoryRefreshRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{43} +} + +func (x *TriggerInventoryRefreshRequest) GetNodeIds() []string { + if x != nil { + return x.NodeIds + } + return nil +} + +// TriggerInventoryRefreshResponse acknowledges an accepted refresh. +// +// Accepted, not finished. A refresh dispatches a Nomad job per host and takes tens of +// seconds, unlike PMM's own collection pass, which never probes and completes in +// milliseconds. Two triggers that different must not look alike to a caller. +type TriggerInventoryRefreshResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The run's ID, to follow with GetInventoryRun. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // Its status, which is RUN_STATUS_RUNNING. + Status RunStatus `protobuf:"varint,2,opt,name=status,proto3,enum=om.v1.RunStatus" json:"status,omitempty"` + // When it began. + StartTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + // The hosts it will refresh. Empty means the whole estate. + Scope []string `protobuf:"bytes,4,rep,name=scope,proto3" json:"scope,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TriggerInventoryRefreshResponse) Reset() { + *x = TriggerInventoryRefreshResponse{} + mi := &file_om_v1_om_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TriggerInventoryRefreshResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerInventoryRefreshResponse) ProtoMessage() {} + +func (x *TriggerInventoryRefreshResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[44] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerInventoryRefreshResponse.ProtoReflect.Descriptor instead. +func (*TriggerInventoryRefreshResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{44} +} + +func (x *TriggerInventoryRefreshResponse) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +func (x *TriggerInventoryRefreshResponse) GetStatus() RunStatus { + if x != nil { + return x.Status + } + return RunStatus_RUN_STATUS_UNSPECIFIED +} + +func (x *TriggerInventoryRefreshResponse) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *TriggerInventoryRefreshResponse) GetScope() []string { + if x != nil { + return x.Scope + } + return nil +} + +// GetInventoryConfigRequest is the request for GetInventoryConfig. +type GetInventoryConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryConfigRequest) Reset() { + *x = GetInventoryConfigRequest{} + mi := &file_om_v1_om_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryConfigRequest) ProtoMessage() {} + +func (x *GetInventoryConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[45] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryConfigRequest.ProtoReflect.Descriptor instead. +func (*GetInventoryConfigRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{45} +} + +// GetInventoryConfigResponse returns the inventory app's configuration. +type GetInventoryConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Every field, whether or not it is overridden. + Settings []*InventorySetting `protobuf:"bytes,1,rep,name=settings,proto3" json:"settings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetInventoryConfigResponse) Reset() { + *x = GetInventoryConfigResponse{} + mi := &file_om_v1_om_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetInventoryConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInventoryConfigResponse) ProtoMessage() {} + +func (x *GetInventoryConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[46] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInventoryConfigResponse.ProtoReflect.Descriptor instead. +func (*GetInventoryConfigResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{46} +} + +func (x *GetInventoryConfigResponse) GetSettings() []*InventorySetting { + if x != nil { + return x.Settings + } + return nil +} + +// UpdateInventoryConfigRequest is the request for UpdateInventoryConfig. +type UpdateInventoryConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The fields to change, as `{key: value}`. + // + // A map of arbitrary JSON rather than named fields, because the app owns which + // fields exist and what they are typed as; mirroring them here would mean a proto + // change and a `make gen` every time it grows a setting. The app validates and + // rejects the batch as a whole. + // + // Bound to the HTTP body directly (`body: "values"`, not `body: "*"`), so the request + // this endpoint takes is the same object it forwards. The alternative wraps it as + // `{"values": {...}}`, which would make the proxy's shape differ from the shape of the + // thing being proxied for no gain to anyone reading either. + // + // A `Struct` carries no field rules, so "name at least one field" is enforced in the + // handler rather than declared here -- the only precondition on this surface that a + // generated validator does not express. + Values *structpb.Struct `protobuf:"bytes,1,opt,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateInventoryConfigRequest) Reset() { + *x = UpdateInventoryConfigRequest{} + mi := &file_om_v1_om_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateInventoryConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateInventoryConfigRequest) ProtoMessage() {} + +func (x *UpdateInventoryConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[47] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateInventoryConfigRequest.ProtoReflect.Descriptor instead. +func (*UpdateInventoryConfigRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{47} +} + +func (x *UpdateInventoryConfigRequest) GetValues() *structpb.Struct { + if x != nil { + return x.Values + } + return nil +} + +// UpdateInventoryConfigResponse returns the configuration as it now stands. +type UpdateInventoryConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Every field, not only the ones the request named. + // + // The whole resource, because an Update answers with the resource. It is also the only + // honest answer for a nested write: overriding a parent object changes what its + // children effectively resolve to, and a response scoped to the submitted keys would + // report the parent and leave a stale child beside it. + Settings []*InventorySetting `protobuf:"bytes,1,rep,name=settings,proto3" json:"settings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateInventoryConfigResponse) Reset() { + *x = UpdateInventoryConfigResponse{} + mi := &file_om_v1_om_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateInventoryConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateInventoryConfigResponse) ProtoMessage() {} + +func (x *UpdateInventoryConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[48] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateInventoryConfigResponse.ProtoReflect.Descriptor instead. +func (*UpdateInventoryConfigResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{48} +} + +func (x *UpdateInventoryConfigResponse) GetSettings() []*InventorySetting { + if x != nil { + return x.Settings + } + return nil +} + +// DeleteInventoryConfigOverrideRequest is the request for +// DeleteInventoryConfigOverride. +type DeleteInventoryConfigOverrideRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The field whose override to remove, putting it back to its deployed value. Also the + // resource ID within the `overrides` collection. + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryConfigOverrideRequest) Reset() { + *x = DeleteInventoryConfigOverrideRequest{} + mi := &file_om_v1_om_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryConfigOverrideRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryConfigOverrideRequest) ProtoMessage() {} + +func (x *DeleteInventoryConfigOverrideRequest) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryConfigOverrideRequest.ProtoReflect.Descriptor instead. +func (*DeleteInventoryConfigOverrideRequest) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{49} +} + +func (x *DeleteInventoryConfigOverrideRequest) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +// DeleteInventoryConfigOverrideResponse acknowledges the revert. +type DeleteInventoryConfigOverrideResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteInventoryConfigOverrideResponse) Reset() { + *x = DeleteInventoryConfigOverrideResponse{} + mi := &file_om_v1_om_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInventoryConfigOverrideResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInventoryConfigOverrideResponse) ProtoMessage() {} + +func (x *DeleteInventoryConfigOverrideResponse) ProtoReflect() protoreflect.Message { + mi := &file_om_v1_om_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInventoryConfigOverrideResponse.ProtoReflect.Descriptor instead. +func (*DeleteInventoryConfigOverrideResponse) Descriptor() ([]byte, []int) { + return file_om_v1_om_proto_rawDescGZIP(), []int{50} +} + +var File_om_v1_om_proto protoreflect.FileDescriptor + +const file_om_v1_om_proto_rawDesc = "" + + "\n" + + "\x0eom/v1/om.proto\x12\x05om.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\x1a\x17validate/validate.proto\"\xbb\b\n" + + "\x0fTopologyService\x12!\n" + + "\fservice_name\x18\x01 \x01(\tR\vserviceName\x12\x17\n" + + "\x04host\x18\x02 \x01(\tH\x00R\x04host\x88\x01\x01\x12\x1f\n" + + "\bendpoint\x18\x03 \x01(\tH\x01R\bendpoint\x88\x01\x01\x12\"\n" + + "\n" + + "service_id\x18\x04 \x01(\tH\x02R\tserviceId\x88\x01\x01\x12&\n" + + "\fservice_type\x18\x05 \x01(\tH\x03R\vserviceType\x88\x01\x01\x12\x1d\n" + + "\aversion\x18\x06 \x01(\tH\x04R\aversion\x88\x01\x01\x12\x1b\n" + + "\x06vendor\x18\a \x01(\tH\x05R\x06vendor\x88\x01\x01\x12\x1d\n" + + "\aedition\x18\b \x01(\tH\x06R\aedition\x88\x01\x01\x12,\n" + + "\x0freplication_set\x18\t \x01(\tH\aR\x0ereplicationSet\x88\x01\x01\x12\x19\n" + + "\x05state\x18\n" + + " \x01(\tH\bR\x05state\x88\x01\x01\x12,\n" + + "\x06status\x18\v \x01(\x0e2\x14.om.v1.ServiceStatusR\x06status\x12*\n" + + "\x11cpu_usage_percent\x18\f \x01(\x01R\x0fcpuUsagePercent\x128\n" + + "\x18connections_free_percent\x18\r \x01(\x01R\x16connectionsFreePercent\x125\n" + + "\fprocess_role\x18\x0e \x01(\x0e2\x12.om.v1.ProcessRoleR\vprocessRole\x12;\n" + + "\x17replication_lag_seconds\x18\x0f \x01(\x01H\tR\x15replicationLagSeconds\x88\x01\x01\x125\n" + + "\x14oplog_window_seconds\x18\x10 \x01(\x01H\n" + + "R\x12oplogWindowSeconds\x88\x01\x01\x120\n" + + "\x11installed_version\x18\x11 \x01(\tH\vR\x10installedVersion\x88\x01\x01\x12$\n" + + "\vconfig_path\x18\x12 \x01(\tH\fR\n" + + "configPath\x88\x01\x01\x12\x17\n" + + "\x04argv\x18\x13 \x01(\tH\rR\x04argv\x88\x01\x01\x12@\n" + + "\vobserved_at\x18\x14 \x01(\v2\x1a.google.protobuf.TimestampH\x0eR\n" + + "observedAt\x88\x01\x01B\a\n" + + "\x05_hostB\v\n" + + "\t_endpointB\r\n" + + "\v_service_idB\x0f\n" + + "\r_service_typeB\n" + + "\n" + + "\b_versionB\t\n" + + "\a_vendorB\n" + + "\n" + + "\b_editionB\x12\n" + + "\x10_replication_setB\b\n" + + "\x06_stateB\x1a\n" + + "\x18_replication_lag_secondsB\x17\n" + + "\x15_oplog_window_secondsB\x14\n" + + "\x12_installed_versionB\x0e\n" + + "\f_config_pathB\a\n" + + "\x05_argvB\x0e\n" + + "\f_observed_at\"\xc5\x01\n" + + "\aCluster\x12\x17\n" + + "\x04name\x18\x01 \x01(\tH\x00R\x04name\x88\x01\x01\x122\n" + + "\bservices\x18\x02 \x03(\v2\x16.om.v1.TopologyServiceR\bservices\x12\x0e\n" + + "\x02id\x18\x03 \x01(\tR\x02id\x12&\n" + + "\x04type\x18\x04 \x01(\x0e2\x12.om.v1.ClusterTypeR\x04type\x12,\n" + + "\x06health\x18\x05 \x01(\x0e2\x14.om.v1.ClusterHealthR\x06healthB\a\n" + + "\x05_name\"f\n" + + "\vEnvironment\x12\x1e\n" + + "\benv_name\x18\x01 \x01(\tH\x00R\aenvName\x88\x01\x01\x12*\n" + + "\bclusters\x18\x02 \x03(\v2\x0e.om.v1.ClusterR\bclustersB\v\n" + + "\t_env_name\"\xd3\x02\n" + + "\aSummary\x12\"\n" + + "\fenvironments\x18\x01 \x01(\x05R\fenvironments\x12\x1a\n" + + "\bclusters\x18\x02 \x01(\x05R\bclusters\x12%\n" + + "\x0etotal_services\x18\x03 \x01(\x05R\rtotalServices\x12\x1f\n" + + "\vup_services\x18\x04 \x01(\x05R\n" + + "upServices\x12#\n" + + "\rdown_services\x18\x05 \x01(\x05R\fdownServices\x12U\n" + + "\x13process_role_counts\x18\x06 \x03(\v2%.om.v1.Summary.ProcessRoleCountsEntryR\x11processRoleCounts\x1aD\n" + + "\x16ProcessRoleCountsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01\"\xda\x01\n" + + "\bSnapshot\x12=\n" + + "\fgenerated_at\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\vgeneratedAt\x12;\n" + + "\vobserved_at\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "observedAt\x12\x14\n" + + "\x05stale\x18\x03 \x01(\bR\x05stale\x12%\n" + + "\x0eschema_version\x18\x04 \x01(\x05R\rschemaVersion\x12\x15\n" + + "\x06run_id\x18\x05 \x01(\tR\x05runId\"\x14\n" + + "\x12GetTopologyRequest\"\x81\x02\n" + + "\x13GetTopologyResponse\x12+\n" + + "\bsnapshot\x18\x01 \x01(\v2\x0f.om.v1.SnapshotR\bsnapshot\x12$\n" + + "\vorigin_node\x18\x02 \x01(\tH\x00R\n" + + "originNode\x88\x01\x01\x12%\n" + + "\x0esource_queries\x18\x03 \x03(\tR\rsourceQueries\x12(\n" + + "\asummary\x18\x04 \x01(\v2\x0e.om.v1.SummaryR\asummary\x126\n" + + "\fenvironments\x18\x05 \x03(\v2\x12.om.v1.EnvironmentR\fenvironmentsB\x0e\n" + + "\f_origin_node\"\xe8\x01\n" + + "\x11TopologyRunCounts\x12%\n" + + "\x0etotal_services\x18\x01 \x01(\x05R\rtotalServices\x12+\n" + + "\x11resolved_services\x18\x02 \x01(\x05R\x10resolvedServices\x12+\n" + + "\x11orphaned_services\x18\x03 \x01(\x05R\x10orphanedServices\x12+\n" + + "\x11successful_probes\x18\x04 \x01(\x05R\x10successfulProbes\x12%\n" + + "\x0estale_services\x18\x05 \x01(\x05R\rstaleServices\"\xdd\x01\n" + + "\fSourceReport\x12\x16\n" + + "\x06source\x18\x01 \x01(\tR\x06source\x12+\n" + + "\x06status\x18\x02 \x01(\x0e2\x13.om.v1.SourceStatusR\x06status\x12\x14\n" + + "\x05facts\x18\x03 \x01(\x05R\x05facts\x127\n" + + "\x06detail\x18\x04 \x03(\v2\x1f.om.v1.SourceReport.DetailEntryR\x06detail\x1a9\n" + + "\vDetailEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x8f\x01\n" + + "\x10TopologyRunError\x12\x14\n" + + "\x05scope\x18\x01 \x01(\tR\x05scope\x12&\n" + + "\fservice_name\x18\x02 \x01(\tH\x00R\vserviceName\x88\x01\x01\x12\x12\n" + + "\x04code\x18\x03 \x01(\tR\x04code\x12\x18\n" + + "\amessage\x18\x04 \x01(\tR\amessageB\x0f\n" + + "\r_service_name\"\xd2\x02\n" + + "\vTopologyRun\x12\x15\n" + + "\x06run_id\x18\x01 \x01(\tR\x05runId\x12(\n" + + "\x06status\x18\x02 \x01(\x0e2\x10.om.v1.RunStatusR\x06status\x129\n" + + "\n" + + "start_time\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x125\n" + + "\bend_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\aendTime\x120\n" + + "\x06counts\x18\x05 \x01(\v2\x18.om.v1.TopologyRunCountsR\x06counts\x12/\n" + + "\x06errors\x18\x06 \x03(\v2\x17.om.v1.TopologyRunErrorR\x06errors\x12-\n" + + "\asources\x18\a \x03(\v2\x13.om.v1.SourceReportR\asources\"7\n" + + "\x15GetTopologyRunRequest\x12\x1e\n" + + "\x06run_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\x05runId\">\n" + + "\x16GetTopologyRunResponse\x12$\n" + + "\x03run\x18\x01 \x01(\v2\x12.om.v1.TopologyRunR\x03run\":\n" + + "\x17ListTopologyRunsRequest\x12\x1f\n" + + "\x05limit\x18\x01 \x01(\x05B\t\xfaB\x06\x1a\x04\x18d(\x00R\x05limit\"B\n" + + "\x18ListTopologyRunsResponse\x12&\n" + + "\x04runs\x18\x01 \x03(\v2\x12.om.v1.TopologyRunR\x04runs\"\"\n" + + " TriggerTopologyCollectionRequest\"\x9f\x01\n" + + "!TriggerTopologyCollectionResponse\x12\x15\n" + + "\x06run_id\x18\x01 \x01(\tR\x05runId\x12(\n" + + "\x06status\x18\x02 \x01(\x0e2\x10.om.v1.RunStatusR\x06status\x129\n" + + "\n" + + "start_time\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\"\xa0\x01\n" + + "\x11InventoryExecutor\x12\x1e\n" + + "\n" + + "registered\x18\x01 \x01(\bR\n" + + "registered\x12\x1c\n" + + "\treachable\x18\x02 \x01(\bR\treachable\x12%\n" + + "\x0edriver_healthy\x18\x03 \x01(\bR\rdriverHealthy\x12\x1b\n" + + "\x06detail\x18\x04 \x01(\tH\x00R\x06detail\x88\x01\x01B\t\n" + + "\a_detail\"\xd8\x01\n" + + "\x12UnregisteredMongod\x12\x17\n" + + "\x04port\x18\x01 \x01(\x05H\x00R\x04port\x88\x01\x01\x12$\n" + + "\vconfig_path\x18\x02 \x01(\tH\x01R\n" + + "configPath\x88\x01\x01\x12\x17\n" + + "\x04argv\x18\x03 \x01(\tH\x02R\x04argv\x88\x01\x01\x12\x1d\n" + + "\aprogram\x18\x04 \x01(\tH\x03R\aprogram\x88\x01\x01\x12\x15\n" + + "\x03pid\x18\x05 \x01(\x05H\x04R\x03pid\x88\x01\x01B\a\n" + + "\x05_portB\x0e\n" + + "\f_config_pathB\a\n" + + "\x05_argvB\n" + + "\n" + + "\b_programB\x06\n" + + "\x04_pid\"\x83\x03\n" + + "\x12InventoryFreshness\x12>\n" + + "\rfirst_seen_at\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\vfirstSeenAt\x12B\n" + + "\x0flast_attempt_at\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\rlastAttemptAt\x12B\n" + + "\x0flast_success_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\rlastSuccessAt\x12?\n" + + "\rfailing_since\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\ffailingSince\x121\n" + + "\x14consecutive_failures\x18\x05 \x01(\x05R\x13consecutiveFailures\x12\"\n" + + "\n" + + "last_error\x18\x06 \x01(\tH\x00R\tlastError\x88\x01\x01B\r\n" + + "\v_last_error\"\xeb\x05\n" + + "\x10InventoryService\x12\x1d\n" + + "\n" + + "service_id\x18\x01 \x01(\tR\tserviceId\x12\x17\n" + + "\anode_id\x18\x02 \x01(\tR\x06nodeId\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x17\n" + + "\x04port\x18\x04 \x01(\x05H\x00R\x04port\x88\x01\x01\x12\x17\n" + + "\x04role\x18\x05 \x01(\tH\x01R\x04role\x88\x01\x01\x120\n" + + "\x11installed_version\x18\x06 \x01(\tH\x02R\x10installedVersion\x88\x01\x01\x12,\n" + + "\x0frunning_version\x18\a \x01(\tH\x03R\x0erunningVersion\x88\x01\x01\x12$\n" + + "\vconfig_path\x18\b \x01(\tH\x04R\n" + + "configPath\x88\x01\x01\x12\x17\n" + + "\x04argv\x18\t \x01(\tH\x05R\x04argv\x88\x01\x01\x12&\n" + + "\fprobe_status\x18\n" + + " \x01(\tH\x06R\vprobeStatus\x88\x01\x01\x12*\n" + + "\x0eserver_running\x18\v \x01(\bH\aR\rserverRunning\x88\x01\x01\x12*\n" + + "\x0euptime_seconds\x18\f \x01(\x01H\bR\ruptimeSeconds\x88\x01\x01\x12,\n" + + "\x0freplication_set\x18\r \x01(\tH\tR\x0ereplicationSet\x88\x01\x01\x123\n" + + "\bobserved\x18\x0e \x01(\v2\x17.google.protobuf.StructR\bobserved\x127\n" + + "\tfreshness\x18\x0f \x01(\v2\x19.om.v1.InventoryFreshnessR\tfreshnessB\a\n" + + "\x05_portB\a\n" + + "\x05_roleB\x14\n" + + "\x12_installed_versionB\x12\n" + + "\x10_running_versionB\x0e\n" + + "\f_config_pathB\a\n" + + "\x05_argvB\x0f\n" + + "\r_probe_statusB\x11\n" + + "\x0f_server_runningB\x11\n" + + "\x0f_uptime_secondsB\x12\n" + + "\x10_replication_set\"\x8e\x04\n" + + "\rInventoryHost\x12\x17\n" + + "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1d\n" + + "\aaddress\x18\x03 \x01(\tH\x00R\aaddress\x88\x01\x01\x12(\n" + + "\rexecutor_host\x18\x04 \x01(\tH\x01R\fexecutorHost\x88\x01\x01\x12\x13\n" + + "\x02os\x18\x05 \x01(\tH\x02R\x02os\x88\x01\x01\x12\x1b\n" + + "\x06kernel\x18\x06 \x01(\tH\x03R\x06kernel\x88\x01\x01\x124\n" + + "\bexecutor\x18\a \x01(\v2\x18.om.v1.InventoryExecutorR\bexecutor\x12L\n" + + "\x14unregistered_mongods\x18\b \x03(\v2\x19.om.v1.UnregisteredMongodR\x13unregisteredMongods\x123\n" + + "\bobserved\x18\t \x01(\v2\x17.google.protobuf.StructR\bobserved\x127\n" + + "\tfreshness\x18\n" + + " \x01(\v2\x19.om.v1.InventoryFreshnessR\tfreshness\x123\n" + + "\bservices\x18\v \x03(\v2\x17.om.v1.InventoryServiceR\bservicesB\n" + + "\n" + + "\b_addressB\x10\n" + + "\x0e_executor_hostB\x05\n" + + "\x03_osB\t\n" + + "\a_kernel\"\xb3\x02\n" + + "\x12InventoryRunCounts\x12%\n" + + "\x0etotal_services\x18\x01 \x01(\x05R\rtotalServices\x12+\n" + + "\x11resolved_services\x18\x02 \x01(\x05R\x10resolvedServices\x12+\n" + + "\x11orphaned_services\x18\x03 \x01(\x05R\x10orphanedServices\x12+\n" + + "\x11answered_services\x18\x04 \x01(\x05R\x10answeredServices\x12\x1f\n" + + "\vtotal_hosts\x18\x05 \x01(\x05R\n" + + "totalHosts\x12'\n" + + "\x0fprobeable_hosts\x18\x06 \x01(\x05R\x0eprobeableHosts\x12%\n" + + "\x0eanswered_hosts\x18\a \x01(\x05R\ransweredHosts\"\xc8\x01\n" + + "\x19InventoryRunEntityService\x12\"\n" + + "\n" + + "service_id\x18\x01 \x01(\tH\x00R\tserviceId\x88\x01\x01\x12&\n" + + "\fservice_name\x18\x02 \x01(\tH\x01R\vserviceName\x88\x01\x01\x12\x1a\n" + + "\banswered\x18\x03 \x01(\bR\banswered\x12\x19\n" + + "\x05error\x18\x04 \x01(\tH\x02R\x05error\x88\x01\x01B\r\n" + + "\v_service_idB\x0f\n" + + "\r_service_nameB\b\n" + + "\x06_error\"\xd9\x03\n" + + "\x12InventoryRunEntity\x12\x17\n" + + "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12 \n" + + "\thost_name\x18\x02 \x01(\tH\x00R\bhostName\x88\x01\x01\x12(\n" + + "\rexecutor_host\x18\x03 \x01(\tH\x01R\fexecutorHost\x88\x01\x01\x129\n" + + "\n" + + "resolution\x18\x04 \x01(\x0e2\x19.om.v1.ExecutorResolutionR\n" + + "resolution\x12\x1a\n" + + "\banswered\x18\x05 \x01(\bR\banswered\x12.\n" + + "\x10duration_seconds\x18\x06 \x01(\x01H\x02R\x0fdurationSeconds\x88\x01\x01\x12\x19\n" + + "\x05error\x18\a \x01(\tH\x03R\x05error\x88\x01\x01\x12<\n" + + "\bservices\x18\b \x03(\v2 .om.v1.InventoryRunEntityServiceR\bservices\x12+\n" + + "\x0ftask_history_id\x18\t \x01(\x03H\x04R\rtaskHistoryId\x88\x01\x01B\f\n" + + "\n" + + "_host_nameB\x10\n" + + "\x0e_executor_hostB\x13\n" + + "\x11_duration_secondsB\b\n" + + "\x06_errorB\x12\n" + + "\x10_task_history_id\"\xaf\x02\n" + + "\fInventoryRun\x12\x15\n" + + "\x06run_id\x18\x01 \x01(\tR\x05runId\x12(\n" + + "\x06status\x18\x02 \x01(\x0e2\x10.om.v1.RunStatusR\x06status\x129\n" + + "\n" + + "start_time\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x125\n" + + "\bend_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\aendTime\x121\n" + + "\x06counts\x18\x05 \x01(\v2\x19.om.v1.InventoryRunCountsR\x06counts\x12\x14\n" + + "\x05scope\x18\x06 \x03(\tR\x05scope\x12\x19\n" + + "\x05error\x18\a \x01(\tH\x00R\x05error\x88\x01\x01B\b\n" + + "\x06_error\"\xcc\x02\n" + + "\x10InventorySetting\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12,\n" + + "\x05value\x18\x02 \x01(\v2\x16.google.protobuf.ValueR\x05value\x12;\n" + + "\rdefault_value\x18\x03 \x01(\v2\x16.google.protobuf.ValueR\fdefaultValue\x12\x12\n" + + "\x04type\x18\x04 \x01(\tR\x04type\x12,\n" + + "\x06reload\x18\x05 \x01(\x0e2\x14.om.v1.SettingReloadR\x06reload\x12!\n" + + "\fhas_override\x18\x06 \x01(\bR\vhasOverride\x12\x1f\n" + + "\vis_advanced\x18\a \x01(\bR\n" + + "isAdvanced\x12%\n" + + "\vdescription\x18\b \x01(\tH\x00R\vdescription\x88\x01\x01B\x0e\n" + + "\f_description\"\xaa\x01\n" + + "\x19ListInventoryHostsRequest\x12$\n" + + "\vhas_service\x18\x01 \x01(\bH\x00R\n" + + "hasService\x88\x01\x01\x12\x1d\n" + + "\afailing\x18\x02 \x01(\bH\x01R\afailing\x88\x01\x01\x12\x1f\n" + + "\bexecutor\x18\x03 \x01(\bH\x02R\bexecutor\x88\x01\x01B\x0e\n" + + "\f_has_serviceB\n" + + "\n" + + "\b_failingB\v\n" + + "\t_executor\"H\n" + + "\x1aListInventoryHostsResponse\x12*\n" + + "\x05hosts\x18\x01 \x03(\v2\x14.om.v1.InventoryHostR\x05hosts\";\n" + + "\x17GetInventoryHostRequest\x12 \n" + + "\anode_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\x06nodeId\"D\n" + + "\x18GetInventoryHostResponse\x12(\n" + + "\x04host\x18\x01 \x01(\v2\x14.om.v1.InventoryHostR\x04host\">\n" + + "\x1aDeleteInventoryHostRequest\x12 \n" + + "\anode_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\x06nodeId\"\x1d\n" + + "\x1bDeleteInventoryHostResponse\"s\n" + + "\x1cListInventoryServicesRequest\x12\x1c\n" + + "\anode_id\x18\x01 \x01(\tH\x00R\x06nodeId\x88\x01\x01\x12\x1d\n" + + "\afailing\x18\x02 \x01(\bH\x01R\afailing\x88\x01\x01B\n" + + "\n" + + "\b_node_idB\n" + + "\n" + + "\b_failing\"T\n" + + "\x1dListInventoryServicesResponse\x123\n" + + "\bservices\x18\x01 \x03(\v2\x17.om.v1.InventoryServiceR\bservices\"D\n" + + "\x1aGetInventoryServiceRequest\x12&\n" + + "\n" + + "service_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\tserviceId\"P\n" + + "\x1bGetInventoryServiceResponse\x121\n" + + "\aservice\x18\x01 \x01(\v2\x17.om.v1.InventoryServiceR\aservice\"G\n" + + "\x1dDeleteInventoryServiceRequest\x12&\n" + + "\n" + + "service_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\tserviceId\" \n" + + "\x1eDeleteInventoryServiceResponse\"\x9f\x01\n" + + "\x18ListInventoryRunsRequest\x12\x1f\n" + + "\x05limit\x18\x01 \x01(\x05B\t\xfaB\x06\x1a\x04\x18d(\x00R\x05limit\x120\n" + + "\x05since\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x05since\x120\n" + + "\x05until\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x05until\"D\n" + + "\x19ListInventoryRunsResponse\x12'\n" + + "\x04runs\x18\x01 \x03(\v2\x13.om.v1.InventoryRunR\x04runs\"8\n" + + "\x16GetInventoryRunRequest\x12\x1e\n" + + "\x06run_id\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\x05runId\"w\n" + + "\x17GetInventoryRunResponse\x12%\n" + + "\x03run\x18\x01 \x01(\v2\x13.om.v1.InventoryRunR\x03run\x125\n" + + "\bentities\x18\x02 \x03(\v2\x19.om.v1.InventoryRunEntityR\bentities\"L\n" + + "\x1eTriggerInventoryRefreshRequest\x12*\n" + + "\bnode_ids\x18\x01 \x03(\tB\x0f\xfaB\f\x92\x01\t\x10\xe8\a\"\x04r\x02\x10\x01R\anodeIds\"\xb3\x01\n" + + "\x1fTriggerInventoryRefreshResponse\x12\x15\n" + + "\x06run_id\x18\x01 \x01(\tR\x05runId\x12(\n" + + "\x06status\x18\x02 \x01(\x0e2\x10.om.v1.RunStatusR\x06status\x129\n" + + "\n" + + "start_time\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x12\x14\n" + + "\x05scope\x18\x04 \x03(\tR\x05scope\"\x1b\n" + + "\x19GetInventoryConfigRequest\"Q\n" + + "\x1aGetInventoryConfigResponse\x123\n" + + "\bsettings\x18\x01 \x03(\v2\x17.om.v1.InventorySettingR\bsettings\"O\n" + + "\x1cUpdateInventoryConfigRequest\x12/\n" + + "\x06values\x18\x01 \x01(\v2\x17.google.protobuf.StructR\x06values\"T\n" + + "\x1dUpdateInventoryConfigResponse\x123\n" + + "\bsettings\x18\x01 \x03(\v2\x17.om.v1.InventorySettingR\bsettings\"A\n" + + "$DeleteInventoryConfigOverrideRequest\x12\x19\n" + + "\x03key\x18\x01 \x01(\tB\a\xfaB\x04r\x02\x10\x01R\x03key\"'\n" + + "%DeleteInventoryConfigOverrideResponse*_\n" + + "\rServiceStatus\x12\x1e\n" + + "\x1aSERVICE_STATUS_UNSPECIFIED\x10\x00\x12\x15\n" + + "\x11SERVICE_STATUS_UP\x10\x01\x12\x17\n" + + "\x13SERVICE_STATUS_DOWN\x10\x02*\x94\x01\n" + + "\vProcessRole\x12\x1c\n" + + "\x18PROCESS_ROLE_UNSPECIFIED\x10\x00\x12\x17\n" + + "\x13PROCESS_ROLE_MONGOD\x10\x01\x12\x17\n" + + "\x13PROCESS_ROLE_MONGOS\x10\x02\x12\x1a\n" + + "\x16PROCESS_ROLE_CONFIGSVR\x10\x03\x12\x19\n" + + "\x15PROCESS_ROLE_SHARDSVR\x10\x04*\x9e\x01\n" + + "\tRunStatus\x12\x1a\n" + + "\x16RUN_STATUS_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12RUN_STATUS_RUNNING\x10\x01\x12\x16\n" + + "\x12RUN_STATUS_SUCCESS\x10\x02\x12\x16\n" + + "\x12RUN_STATUS_PARTIAL\x10\x03\x12\x15\n" + + "\x11RUN_STATUS_FAILED\x10\x04\x12\x16\n" + + "\x12RUN_STATUS_SKIPPED\x10\x05*\x94\x01\n" + + "\fSourceStatus\x12\x1d\n" + + "\x19SOURCE_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" + + "\x10SOURCE_STATUS_OK\x10\x01\x12\x19\n" + + "\x15SOURCE_STATUS_PARTIAL\x10\x02\x12\x18\n" + + "\x14SOURCE_STATUS_FAILED\x10\x03\x12\x1a\n" + + "\x16SOURCE_STATUS_DISABLED\x10\x04*\x80\x01\n" + + "\vClusterType\x12\x1c\n" + + "\x18CLUSTER_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n" + + "\x18CLUSTER_TYPE_REPLICA_SET\x10\x01\x12\x18\n" + + "\x14CLUSTER_TYPE_SHARDED\x10\x02\x12\x1b\n" + + "\x17CLUSTER_TYPE_STANDALONE\x10\x03*/\n" + + "\rClusterHealth\x12\x1e\n" + + "\x1aCLUSTER_HEALTH_UNSPECIFIED\x10\x00*\x9a\x01\n" + + "\x12ExecutorResolution\x12#\n" + + "\x1fEXECUTOR_RESOLUTION_UNSPECIFIED\x10\x00\x12\x1c\n" + + "\x18EXECUTOR_RESOLUTION_NAME\x10\x01\x12\x1f\n" + + "\x1bEXECUTOR_RESOLUTION_ADDRESS\x10\x02\x12 \n" + + "\x1cEXECUTOR_RESOLUTION_ORPHANED\x10\x03*\x8b\x01\n" + + "\rSettingReload\x12\x1e\n" + + "\x1aSETTING_RELOAD_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12SETTING_RELOAD_HOT\x10\x01\x12\x1e\n" + + "\x1aSETTING_RELOAD_NESTED_ONLY\x10\x02\x12\"\n" + + "\x1eSETTING_RELOAD_NOT_OVERRIDABLE\x10\x032\xbe$\n" + + "\tOmService\x12\x89\x02\n" + + "\vGetTopology\x12\x19.om.v1.GetTopologyRequest\x1a\x1a.om.v1.GetTopologyResponse\"\xc2\x01\x92A\xa7\x01\x12\x18Get the MongoDB topology\x1a\x8a\x01Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load.\x82\xd3\xe4\x93\x02\x11\x12\x0f/v1/om/topology\x12\xee\x01\n" + + "\x10ListTopologyRuns\x12\x1e.om.v1.ListTopologyRunsRequest\x1a\x1f.om.v1.ListTopologyRunsResponse\"\x98\x01\x92Ay\x12\x14List collection runs\x1aaReturns the recorded collection runs, newest first, with what each one saw and any errors it hit.\x82\xd3\xe4\x93\x02\x16\x12\x14/v1/om/topology/runs\x12\xf7\x01\n" + + "\x0eGetTopologyRun\x12\x1c.om.v1.GetTopologyRunRequest\x1a\x1d.om.v1.GetTopologyRunResponse\"\xa7\x01\x92A\x7f\x12\x14Get a collection run\x1agReturns one recorded collection run, with what it saw, how each source answered, and any errors it hit.\x82\xd3\xe4\x93\x02\x1f\x12\x1d/v1/om/topology/runs/{run_id}\x12\x92\x02\n" + + "\x19TriggerTopologyCollection\x12'.om.v1.TriggerTopologyCollectionRequest\x1a(.om.v1.TriggerTopologyCollectionResponse\"\xa1\x01\x92Aw\x12\x18Trigger a collection run\x1a[Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run.\x82\xd3\xe4\x93\x02!:\x01*\"\x1c/v1/om/topology/runs:collect\x12\xb5\x02\n" + + "\x12ListInventoryHosts\x12 .om.v1.ListInventoryHostsRequest\x1a!.om.v1.ListInventoryHostsResponse\"\xd9\x01\x92A\xb7\x01\x12\x14List inventory hosts\x1a\x9e\x01Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are.\x82\xd3\xe4\x93\x02\x18\x12\x16/v1/om/inventory/hosts\x12\xd2\x01\n" + + "\x10GetInventoryHost\x12\x1e.om.v1.GetInventoryHostRequest\x1a\x1f.om.v1.GetInventoryHostResponse\"}\x92AR\x12\x15Get an inventory host\x1a9Returns one host by PMM node ID, with the services on it.\x82\xd3\xe4\x93\x02\"\x12 /v1/om/inventory/hosts/{node_id}\x12\x85\x03\n" + + "\x13DeleteInventoryHost\x12!.om.v1.DeleteInventoryHostRequest\x1a\".om.v1.DeleteInventoryHostResponse\"\xa6\x02\x92A\xfa\x01\x12\x18Forget an inventory host\x1a\xdd\x01Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID.\x82\xd3\xe4\x93\x02\"* /v1/om/inventory/hosts/{node_id}\x12\x8a\x02\n" + + "\x15ListInventoryServices\x12#.om.v1.ListInventoryServicesRequest\x1a$.om.v1.ListInventoryServicesResponse\"\xa5\x01\x92A\x80\x01\x12\x17List inventory services\x1aeReturns every MongoDB service the inventory app has a row for, with what each last reported and when.\x82\xd3\xe4\x93\x02\x1b\x12\x19/v1/om/inventory/services\x12\xd1\x01\n" + + "\x13GetInventoryService\x12!.om.v1.GetInventoryServiceRequest\x1a\".om.v1.GetInventoryServiceResponse\"s\x92AB\x12\x18Get an inventory service\x1a&Returns one service by PMM service ID.\x82\xd3\xe4\x93\x02(\x12&/v1/om/inventory/services/{service_id}\x12\xc3\x02\n" + + "\x16DeleteInventoryService\x12$.om.v1.DeleteInventoryServiceRequest\x1a%.om.v1.DeleteInventoryServiceResponse\"\xdb\x01\x92A\xa9\x01\x12\x1bForget an inventory service\x1a\x89\x01Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh.\x82\xd3\xe4\x93\x02(*&/v1/om/inventory/services/{service_id}\x12\xb1\x02\n" + + "\x11ListInventoryRuns\x12\x1f.om.v1.ListInventoryRunsRequest\x1a .om.v1.ListInventoryRunsResponse\"\xd8\x01\x92A\xb7\x01\x12\x18List inventory refreshes\x1a\x9a\x01Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host.\x82\xd3\xe4\x93\x02\x17\x12\x15/v1/om/inventory/runs\x12\xdf\x01\n" + + "\x0fGetInventoryRun\x12\x1d.om.v1.GetInventoryRunRequest\x1a\x1e.om.v1.GetInventoryRunResponse\"\x8c\x01\x92Ac\x12\x18Get an inventory refresh\x1aGReturns one refresh by ID, with what it saw and which hosts it covered.\x82\xd3\xe4\x93\x02 \x12\x1e/v1/om/inventory/runs/{run_id}\x12\xa1\x03\n" + + "\x17TriggerInventoryRefresh\x12%.om.v1.TriggerInventoryRefreshRequest\x1a&.om.v1.TriggerInventoryRefreshResponse\"\xb6\x02\x92A\x8a\x02\x12\x15Refresh the inventory\x1a\xf0\x01Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them.\x82\xd3\xe4\x93\x02\":\x01*\"\x1d/v1/om/inventory/runs:trigger\x12\x94\x02\n" + + "\x12GetInventoryConfig\x12 .om.v1.GetInventoryConfigRequest\x1a!.om.v1.GetInventoryConfigResponse\"\xb8\x01\x92A\x95\x01\x12\x1fGet the inventory configuration\x1arReturns every configuration field of the inventory app, its effective value, and whether an override is in effect.\x82\xd3\xe4\x93\x02\x19\x12\x17/v1/om/inventory/config\x12\xd6\x02\n" + + "\x15UpdateInventoryConfig\x12#.om.v1.UpdateInventoryConfigRequest\x1a$.om.v1.UpdateInventoryConfigResponse\"\xf1\x01\x92A\xc6\x01\x12\"Change the inventory configuration\x1a\x9f\x01Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted.\x82\xd3\xe4\x93\x02!:\x06values\x1a\x17/v1/om/inventory/config\x12\xbe\x02\n" + + "\x1dDeleteInventoryConfigOverride\x12+.om.v1.DeleteInventoryConfigOverrideRequest\x1a,.om.v1.DeleteInventoryConfigOverrideResponse\"\xc1\x01\x92A\x8e\x01\x12'Revert an inventory configuration field\x1acRemoves the override for one field so it returns to whatever the deployment configured. Idempotent.\x82\xd3\xe4\x93\x02)*'/v1/om/inventory/config/overrides/{key}Bp\n" + + "\tcom.om.v1B\aOmProtoP\x01Z%github.com/percona/pmm/api/om/v1;omv1\xa2\x02\x03OXX\xaa\x02\x05Om.V1\xca\x02\x05Om\\V1\xe2\x02\x11Om\\V1\\GPBMetadata\xea\x02\x06Om::V1b\x06proto3" + +var ( + file_om_v1_om_proto_rawDescOnce sync.Once + file_om_v1_om_proto_rawDescData []byte +) + +func file_om_v1_om_proto_rawDescGZIP() []byte { + file_om_v1_om_proto_rawDescOnce.Do(func() { + file_om_v1_om_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_om_v1_om_proto_rawDesc), len(file_om_v1_om_proto_rawDesc))) + }) + return file_om_v1_om_proto_rawDescData +} + +var ( + file_om_v1_om_proto_enumTypes = make([]protoimpl.EnumInfo, 8) + file_om_v1_om_proto_msgTypes = make([]protoimpl.MessageInfo, 53) + file_om_v1_om_proto_goTypes = []any{ + ServiceStatus(0), // 0: om.v1.ServiceStatus + ProcessRole(0), // 1: om.v1.ProcessRole + RunStatus(0), // 2: om.v1.RunStatus + SourceStatus(0), // 3: om.v1.SourceStatus + ClusterType(0), // 4: om.v1.ClusterType + ClusterHealth(0), // 5: om.v1.ClusterHealth + ExecutorResolution(0), // 6: om.v1.ExecutorResolution + SettingReload(0), // 7: om.v1.SettingReload + (*TopologyService)(nil), // 8: om.v1.TopologyService + (*Cluster)(nil), // 9: om.v1.Cluster + (*Environment)(nil), // 10: om.v1.Environment + (*Summary)(nil), // 11: om.v1.Summary + (*Snapshot)(nil), // 12: om.v1.Snapshot + (*GetTopologyRequest)(nil), // 13: om.v1.GetTopologyRequest + (*GetTopologyResponse)(nil), // 14: om.v1.GetTopologyResponse + (*TopologyRunCounts)(nil), // 15: om.v1.TopologyRunCounts + (*SourceReport)(nil), // 16: om.v1.SourceReport + (*TopologyRunError)(nil), // 17: om.v1.TopologyRunError + (*TopologyRun)(nil), // 18: om.v1.TopologyRun + (*GetTopologyRunRequest)(nil), // 19: om.v1.GetTopologyRunRequest + (*GetTopologyRunResponse)(nil), // 20: om.v1.GetTopologyRunResponse + (*ListTopologyRunsRequest)(nil), // 21: om.v1.ListTopologyRunsRequest + (*ListTopologyRunsResponse)(nil), // 22: om.v1.ListTopologyRunsResponse + (*TriggerTopologyCollectionRequest)(nil), // 23: om.v1.TriggerTopologyCollectionRequest + (*TriggerTopologyCollectionResponse)(nil), // 24: om.v1.TriggerTopologyCollectionResponse + (*InventoryExecutor)(nil), // 25: om.v1.InventoryExecutor + (*UnregisteredMongod)(nil), // 26: om.v1.UnregisteredMongod + (*InventoryFreshness)(nil), // 27: om.v1.InventoryFreshness + (*InventoryService)(nil), // 28: om.v1.InventoryService + (*InventoryHost)(nil), // 29: om.v1.InventoryHost + (*InventoryRunCounts)(nil), // 30: om.v1.InventoryRunCounts + (*InventoryRunEntityService)(nil), // 31: om.v1.InventoryRunEntityService + (*InventoryRunEntity)(nil), // 32: om.v1.InventoryRunEntity + (*InventoryRun)(nil), // 33: om.v1.InventoryRun + (*InventorySetting)(nil), // 34: om.v1.InventorySetting + (*ListInventoryHostsRequest)(nil), // 35: om.v1.ListInventoryHostsRequest + (*ListInventoryHostsResponse)(nil), // 36: om.v1.ListInventoryHostsResponse + (*GetInventoryHostRequest)(nil), // 37: om.v1.GetInventoryHostRequest + (*GetInventoryHostResponse)(nil), // 38: om.v1.GetInventoryHostResponse + (*DeleteInventoryHostRequest)(nil), // 39: om.v1.DeleteInventoryHostRequest + (*DeleteInventoryHostResponse)(nil), // 40: om.v1.DeleteInventoryHostResponse + (*ListInventoryServicesRequest)(nil), // 41: om.v1.ListInventoryServicesRequest + (*ListInventoryServicesResponse)(nil), // 42: om.v1.ListInventoryServicesResponse + (*GetInventoryServiceRequest)(nil), // 43: om.v1.GetInventoryServiceRequest + (*GetInventoryServiceResponse)(nil), // 44: om.v1.GetInventoryServiceResponse + (*DeleteInventoryServiceRequest)(nil), // 45: om.v1.DeleteInventoryServiceRequest + (*DeleteInventoryServiceResponse)(nil), // 46: om.v1.DeleteInventoryServiceResponse + (*ListInventoryRunsRequest)(nil), // 47: om.v1.ListInventoryRunsRequest + (*ListInventoryRunsResponse)(nil), // 48: om.v1.ListInventoryRunsResponse + (*GetInventoryRunRequest)(nil), // 49: om.v1.GetInventoryRunRequest + (*GetInventoryRunResponse)(nil), // 50: om.v1.GetInventoryRunResponse + (*TriggerInventoryRefreshRequest)(nil), // 51: om.v1.TriggerInventoryRefreshRequest + (*TriggerInventoryRefreshResponse)(nil), // 52: om.v1.TriggerInventoryRefreshResponse + (*GetInventoryConfigRequest)(nil), // 53: om.v1.GetInventoryConfigRequest + (*GetInventoryConfigResponse)(nil), // 54: om.v1.GetInventoryConfigResponse + (*UpdateInventoryConfigRequest)(nil), // 55: om.v1.UpdateInventoryConfigRequest + (*UpdateInventoryConfigResponse)(nil), // 56: om.v1.UpdateInventoryConfigResponse + (*DeleteInventoryConfigOverrideRequest)(nil), // 57: om.v1.DeleteInventoryConfigOverrideRequest + (*DeleteInventoryConfigOverrideResponse)(nil), // 58: om.v1.DeleteInventoryConfigOverrideResponse + nil, // 59: om.v1.Summary.ProcessRoleCountsEntry + nil, // 60: om.v1.SourceReport.DetailEntry + (*timestamppb.Timestamp)(nil), // 61: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 62: google.protobuf.Struct + (*structpb.Value)(nil), // 63: google.protobuf.Value + } +) + +var file_om_v1_om_proto_depIdxs = []int32{ + 0, // 0: om.v1.TopologyService.status:type_name -> om.v1.ServiceStatus + 1, // 1: om.v1.TopologyService.process_role:type_name -> om.v1.ProcessRole + 61, // 2: om.v1.TopologyService.observed_at:type_name -> google.protobuf.Timestamp + 8, // 3: om.v1.Cluster.services:type_name -> om.v1.TopologyService + 4, // 4: om.v1.Cluster.type:type_name -> om.v1.ClusterType + 5, // 5: om.v1.Cluster.health:type_name -> om.v1.ClusterHealth + 9, // 6: om.v1.Environment.clusters:type_name -> om.v1.Cluster + 59, // 7: om.v1.Summary.process_role_counts:type_name -> om.v1.Summary.ProcessRoleCountsEntry + 61, // 8: om.v1.Snapshot.generated_at:type_name -> google.protobuf.Timestamp + 61, // 9: om.v1.Snapshot.observed_at:type_name -> google.protobuf.Timestamp + 12, // 10: om.v1.GetTopologyResponse.snapshot:type_name -> om.v1.Snapshot + 11, // 11: om.v1.GetTopologyResponse.summary:type_name -> om.v1.Summary + 10, // 12: om.v1.GetTopologyResponse.environments:type_name -> om.v1.Environment + 3, // 13: om.v1.SourceReport.status:type_name -> om.v1.SourceStatus + 60, // 14: om.v1.SourceReport.detail:type_name -> om.v1.SourceReport.DetailEntry + 2, // 15: om.v1.TopologyRun.status:type_name -> om.v1.RunStatus + 61, // 16: om.v1.TopologyRun.start_time:type_name -> google.protobuf.Timestamp + 61, // 17: om.v1.TopologyRun.end_time:type_name -> google.protobuf.Timestamp + 15, // 18: om.v1.TopologyRun.counts:type_name -> om.v1.TopologyRunCounts + 17, // 19: om.v1.TopologyRun.errors:type_name -> om.v1.TopologyRunError + 16, // 20: om.v1.TopologyRun.sources:type_name -> om.v1.SourceReport + 18, // 21: om.v1.GetTopologyRunResponse.run:type_name -> om.v1.TopologyRun + 18, // 22: om.v1.ListTopologyRunsResponse.runs:type_name -> om.v1.TopologyRun + 2, // 23: om.v1.TriggerTopologyCollectionResponse.status:type_name -> om.v1.RunStatus + 61, // 24: om.v1.TriggerTopologyCollectionResponse.start_time:type_name -> google.protobuf.Timestamp + 61, // 25: om.v1.InventoryFreshness.first_seen_at:type_name -> google.protobuf.Timestamp + 61, // 26: om.v1.InventoryFreshness.last_attempt_at:type_name -> google.protobuf.Timestamp + 61, // 27: om.v1.InventoryFreshness.last_success_at:type_name -> google.protobuf.Timestamp + 61, // 28: om.v1.InventoryFreshness.failing_since:type_name -> google.protobuf.Timestamp + 62, // 29: om.v1.InventoryService.observed:type_name -> google.protobuf.Struct + 27, // 30: om.v1.InventoryService.freshness:type_name -> om.v1.InventoryFreshness + 25, // 31: om.v1.InventoryHost.executor:type_name -> om.v1.InventoryExecutor + 26, // 32: om.v1.InventoryHost.unregistered_mongods:type_name -> om.v1.UnregisteredMongod + 62, // 33: om.v1.InventoryHost.observed:type_name -> google.protobuf.Struct + 27, // 34: om.v1.InventoryHost.freshness:type_name -> om.v1.InventoryFreshness + 28, // 35: om.v1.InventoryHost.services:type_name -> om.v1.InventoryService + 6, // 36: om.v1.InventoryRunEntity.resolution:type_name -> om.v1.ExecutorResolution + 31, // 37: om.v1.InventoryRunEntity.services:type_name -> om.v1.InventoryRunEntityService + 2, // 38: om.v1.InventoryRun.status:type_name -> om.v1.RunStatus + 61, // 39: om.v1.InventoryRun.start_time:type_name -> google.protobuf.Timestamp + 61, // 40: om.v1.InventoryRun.end_time:type_name -> google.protobuf.Timestamp + 30, // 41: om.v1.InventoryRun.counts:type_name -> om.v1.InventoryRunCounts + 63, // 42: om.v1.InventorySetting.value:type_name -> google.protobuf.Value + 63, // 43: om.v1.InventorySetting.default_value:type_name -> google.protobuf.Value + 7, // 44: om.v1.InventorySetting.reload:type_name -> om.v1.SettingReload + 29, // 45: om.v1.ListInventoryHostsResponse.hosts:type_name -> om.v1.InventoryHost + 29, // 46: om.v1.GetInventoryHostResponse.host:type_name -> om.v1.InventoryHost + 28, // 47: om.v1.ListInventoryServicesResponse.services:type_name -> om.v1.InventoryService + 28, // 48: om.v1.GetInventoryServiceResponse.service:type_name -> om.v1.InventoryService + 61, // 49: om.v1.ListInventoryRunsRequest.since:type_name -> google.protobuf.Timestamp + 61, // 50: om.v1.ListInventoryRunsRequest.until:type_name -> google.protobuf.Timestamp + 33, // 51: om.v1.ListInventoryRunsResponse.runs:type_name -> om.v1.InventoryRun + 33, // 52: om.v1.GetInventoryRunResponse.run:type_name -> om.v1.InventoryRun + 32, // 53: om.v1.GetInventoryRunResponse.entities:type_name -> om.v1.InventoryRunEntity + 2, // 54: om.v1.TriggerInventoryRefreshResponse.status:type_name -> om.v1.RunStatus + 61, // 55: om.v1.TriggerInventoryRefreshResponse.start_time:type_name -> google.protobuf.Timestamp + 34, // 56: om.v1.GetInventoryConfigResponse.settings:type_name -> om.v1.InventorySetting + 62, // 57: om.v1.UpdateInventoryConfigRequest.values:type_name -> google.protobuf.Struct + 34, // 58: om.v1.UpdateInventoryConfigResponse.settings:type_name -> om.v1.InventorySetting + 13, // 59: om.v1.OmService.GetTopology:input_type -> om.v1.GetTopologyRequest + 21, // 60: om.v1.OmService.ListTopologyRuns:input_type -> om.v1.ListTopologyRunsRequest + 19, // 61: om.v1.OmService.GetTopologyRun:input_type -> om.v1.GetTopologyRunRequest + 23, // 62: om.v1.OmService.TriggerTopologyCollection:input_type -> om.v1.TriggerTopologyCollectionRequest + 35, // 63: om.v1.OmService.ListInventoryHosts:input_type -> om.v1.ListInventoryHostsRequest + 37, // 64: om.v1.OmService.GetInventoryHost:input_type -> om.v1.GetInventoryHostRequest + 39, // 65: om.v1.OmService.DeleteInventoryHost:input_type -> om.v1.DeleteInventoryHostRequest + 41, // 66: om.v1.OmService.ListInventoryServices:input_type -> om.v1.ListInventoryServicesRequest + 43, // 67: om.v1.OmService.GetInventoryService:input_type -> om.v1.GetInventoryServiceRequest + 45, // 68: om.v1.OmService.DeleteInventoryService:input_type -> om.v1.DeleteInventoryServiceRequest + 47, // 69: om.v1.OmService.ListInventoryRuns:input_type -> om.v1.ListInventoryRunsRequest + 49, // 70: om.v1.OmService.GetInventoryRun:input_type -> om.v1.GetInventoryRunRequest + 51, // 71: om.v1.OmService.TriggerInventoryRefresh:input_type -> om.v1.TriggerInventoryRefreshRequest + 53, // 72: om.v1.OmService.GetInventoryConfig:input_type -> om.v1.GetInventoryConfigRequest + 55, // 73: om.v1.OmService.UpdateInventoryConfig:input_type -> om.v1.UpdateInventoryConfigRequest + 57, // 74: om.v1.OmService.DeleteInventoryConfigOverride:input_type -> om.v1.DeleteInventoryConfigOverrideRequest + 14, // 75: om.v1.OmService.GetTopology:output_type -> om.v1.GetTopologyResponse + 22, // 76: om.v1.OmService.ListTopologyRuns:output_type -> om.v1.ListTopologyRunsResponse + 20, // 77: om.v1.OmService.GetTopologyRun:output_type -> om.v1.GetTopologyRunResponse + 24, // 78: om.v1.OmService.TriggerTopologyCollection:output_type -> om.v1.TriggerTopologyCollectionResponse + 36, // 79: om.v1.OmService.ListInventoryHosts:output_type -> om.v1.ListInventoryHostsResponse + 38, // 80: om.v1.OmService.GetInventoryHost:output_type -> om.v1.GetInventoryHostResponse + 40, // 81: om.v1.OmService.DeleteInventoryHost:output_type -> om.v1.DeleteInventoryHostResponse + 42, // 82: om.v1.OmService.ListInventoryServices:output_type -> om.v1.ListInventoryServicesResponse + 44, // 83: om.v1.OmService.GetInventoryService:output_type -> om.v1.GetInventoryServiceResponse + 46, // 84: om.v1.OmService.DeleteInventoryService:output_type -> om.v1.DeleteInventoryServiceResponse + 48, // 85: om.v1.OmService.ListInventoryRuns:output_type -> om.v1.ListInventoryRunsResponse + 50, // 86: om.v1.OmService.GetInventoryRun:output_type -> om.v1.GetInventoryRunResponse + 52, // 87: om.v1.OmService.TriggerInventoryRefresh:output_type -> om.v1.TriggerInventoryRefreshResponse + 54, // 88: om.v1.OmService.GetInventoryConfig:output_type -> om.v1.GetInventoryConfigResponse + 56, // 89: om.v1.OmService.UpdateInventoryConfig:output_type -> om.v1.UpdateInventoryConfigResponse + 58, // 90: om.v1.OmService.DeleteInventoryConfigOverride:output_type -> om.v1.DeleteInventoryConfigOverrideResponse + 75, // [75:91] is the sub-list for method output_type + 59, // [59:75] is the sub-list for method input_type + 59, // [59:59] is the sub-list for extension type_name + 59, // [59:59] is the sub-list for extension extendee + 0, // [0:59] is the sub-list for field type_name +} + +func init() { file_om_v1_om_proto_init() } +func file_om_v1_om_proto_init() { + if File_om_v1_om_proto != nil { + return + } + file_om_v1_om_proto_msgTypes[0].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[1].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[2].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[6].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[9].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[17].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[18].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[19].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[20].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[21].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[23].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[24].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[25].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[26].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[27].OneofWrappers = []any{} + file_om_v1_om_proto_msgTypes[33].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_om_v1_om_proto_rawDesc), len(file_om_v1_om_proto_rawDesc)), + NumEnums: 8, + NumMessages: 53, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_om_v1_om_proto_goTypes, + DependencyIndexes: file_om_v1_om_proto_depIdxs, + EnumInfos: file_om_v1_om_proto_enumTypes, + MessageInfos: file_om_v1_om_proto_msgTypes, + }.Build() + File_om_v1_om_proto = out.File + file_om_v1_om_proto_goTypes = nil + file_om_v1_om_proto_depIdxs = nil +} diff --git a/api/om/v1/om.pb.gw.go b/api/om/v1/om.pb.gw.go new file mode 100644 index 00000000000..57816405f21 --- /dev/null +++ b/api/om/v1/om.pb.gw.go @@ -0,0 +1,1251 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: om/v1/om.proto + +/* +Package omv1 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package omv1 + +import ( + "context" + "errors" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) + +func request_OmService_GetTopology_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetTopologyRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetTopology(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetTopology_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetTopologyRequest + metadata runtime.ServerMetadata + ) + msg, err := server.GetTopology(ctx, &protoReq) + return msg, metadata, err +} + +var filter_OmService_ListTopologyRuns_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_OmService_ListTopologyRuns_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListTopologyRunsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListTopologyRuns_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListTopologyRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_ListTopologyRuns_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListTopologyRunsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListTopologyRuns_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListTopologyRuns(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_GetTopologyRun_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetTopologyRunRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["run_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "run_id") + } + protoReq.RunId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "run_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetTopologyRun(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetTopologyRun_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetTopologyRunRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["run_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "run_id") + } + protoReq.RunId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "run_id", err) + } + msg, err := server.GetTopologyRun(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_TriggerTopologyCollection_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq TriggerTopologyCollectionRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.TriggerTopologyCollection(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_TriggerTopologyCollection_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq TriggerTopologyCollectionRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.TriggerTopologyCollection(ctx, &protoReq) + return msg, metadata, err +} + +var filter_OmService_ListInventoryHosts_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_OmService_ListInventoryHosts_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryHostsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryHosts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListInventoryHosts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_ListInventoryHosts_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryHostsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryHosts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListInventoryHosts(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_GetInventoryHost_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryHostRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetInventoryHost(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetInventoryHost_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryHostRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + msg, err := server.GetInventoryHost(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_DeleteInventoryHost_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryHostRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.DeleteInventoryHost(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_DeleteInventoryHost_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryHostRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["node_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node_id") + } + protoReq.NodeId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node_id", err) + } + msg, err := server.DeleteInventoryHost(ctx, &protoReq) + return msg, metadata, err +} + +var filter_OmService_ListInventoryServices_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_OmService_ListInventoryServices_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryServicesRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryServices_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListInventoryServices(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_ListInventoryServices_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryServicesRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryServices_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListInventoryServices(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_GetInventoryService_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryServiceRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["service_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "service_id") + } + protoReq.ServiceId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "service_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetInventoryService(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetInventoryService_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryServiceRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["service_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "service_id") + } + protoReq.ServiceId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "service_id", err) + } + msg, err := server.GetInventoryService(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_DeleteInventoryService_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryServiceRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["service_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "service_id") + } + protoReq.ServiceId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "service_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.DeleteInventoryService(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_DeleteInventoryService_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryServiceRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["service_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "service_id") + } + protoReq.ServiceId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "service_id", err) + } + msg, err := server.DeleteInventoryService(ctx, &protoReq) + return msg, metadata, err +} + +var filter_OmService_ListInventoryRuns_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_OmService_ListInventoryRuns_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryRunsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryRuns_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListInventoryRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_ListInventoryRuns_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListInventoryRunsRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_OmService_ListInventoryRuns_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListInventoryRuns(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_GetInventoryRun_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryRunRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["run_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "run_id") + } + protoReq.RunId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "run_id", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetInventoryRun(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetInventoryRun_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryRunRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["run_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "run_id") + } + protoReq.RunId, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "run_id", err) + } + msg, err := server.GetInventoryRun(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_TriggerInventoryRefresh_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq TriggerInventoryRefreshRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.TriggerInventoryRefresh(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_TriggerInventoryRefresh_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq TriggerInventoryRefreshRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.TriggerInventoryRefresh(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_GetInventoryConfig_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryConfigRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.GetInventoryConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_GetInventoryConfig_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetInventoryConfigRequest + metadata runtime.ServerMetadata + ) + msg, err := server.GetInventoryConfig(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_UpdateInventoryConfig_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateInventoryConfigRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Values); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.UpdateInventoryConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_UpdateInventoryConfig_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateInventoryConfigRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Values); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.UpdateInventoryConfig(ctx, &protoReq) + return msg, metadata, err +} + +func request_OmService_DeleteInventoryConfigOverride_0(ctx context.Context, marshaler runtime.Marshaler, client OmServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryConfigOverrideRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["key"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key") + } + protoReq.Key, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.DeleteInventoryConfigOverride(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_OmService_DeleteInventoryConfigOverride_0(ctx context.Context, marshaler runtime.Marshaler, server OmServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteInventoryConfigOverrideRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["key"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key") + } + protoReq.Key, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err) + } + msg, err := server.DeleteInventoryConfigOverride(ctx, &protoReq) + return msg, metadata, err +} + +// RegisterOmServiceHandlerServer registers the http handlers for service OmService to "mux". +// UnaryRPC :call OmServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterOmServiceHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. +func RegisterOmServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server OmServiceServer) error { + mux.Handle(http.MethodGet, pattern_OmService_GetTopology_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetTopology", runtime.WithHTTPPathPattern("/v1/om/topology")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetTopology_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetTopology_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListTopologyRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/ListTopologyRuns", runtime.WithHTTPPathPattern("/v1/om/topology/runs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_ListTopologyRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListTopologyRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetTopologyRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetTopologyRun", runtime.WithHTTPPathPattern("/v1/om/topology/runs/{run_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetTopologyRun_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetTopologyRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_OmService_TriggerTopologyCollection_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/TriggerTopologyCollection", runtime.WithHTTPPathPattern("/v1/om/topology/runs:collect")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_TriggerTopologyCollection_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_TriggerTopologyCollection_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryHosts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/ListInventoryHosts", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_ListInventoryHosts_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryHosts_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryHost_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetInventoryHost", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts/{node_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetInventoryHost_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryHost_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryHost_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryHost", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts/{node_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_DeleteInventoryHost_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryHost_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryServices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/ListInventoryServices", runtime.WithHTTPPathPattern("/v1/om/inventory/services")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_ListInventoryServices_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryServices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetInventoryService", runtime.WithHTTPPathPattern("/v1/om/inventory/services/{service_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetInventoryService_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryService_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryService", runtime.WithHTTPPathPattern("/v1/om/inventory/services/{service_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_DeleteInventoryService_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryService_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/ListInventoryRuns", runtime.WithHTTPPathPattern("/v1/om/inventory/runs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_ListInventoryRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetInventoryRun", runtime.WithHTTPPathPattern("/v1/om/inventory/runs/{run_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetInventoryRun_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_OmService_TriggerInventoryRefresh_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/TriggerInventoryRefresh", runtime.WithHTTPPathPattern("/v1/om/inventory/runs:trigger")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_TriggerInventoryRefresh_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_TriggerInventoryRefresh_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/GetInventoryConfig", runtime.WithHTTPPathPattern("/v1/om/inventory/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_GetInventoryConfig_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPut, pattern_OmService_UpdateInventoryConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/UpdateInventoryConfig", runtime.WithHTTPPathPattern("/v1/om/inventory/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_UpdateInventoryConfig_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_UpdateInventoryConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryConfigOverride_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryConfigOverride", runtime.WithHTTPPathPattern("/v1/om/inventory/config/overrides/{key}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_OmService_DeleteInventoryConfigOverride_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryConfigOverride_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + + return nil +} + +// RegisterOmServiceHandlerFromEndpoint is same as RegisterOmServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterOmServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.NewClient(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + return RegisterOmServiceHandler(ctx, mux, conn) +} + +// RegisterOmServiceHandler registers the http handlers for service OmService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterOmServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterOmServiceHandlerClient(ctx, mux, NewOmServiceClient(conn)) +} + +// RegisterOmServiceHandlerClient registers the http handlers for service OmService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "OmServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "OmServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "OmServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares. +func RegisterOmServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client OmServiceClient) error { + mux.Handle(http.MethodGet, pattern_OmService_GetTopology_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetTopology", runtime.WithHTTPPathPattern("/v1/om/topology")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetTopology_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetTopology_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListTopologyRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/ListTopologyRuns", runtime.WithHTTPPathPattern("/v1/om/topology/runs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_ListTopologyRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListTopologyRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetTopologyRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetTopologyRun", runtime.WithHTTPPathPattern("/v1/om/topology/runs/{run_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetTopologyRun_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetTopologyRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_OmService_TriggerTopologyCollection_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/TriggerTopologyCollection", runtime.WithHTTPPathPattern("/v1/om/topology/runs:collect")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_TriggerTopologyCollection_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_TriggerTopologyCollection_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryHosts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/ListInventoryHosts", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_ListInventoryHosts_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryHosts_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryHost_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetInventoryHost", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts/{node_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetInventoryHost_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryHost_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryHost_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryHost", runtime.WithHTTPPathPattern("/v1/om/inventory/hosts/{node_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_DeleteInventoryHost_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryHost_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryServices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/ListInventoryServices", runtime.WithHTTPPathPattern("/v1/om/inventory/services")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_ListInventoryServices_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryServices_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetInventoryService", runtime.WithHTTPPathPattern("/v1/om/inventory/services/{service_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetInventoryService_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryService_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryService_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryService", runtime.WithHTTPPathPattern("/v1/om/inventory/services/{service_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_DeleteInventoryService_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryService_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_ListInventoryRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/ListInventoryRuns", runtime.WithHTTPPathPattern("/v1/om/inventory/runs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_ListInventoryRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_ListInventoryRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetInventoryRun", runtime.WithHTTPPathPattern("/v1/om/inventory/runs/{run_id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetInventoryRun_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_OmService_TriggerInventoryRefresh_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/TriggerInventoryRefresh", runtime.WithHTTPPathPattern("/v1/om/inventory/runs:trigger")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_TriggerInventoryRefresh_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_TriggerInventoryRefresh_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_OmService_GetInventoryConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/GetInventoryConfig", runtime.WithHTTPPathPattern("/v1/om/inventory/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_GetInventoryConfig_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_GetInventoryConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPut, pattern_OmService_UpdateInventoryConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/UpdateInventoryConfig", runtime.WithHTTPPathPattern("/v1/om/inventory/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_UpdateInventoryConfig_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_UpdateInventoryConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_OmService_DeleteInventoryConfigOverride_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/om.v1.OmService/DeleteInventoryConfigOverride", runtime.WithHTTPPathPattern("/v1/om/inventory/config/overrides/{key}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_OmService_DeleteInventoryConfigOverride_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_OmService_DeleteInventoryConfigOverride_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + return nil +} + +var ( + pattern_OmService_GetTopology_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "om", "topology"}, "")) + pattern_OmService_ListTopologyRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "topology", "runs"}, "")) + pattern_OmService_GetTopologyRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "topology", "runs", "run_id"}, "")) + pattern_OmService_TriggerTopologyCollection_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "topology", "runs"}, "collect")) + pattern_OmService_ListInventoryHosts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "hosts"}, "")) + pattern_OmService_GetInventoryHost_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "inventory", "hosts", "node_id"}, "")) + pattern_OmService_DeleteInventoryHost_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "inventory", "hosts", "node_id"}, "")) + pattern_OmService_ListInventoryServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "services"}, "")) + pattern_OmService_GetInventoryService_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "inventory", "services", "service_id"}, "")) + pattern_OmService_DeleteInventoryService_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "inventory", "services", "service_id"}, "")) + pattern_OmService_ListInventoryRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "runs"}, "")) + pattern_OmService_GetInventoryRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "om", "inventory", "runs", "run_id"}, "")) + pattern_OmService_TriggerInventoryRefresh_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "runs"}, "trigger")) + pattern_OmService_GetInventoryConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "config"}, "")) + pattern_OmService_UpdateInventoryConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "om", "inventory", "config"}, "")) + pattern_OmService_DeleteInventoryConfigOverride_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "om", "inventory", "config", "overrides", "key"}, "")) +) + +var ( + forward_OmService_GetTopology_0 = runtime.ForwardResponseMessage + forward_OmService_ListTopologyRuns_0 = runtime.ForwardResponseMessage + forward_OmService_GetTopologyRun_0 = runtime.ForwardResponseMessage + forward_OmService_TriggerTopologyCollection_0 = runtime.ForwardResponseMessage + forward_OmService_ListInventoryHosts_0 = runtime.ForwardResponseMessage + forward_OmService_GetInventoryHost_0 = runtime.ForwardResponseMessage + forward_OmService_DeleteInventoryHost_0 = runtime.ForwardResponseMessage + forward_OmService_ListInventoryServices_0 = runtime.ForwardResponseMessage + forward_OmService_GetInventoryService_0 = runtime.ForwardResponseMessage + forward_OmService_DeleteInventoryService_0 = runtime.ForwardResponseMessage + forward_OmService_ListInventoryRuns_0 = runtime.ForwardResponseMessage + forward_OmService_GetInventoryRun_0 = runtime.ForwardResponseMessage + forward_OmService_TriggerInventoryRefresh_0 = runtime.ForwardResponseMessage + forward_OmService_GetInventoryConfig_0 = runtime.ForwardResponseMessage + forward_OmService_UpdateInventoryConfig_0 = runtime.ForwardResponseMessage + forward_OmService_DeleteInventoryConfigOverride_0 = runtime.ForwardResponseMessage +) diff --git a/api/om/v1/om.pb.validate.go b/api/om/v1/om.pb.validate.go new file mode 100644 index 00000000000..8ae44793d4a --- /dev/null +++ b/api/om/v1/om.pb.validate.go @@ -0,0 +1,7155 @@ +// Code generated by protoc-gen-validate. DO NOT EDIT. +// source: om/v1/om.proto + +package omv1 + +import ( + "bytes" + "errors" + "fmt" + "net" + "net/mail" + "net/url" + "regexp" + "sort" + "strings" + "time" + "unicode/utf8" + + "google.golang.org/protobuf/types/known/anypb" +) + +// ensure the imports are used +var ( + _ = bytes.MinRead + _ = errors.New("") + _ = fmt.Print + _ = utf8.UTFMax + _ = (*regexp.Regexp)(nil) + _ = (*strings.Reader)(nil) + _ = net.IPv4len + _ = time.Duration(0) + _ = (*url.URL)(nil) + _ = (*mail.Address)(nil) + _ = anypb.Any{} + _ = sort.Sort +) + +// Validate checks the field values on TopologyService with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *TopologyService) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TopologyService with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// TopologyServiceMultiError, or nil if none found. +func (m *TopologyService) ValidateAll() error { + return m.validate(true) +} + +func (m *TopologyService) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ServiceName + + // no validation rules for Status + + // no validation rules for CpuUsagePercent + + // no validation rules for ConnectionsFreePercent + + // no validation rules for ProcessRole + + if m.Host != nil { + // no validation rules for Host + } + + if m.Endpoint != nil { + // no validation rules for Endpoint + } + + if m.ServiceId != nil { + // no validation rules for ServiceId + } + + if m.ServiceType != nil { + // no validation rules for ServiceType + } + + if m.Version != nil { + // no validation rules for Version + } + + if m.Vendor != nil { + // no validation rules for Vendor + } + + if m.Edition != nil { + // no validation rules for Edition + } + + if m.ReplicationSet != nil { + // no validation rules for ReplicationSet + } + + if m.State != nil { + // no validation rules for State + } + + if m.ReplicationLagSeconds != nil { + // no validation rules for ReplicationLagSeconds + } + + if m.OplogWindowSeconds != nil { + // no validation rules for OplogWindowSeconds + } + + if m.InstalledVersion != nil { + // no validation rules for InstalledVersion + } + + if m.ConfigPath != nil { + // no validation rules for ConfigPath + } + + if m.Argv != nil { + // no validation rules for Argv + } + + if m.ObservedAt != nil { + if all { + switch v := interface{}(m.GetObservedAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyServiceValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyServiceValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetObservedAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyServiceValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + } + + if len(errors) > 0 { + return TopologyServiceMultiError(errors) + } + + return nil +} + +// TopologyServiceMultiError is an error wrapping multiple validation errors +// returned by TopologyService.ValidateAll() if the designated constraints +// aren't met. +type TopologyServiceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TopologyServiceMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TopologyServiceMultiError) AllErrors() []error { return m } + +// TopologyServiceValidationError is the validation error returned by +// TopologyService.Validate if the designated constraints aren't met. +type TopologyServiceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TopologyServiceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TopologyServiceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TopologyServiceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TopologyServiceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TopologyServiceValidationError) ErrorName() string { return "TopologyServiceValidationError" } + +// Error satisfies the builtin error interface +func (e TopologyServiceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTopologyService.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TopologyServiceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TopologyServiceValidationError{} + +// Validate checks the field values on Cluster with the rules defined in the +// proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Cluster) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Cluster with the rules defined in the +// proto definition for this message. If any rules are violated, the result is +// a list of violation errors wrapped in ClusterMultiError, or nil if none found. +func (m *Cluster) ValidateAll() error { + return m.validate(true) +} + +func (m *Cluster) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetServices() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClusterValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClusterValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClusterValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + // no validation rules for Id + + // no validation rules for Type + + // no validation rules for Health + + if m.Name != nil { + // no validation rules for Name + } + + if len(errors) > 0 { + return ClusterMultiError(errors) + } + + return nil +} + +// ClusterMultiError is an error wrapping multiple validation errors returned +// by Cluster.ValidateAll() if the designated constraints aren't met. +type ClusterMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClusterMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClusterMultiError) AllErrors() []error { return m } + +// ClusterValidationError is the validation error returned by Cluster.Validate +// if the designated constraints aren't met. +type ClusterValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClusterValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClusterValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClusterValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClusterValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClusterValidationError) ErrorName() string { return "ClusterValidationError" } + +// Error satisfies the builtin error interface +func (e ClusterValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCluster.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ClusterValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClusterValidationError{} + +// Validate checks the field values on Environment with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Environment) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Environment with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in EnvironmentMultiError, or +// nil if none found. +func (m *Environment) ValidateAll() error { + return m.validate(true) +} + +func (m *Environment) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetClusters() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, EnvironmentValidationError{ + field: fmt.Sprintf("Clusters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, EnvironmentValidationError{ + field: fmt.Sprintf("Clusters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return EnvironmentValidationError{ + field: fmt.Sprintf("Clusters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if m.EnvName != nil { + // no validation rules for EnvName + } + + if len(errors) > 0 { + return EnvironmentMultiError(errors) + } + + return nil +} + +// EnvironmentMultiError is an error wrapping multiple validation errors +// returned by Environment.ValidateAll() if the designated constraints aren't met. +type EnvironmentMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m EnvironmentMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m EnvironmentMultiError) AllErrors() []error { return m } + +// EnvironmentValidationError is the validation error returned by +// Environment.Validate if the designated constraints aren't met. +type EnvironmentValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e EnvironmentValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e EnvironmentValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e EnvironmentValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e EnvironmentValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e EnvironmentValidationError) ErrorName() string { return "EnvironmentValidationError" } + +// Error satisfies the builtin error interface +func (e EnvironmentValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sEnvironment.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = EnvironmentValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = EnvironmentValidationError{} + +// Validate checks the field values on Summary with the rules defined in the +// proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Summary) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Summary with the rules defined in the +// proto definition for this message. If any rules are violated, the result is +// a list of violation errors wrapped in SummaryMultiError, or nil if none found. +func (m *Summary) ValidateAll() error { + return m.validate(true) +} + +func (m *Summary) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Environments + + // no validation rules for Clusters + + // no validation rules for TotalServices + + // no validation rules for UpServices + + // no validation rules for DownServices + + // no validation rules for ProcessRoleCounts + + if len(errors) > 0 { + return SummaryMultiError(errors) + } + + return nil +} + +// SummaryMultiError is an error wrapping multiple validation errors returned +// by Summary.ValidateAll() if the designated constraints aren't met. +type SummaryMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m SummaryMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m SummaryMultiError) AllErrors() []error { return m } + +// SummaryValidationError is the validation error returned by Summary.Validate +// if the designated constraints aren't met. +type SummaryValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e SummaryValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e SummaryValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e SummaryValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e SummaryValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e SummaryValidationError) ErrorName() string { return "SummaryValidationError" } + +// Error satisfies the builtin error interface +func (e SummaryValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sSummary.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = SummaryValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = SummaryValidationError{} + +// Validate checks the field values on Snapshot with the rules defined in the +// proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Snapshot) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Snapshot with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in SnapshotMultiError, or nil +// if none found. +func (m *Snapshot) ValidateAll() error { + return m.validate(true) +} + +func (m *Snapshot) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetGeneratedAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SnapshotValidationError{ + field: "GeneratedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SnapshotValidationError{ + field: "GeneratedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetGeneratedAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SnapshotValidationError{ + field: "GeneratedAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetObservedAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SnapshotValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SnapshotValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetObservedAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SnapshotValidationError{ + field: "ObservedAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for Stale + + // no validation rules for SchemaVersion + + // no validation rules for RunId + + if len(errors) > 0 { + return SnapshotMultiError(errors) + } + + return nil +} + +// SnapshotMultiError is an error wrapping multiple validation errors returned +// by Snapshot.ValidateAll() if the designated constraints aren't met. +type SnapshotMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m SnapshotMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m SnapshotMultiError) AllErrors() []error { return m } + +// SnapshotValidationError is the validation error returned by +// Snapshot.Validate if the designated constraints aren't met. +type SnapshotValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e SnapshotValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e SnapshotValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e SnapshotValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e SnapshotValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e SnapshotValidationError) ErrorName() string { return "SnapshotValidationError" } + +// Error satisfies the builtin error interface +func (e SnapshotValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sSnapshot.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = SnapshotValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = SnapshotValidationError{} + +// Validate checks the field values on GetTopologyRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetTopologyRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTopologyRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTopologyRequestMultiError, or nil if none found. +func (m *GetTopologyRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTopologyRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return GetTopologyRequestMultiError(errors) + } + + return nil +} + +// GetTopologyRequestMultiError is an error wrapping multiple validation errors +// returned by GetTopologyRequest.ValidateAll() if the designated constraints +// aren't met. +type GetTopologyRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTopologyRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTopologyRequestMultiError) AllErrors() []error { return m } + +// GetTopologyRequestValidationError is the validation error returned by +// GetTopologyRequest.Validate if the designated constraints aren't met. +type GetTopologyRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTopologyRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTopologyRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTopologyRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTopologyRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTopologyRequestValidationError) ErrorName() string { + return "GetTopologyRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetTopologyRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTopologyRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetTopologyRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTopologyRequestValidationError{} + +// Validate checks the field values on GetTopologyResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetTopologyResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTopologyResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTopologyResponseMultiError, or nil if none found. +func (m *GetTopologyResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTopologyResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetSnapshot()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: "Snapshot", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: "Snapshot", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSnapshot()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetTopologyResponseValidationError{ + field: "Snapshot", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetSummary()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: "Summary", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: "Summary", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSummary()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetTopologyResponseValidationError{ + field: "Summary", + reason: "embedded message failed validation", + cause: err, + } + } + } + + for idx, item := range m.GetEnvironments() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetTopologyResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetTopologyResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if m.OriginNode != nil { + // no validation rules for OriginNode + } + + if len(errors) > 0 { + return GetTopologyResponseMultiError(errors) + } + + return nil +} + +// GetTopologyResponseMultiError is an error wrapping multiple validation +// errors returned by GetTopologyResponse.ValidateAll() if the designated +// constraints aren't met. +type GetTopologyResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTopologyResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTopologyResponseMultiError) AllErrors() []error { return m } + +// GetTopologyResponseValidationError is the validation error returned by +// GetTopologyResponse.Validate if the designated constraints aren't met. +type GetTopologyResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTopologyResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTopologyResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTopologyResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTopologyResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTopologyResponseValidationError) ErrorName() string { + return "GetTopologyResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetTopologyResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTopologyResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetTopologyResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTopologyResponseValidationError{} + +// Validate checks the field values on TopologyRunCounts with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *TopologyRunCounts) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TopologyRunCounts with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// TopologyRunCountsMultiError, or nil if none found. +func (m *TopologyRunCounts) ValidateAll() error { + return m.validate(true) +} + +func (m *TopologyRunCounts) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for TotalServices + + // no validation rules for ResolvedServices + + // no validation rules for OrphanedServices + + // no validation rules for SuccessfulProbes + + // no validation rules for StaleServices + + if len(errors) > 0 { + return TopologyRunCountsMultiError(errors) + } + + return nil +} + +// TopologyRunCountsMultiError is an error wrapping multiple validation errors +// returned by TopologyRunCounts.ValidateAll() if the designated constraints +// aren't met. +type TopologyRunCountsMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TopologyRunCountsMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TopologyRunCountsMultiError) AllErrors() []error { return m } + +// TopologyRunCountsValidationError is the validation error returned by +// TopologyRunCounts.Validate if the designated constraints aren't met. +type TopologyRunCountsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TopologyRunCountsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TopologyRunCountsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TopologyRunCountsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TopologyRunCountsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TopologyRunCountsValidationError) ErrorName() string { + return "TopologyRunCountsValidationError" +} + +// Error satisfies the builtin error interface +func (e TopologyRunCountsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTopologyRunCounts.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TopologyRunCountsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TopologyRunCountsValidationError{} + +// Validate checks the field values on SourceReport with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *SourceReport) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on SourceReport with the rules defined +// in the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in SourceReportMultiError, or +// nil if none found. +func (m *SourceReport) ValidateAll() error { + return m.validate(true) +} + +func (m *SourceReport) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Source + + // no validation rules for Status + + // no validation rules for Facts + + // no validation rules for Detail + + if len(errors) > 0 { + return SourceReportMultiError(errors) + } + + return nil +} + +// SourceReportMultiError is an error wrapping multiple validation errors +// returned by SourceReport.ValidateAll() if the designated constraints aren't met. +type SourceReportMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m SourceReportMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m SourceReportMultiError) AllErrors() []error { return m } + +// SourceReportValidationError is the validation error returned by +// SourceReport.Validate if the designated constraints aren't met. +type SourceReportValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e SourceReportValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e SourceReportValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e SourceReportValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e SourceReportValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e SourceReportValidationError) ErrorName() string { return "SourceReportValidationError" } + +// Error satisfies the builtin error interface +func (e SourceReportValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sSourceReport.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = SourceReportValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = SourceReportValidationError{} + +// Validate checks the field values on TopologyRunError with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *TopologyRunError) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TopologyRunError with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// TopologyRunErrorMultiError, or nil if none found. +func (m *TopologyRunError) ValidateAll() error { + return m.validate(true) +} + +func (m *TopologyRunError) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Scope + + // no validation rules for Code + + // no validation rules for Message + + if m.ServiceName != nil { + // no validation rules for ServiceName + } + + if len(errors) > 0 { + return TopologyRunErrorMultiError(errors) + } + + return nil +} + +// TopologyRunErrorMultiError is an error wrapping multiple validation errors +// returned by TopologyRunError.ValidateAll() if the designated constraints +// aren't met. +type TopologyRunErrorMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TopologyRunErrorMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TopologyRunErrorMultiError) AllErrors() []error { return m } + +// TopologyRunErrorValidationError is the validation error returned by +// TopologyRunError.Validate if the designated constraints aren't met. +type TopologyRunErrorValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TopologyRunErrorValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TopologyRunErrorValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TopologyRunErrorValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TopologyRunErrorValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TopologyRunErrorValidationError) ErrorName() string { return "TopologyRunErrorValidationError" } + +// Error satisfies the builtin error interface +func (e TopologyRunErrorValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTopologyRunError.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TopologyRunErrorValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TopologyRunErrorValidationError{} + +// Validate checks the field values on TopologyRun with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *TopologyRun) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TopologyRun with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in TopologyRunMultiError, or +// nil if none found. +func (m *TopologyRun) ValidateAll() error { + return m.validate(true) +} + +func (m *TopologyRun) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for RunId + + // no validation rules for Status + + if all { + switch v := interface{}(m.GetStartTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetStartTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetEndTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetEndTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetCounts()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCounts()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + } + } + } + + for idx, item := range m.GetErrors() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: fmt.Sprintf("Errors[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: fmt.Sprintf("Errors[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyRunValidationError{ + field: fmt.Sprintf("Errors[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + for idx, item := range m.GetSources() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: fmt.Sprintf("Sources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TopologyRunValidationError{ + field: fmt.Sprintf("Sources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TopologyRunValidationError{ + field: fmt.Sprintf("Sources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return TopologyRunMultiError(errors) + } + + return nil +} + +// TopologyRunMultiError is an error wrapping multiple validation errors +// returned by TopologyRun.ValidateAll() if the designated constraints aren't met. +type TopologyRunMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TopologyRunMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TopologyRunMultiError) AllErrors() []error { return m } + +// TopologyRunValidationError is the validation error returned by +// TopologyRun.Validate if the designated constraints aren't met. +type TopologyRunValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TopologyRunValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TopologyRunValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TopologyRunValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TopologyRunValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TopologyRunValidationError) ErrorName() string { return "TopologyRunValidationError" } + +// Error satisfies the builtin error interface +func (e TopologyRunValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTopologyRun.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TopologyRunValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TopologyRunValidationError{} + +// Validate checks the field values on GetTopologyRunRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetTopologyRunRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTopologyRunRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTopologyRunRequestMultiError, or nil if none found. +func (m *GetTopologyRunRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTopologyRunRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetRunId()) < 1 { + err := GetTopologyRunRequestValidationError{ + field: "RunId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return GetTopologyRunRequestMultiError(errors) + } + + return nil +} + +// GetTopologyRunRequestMultiError is an error wrapping multiple validation +// errors returned by GetTopologyRunRequest.ValidateAll() if the designated +// constraints aren't met. +type GetTopologyRunRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTopologyRunRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTopologyRunRequestMultiError) AllErrors() []error { return m } + +// GetTopologyRunRequestValidationError is the validation error returned by +// GetTopologyRunRequest.Validate if the designated constraints aren't met. +type GetTopologyRunRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTopologyRunRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTopologyRunRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTopologyRunRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTopologyRunRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTopologyRunRequestValidationError) ErrorName() string { + return "GetTopologyRunRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetTopologyRunRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTopologyRunRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetTopologyRunRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTopologyRunRequestValidationError{} + +// Validate checks the field values on GetTopologyRunResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetTopologyRunResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTopologyRunResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTopologyRunResponseMultiError, or nil if none found. +func (m *GetTopologyRunResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTopologyRunResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetRun()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetTopologyRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetTopologyRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRun()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetTopologyRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return GetTopologyRunResponseMultiError(errors) + } + + return nil +} + +// GetTopologyRunResponseMultiError is an error wrapping multiple validation +// errors returned by GetTopologyRunResponse.ValidateAll() if the designated +// constraints aren't met. +type GetTopologyRunResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTopologyRunResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTopologyRunResponseMultiError) AllErrors() []error { return m } + +// GetTopologyRunResponseValidationError is the validation error returned by +// GetTopologyRunResponse.Validate if the designated constraints aren't met. +type GetTopologyRunResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTopologyRunResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTopologyRunResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTopologyRunResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTopologyRunResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTopologyRunResponseValidationError) ErrorName() string { + return "GetTopologyRunResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetTopologyRunResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTopologyRunResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetTopologyRunResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTopologyRunResponseValidationError{} + +// Validate checks the field values on ListTopologyRunsRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListTopologyRunsRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListTopologyRunsRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListTopologyRunsRequestMultiError, or nil if none found. +func (m *ListTopologyRunsRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListTopologyRunsRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if val := m.GetLimit(); val < 0 || val > 100 { + err := ListTopologyRunsRequestValidationError{ + field: "Limit", + reason: "value must be inside range [0, 100]", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return ListTopologyRunsRequestMultiError(errors) + } + + return nil +} + +// ListTopologyRunsRequestMultiError is an error wrapping multiple validation +// errors returned by ListTopologyRunsRequest.ValidateAll() if the designated +// constraints aren't met. +type ListTopologyRunsRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListTopologyRunsRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListTopologyRunsRequestMultiError) AllErrors() []error { return m } + +// ListTopologyRunsRequestValidationError is the validation error returned by +// ListTopologyRunsRequest.Validate if the designated constraints aren't met. +type ListTopologyRunsRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListTopologyRunsRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListTopologyRunsRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListTopologyRunsRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListTopologyRunsRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListTopologyRunsRequestValidationError) ErrorName() string { + return "ListTopologyRunsRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListTopologyRunsRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListTopologyRunsRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListTopologyRunsRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListTopologyRunsRequestValidationError{} + +// Validate checks the field values on ListTopologyRunsResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListTopologyRunsResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListTopologyRunsResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListTopologyRunsResponseMultiError, or nil if none found. +func (m *ListTopologyRunsResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListTopologyRunsResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetRuns() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListTopologyRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListTopologyRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListTopologyRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ListTopologyRunsResponseMultiError(errors) + } + + return nil +} + +// ListTopologyRunsResponseMultiError is an error wrapping multiple validation +// errors returned by ListTopologyRunsResponse.ValidateAll() if the designated +// constraints aren't met. +type ListTopologyRunsResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListTopologyRunsResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListTopologyRunsResponseMultiError) AllErrors() []error { return m } + +// ListTopologyRunsResponseValidationError is the validation error returned by +// ListTopologyRunsResponse.Validate if the designated constraints aren't met. +type ListTopologyRunsResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListTopologyRunsResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListTopologyRunsResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListTopologyRunsResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListTopologyRunsResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListTopologyRunsResponseValidationError) ErrorName() string { + return "ListTopologyRunsResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListTopologyRunsResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListTopologyRunsResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListTopologyRunsResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListTopologyRunsResponseValidationError{} + +// Validate checks the field values on TriggerTopologyCollectionRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *TriggerTopologyCollectionRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TriggerTopologyCollectionRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// TriggerTopologyCollectionRequestMultiError, or nil if none found. +func (m *TriggerTopologyCollectionRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *TriggerTopologyCollectionRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return TriggerTopologyCollectionRequestMultiError(errors) + } + + return nil +} + +// TriggerTopologyCollectionRequestMultiError is an error wrapping multiple +// validation errors returned by +// TriggerTopologyCollectionRequest.ValidateAll() if the designated +// constraints aren't met. +type TriggerTopologyCollectionRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TriggerTopologyCollectionRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TriggerTopologyCollectionRequestMultiError) AllErrors() []error { return m } + +// TriggerTopologyCollectionRequestValidationError is the validation error +// returned by TriggerTopologyCollectionRequest.Validate if the designated +// constraints aren't met. +type TriggerTopologyCollectionRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TriggerTopologyCollectionRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TriggerTopologyCollectionRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TriggerTopologyCollectionRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TriggerTopologyCollectionRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TriggerTopologyCollectionRequestValidationError) ErrorName() string { + return "TriggerTopologyCollectionRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e TriggerTopologyCollectionRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTriggerTopologyCollectionRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TriggerTopologyCollectionRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TriggerTopologyCollectionRequestValidationError{} + +// Validate checks the field values on TriggerTopologyCollectionResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *TriggerTopologyCollectionResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TriggerTopologyCollectionResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// TriggerTopologyCollectionResponseMultiError, or nil if none found. +func (m *TriggerTopologyCollectionResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *TriggerTopologyCollectionResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for RunId + + // no validation rules for Status + + if all { + switch v := interface{}(m.GetStartTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TriggerTopologyCollectionResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TriggerTopologyCollectionResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetStartTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TriggerTopologyCollectionResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return TriggerTopologyCollectionResponseMultiError(errors) + } + + return nil +} + +// TriggerTopologyCollectionResponseMultiError is an error wrapping multiple +// validation errors returned by +// TriggerTopologyCollectionResponse.ValidateAll() if the designated +// constraints aren't met. +type TriggerTopologyCollectionResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TriggerTopologyCollectionResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TriggerTopologyCollectionResponseMultiError) AllErrors() []error { return m } + +// TriggerTopologyCollectionResponseValidationError is the validation error +// returned by TriggerTopologyCollectionResponse.Validate if the designated +// constraints aren't met. +type TriggerTopologyCollectionResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TriggerTopologyCollectionResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TriggerTopologyCollectionResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TriggerTopologyCollectionResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TriggerTopologyCollectionResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TriggerTopologyCollectionResponseValidationError) ErrorName() string { + return "TriggerTopologyCollectionResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e TriggerTopologyCollectionResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTriggerTopologyCollectionResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TriggerTopologyCollectionResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TriggerTopologyCollectionResponseValidationError{} + +// Validate checks the field values on InventoryExecutor with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *InventoryExecutor) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryExecutor with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryExecutorMultiError, or nil if none found. +func (m *InventoryExecutor) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryExecutor) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Registered + + // no validation rules for Reachable + + // no validation rules for DriverHealthy + + if m.Detail != nil { + // no validation rules for Detail + } + + if len(errors) > 0 { + return InventoryExecutorMultiError(errors) + } + + return nil +} + +// InventoryExecutorMultiError is an error wrapping multiple validation errors +// returned by InventoryExecutor.ValidateAll() if the designated constraints +// aren't met. +type InventoryExecutorMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryExecutorMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryExecutorMultiError) AllErrors() []error { return m } + +// InventoryExecutorValidationError is the validation error returned by +// InventoryExecutor.Validate if the designated constraints aren't met. +type InventoryExecutorValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryExecutorValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryExecutorValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryExecutorValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryExecutorValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryExecutorValidationError) ErrorName() string { + return "InventoryExecutorValidationError" +} + +// Error satisfies the builtin error interface +func (e InventoryExecutorValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryExecutor.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryExecutorValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryExecutorValidationError{} + +// Validate checks the field values on UnregisteredMongod with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UnregisteredMongod) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UnregisteredMongod with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UnregisteredMongodMultiError, or nil if none found. +func (m *UnregisteredMongod) ValidateAll() error { + return m.validate(true) +} + +func (m *UnregisteredMongod) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if m.Port != nil { + // no validation rules for Port + } + + if m.ConfigPath != nil { + // no validation rules for ConfigPath + } + + if m.Argv != nil { + // no validation rules for Argv + } + + if m.Program != nil { + // no validation rules for Program + } + + if m.Pid != nil { + // no validation rules for Pid + } + + if len(errors) > 0 { + return UnregisteredMongodMultiError(errors) + } + + return nil +} + +// UnregisteredMongodMultiError is an error wrapping multiple validation errors +// returned by UnregisteredMongod.ValidateAll() if the designated constraints +// aren't met. +type UnregisteredMongodMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UnregisteredMongodMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UnregisteredMongodMultiError) AllErrors() []error { return m } + +// UnregisteredMongodValidationError is the validation error returned by +// UnregisteredMongod.Validate if the designated constraints aren't met. +type UnregisteredMongodValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UnregisteredMongodValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UnregisteredMongodValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UnregisteredMongodValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UnregisteredMongodValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UnregisteredMongodValidationError) ErrorName() string { + return "UnregisteredMongodValidationError" +} + +// Error satisfies the builtin error interface +func (e UnregisteredMongodValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUnregisteredMongod.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UnregisteredMongodValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UnregisteredMongodValidationError{} + +// Validate checks the field values on InventoryFreshness with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *InventoryFreshness) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryFreshness with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryFreshnessMultiError, or nil if none found. +func (m *InventoryFreshness) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryFreshness) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetFirstSeenAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "FirstSeenAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "FirstSeenAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetFirstSeenAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryFreshnessValidationError{ + field: "FirstSeenAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetLastAttemptAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "LastAttemptAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "LastAttemptAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetLastAttemptAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryFreshnessValidationError{ + field: "LastAttemptAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetLastSuccessAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "LastSuccessAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "LastSuccessAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetLastSuccessAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryFreshnessValidationError{ + field: "LastSuccessAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetFailingSince()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "FailingSince", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryFreshnessValidationError{ + field: "FailingSince", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetFailingSince()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryFreshnessValidationError{ + field: "FailingSince", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for ConsecutiveFailures + + if m.LastError != nil { + // no validation rules for LastError + } + + if len(errors) > 0 { + return InventoryFreshnessMultiError(errors) + } + + return nil +} + +// InventoryFreshnessMultiError is an error wrapping multiple validation errors +// returned by InventoryFreshness.ValidateAll() if the designated constraints +// aren't met. +type InventoryFreshnessMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryFreshnessMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryFreshnessMultiError) AllErrors() []error { return m } + +// InventoryFreshnessValidationError is the validation error returned by +// InventoryFreshness.Validate if the designated constraints aren't met. +type InventoryFreshnessValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryFreshnessValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryFreshnessValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryFreshnessValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryFreshnessValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryFreshnessValidationError) ErrorName() string { + return "InventoryFreshnessValidationError" +} + +// Error satisfies the builtin error interface +func (e InventoryFreshnessValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryFreshness.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryFreshnessValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryFreshnessValidationError{} + +// Validate checks the field values on InventoryService with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *InventoryService) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryService with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryServiceMultiError, or nil if none found. +func (m *InventoryService) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryService) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ServiceId + + // no validation rules for NodeId + + // no validation rules for Name + + if all { + switch v := interface{}(m.GetObserved()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryServiceValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryServiceValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetObserved()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryServiceValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetFreshness()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryServiceValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryServiceValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetFreshness()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryServiceValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if m.Port != nil { + // no validation rules for Port + } + + if m.Role != nil { + // no validation rules for Role + } + + if m.InstalledVersion != nil { + // no validation rules for InstalledVersion + } + + if m.RunningVersion != nil { + // no validation rules for RunningVersion + } + + if m.ConfigPath != nil { + // no validation rules for ConfigPath + } + + if m.Argv != nil { + // no validation rules for Argv + } + + if m.ProbeStatus != nil { + // no validation rules for ProbeStatus + } + + if m.ServerRunning != nil { + // no validation rules for ServerRunning + } + + if m.UptimeSeconds != nil { + // no validation rules for UptimeSeconds + } + + if m.ReplicationSet != nil { + // no validation rules for ReplicationSet + } + + if len(errors) > 0 { + return InventoryServiceMultiError(errors) + } + + return nil +} + +// InventoryServiceMultiError is an error wrapping multiple validation errors +// returned by InventoryService.ValidateAll() if the designated constraints +// aren't met. +type InventoryServiceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryServiceMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryServiceMultiError) AllErrors() []error { return m } + +// InventoryServiceValidationError is the validation error returned by +// InventoryService.Validate if the designated constraints aren't met. +type InventoryServiceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryServiceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryServiceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryServiceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryServiceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryServiceValidationError) ErrorName() string { return "InventoryServiceValidationError" } + +// Error satisfies the builtin error interface +func (e InventoryServiceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryService.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryServiceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryServiceValidationError{} + +// Validate checks the field values on InventoryHost with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *InventoryHost) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryHost with the rules defined +// in the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in InventoryHostMultiError, or +// nil if none found. +func (m *InventoryHost) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryHost) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for NodeId + + // no validation rules for Name + + if all { + switch v := interface{}(m.GetExecutor()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Executor", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Executor", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetExecutor()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryHostValidationError{ + field: "Executor", + reason: "embedded message failed validation", + cause: err, + } + } + } + + for idx, item := range m.GetUnregisteredMongods() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: fmt.Sprintf("UnregisteredMongods[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: fmt.Sprintf("UnregisteredMongods[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryHostValidationError{ + field: fmt.Sprintf("UnregisteredMongods[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if all { + switch v := interface{}(m.GetObserved()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetObserved()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryHostValidationError{ + field: "Observed", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetFreshness()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetFreshness()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryHostValidationError{ + field: "Freshness", + reason: "embedded message failed validation", + cause: err, + } + } + } + + for idx, item := range m.GetServices() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryHostValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryHostValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if m.Address != nil { + // no validation rules for Address + } + + if m.ExecutorHost != nil { + // no validation rules for ExecutorHost + } + + if m.Os != nil { + // no validation rules for Os + } + + if m.Kernel != nil { + // no validation rules for Kernel + } + + if len(errors) > 0 { + return InventoryHostMultiError(errors) + } + + return nil +} + +// InventoryHostMultiError is an error wrapping multiple validation errors +// returned by InventoryHost.ValidateAll() if the designated constraints +// aren't met. +type InventoryHostMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryHostMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryHostMultiError) AllErrors() []error { return m } + +// InventoryHostValidationError is the validation error returned by +// InventoryHost.Validate if the designated constraints aren't met. +type InventoryHostValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryHostValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryHostValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryHostValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryHostValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryHostValidationError) ErrorName() string { return "InventoryHostValidationError" } + +// Error satisfies the builtin error interface +func (e InventoryHostValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryHost.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryHostValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryHostValidationError{} + +// Validate checks the field values on InventoryRunCounts with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *InventoryRunCounts) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryRunCounts with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryRunCountsMultiError, or nil if none found. +func (m *InventoryRunCounts) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryRunCounts) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for TotalServices + + // no validation rules for ResolvedServices + + // no validation rules for OrphanedServices + + // no validation rules for AnsweredServices + + // no validation rules for TotalHosts + + // no validation rules for ProbeableHosts + + // no validation rules for AnsweredHosts + + if len(errors) > 0 { + return InventoryRunCountsMultiError(errors) + } + + return nil +} + +// InventoryRunCountsMultiError is an error wrapping multiple validation errors +// returned by InventoryRunCounts.ValidateAll() if the designated constraints +// aren't met. +type InventoryRunCountsMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryRunCountsMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryRunCountsMultiError) AllErrors() []error { return m } + +// InventoryRunCountsValidationError is the validation error returned by +// InventoryRunCounts.Validate if the designated constraints aren't met. +type InventoryRunCountsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryRunCountsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryRunCountsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryRunCountsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryRunCountsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryRunCountsValidationError) ErrorName() string { + return "InventoryRunCountsValidationError" +} + +// Error satisfies the builtin error interface +func (e InventoryRunCountsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryRunCounts.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryRunCountsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryRunCountsValidationError{} + +// Validate checks the field values on InventoryRunEntityService with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *InventoryRunEntityService) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryRunEntityService with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryRunEntityServiceMultiError, or nil if none found. +func (m *InventoryRunEntityService) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryRunEntityService) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Answered + + if m.ServiceId != nil { + // no validation rules for ServiceId + } + + if m.ServiceName != nil { + // no validation rules for ServiceName + } + + if m.Error != nil { + // no validation rules for Error + } + + if len(errors) > 0 { + return InventoryRunEntityServiceMultiError(errors) + } + + return nil +} + +// InventoryRunEntityServiceMultiError is an error wrapping multiple validation +// errors returned by InventoryRunEntityService.ValidateAll() if the +// designated constraints aren't met. +type InventoryRunEntityServiceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryRunEntityServiceMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryRunEntityServiceMultiError) AllErrors() []error { return m } + +// InventoryRunEntityServiceValidationError is the validation error returned by +// InventoryRunEntityService.Validate if the designated constraints aren't met. +type InventoryRunEntityServiceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryRunEntityServiceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryRunEntityServiceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryRunEntityServiceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryRunEntityServiceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryRunEntityServiceValidationError) ErrorName() string { + return "InventoryRunEntityServiceValidationError" +} + +// Error satisfies the builtin error interface +func (e InventoryRunEntityServiceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryRunEntityService.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryRunEntityServiceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryRunEntityServiceValidationError{} + +// Validate checks the field values on InventoryRunEntity with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *InventoryRunEntity) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryRunEntity with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventoryRunEntityMultiError, or nil if none found. +func (m *InventoryRunEntity) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryRunEntity) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for NodeId + + // no validation rules for Resolution + + // no validation rules for Answered + + for idx, item := range m.GetServices() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryRunEntityValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryRunEntityValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryRunEntityValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if m.HostName != nil { + // no validation rules for HostName + } + + if m.ExecutorHost != nil { + // no validation rules for ExecutorHost + } + + if m.DurationSeconds != nil { + // no validation rules for DurationSeconds + } + + if m.Error != nil { + // no validation rules for Error + } + + if m.TaskHistoryId != nil { + // no validation rules for TaskHistoryId + } + + if len(errors) > 0 { + return InventoryRunEntityMultiError(errors) + } + + return nil +} + +// InventoryRunEntityMultiError is an error wrapping multiple validation errors +// returned by InventoryRunEntity.ValidateAll() if the designated constraints +// aren't met. +type InventoryRunEntityMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryRunEntityMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryRunEntityMultiError) AllErrors() []error { return m } + +// InventoryRunEntityValidationError is the validation error returned by +// InventoryRunEntity.Validate if the designated constraints aren't met. +type InventoryRunEntityValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryRunEntityValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryRunEntityValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryRunEntityValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryRunEntityValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryRunEntityValidationError) ErrorName() string { + return "InventoryRunEntityValidationError" +} + +// Error satisfies the builtin error interface +func (e InventoryRunEntityValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryRunEntity.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryRunEntityValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryRunEntityValidationError{} + +// Validate checks the field values on InventoryRun with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *InventoryRun) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventoryRun with the rules defined +// in the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in InventoryRunMultiError, or +// nil if none found. +func (m *InventoryRun) ValidateAll() error { + return m.validate(true) +} + +func (m *InventoryRun) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for RunId + + // no validation rules for Status + + if all { + switch v := interface{}(m.GetStartTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetStartTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryRunValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetEndTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetEndTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryRunValidationError{ + field: "EndTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetCounts()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventoryRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCounts()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventoryRunValidationError{ + field: "Counts", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if m.Error != nil { + // no validation rules for Error + } + + if len(errors) > 0 { + return InventoryRunMultiError(errors) + } + + return nil +} + +// InventoryRunMultiError is an error wrapping multiple validation errors +// returned by InventoryRun.ValidateAll() if the designated constraints aren't met. +type InventoryRunMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventoryRunMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventoryRunMultiError) AllErrors() []error { return m } + +// InventoryRunValidationError is the validation error returned by +// InventoryRun.Validate if the designated constraints aren't met. +type InventoryRunValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventoryRunValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventoryRunValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventoryRunValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventoryRunValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventoryRunValidationError) ErrorName() string { return "InventoryRunValidationError" } + +// Error satisfies the builtin error interface +func (e InventoryRunValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventoryRun.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventoryRunValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventoryRunValidationError{} + +// Validate checks the field values on InventorySetting with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *InventorySetting) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on InventorySetting with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// InventorySettingMultiError, or nil if none found. +func (m *InventorySetting) ValidateAll() error { + return m.validate(true) +} + +func (m *InventorySetting) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Key + + if all { + switch v := interface{}(m.GetValue()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventorySettingValidationError{ + field: "Value", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventorySettingValidationError{ + field: "Value", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetValue()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventorySettingValidationError{ + field: "Value", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetDefaultValue()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, InventorySettingValidationError{ + field: "DefaultValue", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, InventorySettingValidationError{ + field: "DefaultValue", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDefaultValue()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return InventorySettingValidationError{ + field: "DefaultValue", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for Type + + // no validation rules for Reload + + // no validation rules for HasOverride + + // no validation rules for IsAdvanced + + if m.Description != nil { + // no validation rules for Description + } + + if len(errors) > 0 { + return InventorySettingMultiError(errors) + } + + return nil +} + +// InventorySettingMultiError is an error wrapping multiple validation errors +// returned by InventorySetting.ValidateAll() if the designated constraints +// aren't met. +type InventorySettingMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m InventorySettingMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m InventorySettingMultiError) AllErrors() []error { return m } + +// InventorySettingValidationError is the validation error returned by +// InventorySetting.Validate if the designated constraints aren't met. +type InventorySettingValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e InventorySettingValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e InventorySettingValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e InventorySettingValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e InventorySettingValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e InventorySettingValidationError) ErrorName() string { return "InventorySettingValidationError" } + +// Error satisfies the builtin error interface +func (e InventorySettingValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sInventorySetting.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = InventorySettingValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = InventorySettingValidationError{} + +// Validate checks the field values on ListInventoryHostsRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryHostsRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryHostsRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListInventoryHostsRequestMultiError, or nil if none found. +func (m *ListInventoryHostsRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryHostsRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if m.HasService != nil { + // no validation rules for HasService + } + + if m.Failing != nil { + // no validation rules for Failing + } + + if m.Executor != nil { + // no validation rules for Executor + } + + if len(errors) > 0 { + return ListInventoryHostsRequestMultiError(errors) + } + + return nil +} + +// ListInventoryHostsRequestMultiError is an error wrapping multiple validation +// errors returned by ListInventoryHostsRequest.ValidateAll() if the +// designated constraints aren't met. +type ListInventoryHostsRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryHostsRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryHostsRequestMultiError) AllErrors() []error { return m } + +// ListInventoryHostsRequestValidationError is the validation error returned by +// ListInventoryHostsRequest.Validate if the designated constraints aren't met. +type ListInventoryHostsRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryHostsRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryHostsRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryHostsRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryHostsRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryHostsRequestValidationError) ErrorName() string { + return "ListInventoryHostsRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryHostsRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryHostsRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryHostsRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryHostsRequestValidationError{} + +// Validate checks the field values on ListInventoryHostsResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryHostsResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryHostsResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListInventoryHostsResponseMultiError, or nil if none found. +func (m *ListInventoryHostsResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryHostsResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetHosts() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListInventoryHostsResponseValidationError{ + field: fmt.Sprintf("Hosts[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListInventoryHostsResponseValidationError{ + field: fmt.Sprintf("Hosts[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListInventoryHostsResponseValidationError{ + field: fmt.Sprintf("Hosts[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ListInventoryHostsResponseMultiError(errors) + } + + return nil +} + +// ListInventoryHostsResponseMultiError is an error wrapping multiple +// validation errors returned by ListInventoryHostsResponse.ValidateAll() if +// the designated constraints aren't met. +type ListInventoryHostsResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryHostsResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryHostsResponseMultiError) AllErrors() []error { return m } + +// ListInventoryHostsResponseValidationError is the validation error returned +// by ListInventoryHostsResponse.Validate if the designated constraints aren't met. +type ListInventoryHostsResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryHostsResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryHostsResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryHostsResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryHostsResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryHostsResponseValidationError) ErrorName() string { + return "ListInventoryHostsResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryHostsResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryHostsResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryHostsResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryHostsResponseValidationError{} + +// Validate checks the field values on GetInventoryHostRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryHostRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryHostRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryHostRequestMultiError, or nil if none found. +func (m *GetInventoryHostRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryHostRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetNodeId()) < 1 { + err := GetInventoryHostRequestValidationError{ + field: "NodeId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return GetInventoryHostRequestMultiError(errors) + } + + return nil +} + +// GetInventoryHostRequestMultiError is an error wrapping multiple validation +// errors returned by GetInventoryHostRequest.ValidateAll() if the designated +// constraints aren't met. +type GetInventoryHostRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryHostRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryHostRequestMultiError) AllErrors() []error { return m } + +// GetInventoryHostRequestValidationError is the validation error returned by +// GetInventoryHostRequest.Validate if the designated constraints aren't met. +type GetInventoryHostRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryHostRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryHostRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryHostRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryHostRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryHostRequestValidationError) ErrorName() string { + return "GetInventoryHostRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryHostRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryHostRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryHostRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryHostRequestValidationError{} + +// Validate checks the field values on GetInventoryHostResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryHostResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryHostResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryHostResponseMultiError, or nil if none found. +func (m *GetInventoryHostResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryHostResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetHost()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetInventoryHostResponseValidationError{ + field: "Host", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetInventoryHostResponseValidationError{ + field: "Host", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetHost()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetInventoryHostResponseValidationError{ + field: "Host", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return GetInventoryHostResponseMultiError(errors) + } + + return nil +} + +// GetInventoryHostResponseMultiError is an error wrapping multiple validation +// errors returned by GetInventoryHostResponse.ValidateAll() if the designated +// constraints aren't met. +type GetInventoryHostResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryHostResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryHostResponseMultiError) AllErrors() []error { return m } + +// GetInventoryHostResponseValidationError is the validation error returned by +// GetInventoryHostResponse.Validate if the designated constraints aren't met. +type GetInventoryHostResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryHostResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryHostResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryHostResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryHostResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryHostResponseValidationError) ErrorName() string { + return "GetInventoryHostResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryHostResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryHostResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryHostResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryHostResponseValidationError{} + +// Validate checks the field values on DeleteInventoryHostRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteInventoryHostRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryHostRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// DeleteInventoryHostRequestMultiError, or nil if none found. +func (m *DeleteInventoryHostRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryHostRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetNodeId()) < 1 { + err := DeleteInventoryHostRequestValidationError{ + field: "NodeId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return DeleteInventoryHostRequestMultiError(errors) + } + + return nil +} + +// DeleteInventoryHostRequestMultiError is an error wrapping multiple +// validation errors returned by DeleteInventoryHostRequest.ValidateAll() if +// the designated constraints aren't met. +type DeleteInventoryHostRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryHostRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryHostRequestMultiError) AllErrors() []error { return m } + +// DeleteInventoryHostRequestValidationError is the validation error returned +// by DeleteInventoryHostRequest.Validate if the designated constraints aren't met. +type DeleteInventoryHostRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryHostRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryHostRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryHostRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryHostRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryHostRequestValidationError) ErrorName() string { + return "DeleteInventoryHostRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryHostRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryHostRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryHostRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryHostRequestValidationError{} + +// Validate checks the field values on DeleteInventoryHostResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteInventoryHostResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryHostResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// DeleteInventoryHostResponseMultiError, or nil if none found. +func (m *DeleteInventoryHostResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryHostResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return DeleteInventoryHostResponseMultiError(errors) + } + + return nil +} + +// DeleteInventoryHostResponseMultiError is an error wrapping multiple +// validation errors returned by DeleteInventoryHostResponse.ValidateAll() if +// the designated constraints aren't met. +type DeleteInventoryHostResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryHostResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryHostResponseMultiError) AllErrors() []error { return m } + +// DeleteInventoryHostResponseValidationError is the validation error returned +// by DeleteInventoryHostResponse.Validate if the designated constraints +// aren't met. +type DeleteInventoryHostResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryHostResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryHostResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryHostResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryHostResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryHostResponseValidationError) ErrorName() string { + return "DeleteInventoryHostResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryHostResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryHostResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryHostResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryHostResponseValidationError{} + +// Validate checks the field values on ListInventoryServicesRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryServicesRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryServicesRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListInventoryServicesRequestMultiError, or nil if none found. +func (m *ListInventoryServicesRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryServicesRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if m.NodeId != nil { + // no validation rules for NodeId + } + + if m.Failing != nil { + // no validation rules for Failing + } + + if len(errors) > 0 { + return ListInventoryServicesRequestMultiError(errors) + } + + return nil +} + +// ListInventoryServicesRequestMultiError is an error wrapping multiple +// validation errors returned by ListInventoryServicesRequest.ValidateAll() if +// the designated constraints aren't met. +type ListInventoryServicesRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryServicesRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryServicesRequestMultiError) AllErrors() []error { return m } + +// ListInventoryServicesRequestValidationError is the validation error returned +// by ListInventoryServicesRequest.Validate if the designated constraints +// aren't met. +type ListInventoryServicesRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryServicesRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryServicesRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryServicesRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryServicesRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryServicesRequestValidationError) ErrorName() string { + return "ListInventoryServicesRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryServicesRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryServicesRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryServicesRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryServicesRequestValidationError{} + +// Validate checks the field values on ListInventoryServicesResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryServicesResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryServicesResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// ListInventoryServicesResponseMultiError, or nil if none found. +func (m *ListInventoryServicesResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryServicesResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetServices() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListInventoryServicesResponseValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListInventoryServicesResponseValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListInventoryServicesResponseValidationError{ + field: fmt.Sprintf("Services[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ListInventoryServicesResponseMultiError(errors) + } + + return nil +} + +// ListInventoryServicesResponseMultiError is an error wrapping multiple +// validation errors returned by ListInventoryServicesResponse.ValidateAll() +// if the designated constraints aren't met. +type ListInventoryServicesResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryServicesResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryServicesResponseMultiError) AllErrors() []error { return m } + +// ListInventoryServicesResponseValidationError is the validation error +// returned by ListInventoryServicesResponse.Validate if the designated +// constraints aren't met. +type ListInventoryServicesResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryServicesResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryServicesResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryServicesResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryServicesResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryServicesResponseValidationError) ErrorName() string { + return "ListInventoryServicesResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryServicesResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryServicesResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryServicesResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryServicesResponseValidationError{} + +// Validate checks the field values on GetInventoryServiceRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryServiceRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryServiceRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryServiceRequestMultiError, or nil if none found. +func (m *GetInventoryServiceRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryServiceRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetServiceId()) < 1 { + err := GetInventoryServiceRequestValidationError{ + field: "ServiceId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return GetInventoryServiceRequestMultiError(errors) + } + + return nil +} + +// GetInventoryServiceRequestMultiError is an error wrapping multiple +// validation errors returned by GetInventoryServiceRequest.ValidateAll() if +// the designated constraints aren't met. +type GetInventoryServiceRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryServiceRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryServiceRequestMultiError) AllErrors() []error { return m } + +// GetInventoryServiceRequestValidationError is the validation error returned +// by GetInventoryServiceRequest.Validate if the designated constraints aren't met. +type GetInventoryServiceRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryServiceRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryServiceRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryServiceRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryServiceRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryServiceRequestValidationError) ErrorName() string { + return "GetInventoryServiceRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryServiceRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryServiceRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryServiceRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryServiceRequestValidationError{} + +// Validate checks the field values on GetInventoryServiceResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryServiceResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryServiceResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryServiceResponseMultiError, or nil if none found. +func (m *GetInventoryServiceResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryServiceResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetService()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetInventoryServiceResponseValidationError{ + field: "Service", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetInventoryServiceResponseValidationError{ + field: "Service", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetService()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetInventoryServiceResponseValidationError{ + field: "Service", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return GetInventoryServiceResponseMultiError(errors) + } + + return nil +} + +// GetInventoryServiceResponseMultiError is an error wrapping multiple +// validation errors returned by GetInventoryServiceResponse.ValidateAll() if +// the designated constraints aren't met. +type GetInventoryServiceResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryServiceResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryServiceResponseMultiError) AllErrors() []error { return m } + +// GetInventoryServiceResponseValidationError is the validation error returned +// by GetInventoryServiceResponse.Validate if the designated constraints +// aren't met. +type GetInventoryServiceResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryServiceResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryServiceResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryServiceResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryServiceResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryServiceResponseValidationError) ErrorName() string { + return "GetInventoryServiceResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryServiceResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryServiceResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryServiceResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryServiceResponseValidationError{} + +// Validate checks the field values on DeleteInventoryServiceRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteInventoryServiceRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryServiceRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// DeleteInventoryServiceRequestMultiError, or nil if none found. +func (m *DeleteInventoryServiceRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryServiceRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetServiceId()) < 1 { + err := DeleteInventoryServiceRequestValidationError{ + field: "ServiceId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return DeleteInventoryServiceRequestMultiError(errors) + } + + return nil +} + +// DeleteInventoryServiceRequestMultiError is an error wrapping multiple +// validation errors returned by DeleteInventoryServiceRequest.ValidateAll() +// if the designated constraints aren't met. +type DeleteInventoryServiceRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryServiceRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryServiceRequestMultiError) AllErrors() []error { return m } + +// DeleteInventoryServiceRequestValidationError is the validation error +// returned by DeleteInventoryServiceRequest.Validate if the designated +// constraints aren't met. +type DeleteInventoryServiceRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryServiceRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryServiceRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryServiceRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryServiceRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryServiceRequestValidationError) ErrorName() string { + return "DeleteInventoryServiceRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryServiceRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryServiceRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryServiceRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryServiceRequestValidationError{} + +// Validate checks the field values on DeleteInventoryServiceResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteInventoryServiceResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryServiceResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// DeleteInventoryServiceResponseMultiError, or nil if none found. +func (m *DeleteInventoryServiceResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryServiceResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return DeleteInventoryServiceResponseMultiError(errors) + } + + return nil +} + +// DeleteInventoryServiceResponseMultiError is an error wrapping multiple +// validation errors returned by DeleteInventoryServiceResponse.ValidateAll() +// if the designated constraints aren't met. +type DeleteInventoryServiceResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryServiceResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryServiceResponseMultiError) AllErrors() []error { return m } + +// DeleteInventoryServiceResponseValidationError is the validation error +// returned by DeleteInventoryServiceResponse.Validate if the designated +// constraints aren't met. +type DeleteInventoryServiceResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryServiceResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryServiceResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryServiceResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryServiceResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryServiceResponseValidationError) ErrorName() string { + return "DeleteInventoryServiceResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryServiceResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryServiceResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryServiceResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryServiceResponseValidationError{} + +// Validate checks the field values on ListInventoryRunsRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryRunsRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryRunsRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListInventoryRunsRequestMultiError, or nil if none found. +func (m *ListInventoryRunsRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryRunsRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if val := m.GetLimit(); val < 0 || val > 100 { + err := ListInventoryRunsRequestValidationError{ + field: "Limit", + reason: "value must be inside range [0, 100]", + } + if !all { + return err + } + errors = append(errors, err) + } + + if all { + switch v := interface{}(m.GetSince()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListInventoryRunsRequestValidationError{ + field: "Since", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListInventoryRunsRequestValidationError{ + field: "Since", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSince()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListInventoryRunsRequestValidationError{ + field: "Since", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetUntil()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListInventoryRunsRequestValidationError{ + field: "Until", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListInventoryRunsRequestValidationError{ + field: "Until", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetUntil()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListInventoryRunsRequestValidationError{ + field: "Until", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return ListInventoryRunsRequestMultiError(errors) + } + + return nil +} + +// ListInventoryRunsRequestMultiError is an error wrapping multiple validation +// errors returned by ListInventoryRunsRequest.ValidateAll() if the designated +// constraints aren't met. +type ListInventoryRunsRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryRunsRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryRunsRequestMultiError) AllErrors() []error { return m } + +// ListInventoryRunsRequestValidationError is the validation error returned by +// ListInventoryRunsRequest.Validate if the designated constraints aren't met. +type ListInventoryRunsRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryRunsRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryRunsRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryRunsRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryRunsRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryRunsRequestValidationError) ErrorName() string { + return "ListInventoryRunsRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryRunsRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryRunsRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryRunsRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryRunsRequestValidationError{} + +// Validate checks the field values on ListInventoryRunsResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListInventoryRunsResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListInventoryRunsResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ListInventoryRunsResponseMultiError, or nil if none found. +func (m *ListInventoryRunsResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListInventoryRunsResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetRuns() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListInventoryRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListInventoryRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListInventoryRunsResponseValidationError{ + field: fmt.Sprintf("Runs[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ListInventoryRunsResponseMultiError(errors) + } + + return nil +} + +// ListInventoryRunsResponseMultiError is an error wrapping multiple validation +// errors returned by ListInventoryRunsResponse.ValidateAll() if the +// designated constraints aren't met. +type ListInventoryRunsResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListInventoryRunsResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListInventoryRunsResponseMultiError) AllErrors() []error { return m } + +// ListInventoryRunsResponseValidationError is the validation error returned by +// ListInventoryRunsResponse.Validate if the designated constraints aren't met. +type ListInventoryRunsResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListInventoryRunsResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListInventoryRunsResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListInventoryRunsResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListInventoryRunsResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListInventoryRunsResponseValidationError) ErrorName() string { + return "ListInventoryRunsResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListInventoryRunsResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListInventoryRunsResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListInventoryRunsResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListInventoryRunsResponseValidationError{} + +// Validate checks the field values on GetInventoryRunRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryRunRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryRunRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryRunRequestMultiError, or nil if none found. +func (m *GetInventoryRunRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryRunRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetRunId()) < 1 { + err := GetInventoryRunRequestValidationError{ + field: "RunId", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return GetInventoryRunRequestMultiError(errors) + } + + return nil +} + +// GetInventoryRunRequestMultiError is an error wrapping multiple validation +// errors returned by GetInventoryRunRequest.ValidateAll() if the designated +// constraints aren't met. +type GetInventoryRunRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryRunRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryRunRequestMultiError) AllErrors() []error { return m } + +// GetInventoryRunRequestValidationError is the validation error returned by +// GetInventoryRunRequest.Validate if the designated constraints aren't met. +type GetInventoryRunRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryRunRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryRunRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryRunRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryRunRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryRunRequestValidationError) ErrorName() string { + return "GetInventoryRunRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryRunRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryRunRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryRunRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryRunRequestValidationError{} + +// Validate checks the field values on GetInventoryRunResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryRunResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryRunResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryRunResponseMultiError, or nil if none found. +func (m *GetInventoryRunResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryRunResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetRun()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetInventoryRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetInventoryRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRun()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetInventoryRunResponseValidationError{ + field: "Run", + reason: "embedded message failed validation", + cause: err, + } + } + } + + for idx, item := range m.GetEntities() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetInventoryRunResponseValidationError{ + field: fmt.Sprintf("Entities[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetInventoryRunResponseValidationError{ + field: fmt.Sprintf("Entities[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetInventoryRunResponseValidationError{ + field: fmt.Sprintf("Entities[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return GetInventoryRunResponseMultiError(errors) + } + + return nil +} + +// GetInventoryRunResponseMultiError is an error wrapping multiple validation +// errors returned by GetInventoryRunResponse.ValidateAll() if the designated +// constraints aren't met. +type GetInventoryRunResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryRunResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryRunResponseMultiError) AllErrors() []error { return m } + +// GetInventoryRunResponseValidationError is the validation error returned by +// GetInventoryRunResponse.Validate if the designated constraints aren't met. +type GetInventoryRunResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryRunResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryRunResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryRunResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryRunResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryRunResponseValidationError) ErrorName() string { + return "GetInventoryRunResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryRunResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryRunResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryRunResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryRunResponseValidationError{} + +// Validate checks the field values on TriggerInventoryRefreshRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *TriggerInventoryRefreshRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TriggerInventoryRefreshRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// TriggerInventoryRefreshRequestMultiError, or nil if none found. +func (m *TriggerInventoryRefreshRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *TriggerInventoryRefreshRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(m.GetNodeIds()) > 1000 { + err := TriggerInventoryRefreshRequestValidationError{ + field: "NodeIds", + reason: "value must contain no more than 1000 item(s)", + } + if !all { + return err + } + errors = append(errors, err) + } + + for idx, item := range m.GetNodeIds() { + _, _ = idx, item + + if utf8.RuneCountInString(item) < 1 { + err := TriggerInventoryRefreshRequestValidationError{ + field: fmt.Sprintf("NodeIds[%v]", idx), + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if len(errors) > 0 { + return TriggerInventoryRefreshRequestMultiError(errors) + } + + return nil +} + +// TriggerInventoryRefreshRequestMultiError is an error wrapping multiple +// validation errors returned by TriggerInventoryRefreshRequest.ValidateAll() +// if the designated constraints aren't met. +type TriggerInventoryRefreshRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TriggerInventoryRefreshRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TriggerInventoryRefreshRequestMultiError) AllErrors() []error { return m } + +// TriggerInventoryRefreshRequestValidationError is the validation error +// returned by TriggerInventoryRefreshRequest.Validate if the designated +// constraints aren't met. +type TriggerInventoryRefreshRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TriggerInventoryRefreshRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TriggerInventoryRefreshRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TriggerInventoryRefreshRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TriggerInventoryRefreshRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TriggerInventoryRefreshRequestValidationError) ErrorName() string { + return "TriggerInventoryRefreshRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e TriggerInventoryRefreshRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTriggerInventoryRefreshRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TriggerInventoryRefreshRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TriggerInventoryRefreshRequestValidationError{} + +// Validate checks the field values on TriggerInventoryRefreshResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *TriggerInventoryRefreshResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TriggerInventoryRefreshResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// TriggerInventoryRefreshResponseMultiError, or nil if none found. +func (m *TriggerInventoryRefreshResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *TriggerInventoryRefreshResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for RunId + + // no validation rules for Status + + if all { + switch v := interface{}(m.GetStartTime()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TriggerInventoryRefreshResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TriggerInventoryRefreshResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetStartTime()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TriggerInventoryRefreshResponseValidationError{ + field: "StartTime", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return TriggerInventoryRefreshResponseMultiError(errors) + } + + return nil +} + +// TriggerInventoryRefreshResponseMultiError is an error wrapping multiple +// validation errors returned by TriggerInventoryRefreshResponse.ValidateAll() +// if the designated constraints aren't met. +type TriggerInventoryRefreshResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TriggerInventoryRefreshResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TriggerInventoryRefreshResponseMultiError) AllErrors() []error { return m } + +// TriggerInventoryRefreshResponseValidationError is the validation error +// returned by TriggerInventoryRefreshResponse.Validate if the designated +// constraints aren't met. +type TriggerInventoryRefreshResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TriggerInventoryRefreshResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TriggerInventoryRefreshResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TriggerInventoryRefreshResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TriggerInventoryRefreshResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TriggerInventoryRefreshResponseValidationError) ErrorName() string { + return "TriggerInventoryRefreshResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e TriggerInventoryRefreshResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTriggerInventoryRefreshResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = TriggerInventoryRefreshResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TriggerInventoryRefreshResponseValidationError{} + +// Validate checks the field values on GetInventoryConfigRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryConfigRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryConfigRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryConfigRequestMultiError, or nil if none found. +func (m *GetInventoryConfigRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryConfigRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return GetInventoryConfigRequestMultiError(errors) + } + + return nil +} + +// GetInventoryConfigRequestMultiError is an error wrapping multiple validation +// errors returned by GetInventoryConfigRequest.ValidateAll() if the +// designated constraints aren't met. +type GetInventoryConfigRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryConfigRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryConfigRequestMultiError) AllErrors() []error { return m } + +// GetInventoryConfigRequestValidationError is the validation error returned by +// GetInventoryConfigRequest.Validate if the designated constraints aren't met. +type GetInventoryConfigRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryConfigRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryConfigRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryConfigRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryConfigRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryConfigRequestValidationError) ErrorName() string { + return "GetInventoryConfigRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryConfigRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryConfigRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryConfigRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryConfigRequestValidationError{} + +// Validate checks the field values on GetInventoryConfigResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetInventoryConfigResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetInventoryConfigResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetInventoryConfigResponseMultiError, or nil if none found. +func (m *GetInventoryConfigResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetInventoryConfigResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetSettings() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return GetInventoryConfigResponseMultiError(errors) + } + + return nil +} + +// GetInventoryConfigResponseMultiError is an error wrapping multiple +// validation errors returned by GetInventoryConfigResponse.ValidateAll() if +// the designated constraints aren't met. +type GetInventoryConfigResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetInventoryConfigResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetInventoryConfigResponseMultiError) AllErrors() []error { return m } + +// GetInventoryConfigResponseValidationError is the validation error returned +// by GetInventoryConfigResponse.Validate if the designated constraints aren't met. +type GetInventoryConfigResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetInventoryConfigResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetInventoryConfigResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetInventoryConfigResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetInventoryConfigResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetInventoryConfigResponseValidationError) ErrorName() string { + return "GetInventoryConfigResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetInventoryConfigResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetInventoryConfigResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetInventoryConfigResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetInventoryConfigResponseValidationError{} + +// Validate checks the field values on UpdateInventoryConfigRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UpdateInventoryConfigRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateInventoryConfigRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UpdateInventoryConfigRequestMultiError, or nil if none found. +func (m *UpdateInventoryConfigRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateInventoryConfigRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetValues()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, UpdateInventoryConfigRequestValidationError{ + field: "Values", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, UpdateInventoryConfigRequestValidationError{ + field: "Values", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetValues()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return UpdateInventoryConfigRequestValidationError{ + field: "Values", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return UpdateInventoryConfigRequestMultiError(errors) + } + + return nil +} + +// UpdateInventoryConfigRequestMultiError is an error wrapping multiple +// validation errors returned by UpdateInventoryConfigRequest.ValidateAll() if +// the designated constraints aren't met. +type UpdateInventoryConfigRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateInventoryConfigRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UpdateInventoryConfigRequestMultiError) AllErrors() []error { return m } + +// UpdateInventoryConfigRequestValidationError is the validation error returned +// by UpdateInventoryConfigRequest.Validate if the designated constraints +// aren't met. +type UpdateInventoryConfigRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateInventoryConfigRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateInventoryConfigRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateInventoryConfigRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateInventoryConfigRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateInventoryConfigRequestValidationError) ErrorName() string { + return "UpdateInventoryConfigRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateInventoryConfigRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUpdateInventoryConfigRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateInventoryConfigRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateInventoryConfigRequestValidationError{} + +// Validate checks the field values on UpdateInventoryConfigResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UpdateInventoryConfigResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateInventoryConfigResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// UpdateInventoryConfigResponseMultiError, or nil if none found. +func (m *UpdateInventoryConfigResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateInventoryConfigResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetSettings() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, UpdateInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, UpdateInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return UpdateInventoryConfigResponseValidationError{ + field: fmt.Sprintf("Settings[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return UpdateInventoryConfigResponseMultiError(errors) + } + + return nil +} + +// UpdateInventoryConfigResponseMultiError is an error wrapping multiple +// validation errors returned by UpdateInventoryConfigResponse.ValidateAll() +// if the designated constraints aren't met. +type UpdateInventoryConfigResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateInventoryConfigResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UpdateInventoryConfigResponseMultiError) AllErrors() []error { return m } + +// UpdateInventoryConfigResponseValidationError is the validation error +// returned by UpdateInventoryConfigResponse.Validate if the designated +// constraints aren't met. +type UpdateInventoryConfigResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateInventoryConfigResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateInventoryConfigResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateInventoryConfigResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateInventoryConfigResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateInventoryConfigResponseValidationError) ErrorName() string { + return "UpdateInventoryConfigResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateInventoryConfigResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUpdateInventoryConfigResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateInventoryConfigResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateInventoryConfigResponseValidationError{} + +// Validate checks the field values on DeleteInventoryConfigOverrideRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the first error encountered is returned, or nil if +// there are no violations. +func (m *DeleteInventoryConfigOverrideRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryConfigOverrideRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// DeleteInventoryConfigOverrideRequestMultiError, or nil if none found. +func (m *DeleteInventoryConfigOverrideRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryConfigOverrideRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetKey()) < 1 { + err := DeleteInventoryConfigOverrideRequestValidationError{ + field: "Key", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return DeleteInventoryConfigOverrideRequestMultiError(errors) + } + + return nil +} + +// DeleteInventoryConfigOverrideRequestMultiError is an error wrapping multiple +// validation errors returned by +// DeleteInventoryConfigOverrideRequest.ValidateAll() if the designated +// constraints aren't met. +type DeleteInventoryConfigOverrideRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryConfigOverrideRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryConfigOverrideRequestMultiError) AllErrors() []error { return m } + +// DeleteInventoryConfigOverrideRequestValidationError is the validation error +// returned by DeleteInventoryConfigOverrideRequest.Validate if the designated +// constraints aren't met. +type DeleteInventoryConfigOverrideRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryConfigOverrideRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryConfigOverrideRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryConfigOverrideRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryConfigOverrideRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryConfigOverrideRequestValidationError) ErrorName() string { + return "DeleteInventoryConfigOverrideRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryConfigOverrideRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryConfigOverrideRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryConfigOverrideRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryConfigOverrideRequestValidationError{} + +// Validate checks the field values on DeleteInventoryConfigOverrideResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the first error encountered is returned, or nil if +// there are no violations. +func (m *DeleteInventoryConfigOverrideResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteInventoryConfigOverrideResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// DeleteInventoryConfigOverrideResponseMultiError, or nil if none found. +func (m *DeleteInventoryConfigOverrideResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteInventoryConfigOverrideResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return DeleteInventoryConfigOverrideResponseMultiError(errors) + } + + return nil +} + +// DeleteInventoryConfigOverrideResponseMultiError is an error wrapping +// multiple validation errors returned by +// DeleteInventoryConfigOverrideResponse.ValidateAll() if the designated +// constraints aren't met. +type DeleteInventoryConfigOverrideResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteInventoryConfigOverrideResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteInventoryConfigOverrideResponseMultiError) AllErrors() []error { return m } + +// DeleteInventoryConfigOverrideResponseValidationError is the validation error +// returned by DeleteInventoryConfigOverrideResponse.Validate if the +// designated constraints aren't met. +type DeleteInventoryConfigOverrideResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteInventoryConfigOverrideResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteInventoryConfigOverrideResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteInventoryConfigOverrideResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteInventoryConfigOverrideResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteInventoryConfigOverrideResponseValidationError) ErrorName() string { + return "DeleteInventoryConfigOverrideResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteInventoryConfigOverrideResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteInventoryConfigOverrideResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteInventoryConfigOverrideResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteInventoryConfigOverrideResponseValidationError{} diff --git a/api/om/v1/om.proto b/api/om/v1/om.proto new file mode 100644 index 00000000000..d848f361ff9 --- /dev/null +++ b/api/om/v1/om.proto @@ -0,0 +1,1027 @@ +syntax = "proto3"; + +package om.v1; + +import "google/api/annotations.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; +import "validate/validate.proto"; + +// ServiceStatus is whether the exporter reached a service. +// +// Two values and no third: this is the exporter's reachability, not the server's health. +// "we did not look" is UNSPECIFIED, which the collector never emits. +enum ServiceStatus { + SERVICE_STATUS_UNSPECIFIED = 0; + // The exporter reached the service. + SERVICE_STATUS_UP = 1; + // It did not. + SERVICE_STATUS_DOWN = 2; +} + +// ProcessRole is what a mongod or mongos is doing in the deployment. +// +// Not the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This +// is the role the process was started in, which is a property of the deployment's shape. +enum ProcessRole { + PROCESS_ROLE_UNSPECIFIED = 0; + // A standalone or replica-set member with no sharding role. + PROCESS_ROLE_MONGOD = 1; + // A router. + PROCESS_ROLE_MONGOS = 2; + // A config-server member. + PROCESS_ROLE_CONFIGSVR = 3; + // A shard member. + PROCESS_ROLE_SHARDSVR = 4; +} + +// RunStatus is how a run ended, for both kinds of run. +// +// Shared by the topology collection pass and the inventory refresh deliberately: the two +// runs differ in what they do, not in how they finish, and two identical enums would +// invite them to drift apart for no reason. +enum RunStatus { + RUN_STATUS_UNSPECIFIED = 0; + // Still going. Not a terminal status. + RUN_STATUS_RUNNING = 1; + // Everything it attempted answered. + RUN_STATUS_SUCCESS = 2; + // Some of it did. The counts say which. For an inventory refresh this is the common + // steady state rather than an alarm: a row routinely outlives the executor that served + // it. + RUN_STATUS_PARTIAL = 3; + // The run itself failed, as opposed to the things it was probing. + RUN_STATUS_FAILED = 4; + // Refused before doing any work, because another refresh already held the hosts it + // would have covered. Neither a failure nor a success: it did nothing, deliberately, + // and it is recorded so a schedule cannot look like it fired and found nothing. + // + // Only an inventory refresh reaches this. The collection pass has a single-flight + // guard too, but a refusal there never reaches a run row at all -- the RPC answers + // Aborted (already running) or FailedPrecondition (not the HA leader) and nothing is + // recorded, so this status never applies to it. + RUN_STATUS_SKIPPED = 5; +} + +// SourceStatus is how completely one collection source answered. +// +// Separate from RunStatus because it carries DISABLED, which a run cannot be: a source +// switched off in configuration is a deliberate state, not a degraded one. +enum SourceStatus { + SOURCE_STATUS_UNSPECIFIED = 0; + // Answered everything asked of it. + SOURCE_STATUS_OK = 1; + // Answered some of it. + SOURCE_STATUS_PARTIAL = 2; + // Did not answer. + SOURCE_STATUS_FAILED = 3; + // Switched off in configuration, so it was never asked. + SOURCE_STATUS_DISABLED = 4; +} + +// TopologyService represents one monitored MongoDB service as the topology document +// records it. +// +// Two conventions for "no value", and they differ on purpose. cpu_usage_percent and +// connections_free_percent are -1 when not measured, never absent and never 0, because +// zero CPU is a legitimate reading and a numeric column must keep "idle" and "unknown" +// apart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is +// absent when they do not apply -- a router and a standalone have no replica-set oplog -- +// which is a different statement from -1's "we could not measure it". +// +// The optional fields were wrapper messages until the REST contract was checked: +// protoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema +// and the generated Go client both collapsed to a value type and lost the distinction +// entirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting +// the key rather than emitting an explicit null. +message TopologyService { + // Service name as PMM inventory registered it. + string service_name = 1; + // Node the service runs on. + optional string host = 2; + // host:port as the replica set itself addresses the member. + optional string endpoint = 3; + // PMM's service ID. The join key against VictoriaMetrics. + optional string service_id = 4; + // Always "mongodb" today. + optional string service_type = 5; + // Running server version. + optional string version = 6; + // MongoDB or Percona. + optional string vendor = 7; + // Community or Enterprise. + optional string edition = 8; + // Replica set, or unset for a router or a standalone. + optional string replication_set = 9; + // PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state. + optional string state = 10; + // Whether the exporter reached the service. + ServiceStatus status = 11; + // CPU percentage, or -1 when not measured. + double cpu_usage_percent = 12; + // Percentage of free connections, or -1 when not measured. + double connections_free_percent = 13; + // What this process is doing in the deployment. + ProcessRole process_role = 14; + // Seconds this member trails the primary; unset where there is no primary to trail. + optional double replication_lag_seconds = 15; + // Seconds of history the oplog holds; unset where there is no replica-set oplog. + optional double oplog_window_seconds = 16; + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from `version` is the upgraded-but-not-restarted case. Only + // an on-host probe can see it, so this is unset wherever one has not run. + optional string installed_version = 17; + // The configuration file the running server read. Probe-only. + optional string config_path = 18; + // The command line the running server was started with. Probe-only. + optional string argv = 19; + + // When the newest *live* field on this row was observed, unset when every field on it + // is either absent or not time-bounded (inventory only, no metric and no probe ever + // seen). This is the row's own provenance -- Snapshot.observed_at is the newest across + // the whole estate, which cannot tell "this row is current" from "this row is the one + // that made the snapshot look fresh". A field's own MergedField.ObservedAt exists + // internally; this is the first one exposed on the wire. + optional google.protobuf.Timestamp observed_at = 20; +} + +// ClusterType is the shape buildDocument inferred for one grouped service inventory. +// +// Inferred, not reconstructed: this package groups services by label and infers a shape +// from what is in the group, it does not walk a replica set's own config to build a +// member list. See the package comment. +enum ClusterType { + CLUSTER_TYPE_UNSPECIFIED = 0; + // Exactly one replication_set label under this cluster, and no mongos. + CLUSTER_TYPE_REPLICA_SET = 1; + // A mongos is present, or more than one replication_set label shares this cluster + // label. + CLUSTER_TYPE_SHARDED = 2; + // Neither: services grouped under one label with no replica-set identity at all. + CLUSTER_TYPE_STANDALONE = 3; +} + +// ClusterHealth is a reserved verdict slot, not yet computed by anything. +// +// UNSPECIFIED is the only value that exists today. It is declared now, alongside the +// applyHealth seam in the collector, so a rollup status has a field to land in without a +// later schema change -- see the om package's health-pipeline comment. +enum ClusterHealth { + CLUSTER_HEALTH_UNSPECIFIED = 0; +} + +// Cluster represents one grouped service inventory: every service PMM's inventory +// labelled with the same (environment, cluster) or (environment, replication_set), not a +// reconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat +// list of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for +// the one thing inferred about that shape, and the package comment for what is +// deliberately not. +message Cluster { + // Cluster label, unset when its services carry none. Not a stable identity: two + // clusters can share this label (a second generation of a sandbox reusing a name), and + // `id` is what tells them apart. + optional string name = 1; + // Its services, ordered by name. + repeated TopologyService services = 2; + // Opaque, server-issued, stable across a rename of `name`. Derived from + // (environment, cluster, replication_set) so the same estate group always gets the + // same id -- clients must not parse it or assume a derivation. + string id = 3; + // What buildDocument inferred about this group's shape. + ClusterType type = 4; + // Reserved for the health pipeline. Always UNSPECIFIED today. + ClusterHealth health = 5; +} + +// Environment represents one monitoring environment. +message Environment { + // Environment label, unset when its services carry none. + optional string env_name = 1; + // Its clusters, ordered by name. + repeated Cluster clusters = 2; +} + +// Summary carries the fleet-level counts, so a caller need not re-derive them. +message Summary { + // Environments in the document. + int32 environments = 1; + // Clusters across all of them. + int32 clusters = 2; + // Services in the document. + int32 total_services = 3; + // Services the exporter reached. + int32 up_services = 4; + // Services it did not. + int32 down_services = 5; + // Service counts per process role, keyed by the ProcessRole enum's name. + map process_role_counts = 6; +} + +// Snapshot carries the provenance every snapshot-backed response repeats. +message Snapshot { + // When the document was assembled. + google.protobuf.Timestamp generated_at = 1; + // The newest observation in it, unset when nothing was observed at all. + google.protobuf.Timestamp observed_at = 2; + // Whether the document is older than the staleness grace period. Also true, with + // observed_at unset and every environment empty, on a genuinely cold estate -- no + // collection has completed anywhere yet. That is a startup state, not a statement that + // the estate itself is empty; a reader should render it as "collecting" rather than as + // an empty result. + bool stale = 3; + // The document schema version. + int32 schema_version = 4; + // The collection run that produced it. + string run_id = 5; +} + +// GetTopologyRequest is the request for GetTopology. It takes no parameters: the +// document describes the whole estate, and filtering it is the caller's business. +message GetTopologyRequest {} + +// GetTopologyResponse is the whole topology document plus the provenance of the run +// behind it. +message GetTopologyResponse { + // Which run produced this, when, and whether it is stale. + Snapshot snapshot = 1; + // The PMM node the document was assembled on. + optional string origin_node = 2; + // The VictoriaMetrics queries the document was derived from. + repeated string source_queries = 3; + // Fleet-level counts. + Summary summary = 4; + // The estate, grouped environment then cluster. + repeated Environment environments = 5; +} + +// TopologyRunCounts counts what one collection run saw. +message TopologyRunCounts { + // MongoDB services inventory reported. + int32 total_services = 1; + // ...of which carried a service ID to join metrics on. + int32 resolved_services = 2; + // ...of which did not. Not an error. + int32 orphaned_services = 3; + // Services metrics actually observed as reachable. + int32 successful_probes = 4; + // Services carrying at least one volatile fact too old to read as current. + int32 stale_services = 5; +} + +// SourceReport says how completely one collection source answered, and what it saw. +// +// Recorded per source so a thin document is legible rather than merely thin: a snapshot +// assembled with metrics=ok and probe=failed is still correct about every version and +// honest about reachability. +message SourceReport { + // The source key, e.g. "inventory", "metrics" or "probe". An open set on purpose: a + // source is named by whatever produced it, so this stays a string where the statuses + // beside it are enums. + string source = 1; + // How completely it answered. + SourceStatus status = 2; + // How many facts it produced. + int32 facts = 3; + // Source-specific counters, rendered as strings so a source can report whatever it has + // without this contract naming every counter. + map detail = 4; +} + +// TopologyRunError describes one thing that went wrong during a collection run. +message TopologyRunError { + // What the error is about, e.g. "run" or "query". + string scope = 1; + // The service it concerns, when scoped to one. + optional string service_name = 2; + // A machine-readable cause. + string code = 3; + // The human-readable detail. + string message = 4; +} + +// TopologyRun represents one collection run. +message TopologyRun { + // The run's ID, also the snapshot key. + string run_id = 1; + // How it ended. + RunStatus status = 2; + // When the run began. + google.protobuf.Timestamp start_time = 3; + // When it reached a terminal status; unset while running. + google.protobuf.Timestamp end_time = 4; + // What it saw. + TopologyRunCounts counts = 5; + // Query-level, service-level and run-level failures. + repeated TopologyRunError errors = 6; + // How completely each collection source answered. + repeated SourceReport sources = 7; +} + +// GetTopologyRunRequest is the request for GetTopologyRun. +message GetTopologyRunRequest { + // The run to return. + string run_id = 1 [(validate.rules).string.min_len = 1]; +} + +// GetTopologyRunResponse returns one collection run. +message GetTopologyRunResponse { + // The run. + TopologyRun run = 1; +} + +// ListTopologyRunsRequest is the request for ListTopologyRuns. +message ListTopologyRunsRequest { + // How many runs to return, newest first. Defaults to 25, capped at 100. + int32 limit = 1 [(validate.rules).int32 = { + gte: 0 + lte: 100 + }]; +} + +// ListTopologyRunsResponse returns the run history, newest first. +message ListTopologyRunsResponse { + // The runs. + repeated TopologyRun runs = 1; +} + +// TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection. +message TriggerTopologyCollectionRequest {} + +// TriggerTopologyCollectionResponse acknowledges a completed collection run. +message TriggerTopologyCollectionResponse { + // The run's ID. + string run_id = 1; + // The run's terminal status. + RunStatus status = 2; + // When the run began. + google.protobuf.Timestamp start_time = 3; +} + +// InventoryExecutor reports whether SEP can run anything on a host. +// +// Three flags rather than one, because "orphaned" hid three different problems with +// three different fixes: never onboarded (registered false), onboarded and down +// (reachable false), and up with a broken raw_exec driver (driver_healthy false). This +// is SEP's own knowledge rather than probe output, so it is filled in for every host +// on every sweep, including hosts no probe reached. +message InventoryExecutor { + // Whether the Tasks backend knows this node at all. + bool registered = 1; + // Whether it is currently up. + bool reachable = 2; + // Whether its raw_exec driver is healthy, which is what a probe actually needs. + bool driver_healthy = 3; + // Whatever detail the backend gave, when it gave any. + optional string detail = 4; +} + +// UnregisteredMongod is a mongod found running that PMM has no service for. +// +// The arbiter case, mostly: PMM registers no service for an arbiter, so nothing else +// in OM would report the process at all. Also what stands in the way of installing +// anything over a port that is already taken. +message UnregisteredMongod { + // The port it is listening on. + optional int32 port = 1; + // The configuration file it read. + optional string config_path = 2; + // The command line it was started with. + optional string argv = 3; + // The process name, e.g. "mongod". + optional string program = 4; + // Its process ID at the time of the probe. + optional int32 pid = 5; +} + +// ExecutorResolution is how a host was matched to the client its probe ran on. +// +// ORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact +// about onboarding. NAME and ADDRESS record *which* of the two joins matched, because a +// host reachable only by address is a different estate problem from one matched by name. +enum ExecutorResolution { + EXECUTOR_RESOLUTION_UNSPECIFIED = 0; + // Matched on the node's registered name. + EXECUTOR_RESOLUTION_NAME = 1; + // Matched on the node's address. + EXECUTOR_RESOLUTION_ADDRESS = 2; + // Not matched, so nothing was dispatched. + EXECUTOR_RESOLUTION_ORPHANED = 3; +} + +// SettingReload is how a configuration field may be overridden, if at all. +// +// Mirrors the app's own three-valued classification rather than collapsing it to +// editable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a +// whole-object write while its children accept one, so a form that read it as +// "not overridable" would refuse to edit a leaf the API would have accepted. +// +// The distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable +// promises a change the API cannot deliver. +enum SettingReload { + SETTING_RELOAD_UNSPECIFIED = 0; + // Overridable at runtime; the new value takes effect on the next snapshot refresh. + SETTING_RELOAD_HOT = 1; + // A nested object whose children are overridable, but which rejects being written + // whole. + SETTING_RELOAD_NESTED_ONLY = 2; + // Not overridable at all: YAML and environment variables remain the only sources. + SETTING_RELOAD_NOT_OVERRIDABLE = 3; +} + +// InventoryFreshness says how current the rest of a row is, and how it is failing. +// +// Carried on hosts and services alike because the estate is upserted rather than +// rebuilt: a row keeps what it last reported, so every attribute is only meaningful +// beside the time it was collected. `failing_since` is the *first* failure after the +// last success, which is what makes "failing for three days" expressible rather than +// only "failed a minute ago". +message InventoryFreshness { + // When OM first wrote a row for this entity. + google.protobuf.Timestamp first_seen_at = 1; + // When a refresh last tried it. + google.protobuf.Timestamp last_attempt_at = 2; + // When it last answered. Unset means it never has, which is different from having + // answered nothing. + google.protobuf.Timestamp last_success_at = 3; + // The first failure after the last success. Unset means it is not failing. + google.protobuf.Timestamp failing_since = 4; + // Failures since the last success. + int32 consecutive_failures = 5; + // The most recent failure detail. + optional string last_error = 6; +} + +// InventoryService is one MongoDB service OM has probed, or tried to. +// +// The typed fields are the ones a table sorts by; `observed` carries the whole +// document besides. That split is deliberate: the app stores observations as JSON so +// that collecting a new attribute is a payload change rather than a schema change, and +// enumerating every attribute here would put that coupling straight back. A new +// attribute appears in `observed` the day it is collected and is promoted to a field +// of its own only when something wants to sort by it. +message InventoryService { + // PMM's service ID. The join key against the topology document. + string service_id = 1; + // The node it runs on, as PMM's node ID. + string node_id = 2; + // The service name PMM registered. + string name = 3; + // The port it listens on, where OM knows it. + optional int32 port = 4; + // PRIMARY, SECONDARY, ARBITER, or unset. + optional string role = 5; + + // The MongoDB binary installed on the node, which is not necessarily the one + // running. Divergence from running_version is the upgraded-but-not-restarted case, + // and no metric anywhere carries it. + optional string installed_version = 6; + // The version the running server reports. + optional string running_version = 7; + // The configuration file the running server read. + optional string config_path = 8; + // The command line it was started with. + optional string argv = 9; + // What the last probe of this service concluded, in the payload's own words. + optional string probe_status = 10; + // Whether a server was found running. Unset where no probe has looked. + optional bool server_running = 11; + // How long it has been up, seconds. + optional double uptime_seconds = 12; + // The replica set it belongs to, or unset for a standalone or a router. + optional string replication_set = 13; + + // Everything the probe recorded, including attributes with no field above. + google.protobuf.Struct observed = 14; + // How current the above is, and how it is failing. + InventoryFreshness freshness = 15; +} + +// InventoryHost is one machine OM knows about, with the services on it. +// +// A host is a row whether or not any MongoDB was found on it. That is what makes +// "which machines have no database" a query rather than an absence, and it is the only +// way a machine that has never run one appears at all - which is the case installing a +// database somewhere later depends on. +message InventoryHost { + // PMM's node ID. Also what a scoped refresh is addressed by. + string node_id = 1; + // The node name PMM registered. + string name = 2; + // The node address PMM registered. + optional string address = 3; + // The Nomad client that serves it. Unset means nothing can be run there, which is a + // fact about the estate rather than a probe failure. + optional string executor_host = 4; + + // The operating system, as the host reports it. Worth having from a probe because + // PMM does not know it for some nodes. + optional string os = 5; + // The kernel release. + optional string kernel = 6; + // Whether anything can be run here, in three parts. + InventoryExecutor executor = 7; + // Mongods running that PMM has no service for. + repeated UnregisteredMongod unregistered_mongods = 8; + + // Everything the probe recorded about the host, including attributes with no field + // above. + google.protobuf.Struct observed = 9; + // How current the above is, and how it is failing. + InventoryFreshness freshness = 10; + // The services on it. Empty is a meaningful answer, not a gap. + repeated InventoryService services = 11; +} + +// InventoryRunCounts is what one refresh saw. +message InventoryRunCounts { + // Services enumeration found. + int32 total_services = 1; + // ...of which matched a host something could be run on. + int32 resolved_services = 2; + // ...of which did not. Not an error. + int32 orphaned_services = 3; + // Services that answered a probe. + int32 answered_services = 4; + // Hosts in scope this run, service or no service. + // + // A refresh attempts hosts as well as the services on them, so counting only + // services makes a refresh of a host with no database read as "0 of 0" - which is + // exactly what a run that did nothing looks like, on the one kind of host OM most + // exists to describe. + int32 total_hosts = 5; + // ...of which had somewhere to run a probe. The gap is the estate nothing can be + // dispatched to, which is a fact about onboarding rather than a failed run. + int32 probeable_hosts = 6; + // Hosts that answered. + int32 answered_hosts = 7; +} + +// InventoryRunEntityService is one service on a host, as a refresh saw it. +message InventoryRunEntityService { + // PMM's service ID, when OM could key one. + optional string service_id = 1; + // Its name, so a reader is not left joining UUIDs by hand. + optional string service_name = 2; + // Whether the host returned a usable record for it. + bool answered = 3; + // Why it did not, when it did not. + optional string error = 4; +} + +// InventoryRunEntity is one host a refresh attempted, and what came of it. +// +// Host-oriented, because a refresh attempts hosts. A flat list of services - which +// this was - cannot show a machine carrying a PMM client and no database, however +// many times it is probed, and that machine is the case OM most exists to describe: +// it is where a database can be installed. +// +// One dispatch covers every service on a host, so the host owns the timing and the +// failure and its services carry only what is theirs. Previously the duration was +// copied onto each service, which read as several measurements when it was one. +// +// Deliberately outcomes and not observations. What the probe *found* lives on the +// estate, where it is upserted and stays current; a receipt that also carried the +// attributes would be a second copy that goes stale the moment the next refresh runs. +message InventoryRunEntity { + // PMM's node ID, the key OM holds this host under. + string node_id = 1; + // The node's registered name. + optional string host_name = 2; + // The client its probe ran on. Unset when none matched. + optional string executor_host = 3; + // How that client was matched, or that it was not. + ExecutorResolution resolution = 4; + // Whether the *host* answered. A different question from whether its services did: + // a host with no database answers perfectly well and has no services at all. + bool answered = 5; + // The host's wall clock, dispatch to collected output. + optional double duration_seconds = 6; + // The host-level failure, when its probe failed. + optional string error = 7; + // The services on it. Empty is a meaningful answer, not a gap. + repeated InventoryRunEntityService services = 8; + // The task history id of the dispatch, so a reader can open the probe's own log. + // Unset when the dispatch never got one. + optional int64 task_history_id = 9; +} + +// InventoryRun is one refresh of the estate. +message InventoryRun { + // The run's ID. + string run_id = 1; + // How it ended. + RunStatus status = 2; + // When it began. + google.protobuf.Timestamp start_time = 3; + // When it stopped. Unset while it is still going. + google.protobuf.Timestamp end_time = 4; + // What it saw. + InventoryRunCounts counts = 5; + // The hosts it was limited to. Empty means it refreshed the whole estate, which is + // what the scheduled sweep does. + repeated string scope = 6; + // What went wrong, when something did. + optional string error = 7; +} + +// InventorySetting is one of the inventory app's configuration fields. +message InventorySetting { + // The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every. + string key = 1; + // The value in effect. + google.protobuf.Value value = 2; + // What it would be with no override. + google.protobuf.Value default_value = 3; + // The field's type, for rendering an input. A string because the app's own schema + // names it, so this contract does not get to enumerate the possibilities. + string type = 4; + // Whether it can be changed at runtime. + SettingReload reload = 5; + // Whether an override is in effect, which is how "why is it set to this" is + // answerable without also reading the deployment's configuration file. + bool has_override = 6; + // Whether to hide it behind an "advanced" disclosure. + bool is_advanced = 7; + // The field's documentation, where it has any. + optional string description = 8; +} + +// ListInventoryHostsRequest is the request for ListInventoryHosts. +message ListInventoryHostsRequest { + // When set, return only hosts that do (or do not) carry a registered service. + // Unset returns both, which is the ordinary listing. + optional bool has_service = 1; + // When true, return only hosts currently failing. + optional bool failing = 2; + // When set, return only hosts that do (or do not) have an executor to run a probe + // on. Not a client name: the app filters on whether one is matched at all, and + // "which machines can nothing be dispatched to" is the question worth asking. + optional bool executor = 3; +} + +// ListInventoryHostsResponse returns the hosts OM knows about. +message ListInventoryHostsResponse { + // The hosts. + repeated InventoryHost hosts = 1; +} + +// GetInventoryHostRequest is the request for GetInventoryHost. +message GetInventoryHostRequest { + // PMM's node ID. + string node_id = 1 [(validate.rules).string.min_len = 1]; +} + +// GetInventoryHostResponse returns one host. +message GetInventoryHostResponse { + // The host. + InventoryHost host = 1; +} + +// DeleteInventoryHostRequest is the request for DeleteInventoryHost. +message DeleteInventoryHostRequest { + // PMM's node ID. + string node_id = 1 [(validate.rules).string.min_len = 1]; +} + +// DeleteInventoryHostResponse acknowledges forgetting a host. +message DeleteInventoryHostResponse {} + +// ListInventoryServicesRequest is the request for ListInventoryServices. +message ListInventoryServicesRequest { + // When set, return only the services on this host. + optional string node_id = 1; + // When true, return only services currently failing. + optional bool failing = 2; +} + +// ListInventoryServicesResponse returns the services OM knows about, flat. +message ListInventoryServicesResponse { + // The services. + repeated InventoryService services = 1; +} + +// GetInventoryServiceRequest is the request for GetInventoryService. +message GetInventoryServiceRequest { + // PMM's service ID. + string service_id = 1 [(validate.rules).string.min_len = 1]; +} + +// GetInventoryServiceResponse returns one service. +message GetInventoryServiceResponse { + // The service. + InventoryService service = 1; +} + +// DeleteInventoryServiceRequest is the request for DeleteInventoryService. +message DeleteInventoryServiceRequest { + // PMM's service ID. + string service_id = 1 [(validate.rules).string.min_len = 1]; +} + +// DeleteInventoryServiceResponse acknowledges forgetting a service. +message DeleteInventoryServiceResponse {} + +// ListInventoryRunsRequest is the request for ListInventoryRuns. +message ListInventoryRunsRequest { + // How many to return, newest first. Defaults to 20, capped at 100. + int32 limit = 1 [(validate.rules).int32 = { + gte: 0 + lte: 100 + }]; + // Inclusive lower bound on start_time. Unset means no lower bound. + // + // Applied before limit, so a week window is the newest runs *in that week*, + // not the newest overall then those that happen to fall in it. + google.protobuf.Timestamp since = 2; + // Inclusive upper bound on start_time. Unset means no upper bound. + google.protobuf.Timestamp until = 3; +} + +// ListInventoryRunsResponse returns the refresh history, newest first. +message ListInventoryRunsResponse { + // The runs. + repeated InventoryRun runs = 1; +} + +// GetInventoryRunRequest is the request for GetInventoryRun. +message GetInventoryRunRequest { + // The run's ID. + string run_id = 1 [(validate.rules).string.min_len = 1]; +} + +// GetInventoryRunResponse returns one refresh, with the rows behind its counters. +message GetInventoryRunResponse { + // The run. + InventoryRun run = 1; + // What it attempted, one entry per entity. + // + // Only on the detail response, never on the list: a refresh of a real estate has a + // row per service, and a history of twenty-five would carry the lot to render a + // page that shows one at a time. + repeated InventoryRunEntity entities = 2; +} + +// TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh. +message TriggerInventoryRefreshRequest { + // The hosts to refresh, by PMM node ID. Empty refreshes the whole estate. + // + // Plural on purpose: PMM's node ID is also OM's key, so ids pass through + // untranslated, and one host is a list of one. A surface taking a single id where + // the app takes a list would be a translation step in disguise. + // + // Bounded because a refresh dispatches a Nomad job per host: the empty list already + // means "the whole estate", so a caller naming hosts individually is naming a few, + // and an unbounded list is only reachable by accident. An empty string is rejected + // rather than forwarded, where it would read as a node ID that matches nothing. + repeated string node_ids = 1 [(validate.rules).repeated = { + max_items: 1000 + items: { + string: {min_len: 1} + } + }]; +} + +// TriggerInventoryRefreshResponse acknowledges an accepted refresh. +// +// Accepted, not finished. A refresh dispatches a Nomad job per host and takes tens of +// seconds, unlike PMM's own collection pass, which never probes and completes in +// milliseconds. Two triggers that different must not look alike to a caller. +message TriggerInventoryRefreshResponse { + // The run's ID, to follow with GetInventoryRun. + string run_id = 1; + // Its status, which is RUN_STATUS_RUNNING. + RunStatus status = 2; + // When it began. + google.protobuf.Timestamp start_time = 3; + // The hosts it will refresh. Empty means the whole estate. + repeated string scope = 4; +} + +// GetInventoryConfigRequest is the request for GetInventoryConfig. +message GetInventoryConfigRequest {} + +// GetInventoryConfigResponse returns the inventory app's configuration. +message GetInventoryConfigResponse { + // Every field, whether or not it is overridden. + repeated InventorySetting settings = 1; +} + +// UpdateInventoryConfigRequest is the request for UpdateInventoryConfig. +message UpdateInventoryConfigRequest { + // The fields to change, as `{key: value}`. + // + // A map of arbitrary JSON rather than named fields, because the app owns which + // fields exist and what they are typed as; mirroring them here would mean a proto + // change and a `make gen` every time it grows a setting. The app validates and + // rejects the batch as a whole. + // + // Bound to the HTTP body directly (`body: "values"`, not `body: "*"`), so the request + // this endpoint takes is the same object it forwards. The alternative wraps it as + // `{"values": {...}}`, which would make the proxy's shape differ from the shape of the + // thing being proxied for no gain to anyone reading either. + // + // A `Struct` carries no field rules, so "name at least one field" is enforced in the + // handler rather than declared here -- the only precondition on this surface that a + // generated validator does not express. + google.protobuf.Struct values = 1; +} + +// UpdateInventoryConfigResponse returns the configuration as it now stands. +message UpdateInventoryConfigResponse { + // Every field, not only the ones the request named. + // + // The whole resource, because an Update answers with the resource. It is also the only + // honest answer for a nested write: overriding a parent object changes what its + // children effectively resolve to, and a response scoped to the submitted keys would + // report the parent and leave a stale child beside it. + repeated InventorySetting settings = 1; +} + +// DeleteInventoryConfigOverrideRequest is the request for +// DeleteInventoryConfigOverride. +message DeleteInventoryConfigOverrideRequest { + // The field whose override to remove, putting it back to its deployed value. Also the + // resource ID within the `overrides` collection. + string key = 1 [(validate.rules).string.min_len = 1]; +} + +// DeleteInventoryConfigOverrideResponse acknowledges the revert. +message DeleteInventoryConfigOverrideResponse {} + +// OmService provides the OpenManager topology and health API. +service OmService { + // GetTopology returns the whole MongoDB estate as one document. + rpc GetTopology(GetTopologyRequest) returns (GetTopologyResponse) { + option (google.api.http) = {get: "/v1/om/topology"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get the MongoDB topology" + description: "Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load." + }; + } + + // ListTopologyRuns returns the collection run history, newest first. + rpc ListTopologyRuns(ListTopologyRunsRequest) returns (ListTopologyRunsResponse) { + option (google.api.http) = {get: "/v1/om/topology/runs"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List collection runs" + description: "Returns the recorded collection runs, newest first, with what each one saw and any errors it hit." + }; + } + + // GetTopologyRun returns one collection run. + rpc GetTopologyRun(GetTopologyRunRequest) returns (GetTopologyRunResponse) { + option (google.api.http) = {get: "/v1/om/topology/runs/{run_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get a collection run" + description: "Returns one recorded collection run, with what it saw, how each source answered, and any errors it hit." + }; + } + + // TriggerTopologyCollection rebuilds the topology document now. + rpc TriggerTopologyCollection(TriggerTopologyCollectionRequest) returns (TriggerTopologyCollectionResponse) { + // A custom method, so the URL carries the colon verb: this is not a plain Create on + // the runs collection, and a caller reading `:collect` does not expect the finished + // resource back the way `POST /runs` would promise it. + option (google.api.http) = { + post: "/v1/om/topology/runs:collect" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Trigger a collection run" + description: "Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run." + }; + } + + // ListInventoryHosts returns every host OM knows about, with its services. + rpc ListInventoryHosts(ListInventoryHostsRequest) returns (ListInventoryHostsResponse) { + option (google.api.http) = {get: "/v1/om/inventory/hosts"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List inventory hosts" + description: "Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are." + }; + } + + // GetInventoryHost returns one host. + rpc GetInventoryHost(GetInventoryHostRequest) returns (GetInventoryHostResponse) { + option (google.api.http) = {get: "/v1/om/inventory/hosts/{node_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get an inventory host" + description: "Returns one host by PMM node ID, with the services on it." + }; + } + + // DeleteInventoryHost forgets a host and its services. + rpc DeleteInventoryHost(DeleteInventoryHostRequest) returns (DeleteInventoryHostResponse) { + option (google.api.http) = {delete: "/v1/om/inventory/hosts/{node_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Forget an inventory host" + description: "Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID." + }; + } + + // ListInventoryServices returns every service OM knows about, flat. + rpc ListInventoryServices(ListInventoryServicesRequest) returns (ListInventoryServicesResponse) { + option (google.api.http) = {get: "/v1/om/inventory/services"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List inventory services" + description: "Returns every MongoDB service the inventory app has a row for, with what each last reported and when." + }; + } + + // GetInventoryService returns one service. + rpc GetInventoryService(GetInventoryServiceRequest) returns (GetInventoryServiceResponse) { + option (google.api.http) = {get: "/v1/om/inventory/services/{service_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get an inventory service" + description: "Returns one service by PMM service ID." + }; + } + + // DeleteInventoryService forgets one service. + rpc DeleteInventoryService(DeleteInventoryServiceRequest) returns (DeleteInventoryServiceResponse) { + option (google.api.http) = {delete: "/v1/om/inventory/services/{service_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Forget an inventory service" + description: "Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh." + }; + } + + // ListInventoryRuns returns the estate-refresh history, newest first. + rpc ListInventoryRuns(ListInventoryRunsRequest) returns (ListInventoryRunsResponse) { + option (google.api.http) = {get: "/v1/om/inventory/runs"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List inventory refreshes" + description: "Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host." + }; + } + + // GetInventoryRun returns one estate refresh. + rpc GetInventoryRun(GetInventoryRunRequest) returns (GetInventoryRunResponse) { + option (google.api.http) = {get: "/v1/om/inventory/runs/{run_id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get an inventory refresh" + description: "Returns one refresh by ID, with what it saw and which hosts it covered." + }; + } + + // TriggerInventoryRefresh probes the estate, or named hosts within it. + rpc TriggerInventoryRefresh(TriggerInventoryRefreshRequest) returns (TriggerInventoryRefreshResponse) { + // A custom method, so the URL carries the colon verb. It matters more here than on + // the collection pass: this returns an *accepted* run that finishes tens of seconds + // later, and `POST /runs` returning 200 reads as "done" to anyone checking the status + // code alone. + option (google.api.http) = { + post: "/v1/om/inventory/runs:trigger" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Refresh the inventory" + description: "Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them." + }; + } + + // GetInventoryConfig returns the inventory app's configuration. + rpc GetInventoryConfig(GetInventoryConfigRequest) returns (GetInventoryConfigResponse) { + option (google.api.http) = {get: "/v1/om/inventory/config"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get the inventory configuration" + description: "Returns every configuration field of the inventory app, its effective value, and whether an override is in effect." + }; + } + + // UpdateInventoryConfig changes the inventory app's configuration. + rpc UpdateInventoryConfig(UpdateInventoryConfigRequest) returns (UpdateInventoryConfigResponse) { + option (google.api.http) = { + put: "/v1/om/inventory/config" + body: "values" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Change the inventory configuration" + description: "Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted." + }; + } + + // DeleteInventoryConfigOverride reverts one field to its deployed value. + // + // Addressed under `config/overrides/{key}` rather than `config/{key}`, which is what + // this was. `config` is a singleton resource -- GetInventoryConfig returns it, + // UpdateInventoryConfig replaces part of it -- so using it as a collection in one + // method and a resource in two made it both at once, and the guidelines' resource + // model has no room for that. + // + // `overrides` also names what is actually removed. The setting always exists; the + // override on it is the thing with a lifecycle, which is why deleting one is not the + // same as deleting a setting. Its read side is `has_override` on each returned + // setting rather than a List of its own, since a caller reading the configuration + // already has every answer that collection would give. + rpc DeleteInventoryConfigOverride(DeleteInventoryConfigOverrideRequest) returns (DeleteInventoryConfigOverrideResponse) { + option (google.api.http) = {delete: "/v1/om/inventory/config/overrides/{key}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Revert an inventory configuration field" + description: "Removes the override for one field so it returns to whatever the deployment configured. Idempotent." + }; + } +} diff --git a/api/om/v1/om_grpc.pb.go b/api/om/v1/om_grpc.pb.go new file mode 100644 index 00000000000..4a7a649f306 --- /dev/null +++ b/api/om/v1/om_grpc.pb.go @@ -0,0 +1,767 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.0 +// - protoc (unknown) +// source: om/v1/om.proto + +package omv1 + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + OmService_GetTopology_FullMethodName = "/om.v1.OmService/GetTopology" + OmService_ListTopologyRuns_FullMethodName = "/om.v1.OmService/ListTopologyRuns" + OmService_GetTopologyRun_FullMethodName = "/om.v1.OmService/GetTopologyRun" + OmService_TriggerTopologyCollection_FullMethodName = "/om.v1.OmService/TriggerTopologyCollection" + OmService_ListInventoryHosts_FullMethodName = "/om.v1.OmService/ListInventoryHosts" + OmService_GetInventoryHost_FullMethodName = "/om.v1.OmService/GetInventoryHost" + OmService_DeleteInventoryHost_FullMethodName = "/om.v1.OmService/DeleteInventoryHost" + OmService_ListInventoryServices_FullMethodName = "/om.v1.OmService/ListInventoryServices" + OmService_GetInventoryService_FullMethodName = "/om.v1.OmService/GetInventoryService" + OmService_DeleteInventoryService_FullMethodName = "/om.v1.OmService/DeleteInventoryService" + OmService_ListInventoryRuns_FullMethodName = "/om.v1.OmService/ListInventoryRuns" + OmService_GetInventoryRun_FullMethodName = "/om.v1.OmService/GetInventoryRun" + OmService_TriggerInventoryRefresh_FullMethodName = "/om.v1.OmService/TriggerInventoryRefresh" + OmService_GetInventoryConfig_FullMethodName = "/om.v1.OmService/GetInventoryConfig" + OmService_UpdateInventoryConfig_FullMethodName = "/om.v1.OmService/UpdateInventoryConfig" + OmService_DeleteInventoryConfigOverride_FullMethodName = "/om.v1.OmService/DeleteInventoryConfigOverride" +) + +// OmServiceClient is the client API for OmService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// OmService provides the OpenManager topology and health API. +type OmServiceClient interface { + // GetTopology returns the whole MongoDB estate as one document. + GetTopology(ctx context.Context, in *GetTopologyRequest, opts ...grpc.CallOption) (*GetTopologyResponse, error) + // ListTopologyRuns returns the collection run history, newest first. + ListTopologyRuns(ctx context.Context, in *ListTopologyRunsRequest, opts ...grpc.CallOption) (*ListTopologyRunsResponse, error) + // GetTopologyRun returns one collection run. + GetTopologyRun(ctx context.Context, in *GetTopologyRunRequest, opts ...grpc.CallOption) (*GetTopologyRunResponse, error) + // TriggerTopologyCollection rebuilds the topology document now. + TriggerTopologyCollection(ctx context.Context, in *TriggerTopologyCollectionRequest, opts ...grpc.CallOption) (*TriggerTopologyCollectionResponse, error) + // ListInventoryHosts returns every host OM knows about, with its services. + ListInventoryHosts(ctx context.Context, in *ListInventoryHostsRequest, opts ...grpc.CallOption) (*ListInventoryHostsResponse, error) + // GetInventoryHost returns one host. + GetInventoryHost(ctx context.Context, in *GetInventoryHostRequest, opts ...grpc.CallOption) (*GetInventoryHostResponse, error) + // DeleteInventoryHost forgets a host and its services. + DeleteInventoryHost(ctx context.Context, in *DeleteInventoryHostRequest, opts ...grpc.CallOption) (*DeleteInventoryHostResponse, error) + // ListInventoryServices returns every service OM knows about, flat. + ListInventoryServices(ctx context.Context, in *ListInventoryServicesRequest, opts ...grpc.CallOption) (*ListInventoryServicesResponse, error) + // GetInventoryService returns one service. + GetInventoryService(ctx context.Context, in *GetInventoryServiceRequest, opts ...grpc.CallOption) (*GetInventoryServiceResponse, error) + // DeleteInventoryService forgets one service. + DeleteInventoryService(ctx context.Context, in *DeleteInventoryServiceRequest, opts ...grpc.CallOption) (*DeleteInventoryServiceResponse, error) + // ListInventoryRuns returns the estate-refresh history, newest first. + ListInventoryRuns(ctx context.Context, in *ListInventoryRunsRequest, opts ...grpc.CallOption) (*ListInventoryRunsResponse, error) + // GetInventoryRun returns one estate refresh. + GetInventoryRun(ctx context.Context, in *GetInventoryRunRequest, opts ...grpc.CallOption) (*GetInventoryRunResponse, error) + // TriggerInventoryRefresh probes the estate, or named hosts within it. + TriggerInventoryRefresh(ctx context.Context, in *TriggerInventoryRefreshRequest, opts ...grpc.CallOption) (*TriggerInventoryRefreshResponse, error) + // GetInventoryConfig returns the inventory app's configuration. + GetInventoryConfig(ctx context.Context, in *GetInventoryConfigRequest, opts ...grpc.CallOption) (*GetInventoryConfigResponse, error) + // UpdateInventoryConfig changes the inventory app's configuration. + UpdateInventoryConfig(ctx context.Context, in *UpdateInventoryConfigRequest, opts ...grpc.CallOption) (*UpdateInventoryConfigResponse, error) + // DeleteInventoryConfigOverride reverts one field to its deployed value. + // + // Addressed under `config/overrides/{key}` rather than `config/{key}`, which is what + // this was. `config` is a singleton resource -- GetInventoryConfig returns it, + // UpdateInventoryConfig replaces part of it -- so using it as a collection in one + // method and a resource in two made it both at once, and the guidelines' resource + // model has no room for that. + // + // `overrides` also names what is actually removed. The setting always exists; the + // override on it is the thing with a lifecycle, which is why deleting one is not the + // same as deleting a setting. Its read side is `has_override` on each returned + // setting rather than a List of its own, since a caller reading the configuration + // already has every answer that collection would give. + DeleteInventoryConfigOverride(ctx context.Context, in *DeleteInventoryConfigOverrideRequest, opts ...grpc.CallOption) (*DeleteInventoryConfigOverrideResponse, error) +} + +type omServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewOmServiceClient(cc grpc.ClientConnInterface) OmServiceClient { + return &omServiceClient{cc} +} + +func (c *omServiceClient) GetTopology(ctx context.Context, in *GetTopologyRequest, opts ...grpc.CallOption) (*GetTopologyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTopologyResponse) + err := c.cc.Invoke(ctx, OmService_GetTopology_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) ListTopologyRuns(ctx context.Context, in *ListTopologyRunsRequest, opts ...grpc.CallOption) (*ListTopologyRunsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListTopologyRunsResponse) + err := c.cc.Invoke(ctx, OmService_ListTopologyRuns_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) GetTopologyRun(ctx context.Context, in *GetTopologyRunRequest, opts ...grpc.CallOption) (*GetTopologyRunResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTopologyRunResponse) + err := c.cc.Invoke(ctx, OmService_GetTopologyRun_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) TriggerTopologyCollection(ctx context.Context, in *TriggerTopologyCollectionRequest, opts ...grpc.CallOption) (*TriggerTopologyCollectionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(TriggerTopologyCollectionResponse) + err := c.cc.Invoke(ctx, OmService_TriggerTopologyCollection_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) ListInventoryHosts(ctx context.Context, in *ListInventoryHostsRequest, opts ...grpc.CallOption) (*ListInventoryHostsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListInventoryHostsResponse) + err := c.cc.Invoke(ctx, OmService_ListInventoryHosts_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) GetInventoryHost(ctx context.Context, in *GetInventoryHostRequest, opts ...grpc.CallOption) (*GetInventoryHostResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetInventoryHostResponse) + err := c.cc.Invoke(ctx, OmService_GetInventoryHost_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) DeleteInventoryHost(ctx context.Context, in *DeleteInventoryHostRequest, opts ...grpc.CallOption) (*DeleteInventoryHostResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteInventoryHostResponse) + err := c.cc.Invoke(ctx, OmService_DeleteInventoryHost_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) ListInventoryServices(ctx context.Context, in *ListInventoryServicesRequest, opts ...grpc.CallOption) (*ListInventoryServicesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListInventoryServicesResponse) + err := c.cc.Invoke(ctx, OmService_ListInventoryServices_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) GetInventoryService(ctx context.Context, in *GetInventoryServiceRequest, opts ...grpc.CallOption) (*GetInventoryServiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetInventoryServiceResponse) + err := c.cc.Invoke(ctx, OmService_GetInventoryService_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) DeleteInventoryService(ctx context.Context, in *DeleteInventoryServiceRequest, opts ...grpc.CallOption) (*DeleteInventoryServiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteInventoryServiceResponse) + err := c.cc.Invoke(ctx, OmService_DeleteInventoryService_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) ListInventoryRuns(ctx context.Context, in *ListInventoryRunsRequest, opts ...grpc.CallOption) (*ListInventoryRunsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListInventoryRunsResponse) + err := c.cc.Invoke(ctx, OmService_ListInventoryRuns_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) GetInventoryRun(ctx context.Context, in *GetInventoryRunRequest, opts ...grpc.CallOption) (*GetInventoryRunResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetInventoryRunResponse) + err := c.cc.Invoke(ctx, OmService_GetInventoryRun_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) TriggerInventoryRefresh(ctx context.Context, in *TriggerInventoryRefreshRequest, opts ...grpc.CallOption) (*TriggerInventoryRefreshResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(TriggerInventoryRefreshResponse) + err := c.cc.Invoke(ctx, OmService_TriggerInventoryRefresh_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) GetInventoryConfig(ctx context.Context, in *GetInventoryConfigRequest, opts ...grpc.CallOption) (*GetInventoryConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetInventoryConfigResponse) + err := c.cc.Invoke(ctx, OmService_GetInventoryConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) UpdateInventoryConfig(ctx context.Context, in *UpdateInventoryConfigRequest, opts ...grpc.CallOption) (*UpdateInventoryConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateInventoryConfigResponse) + err := c.cc.Invoke(ctx, OmService_UpdateInventoryConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *omServiceClient) DeleteInventoryConfigOverride(ctx context.Context, in *DeleteInventoryConfigOverrideRequest, opts ...grpc.CallOption) (*DeleteInventoryConfigOverrideResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteInventoryConfigOverrideResponse) + err := c.cc.Invoke(ctx, OmService_DeleteInventoryConfigOverride_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// OmServiceServer is the server API for OmService service. +// All implementations must embed UnimplementedOmServiceServer +// for forward compatibility. +// +// OmService provides the OpenManager topology and health API. +type OmServiceServer interface { + // GetTopology returns the whole MongoDB estate as one document. + GetTopology(context.Context, *GetTopologyRequest) (*GetTopologyResponse, error) + // ListTopologyRuns returns the collection run history, newest first. + ListTopologyRuns(context.Context, *ListTopologyRunsRequest) (*ListTopologyRunsResponse, error) + // GetTopologyRun returns one collection run. + GetTopologyRun(context.Context, *GetTopologyRunRequest) (*GetTopologyRunResponse, error) + // TriggerTopologyCollection rebuilds the topology document now. + TriggerTopologyCollection(context.Context, *TriggerTopologyCollectionRequest) (*TriggerTopologyCollectionResponse, error) + // ListInventoryHosts returns every host OM knows about, with its services. + ListInventoryHosts(context.Context, *ListInventoryHostsRequest) (*ListInventoryHostsResponse, error) + // GetInventoryHost returns one host. + GetInventoryHost(context.Context, *GetInventoryHostRequest) (*GetInventoryHostResponse, error) + // DeleteInventoryHost forgets a host and its services. + DeleteInventoryHost(context.Context, *DeleteInventoryHostRequest) (*DeleteInventoryHostResponse, error) + // ListInventoryServices returns every service OM knows about, flat. + ListInventoryServices(context.Context, *ListInventoryServicesRequest) (*ListInventoryServicesResponse, error) + // GetInventoryService returns one service. + GetInventoryService(context.Context, *GetInventoryServiceRequest) (*GetInventoryServiceResponse, error) + // DeleteInventoryService forgets one service. + DeleteInventoryService(context.Context, *DeleteInventoryServiceRequest) (*DeleteInventoryServiceResponse, error) + // ListInventoryRuns returns the estate-refresh history, newest first. + ListInventoryRuns(context.Context, *ListInventoryRunsRequest) (*ListInventoryRunsResponse, error) + // GetInventoryRun returns one estate refresh. + GetInventoryRun(context.Context, *GetInventoryRunRequest) (*GetInventoryRunResponse, error) + // TriggerInventoryRefresh probes the estate, or named hosts within it. + TriggerInventoryRefresh(context.Context, *TriggerInventoryRefreshRequest) (*TriggerInventoryRefreshResponse, error) + // GetInventoryConfig returns the inventory app's configuration. + GetInventoryConfig(context.Context, *GetInventoryConfigRequest) (*GetInventoryConfigResponse, error) + // UpdateInventoryConfig changes the inventory app's configuration. + UpdateInventoryConfig(context.Context, *UpdateInventoryConfigRequest) (*UpdateInventoryConfigResponse, error) + // DeleteInventoryConfigOverride reverts one field to its deployed value. + // + // Addressed under `config/overrides/{key}` rather than `config/{key}`, which is what + // this was. `config` is a singleton resource -- GetInventoryConfig returns it, + // UpdateInventoryConfig replaces part of it -- so using it as a collection in one + // method and a resource in two made it both at once, and the guidelines' resource + // model has no room for that. + // + // `overrides` also names what is actually removed. The setting always exists; the + // override on it is the thing with a lifecycle, which is why deleting one is not the + // same as deleting a setting. Its read side is `has_override` on each returned + // setting rather than a List of its own, since a caller reading the configuration + // already has every answer that collection would give. + DeleteInventoryConfigOverride(context.Context, *DeleteInventoryConfigOverrideRequest) (*DeleteInventoryConfigOverrideResponse, error) + mustEmbedUnimplementedOmServiceServer() +} + +// UnimplementedOmServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedOmServiceServer struct{} + +func (UnimplementedOmServiceServer) GetTopology(context.Context, *GetTopologyRequest) (*GetTopologyResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetTopology not implemented") +} + +func (UnimplementedOmServiceServer) ListTopologyRuns(context.Context, *ListTopologyRunsRequest) (*ListTopologyRunsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListTopologyRuns not implemented") +} + +func (UnimplementedOmServiceServer) GetTopologyRun(context.Context, *GetTopologyRunRequest) (*GetTopologyRunResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetTopologyRun not implemented") +} + +func (UnimplementedOmServiceServer) TriggerTopologyCollection(context.Context, *TriggerTopologyCollectionRequest) (*TriggerTopologyCollectionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method TriggerTopologyCollection not implemented") +} + +func (UnimplementedOmServiceServer) ListInventoryHosts(context.Context, *ListInventoryHostsRequest) (*ListInventoryHostsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListInventoryHosts not implemented") +} + +func (UnimplementedOmServiceServer) GetInventoryHost(context.Context, *GetInventoryHostRequest) (*GetInventoryHostResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetInventoryHost not implemented") +} + +func (UnimplementedOmServiceServer) DeleteInventoryHost(context.Context, *DeleteInventoryHostRequest) (*DeleteInventoryHostResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteInventoryHost not implemented") +} + +func (UnimplementedOmServiceServer) ListInventoryServices(context.Context, *ListInventoryServicesRequest) (*ListInventoryServicesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListInventoryServices not implemented") +} + +func (UnimplementedOmServiceServer) GetInventoryService(context.Context, *GetInventoryServiceRequest) (*GetInventoryServiceResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetInventoryService not implemented") +} + +func (UnimplementedOmServiceServer) DeleteInventoryService(context.Context, *DeleteInventoryServiceRequest) (*DeleteInventoryServiceResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteInventoryService not implemented") +} + +func (UnimplementedOmServiceServer) ListInventoryRuns(context.Context, *ListInventoryRunsRequest) (*ListInventoryRunsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListInventoryRuns not implemented") +} + +func (UnimplementedOmServiceServer) GetInventoryRun(context.Context, *GetInventoryRunRequest) (*GetInventoryRunResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetInventoryRun not implemented") +} + +func (UnimplementedOmServiceServer) TriggerInventoryRefresh(context.Context, *TriggerInventoryRefreshRequest) (*TriggerInventoryRefreshResponse, error) { + return nil, status.Error(codes.Unimplemented, "method TriggerInventoryRefresh not implemented") +} + +func (UnimplementedOmServiceServer) GetInventoryConfig(context.Context, *GetInventoryConfigRequest) (*GetInventoryConfigResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetInventoryConfig not implemented") +} + +func (UnimplementedOmServiceServer) UpdateInventoryConfig(context.Context, *UpdateInventoryConfigRequest) (*UpdateInventoryConfigResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateInventoryConfig not implemented") +} + +func (UnimplementedOmServiceServer) DeleteInventoryConfigOverride(context.Context, *DeleteInventoryConfigOverrideRequest) (*DeleteInventoryConfigOverrideResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteInventoryConfigOverride not implemented") +} +func (UnimplementedOmServiceServer) mustEmbedUnimplementedOmServiceServer() {} +func (UnimplementedOmServiceServer) testEmbeddedByValue() {} + +// UnsafeOmServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to OmServiceServer will +// result in compilation errors. +type UnsafeOmServiceServer interface { + mustEmbedUnimplementedOmServiceServer() +} + +func RegisterOmServiceServer(s grpc.ServiceRegistrar, srv OmServiceServer) { + // If the following call panics, it indicates UnimplementedOmServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&OmService_ServiceDesc, srv) +} + +func _OmService_GetTopology_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTopologyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetTopology(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetTopology_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetTopology(ctx, req.(*GetTopologyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_ListTopologyRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListTopologyRunsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).ListTopologyRuns(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_ListTopologyRuns_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).ListTopologyRuns(ctx, req.(*ListTopologyRunsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_GetTopologyRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTopologyRunRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetTopologyRun(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetTopologyRun_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetTopologyRun(ctx, req.(*GetTopologyRunRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_TriggerTopologyCollection_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TriggerTopologyCollectionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).TriggerTopologyCollection(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_TriggerTopologyCollection_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).TriggerTopologyCollection(ctx, req.(*TriggerTopologyCollectionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_ListInventoryHosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListInventoryHostsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).ListInventoryHosts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_ListInventoryHosts_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).ListInventoryHosts(ctx, req.(*ListInventoryHostsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_GetInventoryHost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetInventoryHostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetInventoryHost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetInventoryHost_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetInventoryHost(ctx, req.(*GetInventoryHostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_DeleteInventoryHost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInventoryHostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).DeleteInventoryHost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_DeleteInventoryHost_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).DeleteInventoryHost(ctx, req.(*DeleteInventoryHostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_ListInventoryServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListInventoryServicesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).ListInventoryServices(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_ListInventoryServices_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).ListInventoryServices(ctx, req.(*ListInventoryServicesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_GetInventoryService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetInventoryServiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetInventoryService(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetInventoryService_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetInventoryService(ctx, req.(*GetInventoryServiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_DeleteInventoryService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInventoryServiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).DeleteInventoryService(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_DeleteInventoryService_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).DeleteInventoryService(ctx, req.(*DeleteInventoryServiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_ListInventoryRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListInventoryRunsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).ListInventoryRuns(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_ListInventoryRuns_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).ListInventoryRuns(ctx, req.(*ListInventoryRunsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_GetInventoryRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetInventoryRunRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetInventoryRun(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetInventoryRun_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetInventoryRun(ctx, req.(*GetInventoryRunRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_TriggerInventoryRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TriggerInventoryRefreshRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).TriggerInventoryRefresh(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_TriggerInventoryRefresh_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).TriggerInventoryRefresh(ctx, req.(*TriggerInventoryRefreshRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_GetInventoryConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetInventoryConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).GetInventoryConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_GetInventoryConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).GetInventoryConfig(ctx, req.(*GetInventoryConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_UpdateInventoryConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateInventoryConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).UpdateInventoryConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_UpdateInventoryConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).UpdateInventoryConfig(ctx, req.(*UpdateInventoryConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OmService_DeleteInventoryConfigOverride_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInventoryConfigOverrideRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OmServiceServer).DeleteInventoryConfigOverride(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OmService_DeleteInventoryConfigOverride_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OmServiceServer).DeleteInventoryConfigOverride(ctx, req.(*DeleteInventoryConfigOverrideRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// OmService_ServiceDesc is the grpc.ServiceDesc for OmService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var OmService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "om.v1.OmService", + HandlerType: (*OmServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTopology", + Handler: _OmService_GetTopology_Handler, + }, + { + MethodName: "ListTopologyRuns", + Handler: _OmService_ListTopologyRuns_Handler, + }, + { + MethodName: "GetTopologyRun", + Handler: _OmService_GetTopologyRun_Handler, + }, + { + MethodName: "TriggerTopologyCollection", + Handler: _OmService_TriggerTopologyCollection_Handler, + }, + { + MethodName: "ListInventoryHosts", + Handler: _OmService_ListInventoryHosts_Handler, + }, + { + MethodName: "GetInventoryHost", + Handler: _OmService_GetInventoryHost_Handler, + }, + { + MethodName: "DeleteInventoryHost", + Handler: _OmService_DeleteInventoryHost_Handler, + }, + { + MethodName: "ListInventoryServices", + Handler: _OmService_ListInventoryServices_Handler, + }, + { + MethodName: "GetInventoryService", + Handler: _OmService_GetInventoryService_Handler, + }, + { + MethodName: "DeleteInventoryService", + Handler: _OmService_DeleteInventoryService_Handler, + }, + { + MethodName: "ListInventoryRuns", + Handler: _OmService_ListInventoryRuns_Handler, + }, + { + MethodName: "GetInventoryRun", + Handler: _OmService_GetInventoryRun_Handler, + }, + { + MethodName: "TriggerInventoryRefresh", + Handler: _OmService_TriggerInventoryRefresh_Handler, + }, + { + MethodName: "GetInventoryConfig", + Handler: _OmService_GetInventoryConfig_Handler, + }, + { + MethodName: "UpdateInventoryConfig", + Handler: _OmService_UpdateInventoryConfig_Handler, + }, + { + MethodName: "DeleteInventoryConfigOverride", + Handler: _OmService_DeleteInventoryConfigOverride_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "om/v1/om.proto", +} diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index e7da061958b..c56cd5b949a 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -5223,7 +5223,7 @@ "HAService" ], "summary": "List HA Nodes", - "operationId": "ListNodesMixin12", + "operationId": "ListNodesMixin13", "responses": { "200": { "description": "A successful response.", @@ -29072,6 +29072,2945 @@ } } }, + "/v1/om/inventory/config": { + "get": { + "description": "Returns every configuration field of the inventory app, its effective value, and whether an override is in effect.", + "tags": [ + "OmService" + ], + "summary": "Get the inventory configuration", + "operationId": "GetInventoryConfig", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryConfigResponse returns the inventory app's configuration.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, whether or not it is overridden.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "put": { + "description": "Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted.", + "tags": [ + "OmService" + ], + "summary": "Change the inventory configuration", + "operationId": "UpdateInventoryConfig", + "parameters": [ + { + "description": "The fields to change, as `{key: value}`.\n\nA map of arbitrary JSON rather than named fields, because the app owns which\nfields exist and what they are typed as; mirroring them here would mean a proto\nchange and a `make gen` every time it grows a setting. The app validates and\nrejects the batch as a whole.\n\nBound to the HTTP body directly (`body: \"values\"`, not `body: \"*\"`), so the request\nthis endpoint takes is the same object it forwards. The alternative wraps it as\n`{\"values\": {...}}`, which would make the proxy's shape differ from the shape of the\nthing being proxied for no gain to anyone reading either.\n\nA `Struct` carries no field rules, so \"name at least one field\" is enforced in the\nhandler rather than declared here -- the only precondition on this surface that a\ngenerated validator does not express.", + "name": "values", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "UpdateInventoryConfigResponse returns the configuration as it now stands.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, not only the ones the request named.\n\nThe whole resource, because an Update answers with the resource. It is also the only\nhonest answer for a nested write: overriding a parent object changes what its\nchildren effectively resolve to, and a response scoped to the submitted keys would\nreport the parent and leave a stale child beside it.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/config/overrides/{key}": { + "delete": { + "description": "Removes the override for one field so it returns to whatever the deployment configured. Idempotent.", + "tags": [ + "OmService" + ], + "summary": "Revert an inventory configuration field", + "operationId": "DeleteInventoryConfigOverride", + "parameters": [ + { + "type": "string", + "description": "The field whose override to remove, putting it back to its deployed value. Also the\nresource ID within the `overrides` collection.", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryConfigOverrideResponse acknowledges the revert.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts": { + "get": { + "description": "Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are.", + "tags": [ + "OmService" + ], + "summary": "List inventory hosts", + "operationId": "ListInventoryHosts", + "parameters": [ + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) carry a registered service.\nUnset returns both, which is the ordinary listing.", + "name": "has_service", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only hosts currently failing.", + "name": "failing", + "in": "query" + }, + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) have an executor to run a probe\non. Not a client name: the app filters on whether one is matched at all, and\n\"which machines can nothing be dispatched to\" is the question worth asking.", + "name": "executor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryHostsResponse returns the hosts OM knows about.", + "type": "object", + "properties": { + "hosts": { + "description": "The hosts.", + "type": "array", + "items": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts/{node_id}": { + "get": { + "description": "Returns one host by PMM node ID, with the services on it.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory host", + "operationId": "GetInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryHostResponse returns one host.", + "type": "object", + "properties": { + "host": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory host", + "operationId": "DeleteInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryHostResponse acknowledges forgetting a host.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs": { + "get": { + "description": "Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host.", + "tags": [ + "OmService" + ], + "summary": "List inventory refreshes", + "operationId": "ListInventoryRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many to return, newest first. Defaults to 20, capped at 100.", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive lower bound on start_time. Unset means no lower bound.\n\nApplied before limit, so a week window is the newest runs *in that week*,\nnot the newest overall then those that happen to fall in it.", + "name": "since", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive upper bound on start_time. Unset means no upper bound.", + "name": "until", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryRunsResponse returns the refresh history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs/{run_id}": { + "get": { + "description": "Returns one refresh by ID, with what it saw and which hosts it covered.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory refresh", + "operationId": "GetInventoryRun", + "parameters": [ + { + "type": "string", + "description": "The run's ID.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryRunResponse returns one refresh, with the rows behind its counters.", + "type": "object", + "properties": { + "run": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + }, + "x-order": 0 + }, + "entities": { + "description": "What it attempted, one entry per entity.\n\nOnly on the detail response, never on the list: a refresh of a real estate has a\nrow per service, and a history of twenty-five would carry the lot to render a\npage that shows one at a time.", + "type": "array", + "items": { + "description": "InventoryRunEntity is one host a refresh attempted, and what came of it.\n\nHost-oriented, because a refresh attempts hosts. A flat list of services - which\nthis was - cannot show a machine carrying a PMM client and no database, however\nmany times it is probed, and that machine is the case OM most exists to describe:\nit is where a database can be installed.\n\nOne dispatch covers every service on a host, so the host owns the timing and the\nfailure and its services carry only what is theirs. Previously the duration was\ncopied onto each service, which read as several measurements when it was one.\n\nDeliberately outcomes and not observations. What the probe *found* lives on the\nestate, where it is upserted and stays current; a receipt that also carried the\nattributes would be a second copy that goes stale the moment the next refresh runs.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID, the key OM holds this host under.", + "type": "string", + "x-order": 0 + }, + "host_name": { + "description": "The node's registered name.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "executor_host": { + "description": "The client its probe ran on. Unset when none matched.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "resolution": { + "description": "ExecutorResolution is how a host was matched to the client its probe ran on.\n\nORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact\nabout onboarding. NAME and ADDRESS record *which* of the two joins matched, because a\nhost reachable only by address is a different estate problem from one matched by name.\n\n - EXECUTOR_RESOLUTION_NAME: Matched on the node's registered name.\n - EXECUTOR_RESOLUTION_ADDRESS: Matched on the node's address.\n - EXECUTOR_RESOLUTION_ORPHANED: Not matched, so nothing was dispatched.", + "type": "string", + "default": "EXECUTOR_RESOLUTION_UNSPECIFIED", + "enum": [ + "EXECUTOR_RESOLUTION_UNSPECIFIED", + "EXECUTOR_RESOLUTION_NAME", + "EXECUTOR_RESOLUTION_ADDRESS", + "EXECUTOR_RESOLUTION_ORPHANED" + ], + "x-order": 3 + }, + "answered": { + "description": "Whether the *host* answered. A different question from whether its services did:\na host with no database answers perfectly well and has no services at all.", + "type": "boolean", + "x-order": 4 + }, + "duration_seconds": { + "description": "The host's wall clock, dispatch to collected output.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 5 + }, + "error": { + "description": "The host-level failure, when its probe failed.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryRunEntityService is one service on a host, as a refresh saw it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID, when OM could key one.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "service_name": { + "description": "Its name, so a reader is not left joining UUIDs by hand.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "answered": { + "description": "Whether the host returned a usable record for it.", + "type": "boolean", + "x-order": 2 + }, + "error": { + "description": "Why it did not, when it did not.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + } + }, + "x-order": 7 + }, + "task_history_id": { + "description": "The task history id of the dispatch, so a reader can open the probe's own log.\nUnset when the dispatch never got one.", + "type": "string", + "format": "int64", + "x-nullable": true, + "x-order": 8 + } + } + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs:trigger": { + "post": { + "description": "Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them.", + "tags": [ + "OmService" + ], + "summary": "Refresh the inventory", + "operationId": "TriggerInventoryRefresh", + "parameters": [ + { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "type": "object", + "properties": { + "node_ids": { + "description": "The hosts to refresh, by PMM node ID. Empty refreshes the whole estate.\n\nPlural on purpose: PMM's node ID is also OM's key, so ids pass through\nuntranslated, and one host is a list of one. A surface taking a single id where\nthe app takes a list would be a translation step in disguise.\n\nBounded because a refresh dispatches a Nomad job per host: the empty list already\nmeans \"the whole estate\", so a caller naming hosts individually is naming a few,\nand an unbounded list is only reachable by accident. An empty string is rejected\nrather than forwarded, where it would read as a node ID that matches nothing.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerInventoryRefreshResponse acknowledges an accepted refresh.\n\nAccepted, not finished. A refresh dispatches a Nomad job per host and takes tens of\nseconds, unlike PMM's own collection pass, which never probes and completes in\nmilliseconds. Two triggers that different must not look alike to a caller.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, to follow with GetInventoryRun.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "scope": { + "description": "The hosts it will refresh. Empty means the whole estate.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 3 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services": { + "get": { + "description": "Returns every MongoDB service the inventory app has a row for, with what each last reported and when.", + "tags": [ + "OmService" + ], + "summary": "List inventory services", + "operationId": "ListInventoryServices", + "parameters": [ + { + "type": "string", + "description": "When set, return only the services on this host.", + "name": "node_id", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only services currently failing.", + "name": "failing", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryServicesResponse returns the services OM knows about, flat.", + "type": "object", + "properties": { + "services": { + "description": "The services.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services/{service_id}": { + "get": { + "description": "Returns one service by PMM service ID.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory service", + "operationId": "GetInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryServiceResponse returns one service.", + "type": "object", + "properties": { + "service": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory service", + "operationId": "DeleteInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryServiceResponse acknowledges forgetting a service.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology": { + "get": { + "description": "Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load.", + "tags": [ + "OmService" + ], + "summary": "Get the MongoDB topology", + "operationId": "GetTopology", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyResponse is the whole topology document plus the provenance of the run\nbehind it.", + "type": "object", + "properties": { + "snapshot": { + "description": "Snapshot carries the provenance every snapshot-backed response repeats.", + "type": "object", + "properties": { + "generated_at": { + "description": "When the document was assembled.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "observed_at": { + "description": "The newest observation in it, unset when nothing was observed at all.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "stale": { + "description": "Whether the document is older than the staleness grace period. Also true, with\nobserved_at unset and every environment empty, on a genuinely cold estate -- no\ncollection has completed anywhere yet. That is a startup state, not a statement that\nthe estate itself is empty; a reader should render it as \"collecting\" rather than as\nan empty result.", + "type": "boolean", + "x-order": 2 + }, + "schema_version": { + "description": "The document schema version.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "run_id": { + "description": "The collection run that produced it.", + "type": "string", + "x-order": 4 + } + }, + "x-order": 0 + }, + "origin_node": { + "description": "The PMM node the document was assembled on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "source_queries": { + "description": "The VictoriaMetrics queries the document was derived from.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 2 + }, + "summary": { + "description": "Summary carries the fleet-level counts, so a caller need not re-derive them.", + "type": "object", + "properties": { + "environments": { + "description": "Environments in the document.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "clusters": { + "description": "Clusters across all of them.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "total_services": { + "description": "Services in the document.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "up_services": { + "description": "Services the exporter reached.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "down_services": { + "description": "Services it did not.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "process_role_counts": { + "description": "Service counts per process role, keyed by the ProcessRole enum's name.", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + }, + "x-order": 5 + } + }, + "x-order": 3 + }, + "environments": { + "description": "The estate, grouped environment then cluster.", + "type": "array", + "items": { + "description": "Environment represents one monitoring environment.", + "type": "object", + "properties": { + "env_name": { + "description": "Environment label, unset when its services carry none.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "clusters": { + "description": "Its clusters, ordered by name.", + "type": "array", + "items": { + "description": "Cluster represents one grouped service inventory: every service PMM's inventory\nlabelled with the same (environment, cluster) or (environment, replication_set), not a\nreconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat\nlist of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for\nthe one thing inferred about that shape, and the package comment for what is\ndeliberately not.", + "type": "object", + "properties": { + "name": { + "description": "Cluster label, unset when its services carry none. Not a stable identity: two\nclusters can share this label (a second generation of a sandbox reusing a name), and\n`id` is what tells them apart.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "services": { + "description": "Its services, ordered by name.", + "type": "array", + "items": { + "description": "TopologyService represents one monitored MongoDB service as the topology document\nrecords it.\n\nTwo conventions for \"no value\", and they differ on purpose. cpu_usage_percent and\nconnections_free_percent are -1 when not measured, never absent and never 0, because\nzero CPU is a legitimate reading and a numeric column must keep \"idle\" and \"unknown\"\napart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is\nabsent when they do not apply -- a router and a standalone have no replica-set oplog --\nwhich is a different statement from -1's \"we could not measure it\".\n\nThe optional fields were wrapper messages until the REST contract was checked:\nprotoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema\nand the generated Go client both collapsed to a value type and lost the distinction\nentirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting\nthe key rather than emitting an explicit null.", + "type": "object", + "properties": { + "service_name": { + "description": "Service name as PMM inventory registered it.", + "type": "string", + "x-order": 0 + }, + "host": { + "description": "Node the service runs on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "endpoint": { + "description": "host:port as the replica set itself addresses the member.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "service_id": { + "description": "PMM's service ID. The join key against VictoriaMetrics.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "service_type": { + "description": "Always \"mongodb\" today.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "version": { + "description": "Running server version.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "vendor": { + "description": "MongoDB or Percona.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "edition": { + "description": "Community or Enterprise.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "replication_set": { + "description": "Replica set, or unset for a router or a standalone.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "state": { + "description": "PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "status": { + "description": "ServiceStatus is whether the exporter reached a service.\n\nTwo values and no third: this is the exporter's reachability, not the server's health.\n\"we did not look\" is UNSPECIFIED, which the collector never emits.\n\n - SERVICE_STATUS_UP: The exporter reached the service.\n - SERVICE_STATUS_DOWN: It did not.", + "type": "string", + "default": "SERVICE_STATUS_UNSPECIFIED", + "enum": [ + "SERVICE_STATUS_UNSPECIFIED", + "SERVICE_STATUS_UP", + "SERVICE_STATUS_DOWN" + ], + "x-order": 10 + }, + "cpu_usage_percent": { + "description": "CPU percentage, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 11 + }, + "connections_free_percent": { + "description": "Percentage of free connections, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 12 + }, + "process_role": { + "description": "ProcessRole is what a mongod or mongos is doing in the deployment.\n\nNot the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This\nis the role the process was started in, which is a property of the deployment's shape.\n\n - PROCESS_ROLE_MONGOD: A standalone or replica-set member with no sharding role.\n - PROCESS_ROLE_MONGOS: A router.\n - PROCESS_ROLE_CONFIGSVR: A config-server member.\n - PROCESS_ROLE_SHARDSVR: A shard member.", + "type": "string", + "default": "PROCESS_ROLE_UNSPECIFIED", + "enum": [ + "PROCESS_ROLE_UNSPECIFIED", + "PROCESS_ROLE_MONGOD", + "PROCESS_ROLE_MONGOS", + "PROCESS_ROLE_CONFIGSVR", + "PROCESS_ROLE_SHARDSVR" + ], + "x-order": 13 + }, + "replication_lag_seconds": { + "description": "Seconds this member trails the primary; unset where there is no primary to trail.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 14 + }, + "oplog_window_seconds": { + "description": "Seconds of history the oplog holds; unset where there is no replica-set oplog.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 15 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from `version` is the upgraded-but-not-restarted case. Only\nan on-host probe can see it, so this is unset wherever one has not run.", + "type": "string", + "x-nullable": true, + "x-order": 16 + }, + "config_path": { + "description": "The configuration file the running server read. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 17 + }, + "argv": { + "description": "The command line the running server was started with. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 18 + }, + "observed_at": { + "description": "When the newest *live* field on this row was observed, unset when every field on it\nis either absent or not time-bounded (inventory only, no metric and no probe ever\nseen). This is the row's own provenance -- Snapshot.observed_at is the newest across\nthe whole estate, which cannot tell \"this row is current\" from \"this row is the one\nthat made the snapshot look fresh\". A field's own MergedField.ObservedAt exists\ninternally; this is the first one exposed on the wire.", + "type": "string", + "format": "date-time", + "x-nullable": true, + "x-order": 19 + } + } + }, + "x-order": 1 + }, + "id": { + "description": "Opaque, server-issued, stable across a rename of `name`. Derived from\n(environment, cluster, replication_set) so the same estate group always gets the\nsame id -- clients must not parse it or assume a derivation.", + "type": "string", + "x-order": 2 + }, + "type": { + "description": "ClusterType is the shape buildDocument inferred for one grouped service inventory.\n\nInferred, not reconstructed: this package groups services by label and infers a shape\nfrom what is in the group, it does not walk a replica set's own config to build a\nmember list. See the package comment.\n\n - CLUSTER_TYPE_REPLICA_SET: Exactly one replication_set label under this cluster, and no mongos.\n - CLUSTER_TYPE_SHARDED: A mongos is present, or more than one replication_set label shares this cluster\nlabel.\n - CLUSTER_TYPE_STANDALONE: Neither: services grouped under one label with no replica-set identity at all.", + "type": "string", + "default": "CLUSTER_TYPE_UNSPECIFIED", + "enum": [ + "CLUSTER_TYPE_UNSPECIFIED", + "CLUSTER_TYPE_REPLICA_SET", + "CLUSTER_TYPE_SHARDED", + "CLUSTER_TYPE_STANDALONE" + ], + "x-order": 3 + }, + "health": { + "description": "ClusterHealth is a reserved verdict slot, not yet computed by anything.\n\nUNSPECIFIED is the only value that exists today. It is declared now, alongside the\napplyHealth seam in the collector, so a rollup status has a field to land in without a\nlater schema change -- see the om package's health-pipeline comment.", + "type": "string", + "default": "CLUSTER_HEALTH_UNSPECIFIED", + "enum": [ + "CLUSTER_HEALTH_UNSPECIFIED" + ], + "x-order": 4 + } + } + }, + "x-order": 1 + } + } + }, + "x-order": 4 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs": { + "get": { + "description": "Returns the recorded collection runs, newest first, with what each one saw and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "List collection runs", + "operationId": "ListTopologyRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many runs to return, newest first. Defaults to 25, capped at 100.", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListTopologyRunsResponse returns the run history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs/{run_id}": { + "get": { + "description": "Returns one recorded collection run, with what it saw, how each source answered, and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "Get a collection run", + "operationId": "GetTopologyRun", + "parameters": [ + { + "type": "string", + "description": "The run to return.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyRunResponse returns one collection run.", + "type": "object", + "properties": { + "run": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs:collect": { + "post": { + "description": "Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run.", + "tags": [ + "OmService" + ], + "summary": "Trigger a collection run", + "operationId": "TriggerTopologyCollection", + "parameters": [ + { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerTopologyCollectionResponse acknowledges a completed collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/qan/health": { "get": { "description": "Returns readiness of QAN API2 service.", @@ -33702,6 +36641,10 @@ "description": "RealtimeAnalyticsService provides public API for managing Real-Time Analytics Sessions and Queries.", "name": "RealtimeAnalyticsService" }, + { + "description": "OmService provides the OpenManager topology and health API.", + "name": "OmService" + }, { "description": "HAService provides High Availability cluster status information.", "name": "HAService" diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index e085c0e9477..c650c9190b4 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4250,7 +4250,7 @@ "HAService" ], "summary": "List HA Nodes", - "operationId": "ListNodesMixin10", + "operationId": "ListNodesMixin11", "responses": { "200": { "description": "A successful response.", @@ -28099,6 +28099,2945 @@ } } }, + "/v1/om/inventory/config": { + "get": { + "description": "Returns every configuration field of the inventory app, its effective value, and whether an override is in effect.", + "tags": [ + "OmService" + ], + "summary": "Get the inventory configuration", + "operationId": "GetInventoryConfig", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryConfigResponse returns the inventory app's configuration.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, whether or not it is overridden.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "put": { + "description": "Applies a batch of configuration changes atomically: one invalid field rejects the whole batch and writes nothing. Only runtime-changeable fields are accepted.", + "tags": [ + "OmService" + ], + "summary": "Change the inventory configuration", + "operationId": "UpdateInventoryConfig", + "parameters": [ + { + "description": "The fields to change, as `{key: value}`.\n\nA map of arbitrary JSON rather than named fields, because the app owns which\nfields exist and what they are typed as; mirroring them here would mean a proto\nchange and a `make gen` every time it grows a setting. The app validates and\nrejects the batch as a whole.\n\nBound to the HTTP body directly (`body: \"values\"`, not `body: \"*\"`), so the request\nthis endpoint takes is the same object it forwards. The alternative wraps it as\n`{\"values\": {...}}`, which would make the proxy's shape differ from the shape of the\nthing being proxied for no gain to anyone reading either.\n\nA `Struct` carries no field rules, so \"name at least one field\" is enforced in the\nhandler rather than declared here -- the only precondition on this surface that a\ngenerated validator does not express.", + "name": "values", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "UpdateInventoryConfigResponse returns the configuration as it now stands.", + "type": "object", + "properties": { + "settings": { + "description": "Every field, not only the ones the request named.\n\nThe whole resource, because an Update answers with the resource. It is also the only\nhonest answer for a nested write: overriding a parent object changes what its\nchildren effectively resolve to, and a response scoped to the submitted keys would\nreport the parent and leave a stale child beside it.", + "type": "array", + "items": { + "description": "InventorySetting is one of the inventory app's configuration fields.", + "type": "object", + "properties": { + "key": { + "description": "The field name. Nested fields arrive `__`-delimited, e.g. SCHEDULE__every.", + "type": "string", + "x-order": 0 + }, + "value": { + "description": "The value in effect.", + "x-order": 1 + }, + "default_value": { + "description": "What it would be with no override.", + "x-order": 2 + }, + "type": { + "description": "The field's type, for rendering an input. A string because the app's own schema\nnames it, so this contract does not get to enumerate the possibilities.", + "type": "string", + "x-order": 3 + }, + "reload": { + "description": "SettingReload is how a configuration field may be overridden, if at all.\n\nMirrors the app's own three-valued classification rather than collapsing it to\neditable/not. NESTED_ONLY is the one that would be lost: the parent object rejects a\nwhole-object write while its children accept one, so a form that read it as\n\"not overridable\" would refuse to edit a leaf the API would have accepted.\n\nThe distinction a form has to respect: rendering a NOT_OVERRIDABLE field as editable\npromises a change the API cannot deliver.\n\n - SETTING_RELOAD_HOT: Overridable at runtime; the new value takes effect on the next snapshot refresh.\n - SETTING_RELOAD_NESTED_ONLY: A nested object whose children are overridable, but which rejects being written\nwhole.\n - SETTING_RELOAD_NOT_OVERRIDABLE: Not overridable at all: YAML and environment variables remain the only sources.", + "type": "string", + "default": "SETTING_RELOAD_UNSPECIFIED", + "enum": [ + "SETTING_RELOAD_UNSPECIFIED", + "SETTING_RELOAD_HOT", + "SETTING_RELOAD_NESTED_ONLY", + "SETTING_RELOAD_NOT_OVERRIDABLE" + ], + "x-order": 4 + }, + "has_override": { + "description": "Whether an override is in effect, which is how \"why is it set to this\" is\nanswerable without also reading the deployment's configuration file.", + "type": "boolean", + "x-order": 5 + }, + "is_advanced": { + "description": "Whether to hide it behind an \"advanced\" disclosure.", + "type": "boolean", + "x-order": 6 + }, + "description": { + "description": "The field's documentation, where it has any.", + "type": "string", + "x-nullable": true, + "x-order": 7 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/config/overrides/{key}": { + "delete": { + "description": "Removes the override for one field so it returns to whatever the deployment configured. Idempotent.", + "tags": [ + "OmService" + ], + "summary": "Revert an inventory configuration field", + "operationId": "DeleteInventoryConfigOverride", + "parameters": [ + { + "type": "string", + "description": "The field whose override to remove, putting it back to its deployed value. Also the\nresource ID within the `overrides` collection.", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryConfigOverrideResponse acknowledges the revert.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts": { + "get": { + "description": "Returns every host the inventory app has a row for, whether or not a database was found on it, with the services on each and how current the observations are.", + "tags": [ + "OmService" + ], + "summary": "List inventory hosts", + "operationId": "ListInventoryHosts", + "parameters": [ + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) carry a registered service.\nUnset returns both, which is the ordinary listing.", + "name": "has_service", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only hosts currently failing.", + "name": "failing", + "in": "query" + }, + { + "type": "boolean", + "description": "When set, return only hosts that do (or do not) have an executor to run a probe\non. Not a client name: the app filters on whether one is matched at all, and\n\"which machines can nothing be dispatched to\" is the question worth asking.", + "name": "executor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryHostsResponse returns the hosts OM knows about.", + "type": "object", + "properties": { + "hosts": { + "description": "The hosts.", + "type": "array", + "items": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/hosts/{node_id}": { + "get": { + "description": "Returns one host by PMM node ID, with the services on it.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory host", + "operationId": "GetInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryHostResponse returns one host.", + "type": "object", + "properties": { + "host": { + "description": "InventoryHost is one machine OM knows about, with the services on it.\n\nA host is a row whether or not any MongoDB was found on it. That is what makes\n\"which machines have no database\" a query rather than an absence, and it is the only\nway a machine that has never run one appears at all - which is the case installing a\ndatabase somewhere later depends on.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID. Also what a scoped refresh is addressed by.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "The node name PMM registered.", + "type": "string", + "x-order": 1 + }, + "address": { + "description": "The node address PMM registered.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "executor_host": { + "description": "The Nomad client that serves it. Unset means nothing can be run there, which is a\nfact about the estate rather than a probe failure.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "os": { + "description": "The operating system, as the host reports it. Worth having from a probe because\nPMM does not know it for some nodes.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "kernel": { + "description": "The kernel release.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "executor": { + "description": "InventoryExecutor reports whether SEP can run anything on a host.\n\nThree flags rather than one, because \"orphaned\" hid three different problems with\nthree different fixes: never onboarded (registered false), onboarded and down\n(reachable false), and up with a broken raw_exec driver (driver_healthy false). This\nis SEP's own knowledge rather than probe output, so it is filled in for every host\non every sweep, including hosts no probe reached.", + "type": "object", + "properties": { + "registered": { + "description": "Whether the Tasks backend knows this node at all.", + "type": "boolean", + "x-order": 0 + }, + "reachable": { + "description": "Whether it is currently up.", + "type": "boolean", + "x-order": 1 + }, + "driver_healthy": { + "description": "Whether its raw_exec driver is healthy, which is what a probe actually needs.", + "type": "boolean", + "x-order": 2 + }, + "detail": { + "description": "Whatever detail the backend gave, when it gave any.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + }, + "x-order": 6 + }, + "unregistered_mongods": { + "description": "Mongods running that PMM has no service for.", + "type": "array", + "items": { + "description": "UnregisteredMongod is a mongod found running that PMM has no service for.\n\nThe arbiter case, mostly: PMM registers no service for an arbiter, so nothing else\nin OM would report the process at all. Also what stands in the way of installing\nanything over a port that is already taken.", + "type": "object", + "properties": { + "port": { + "description": "The port it is listening on.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 0 + }, + "config_path": { + "description": "The configuration file it read.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "program": { + "description": "The process name, e.g. \"mongod\".", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "pid": { + "description": "Its process ID at the time of the probe.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 4 + } + } + }, + "x-order": 7 + }, + "observed": { + "description": "Everything the probe recorded about the host, including attributes with no field\nabove.", + "type": "object", + "x-order": 8 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 9 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes a host row and its services from the inventory app's estate. Not suppression: a host PMM still knows about comes back on the next refresh. For clearing rows left behind when a node was replaced and given a new ID.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory host", + "operationId": "DeleteInventoryHost", + "parameters": [ + { + "type": "string", + "description": "PMM's node ID.", + "name": "node_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryHostResponse acknowledges forgetting a host.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs": { + "get": { + "description": "Returns the inventory app's refresh history, newest first. Distinct from /v1/om/topology/runs, which is PMM's own collection pass and never probes a host.", + "tags": [ + "OmService" + ], + "summary": "List inventory refreshes", + "operationId": "ListInventoryRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many to return, newest first. Defaults to 20, capped at 100.", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive lower bound on start_time. Unset means no lower bound.\n\nApplied before limit, so a week window is the newest runs *in that week*,\nnot the newest overall then those that happen to fall in it.", + "name": "since", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Inclusive upper bound on start_time. Unset means no upper bound.", + "name": "until", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryRunsResponse returns the refresh history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs/{run_id}": { + "get": { + "description": "Returns one refresh by ID, with what it saw and which hosts it covered.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory refresh", + "operationId": "GetInventoryRun", + "parameters": [ + { + "type": "string", + "description": "The run's ID.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryRunResponse returns one refresh, with the rows behind its counters.", + "type": "object", + "properties": { + "run": { + "description": "InventoryRun is one refresh of the estate.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it stopped. Unset while it is still going.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "InventoryRunCounts is what one refresh saw.", + "type": "object", + "properties": { + "total_services": { + "description": "Services enumeration found.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which matched a host something could be run on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "answered_services": { + "description": "Services that answered a probe.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "total_hosts": { + "description": "Hosts in scope this run, service or no service.\n\nA refresh attempts hosts as well as the services on them, so counting only\nservices makes a refresh of a host with no database read as \"0 of 0\" - which is\nexactly what a run that did nothing looks like, on the one kind of host OM most\nexists to describe.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "probeable_hosts": { + "description": "...of which had somewhere to run a probe. The gap is the estate nothing can be\ndispatched to, which is a fact about onboarding rather than a failed run.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "answered_hosts": { + "description": "Hosts that answered.", + "type": "integer", + "format": "int32", + "x-order": 6 + } + }, + "x-order": 4 + }, + "scope": { + "description": "The hosts it was limited to. Empty means it refreshed the whole estate, which is\nwhat the scheduled sweep does.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 5 + }, + "error": { + "description": "What went wrong, when something did.", + "type": "string", + "x-nullable": true, + "x-order": 6 + } + }, + "x-order": 0 + }, + "entities": { + "description": "What it attempted, one entry per entity.\n\nOnly on the detail response, never on the list: a refresh of a real estate has a\nrow per service, and a history of twenty-five would carry the lot to render a\npage that shows one at a time.", + "type": "array", + "items": { + "description": "InventoryRunEntity is one host a refresh attempted, and what came of it.\n\nHost-oriented, because a refresh attempts hosts. A flat list of services - which\nthis was - cannot show a machine carrying a PMM client and no database, however\nmany times it is probed, and that machine is the case OM most exists to describe:\nit is where a database can be installed.\n\nOne dispatch covers every service on a host, so the host owns the timing and the\nfailure and its services carry only what is theirs. Previously the duration was\ncopied onto each service, which read as several measurements when it was one.\n\nDeliberately outcomes and not observations. What the probe *found* lives on the\nestate, where it is upserted and stays current; a receipt that also carried the\nattributes would be a second copy that goes stale the moment the next refresh runs.", + "type": "object", + "properties": { + "node_id": { + "description": "PMM's node ID, the key OM holds this host under.", + "type": "string", + "x-order": 0 + }, + "host_name": { + "description": "The node's registered name.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "executor_host": { + "description": "The client its probe ran on. Unset when none matched.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "resolution": { + "description": "ExecutorResolution is how a host was matched to the client its probe ran on.\n\nORPHANED is why nothing ran, and it is not an error: a host with no executor is a fact\nabout onboarding. NAME and ADDRESS record *which* of the two joins matched, because a\nhost reachable only by address is a different estate problem from one matched by name.\n\n - EXECUTOR_RESOLUTION_NAME: Matched on the node's registered name.\n - EXECUTOR_RESOLUTION_ADDRESS: Matched on the node's address.\n - EXECUTOR_RESOLUTION_ORPHANED: Not matched, so nothing was dispatched.", + "type": "string", + "default": "EXECUTOR_RESOLUTION_UNSPECIFIED", + "enum": [ + "EXECUTOR_RESOLUTION_UNSPECIFIED", + "EXECUTOR_RESOLUTION_NAME", + "EXECUTOR_RESOLUTION_ADDRESS", + "EXECUTOR_RESOLUTION_ORPHANED" + ], + "x-order": 3 + }, + "answered": { + "description": "Whether the *host* answered. A different question from whether its services did:\na host with no database answers perfectly well and has no services at all.", + "type": "boolean", + "x-order": 4 + }, + "duration_seconds": { + "description": "The host's wall clock, dispatch to collected output.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 5 + }, + "error": { + "description": "The host-level failure, when its probe failed.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "services": { + "description": "The services on it. Empty is a meaningful answer, not a gap.", + "type": "array", + "items": { + "description": "InventoryRunEntityService is one service on a host, as a refresh saw it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID, when OM could key one.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "service_name": { + "description": "Its name, so a reader is not left joining UUIDs by hand.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "answered": { + "description": "Whether the host returned a usable record for it.", + "type": "boolean", + "x-order": 2 + }, + "error": { + "description": "Why it did not, when it did not.", + "type": "string", + "x-nullable": true, + "x-order": 3 + } + } + }, + "x-order": 7 + }, + "task_history_id": { + "description": "The task history id of the dispatch, so a reader can open the probe's own log.\nUnset when the dispatch never got one.", + "type": "string", + "format": "int64", + "x-nullable": true, + "x-order": 8 + } + } + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/runs:trigger": { + "post": { + "description": "Dispatches an on-host probe per executor host and returns as soon as the refresh is accepted. Takes tens of seconds, unlike /v1/om/topology/runs. Pass node_ids to refresh only those hosts; 409 when another refresh already holds one of them.", + "tags": [ + "OmService" + ], + "summary": "Refresh the inventory", + "operationId": "TriggerInventoryRefresh", + "parameters": [ + { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerInventoryRefreshRequest is the request for TriggerInventoryRefresh.", + "type": "object", + "properties": { + "node_ids": { + "description": "The hosts to refresh, by PMM node ID. Empty refreshes the whole estate.\n\nPlural on purpose: PMM's node ID is also OM's key, so ids pass through\nuntranslated, and one host is a list of one. A surface taking a single id where\nthe app takes a list would be a translation step in disguise.\n\nBounded because a refresh dispatches a Nomad job per host: the empty list already\nmeans \"the whole estate\", so a caller naming hosts individually is naming a few,\nand an unbounded list is only reachable by accident. An empty string is rejected\nrather than forwarded, where it would read as a node ID that matches nothing.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerInventoryRefreshResponse acknowledges an accepted refresh.\n\nAccepted, not finished. A refresh dispatches a Nomad job per host and takes tens of\nseconds, unlike PMM's own collection pass, which never probes and completes in\nmilliseconds. Two triggers that different must not look alike to a caller.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, to follow with GetInventoryRun.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When it began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "scope": { + "description": "The hosts it will refresh. Empty means the whole estate.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 3 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services": { + "get": { + "description": "Returns every MongoDB service the inventory app has a row for, with what each last reported and when.", + "tags": [ + "OmService" + ], + "summary": "List inventory services", + "operationId": "ListInventoryServices", + "parameters": [ + { + "type": "string", + "description": "When set, return only the services on this host.", + "name": "node_id", + "in": "query" + }, + { + "type": "boolean", + "description": "When true, return only services currently failing.", + "name": "failing", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListInventoryServicesResponse returns the services OM knows about, flat.", + "type": "object", + "properties": { + "services": { + "description": "The services.", + "type": "array", + "items": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/inventory/services/{service_id}": { + "get": { + "description": "Returns one service by PMM service ID.", + "tags": [ + "OmService" + ], + "summary": "Get an inventory service", + "operationId": "GetInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetInventoryServiceResponse returns one service.", + "type": "object", + "properties": { + "service": { + "description": "InventoryService is one MongoDB service OM has probed, or tried to.\n\nThe typed fields are the ones a table sorts by; `observed` carries the whole\ndocument besides. That split is deliberate: the app stores observations as JSON so\nthat collecting a new attribute is a payload change rather than a schema change, and\nenumerating every attribute here would put that coupling straight back. A new\nattribute appears in `observed` the day it is collected and is promoted to a field\nof its own only when something wants to sort by it.", + "type": "object", + "properties": { + "service_id": { + "description": "PMM's service ID. The join key against the topology document.", + "type": "string", + "x-order": 0 + }, + "node_id": { + "description": "The node it runs on, as PMM's node ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "The service name PMM registered.", + "type": "string", + "x-order": 2 + }, + "port": { + "description": "The port it listens on, where OM knows it.", + "type": "integer", + "format": "int32", + "x-nullable": true, + "x-order": 3 + }, + "role": { + "description": "PRIMARY, SECONDARY, ARBITER, or unset.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from running_version is the upgraded-but-not-restarted case,\nand no metric anywhere carries it.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "running_version": { + "description": "The version the running server reports.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "config_path": { + "description": "The configuration file the running server read.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "argv": { + "description": "The command line it was started with.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "probe_status": { + "description": "What the last probe of this service concluded, in the payload's own words.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "server_running": { + "description": "Whether a server was found running. Unset where no probe has looked.", + "type": "boolean", + "x-nullable": true, + "x-order": 10 + }, + "uptime_seconds": { + "description": "How long it has been up, seconds.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 11 + }, + "replication_set": { + "description": "The replica set it belongs to, or unset for a standalone or a router.", + "type": "string", + "x-nullable": true, + "x-order": 12 + }, + "observed": { + "description": "Everything the probe recorded, including attributes with no field above.", + "type": "object", + "x-order": 13 + }, + "freshness": { + "description": "InventoryFreshness says how current the rest of a row is, and how it is failing.\n\nCarried on hosts and services alike because the estate is upserted rather than\nrebuilt: a row keeps what it last reported, so every attribute is only meaningful\nbeside the time it was collected. `failing_since` is the *first* failure after the\nlast success, which is what makes \"failing for three days\" expressible rather than\nonly \"failed a minute ago\".", + "type": "object", + "properties": { + "first_seen_at": { + "description": "When OM first wrote a row for this entity.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "last_attempt_at": { + "description": "When a refresh last tried it.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "last_success_at": { + "description": "When it last answered. Unset means it never has, which is different from having\nanswered nothing.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "failing_since": { + "description": "The first failure after the last success. Unset means it is not failing.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "consecutive_failures": { + "description": "Failures since the last success.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "last_error": { + "description": "The most recent failure detail.", + "type": "string", + "x-nullable": true, + "x-order": 5 + } + }, + "x-order": 14 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Removes one service row from the inventory app's estate. Not suppression: a service PMM still knows about comes back on the next refresh.", + "tags": [ + "OmService" + ], + "summary": "Forget an inventory service", + "operationId": "DeleteInventoryService", + "parameters": [ + { + "type": "string", + "description": "PMM's service ID.", + "name": "service_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "DeleteInventoryServiceResponse acknowledges forgetting a service.", + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology": { + "get": { + "description": "Returns every monitored MongoDB service, grouped by environment then cluster, with its identity, replica-set state, reachability and load.", + "tags": [ + "OmService" + ], + "summary": "Get the MongoDB topology", + "operationId": "GetTopology", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyResponse is the whole topology document plus the provenance of the run\nbehind it.", + "type": "object", + "properties": { + "snapshot": { + "description": "Snapshot carries the provenance every snapshot-backed response repeats.", + "type": "object", + "properties": { + "generated_at": { + "description": "When the document was assembled.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "observed_at": { + "description": "The newest observation in it, unset when nothing was observed at all.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "stale": { + "description": "Whether the document is older than the staleness grace period. Also true, with\nobserved_at unset and every environment empty, on a genuinely cold estate -- no\ncollection has completed anywhere yet. That is a startup state, not a statement that\nthe estate itself is empty; a reader should render it as \"collecting\" rather than as\nan empty result.", + "type": "boolean", + "x-order": 2 + }, + "schema_version": { + "description": "The document schema version.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "run_id": { + "description": "The collection run that produced it.", + "type": "string", + "x-order": 4 + } + }, + "x-order": 0 + }, + "origin_node": { + "description": "The PMM node the document was assembled on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "source_queries": { + "description": "The VictoriaMetrics queries the document was derived from.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 2 + }, + "summary": { + "description": "Summary carries the fleet-level counts, so a caller need not re-derive them.", + "type": "object", + "properties": { + "environments": { + "description": "Environments in the document.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "clusters": { + "description": "Clusters across all of them.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "total_services": { + "description": "Services in the document.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "up_services": { + "description": "Services the exporter reached.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "down_services": { + "description": "Services it did not.", + "type": "integer", + "format": "int32", + "x-order": 4 + }, + "process_role_counts": { + "description": "Service counts per process role, keyed by the ProcessRole enum's name.", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + }, + "x-order": 5 + } + }, + "x-order": 3 + }, + "environments": { + "description": "The estate, grouped environment then cluster.", + "type": "array", + "items": { + "description": "Environment represents one monitoring environment.", + "type": "object", + "properties": { + "env_name": { + "description": "Environment label, unset when its services carry none.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "clusters": { + "description": "Its clusters, ordered by name.", + "type": "array", + "items": { + "description": "Cluster represents one grouped service inventory: every service PMM's inventory\nlabelled with the same (environment, cluster) or (environment, replication_set), not a\nreconstructed replica-set or sharded-cluster topology. A sharded cluster here is a flat\nlist of mongos, configsvr and shardsvr rows that share a label -- see ClusterType for\nthe one thing inferred about that shape, and the package comment for what is\ndeliberately not.", + "type": "object", + "properties": { + "name": { + "description": "Cluster label, unset when its services carry none. Not a stable identity: two\nclusters can share this label (a second generation of a sandbox reusing a name), and\n`id` is what tells them apart.", + "type": "string", + "x-nullable": true, + "x-order": 0 + }, + "services": { + "description": "Its services, ordered by name.", + "type": "array", + "items": { + "description": "TopologyService represents one monitored MongoDB service as the topology document\nrecords it.\n\nTwo conventions for \"no value\", and they differ on purpose. cpu_usage_percent and\nconnections_free_percent are -1 when not measured, never absent and never 0, because\nzero CPU is a legitimate reading and a numeric column must keep \"idle\" and \"unknown\"\napart. replication_lag_seconds and oplog_window_seconds are `optional`, so the key is\nabsent when they do not apply -- a router and a standalone have no replica-set oplog --\nwhich is a different statement from -1's \"we could not measure it\".\n\nThe optional fields were wrapper messages until the REST contract was checked:\nprotoc-gen-openapiv2 does not mark a wrapper field x-nullable, so the swagger schema\nand the generated Go client both collapsed to a value type and lost the distinction\nentirely. `optional` gives x-nullable and a pointer, at the cost of protojson omitting\nthe key rather than emitting an explicit null.", + "type": "object", + "properties": { + "service_name": { + "description": "Service name as PMM inventory registered it.", + "type": "string", + "x-order": 0 + }, + "host": { + "description": "Node the service runs on.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "endpoint": { + "description": "host:port as the replica set itself addresses the member.", + "type": "string", + "x-nullable": true, + "x-order": 2 + }, + "service_id": { + "description": "PMM's service ID. The join key against VictoriaMetrics.", + "type": "string", + "x-nullable": true, + "x-order": 3 + }, + "service_type": { + "description": "Always \"mongodb\" today.", + "type": "string", + "x-nullable": true, + "x-order": 4 + }, + "version": { + "description": "Running server version.", + "type": "string", + "x-nullable": true, + "x-order": 5 + }, + "vendor": { + "description": "MongoDB or Percona.", + "type": "string", + "x-nullable": true, + "x-order": 6 + }, + "edition": { + "description": "Community or Enterprise.", + "type": "string", + "x-nullable": true, + "x-order": 7 + }, + "replication_set": { + "description": "Replica set, or unset for a router or a standalone.", + "type": "string", + "x-nullable": true, + "x-order": 8 + }, + "state": { + "description": "PRIMARY, SECONDARY or ARBITER, or unset where there is no replica-set state.", + "type": "string", + "x-nullable": true, + "x-order": 9 + }, + "status": { + "description": "ServiceStatus is whether the exporter reached a service.\n\nTwo values and no third: this is the exporter's reachability, not the server's health.\n\"we did not look\" is UNSPECIFIED, which the collector never emits.\n\n - SERVICE_STATUS_UP: The exporter reached the service.\n - SERVICE_STATUS_DOWN: It did not.", + "type": "string", + "default": "SERVICE_STATUS_UNSPECIFIED", + "enum": [ + "SERVICE_STATUS_UNSPECIFIED", + "SERVICE_STATUS_UP", + "SERVICE_STATUS_DOWN" + ], + "x-order": 10 + }, + "cpu_usage_percent": { + "description": "CPU percentage, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 11 + }, + "connections_free_percent": { + "description": "Percentage of free connections, or -1 when not measured.", + "type": "number", + "format": "double", + "x-order": 12 + }, + "process_role": { + "description": "ProcessRole is what a mongod or mongos is doing in the deployment.\n\nNot the same axis as replica-set state: a SHARDSVR can be PRIMARY or SECONDARY. This\nis the role the process was started in, which is a property of the deployment's shape.\n\n - PROCESS_ROLE_MONGOD: A standalone or replica-set member with no sharding role.\n - PROCESS_ROLE_MONGOS: A router.\n - PROCESS_ROLE_CONFIGSVR: A config-server member.\n - PROCESS_ROLE_SHARDSVR: A shard member.", + "type": "string", + "default": "PROCESS_ROLE_UNSPECIFIED", + "enum": [ + "PROCESS_ROLE_UNSPECIFIED", + "PROCESS_ROLE_MONGOD", + "PROCESS_ROLE_MONGOS", + "PROCESS_ROLE_CONFIGSVR", + "PROCESS_ROLE_SHARDSVR" + ], + "x-order": 13 + }, + "replication_lag_seconds": { + "description": "Seconds this member trails the primary; unset where there is no primary to trail.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 14 + }, + "oplog_window_seconds": { + "description": "Seconds of history the oplog holds; unset where there is no replica-set oplog.", + "type": "number", + "format": "double", + "x-nullable": true, + "x-order": 15 + }, + "installed_version": { + "description": "The MongoDB binary installed on the node, which is not necessarily the one\nrunning. Divergence from `version` is the upgraded-but-not-restarted case. Only\nan on-host probe can see it, so this is unset wherever one has not run.", + "type": "string", + "x-nullable": true, + "x-order": 16 + }, + "config_path": { + "description": "The configuration file the running server read. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 17 + }, + "argv": { + "description": "The command line the running server was started with. Probe-only.", + "type": "string", + "x-nullable": true, + "x-order": 18 + }, + "observed_at": { + "description": "When the newest *live* field on this row was observed, unset when every field on it\nis either absent or not time-bounded (inventory only, no metric and no probe ever\nseen). This is the row's own provenance -- Snapshot.observed_at is the newest across\nthe whole estate, which cannot tell \"this row is current\" from \"this row is the one\nthat made the snapshot look fresh\". A field's own MergedField.ObservedAt exists\ninternally; this is the first one exposed on the wire.", + "type": "string", + "format": "date-time", + "x-nullable": true, + "x-order": 19 + } + } + }, + "x-order": 1 + }, + "id": { + "description": "Opaque, server-issued, stable across a rename of `name`. Derived from\n(environment, cluster, replication_set) so the same estate group always gets the\nsame id -- clients must not parse it or assume a derivation.", + "type": "string", + "x-order": 2 + }, + "type": { + "description": "ClusterType is the shape buildDocument inferred for one grouped service inventory.\n\nInferred, not reconstructed: this package groups services by label and infers a shape\nfrom what is in the group, it does not walk a replica set's own config to build a\nmember list. See the package comment.\n\n - CLUSTER_TYPE_REPLICA_SET: Exactly one replication_set label under this cluster, and no mongos.\n - CLUSTER_TYPE_SHARDED: A mongos is present, or more than one replication_set label shares this cluster\nlabel.\n - CLUSTER_TYPE_STANDALONE: Neither: services grouped under one label with no replica-set identity at all.", + "type": "string", + "default": "CLUSTER_TYPE_UNSPECIFIED", + "enum": [ + "CLUSTER_TYPE_UNSPECIFIED", + "CLUSTER_TYPE_REPLICA_SET", + "CLUSTER_TYPE_SHARDED", + "CLUSTER_TYPE_STANDALONE" + ], + "x-order": 3 + }, + "health": { + "description": "ClusterHealth is a reserved verdict slot, not yet computed by anything.\n\nUNSPECIFIED is the only value that exists today. It is declared now, alongside the\napplyHealth seam in the collector, so a rollup status has a field to land in without a\nlater schema change -- see the om package's health-pipeline comment.", + "type": "string", + "default": "CLUSTER_HEALTH_UNSPECIFIED", + "enum": [ + "CLUSTER_HEALTH_UNSPECIFIED" + ], + "x-order": 4 + } + } + }, + "x-order": 1 + } + } + }, + "x-order": 4 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs": { + "get": { + "description": "Returns the recorded collection runs, newest first, with what each one saw and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "List collection runs", + "operationId": "ListTopologyRuns", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "How many runs to return, newest first. Defaults to 25, capped at 100.", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "ListTopologyRunsResponse returns the run history, newest first.", + "type": "object", + "properties": { + "runs": { + "description": "The runs.", + "type": "array", + "items": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs/{run_id}": { + "get": { + "description": "Returns one recorded collection run, with what it saw, how each source answered, and any errors it hit.", + "tags": [ + "OmService" + ], + "summary": "Get a collection run", + "operationId": "GetTopologyRun", + "parameters": [ + { + "type": "string", + "description": "The run to return.", + "name": "run_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "GetTopologyRunResponse returns one collection run.", + "type": "object", + "properties": { + "run": { + "description": "TopologyRun represents one collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID, also the snapshot key.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "end_time": { + "description": "When it reached a terminal status; unset while running.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "counts": { + "description": "TopologyRunCounts counts what one collection run saw.", + "type": "object", + "properties": { + "total_services": { + "description": "MongoDB services inventory reported.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "resolved_services": { + "description": "...of which carried a service ID to join metrics on.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "orphaned_services": { + "description": "...of which did not. Not an error.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "successful_probes": { + "description": "Services metrics actually observed as reachable.", + "type": "integer", + "format": "int32", + "x-order": 3 + }, + "stale_services": { + "description": "Services carrying at least one volatile fact too old to read as current.", + "type": "integer", + "format": "int32", + "x-order": 4 + } + }, + "x-order": 4 + }, + "errors": { + "description": "Query-level, service-level and run-level failures.", + "type": "array", + "items": { + "description": "TopologyRunError describes one thing that went wrong during a collection run.", + "type": "object", + "properties": { + "scope": { + "description": "What the error is about, e.g. \"run\" or \"query\".", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "The service it concerns, when scoped to one.", + "type": "string", + "x-nullable": true, + "x-order": 1 + }, + "code": { + "description": "A machine-readable cause.", + "type": "string", + "x-order": 2 + }, + "message": { + "description": "The human-readable detail.", + "type": "string", + "x-order": 3 + } + } + }, + "x-order": 5 + }, + "sources": { + "description": "How completely each collection source answered.", + "type": "array", + "items": { + "description": "SourceReport says how completely one collection source answered, and what it saw.\n\nRecorded per source so a thin document is legible rather than merely thin: a snapshot\nassembled with metrics=ok and probe=failed is still correct about every version and\nhonest about reachability.", + "type": "object", + "properties": { + "source": { + "description": "The source key, e.g. \"inventory\", \"metrics\" or \"probe\". An open set on purpose: a\nsource is named by whatever produced it, so this stays a string where the statuses\nbeside it are enums.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "SourceStatus is how completely one collection source answered.\n\nSeparate from RunStatus because it carries DISABLED, which a run cannot be: a source\nswitched off in configuration is a deliberate state, not a degraded one.\n\n - SOURCE_STATUS_OK: Answered everything asked of it.\n - SOURCE_STATUS_PARTIAL: Answered some of it.\n - SOURCE_STATUS_FAILED: Did not answer.\n - SOURCE_STATUS_DISABLED: Switched off in configuration, so it was never asked.", + "type": "string", + "default": "SOURCE_STATUS_UNSPECIFIED", + "enum": [ + "SOURCE_STATUS_UNSPECIFIED", + "SOURCE_STATUS_OK", + "SOURCE_STATUS_PARTIAL", + "SOURCE_STATUS_FAILED", + "SOURCE_STATUS_DISABLED" + ], + "x-order": 1 + }, + "facts": { + "description": "How many facts it produced.", + "type": "integer", + "format": "int32", + "x-order": 2 + }, + "detail": { + "description": "Source-specific counters, rendered as strings so a source can report whatever it has\nwithout this contract naming every counter.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 3 + } + } + }, + "x-order": 6 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/om/topology/runs:collect": { + "post": { + "description": "Rebuilds the topology document from PMM inventory and VictoriaMetrics, and records the run.", + "tags": [ + "OmService" + ], + "summary": "Trigger a collection run", + "operationId": "TriggerTopologyCollection", + "parameters": [ + { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "name": "body", + "in": "body", + "required": true, + "schema": { + "description": "TriggerTopologyCollectionRequest is the request for TriggerTopologyCollection.", + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "description": "TriggerTopologyCollectionResponse acknowledges a completed collection run.", + "type": "object", + "properties": { + "run_id": { + "description": "The run's ID.", + "type": "string", + "x-order": 0 + }, + "status": { + "description": "RunStatus is how a run ended, for both kinds of run.\n\nShared by the topology collection pass and the inventory refresh deliberately: the two\nruns differ in what they do, not in how they finish, and two identical enums would\ninvite them to drift apart for no reason.\n\n - RUN_STATUS_RUNNING: Still going. Not a terminal status.\n - RUN_STATUS_SUCCESS: Everything it attempted answered.\n - RUN_STATUS_PARTIAL: Some of it did. The counts say which. For an inventory refresh this is the common\nsteady state rather than an alarm: a row routinely outlives the executor that served\nit.\n - RUN_STATUS_FAILED: The run itself failed, as opposed to the things it was probing.\n - RUN_STATUS_SKIPPED: Refused before doing any work, because another refresh already held the hosts it\nwould have covered. Neither a failure nor a success: it did nothing, deliberately,\nand it is recorded so a schedule cannot look like it fired and found nothing.\n\nOnly an inventory refresh reaches this. The collection pass has a single-flight\nguard too, but a refusal there never reaches a run row at all -- the RPC answers\nAborted (already running) or FailedPrecondition (not the HA leader) and nothing is\nrecorded, so this status never applies to it.", + "type": "string", + "default": "RUN_STATUS_UNSPECIFIED", + "enum": [ + "RUN_STATUS_UNSPECIFIED", + "RUN_STATUS_RUNNING", + "RUN_STATUS_SUCCESS", + "RUN_STATUS_PARTIAL", + "RUN_STATUS_FAILED", + "RUN_STATUS_SKIPPED" + ], + "x-order": 1 + }, + "start_time": { + "description": "When the run began.", + "type": "string", + "format": "date-time", + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/qan/health": { "get": { "description": "Returns readiness of QAN API2 service.", @@ -32722,6 +35661,10 @@ "description": "RealtimeAnalyticsService provides public API for managing Real-Time Analytics Sessions and Queries.", "name": "RealtimeAnalyticsService" }, + { + "description": "OmService provides the OpenManager topology and health API.", + "name": "OmService" + }, { "description": "HAService provides High Availability cluster status information.", "name": "HAService" diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 79a3bd38d07..79af3da28ac 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -73,6 +73,7 @@ import ( hav1beta1 "github.com/percona/pmm/api/ha/v1beta1" inventoryv1 "github.com/percona/pmm/api/inventory/v1" managementv1 "github.com/percona/pmm/api/management/v1" + omv1 "github.com/percona/pmm/api/om/v1" rtav1 "github.com/percona/pmm/api/realtimeanalytics/v1" serverv1 "github.com/percona/pmm/api/server/v1" userv1 "github.com/percona/pmm/api/user/v1" @@ -95,6 +96,7 @@ import ( managementgrpc "github.com/percona/pmm/managed/services/management/grpc" "github.com/percona/pmm/managed/services/minio" "github.com/percona/pmm/managed/services/nomad" + "github.com/percona/pmm/managed/services/om" "github.com/percona/pmm/managed/services/qan" "github.com/percona/pmm/managed/services/realtimeanalytics" "github.com/percona/pmm/managed/services/scheduler" @@ -234,7 +236,12 @@ type gRPCServerDeps struct { versionCache *versioncache.Service vmdb *victoriametrics.Service vmalert *vmalert.Service - internalNodePrefixes []string + + // Built in main so its collection timer can be registered as an HA leader service. + // runGRPCServer only exposes it. + omService *om.Service + + internalNodePrefixes []string } // parseNodeNamePrefixes splits a comma-separated list of Node name prefixes. @@ -340,6 +347,8 @@ func runGRPCServer(ctx context.Context, deps *gRPCServerDeps) { hav1beta1.RegisterHAServiceServer(gRPCServer, ha.NewHAServer(deps.ha)) + omv1.RegisterOmServiceServer(gRPCServer, deps.omService) + // Register RTA service with in-memory store rtaStore := realtimeanalytics.NewStore() rtaSvc := realtimeanalytics.NewService(deps.db, deps.agentsRegistry, deps.agentsStateUpdater, rtaStore) @@ -447,6 +456,8 @@ func runHTTP1Server(ctx context.Context, deps *http1ServerDeps) { dumpv1beta1.RegisterDumpServiceHandler, + omv1.RegisterOmServiceHandler, + rtav1.RegisterRealtimeAnalyticsServiceHandler, userv1.RegisterUserServiceHandler, @@ -694,6 +705,16 @@ func main() { //nolint:gocognit,maintidx,cyclop kingpin.Version(version.FullInfo()) kingpin.HelpFlag.Short('h') + // Where SEP is, not where any one of its apps is: OM's on-host facts come from + // the om_inventory app today and the actions apps will come from the same SEP, so + // each consumer appends its own /api/apps/ path. Optional -- with no URL + // the probe source reports itself disabled and the document is built from PMM's own + // inventory and metrics alone. + sepURLF := kingpin.Flag("sep-url", "Base URL of SEP, e.g. http://127.0.0.1:8000"). + Envar("PMM_SEP_URL").String() + sepTokenF := kingpin.Flag("sep-token", "Bearer token for SEP's API"). + Envar("PMM_SEP_TOKEN").String() + victoriaMetricsURLF := kingpin.Flag("victoriametrics-url", "VictoriaMetrics base URL").Envar("PMM_VM_URL"). Default(models.VMBaseURL).String() victoriaMetricsVMAlertURLF := kingpin.Flag("victoriametrics-vmalert-url", "VictoriaMetrics VMAlert base URL").Envar("PMM_VM_ALERT_URL"). @@ -1194,6 +1215,21 @@ func main() { //nolint:gocognit,maintidx,cyclop return nil })) + // Where SEP is, optional. Empty means OM builds its document from PMM's own inventory + // and metrics alone and records the probe source as disabled. + omService := om.New(db, v1.NewAPI(vmClient), haService, logrus.WithField("component", "om")) + omService.WithProbeSource(*sepURLF, *sepTokenF) + prom.MustRegister(om.NewMetricsCollector(omService)) + + // Leader-only, like every other periodic writer here. A collection persists a run and + // its snapshot and then prunes the shared history, so running it on every node of an + // HA cluster would have each node writing runs and pruning the others' -- and the + // pruning is what makes that destructive rather than merely wasteful. + haService.AddLeaderService(ha.NewContextService("om", func(ctx context.Context) error { + omService.Run(ctx) + return nil + })) + wg.Go(func() { runGRPCServer(ctx, &gRPCServerDeps{ @@ -1226,6 +1262,7 @@ func main() { //nolint:gocognit,maintidx,cyclop templatesService: alertingService, versionCache: versionCache, vmalert: vmalert, + omService: omService, vmClient: &vmClient, vmdb: vmdb, }) diff --git a/managed/models/database.go b/managed/models/database.go index ce82f304ca0..257860edc1d 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1188,6 +1188,40 @@ var databaseSchema = [][]string{ `ALTER TABLE dumps ADD COLUMN encrypted boolean NOT NULL DEFAULT false`, `UPDATE dumps SET encrypted = false`, }, + 119: { + // OM (OpenManager) topology collection: one row per pass, and the + // topology document it produced. + `CREATE TABLE om_topology_runs ( + run_id VARCHAR PRIMARY KEY, + started_at TIMESTAMP NOT NULL, + finished_at TIMESTAMP, + status VARCHAR NOT NULL, + services_total INTEGER NOT NULL DEFAULT 0, + services_resolved INTEGER NOT NULL DEFAULT 0, + services_orphaned INTEGER NOT NULL DEFAULT 0, + probes_ok INTEGER NOT NULL DEFAULT 0, + services_stale INTEGER NOT NULL DEFAULT 0, + origin_node VARCHAR NOT NULL DEFAULT '', + sources JSONB, + errors JSONB, + created_at TIMESTAMP NOT NULL + )`, + `CREATE INDEX om_topology_runs_started_at_idx ON om_topology_runs (started_at DESC)`, + + // The document is JSONB rather than a relational tree because the topology model + // is still moving; schema_version is what a reader checks. It is deleted with its + // run, which is what bounds retention. + `CREATE TABLE om_topology_snapshots ( + run_id VARCHAR PRIMARY KEY REFERENCES om_topology_runs (run_id) ON DELETE CASCADE, + generated_at TIMESTAMP NOT NULL, + observed_at TIMESTAMP, + stale BOOLEAN NOT NULL DEFAULT false, + schema_version INTEGER NOT NULL, + document JSONB NOT NULL, + created_at TIMESTAMP NOT NULL + )`, + `CREATE INDEX om_topology_snapshots_generated_at_idx ON om_topology_snapshots (generated_at DESC)`, + }, } // ^^^ Avoid default values in schema definition. ^^^ diff --git a/managed/models/om_helpers.go b/managed/models/om_helpers.go new file mode 100644 index 00000000000..4f4d62dd42b --- /dev/null +++ b/managed/models/om_helpers.go @@ -0,0 +1,111 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "errors" + "fmt" + + "gopkg.in/reform.v1" +) + +// CreateOmTopologyRun stores one run and the topology document it produced. +// +// Both in one call because they are one fact: a run with no document is not a state any +// reader should have to handle, and the caller writes them inside a transaction so no +// reader ever sees one without the other. +func CreateOmTopologyRun(q *reform.Querier, run *OmTopologyRun, snapshot *OmTopologySnapshot) error { + err := q.Insert(run) + if err != nil { + return fmt.Errorf("failed to insert OM run: %w", err) + } + if snapshot != nil { + snapshot.RunID = run.RunID + err = q.Insert(snapshot) + if err != nil { + return fmt.Errorf("failed to insert OM snapshot: %w", err) + } + } + return nil +} + +// FindOmTopologyRuns returns the most recent runs, newest first. +func FindOmTopologyRuns(q *reform.Querier, limit int) ([]*OmTopologyRun, error) { + if limit <= 0 { + return []*OmTopologyRun{}, nil + } + structs, err := q.SelectAllFrom(OmTopologyRunTable, "ORDER BY started_at DESC, run_id DESC LIMIT "+q.Placeholder(1), limit) + if err != nil { + return nil, fmt.Errorf("failed to select OM runs: %w", err) + } + runs := make([]*OmTopologyRun, len(structs)) + for i, s := range structs { + runs[i] = s.(*OmTopologyRun) //nolint:forcetypeassert + } + return runs, nil +} + +// FindOmTopologyRunByID returns one run, or ErrNotFound when there is no such run. +func FindOmTopologyRunByID(q *reform.Querier, runID string) (*OmTopologyRun, error) { + if runID == "" { + return nil, NewInvalidArgumentError("run_id shouldn't be empty") + } + run := &OmTopologyRun{RunID: runID} + err := q.Reload(run) + if err != nil { + if errors.Is(err, reform.ErrNoRows) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("failed to select OM run: %w", err) + } + return run, nil +} + +// FindLatestOmTopologySnapshot returns the newest stored topology document, or ErrNotFound when +// no collection has ever run. +// +// This is what lets a restarted pmm-managed serve the estate before it has collected +// anything of its own. +func FindLatestOmTopologySnapshot(q *reform.Querier) (*OmTopologySnapshot, error) { + structs, err := q.SelectAllFrom(OmTopologySnapshotTable, "ORDER BY generated_at DESC LIMIT 1") + if err != nil { + return nil, fmt.Errorf("failed to select the latest OM snapshot: %w", err) + } + if len(structs) == 0 { + return nil, ErrNotFound + } + return structs[0].(*OmTopologySnapshot), nil //nolint:forcetypeassert +} + +// PruneOmTopologyRuns deletes all but the newest keep runs, cascading to their snapshots. +// +// Retention has to be bounded here rather than by an operator: collection runs on a timer +// and on every read past the cache, so the table grows on its own. Pruning on write keeps +// it at a fixed size without a second scheduled job to forget about. +func PruneOmTopologyRuns(q *reform.Querier, keep int) error { + if keep <= 0 { + return NewInvalidArgumentError("keep should be positive") + } + _, err := q.Exec(` + DELETE FROM om_topology_runs + WHERE run_id NOT IN ( + SELECT run_id FROM om_topology_runs ORDER BY started_at DESC, run_id DESC LIMIT `+q.Placeholder(1)+` + )`, keep) + if err != nil { + return fmt.Errorf("failed to prune OM runs: %w", err) + } + return nil +} diff --git a/managed/models/om_helpers_test.go b/managed/models/om_helpers_test.go new file mode 100644 index 00000000000..09ed55f0bd2 --- /dev/null +++ b/managed/models/om_helpers_test.go @@ -0,0 +1,155 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/utils/testdb" +) + +func TestOmTopologyRuns(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + t.Cleanup(func() { require.NoError(t, sqlDB.Close()) }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + base := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC) + + // insert records one run and its document, minutes apart so ordering is unambiguous. + insert := func(t *testing.T, q *reform.Querier, id string, offset time.Duration, document string) { + t.Helper() + started := base.Add(offset) + finished := started.Add(time.Second) + observed := started.Add(-5 * time.Second) + + run := &models.OmTopologyRun{ + RunID: id, StartedAt: started, FinishedAt: &finished, + Status: models.OmTopologyRunSuccess, ServicesTotal: 14, ServicesResolved: 14, + ProbesOK: 13, ServicesStale: 1, OriginNode: "pmm-server", + Sources: models.OmTopologySourceReports{ + {Source: "inventory", Status: "ok", Facts: 81}, + {Source: "metrics", Status: "ok", Facts: 219, Detail: map[string]string{"queries": "13"}}, + }, + Errors: models.OmTopologyRunErrors{ + {Scope: "query", Code: "vm_query_failed", Message: "boom"}, + }, + } + snapshot := &models.OmTopologySnapshot{ + GeneratedAt: finished, ObservedAt: &observed, + SchemaVersion: 3, Document: []byte(document), + } + require.NoError(t, models.CreateOmTopologyRun(q, run, snapshot)) + } + + t.Run("a run round-trips with its receipt and its document", func(t *testing.T) { + q := db.Querier + insert(t, q, "run-1", 0, `{"origin_node":"pmm-server"}`) + + run, err := models.FindOmTopologyRunByID(q, "run-1") + require.NoError(t, err) + assert.Equal(t, models.OmTopologyRunSuccess, run.Status) + assert.Equal(t, int32(14), run.ServicesTotal) + assert.Equal(t, int32(1), run.ServicesStale) + assert.Equal(t, "pmm-server", run.OriginNode) + + // The per-source receipt is the part that makes a thin document legible. + require.Len(t, run.Sources, 2) + assert.Equal(t, "metrics", run.Sources[1].Source) + assert.Equal(t, "13", run.Sources[1].Detail["queries"]) + require.Len(t, run.Errors, 1) + assert.Equal(t, "vm_query_failed", run.Errors[0].Code) + + snapshot, err := models.FindLatestOmTopologySnapshot(q) + require.NoError(t, err) + assert.Equal(t, "run-1", snapshot.RunID) + assert.JSONEq(t, `{"origin_node":"pmm-server"}`, string(snapshot.Document)) + assert.Equal(t, int32(3), snapshot.SchemaVersion) + }) + + t.Run("runs come back newest first", func(t *testing.T) { + q := db.Querier + insert(t, q, "run-2", time.Minute, `{"n":2}`) + insert(t, q, "run-3", 2*time.Minute, `{"n":3}`) + + runs, err := models.FindOmTopologyRuns(q, 2) + require.NoError(t, err) + require.Len(t, runs, 2) + assert.Equal(t, "run-3", runs[0].RunID) + assert.Equal(t, "run-2", runs[1].RunID) + + // And the newest document is the one a cold start restores. + snapshot, err := models.FindLatestOmTopologySnapshot(q) + require.NoError(t, err) + assert.Equal(t, "run-3", snapshot.RunID) + }) + + t.Run("pruning bounds the history and takes the documents with it", func(t *testing.T) { + q := db.Querier + for i := range 5 { + insert(t, q, fmt.Sprintf("prune-%d", i), time.Duration(10+i)*time.Minute, `{}`) + } + + require.NoError(t, models.PruneOmTopologyRuns(q, 3)) + + runs, err := models.FindOmTopologyRuns(q, 100) + require.NoError(t, err) + require.Len(t, runs, 3, "only the newest are kept") + assert.Equal(t, "prune-4", runs[0].RunID) + + // The snapshot cascades, so retention needs no second sweep to stay bounded. + _, err = models.FindOmTopologyRunByID(q, "prune-0") + require.ErrorIs(t, err, models.ErrNotFound) + + var count int + require.NoError(t, db.QueryRow("SELECT count(*) FROM om_topology_snapshots").Scan(&count)) + assert.Equal(t, 3, count) + }) + + t.Run("absent things report absence, not an empty value", func(t *testing.T) { + q := db.Querier + + _, err := models.FindOmTopologyRunByID(q, "nope") + require.ErrorIs(t, err, models.ErrNotFound) + + _, err = models.FindOmTopologyRunByID(q, "") + require.Error(t, err, "an empty id is a caller mistake, not a miss") + + runs, err := models.FindOmTopologyRuns(q, 0) + require.NoError(t, err) + assert.Empty(t, runs) + + require.Error(t, models.PruneOmTopologyRuns(q, 0), "keeping nothing is never what a caller meant") + }) +} + +func TestOmTopologySnapshotAbsentOnEmptyDatabase(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + t.Cleanup(func() { require.NoError(t, sqlDB.Close()) }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + // The cold-start path depends on this being a clean miss rather than an error. + _, err := models.FindLatestOmTopologySnapshot(db.Querier) + require.ErrorIs(t, err, models.ErrNotFound) +} diff --git a/managed/models/om_model.go b/managed/models/om_model.go new file mode 100644 index 00000000000..80b0ec53fd1 --- /dev/null +++ b/managed/models/om_model.go @@ -0,0 +1,173 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "database/sql/driver" + "time" + + "gopkg.in/reform.v1" +) + +//go:generate go tool reform + +// OmTopologyRunStatus is the terminal state of one OM collection run. +type OmTopologyRunStatus string + +// The states an OM run can end in. A run whose sources all answered is a success even if +// some services were never seen: a service inventory knows and metrics have not is a fact +// about the estate, not a failure of the run. +const ( + // OmTopologyRunSuccess means every source answered. + OmTopologyRunSuccess = OmTopologyRunStatus("success") + // OmTopologyRunPartial means at least one source answered incompletely or errored. + OmTopologyRunPartial = OmTopologyRunStatus("partial") + // OmTopologyRunFailed means no source answered. + OmTopologyRunFailed = OmTopologyRunStatus("failed") +) + +// OmTopologySourceReport says how completely one collection source answered, and what it saw. +type OmTopologySourceReport struct { + Source string `json:"source"` + Status string `json:"status"` + Facts int32 `json:"facts"` + Detail map[string]string `json:"detail,omitempty"` +} + +// OmTopologySourceReports is the per-source receipt for one run, stored as JSONB. +// +// This is what makes a thin snapshot legible rather than merely thin: a run recorded with +// metrics=ok and probe=failed is still correct about every version and honest about +// reachability. +type OmTopologySourceReports []OmTopologySourceReport + +// Value implements database/sql/driver.Valuer. +func (r OmTopologySourceReports) Value() (driver.Value, error) { return jsonValue(r) } + +// Scan implements database/sql.Scanner. +func (r *OmTopologySourceReports) Scan(src any) error { return jsonScan(r, src) } + +// OmTopologyRunError describes one thing that went wrong during a run. +type OmTopologyRunError struct { + Scope string `json:"scope"` + ServiceName string `json:"service_name,omitempty"` + Code string `json:"code"` + Message string `json:"message"` +} + +// OmTopologyRunErrors is a run's failures, stored as JSONB. +type OmTopologyRunErrors []OmTopologyRunError + +// Value implements database/sql/driver.Valuer. +func (e OmTopologyRunErrors) Value() (driver.Value, error) { return jsonValue(e) } + +// Scan implements database/sql.Scanner. +func (e *OmTopologyRunErrors) Scan(src any) error { return jsonScan(e, src) } + +// OmTopologyRun records one execution of OM's topology collection. +// +// The run ID is the snapshot key, so a document always names the pass that produced it. +// +//reform:om_topology_runs +type OmTopologyRun struct { + RunID string `reform:"run_id,pk"` + StartedAt time.Time `reform:"started_at"` + FinishedAt *time.Time `reform:"finished_at"` + Status OmTopologyRunStatus `reform:"status"` + + ServicesTotal int32 `reform:"services_total"` + ServicesResolved int32 `reform:"services_resolved"` + ServicesOrphaned int32 `reform:"services_orphaned"` + ProbesOK int32 `reform:"probes_ok"` + ServicesStale int32 `reform:"services_stale"` + + OriginNode string `reform:"origin_node"` + Sources OmTopologySourceReports `reform:"sources"` + Errors OmTopologyRunErrors `reform:"errors"` + + CreatedAt time.Time `reform:"created_at"` +} + +// BeforeInsert implements reform.BeforeInserter. +func (r *OmTopologyRun) BeforeInsert() error { + now := Now() + r.CreatedAt = now + r.StartedAt = r.StartedAt.UTC() + if r.FinishedAt != nil { + finished := r.FinishedAt.UTC() + r.FinishedAt = &finished + } + return nil +} + +// AfterFind implements reform.AfterFinder. +func (r *OmTopologyRun) AfterFind() error { + r.CreatedAt = r.CreatedAt.UTC() + r.StartedAt = r.StartedAt.UTC() + if r.FinishedAt != nil { + finished := r.FinishedAt.UTC() + r.FinishedAt = &finished + } + return nil +} + +// OmTopologySnapshot holds one run's topology document. +// +// Stored as one JSONB document rather than a relational tree on purpose: the topology +// model is still moving -- replica sets, sharded clusters, routers, more metrics -- and a +// schema that has to be migrated for every shape change is a schema that discourages +// changing the shape. A reader checks schema_version instead. +// +//reform:om_topology_snapshots +type OmTopologySnapshot struct { + RunID string `reform:"run_id,pk"` + GeneratedAt time.Time `reform:"generated_at"` + ObservedAt *time.Time `reform:"observed_at"` + Stale bool `reform:"stale"` + SchemaVersion int32 `reform:"schema_version"` + Document []byte `reform:"document"` + CreatedAt time.Time `reform:"created_at"` +} + +// BeforeInsert implements reform.BeforeInserter. +func (s *OmTopologySnapshot) BeforeInsert() error { + s.CreatedAt = Now() + s.GeneratedAt = s.GeneratedAt.UTC() + if s.ObservedAt != nil { + observed := s.ObservedAt.UTC() + s.ObservedAt = &observed + } + return nil +} + +// AfterFind implements reform.AfterFinder. +func (s *OmTopologySnapshot) AfterFind() error { + s.CreatedAt = s.CreatedAt.UTC() + s.GeneratedAt = s.GeneratedAt.UTC() + if s.ObservedAt != nil { + observed := s.ObservedAt.UTC() + s.ObservedAt = &observed + } + return nil +} + +// Check that the models satisfy reform's hooks. +var ( + _ reform.BeforeInserter = (*OmTopologyRun)(nil) + _ reform.AfterFinder = (*OmTopologyRun)(nil) + _ reform.BeforeInserter = (*OmTopologySnapshot)(nil) + _ reform.AfterFinder = (*OmTopologySnapshot)(nil) +) diff --git a/managed/models/om_model_reform.go b/managed/models/om_model_reform.go new file mode 100644 index 00000000000..5ed26833db6 --- /dev/null +++ b/managed/models/om_model_reform.go @@ -0,0 +1,338 @@ +// Code generated by gopkg.in/reform.v1. DO NOT EDIT. + +package models + +import ( + "fmt" + "strings" + + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/parse" +) + +type omTopologyRunTableType struct { + s parse.StructInfo + z []interface{} +} + +// Schema returns a schema name in SQL database (""). +func (v *omTopologyRunTableType) Schema() string { + return v.s.SQLSchema +} + +// Name returns a view or table name in SQL database ("om_topology_runs"). +func (v *omTopologyRunTableType) Name() string { + return v.s.SQLName +} + +// Columns returns a new slice of column names for that view or table in SQL database. +func (v *omTopologyRunTableType) Columns() []string { + return []string{ + "run_id", + "started_at", + "finished_at", + "status", + "services_total", + "services_resolved", + "services_orphaned", + "probes_ok", + "services_stale", + "origin_node", + "sources", + "errors", + "created_at", + } +} + +// NewStruct makes a new struct for that view or table. +func (v *omTopologyRunTableType) NewStruct() reform.Struct { + return new(OmTopologyRun) +} + +// NewRecord makes a new record for that table. +func (v *omTopologyRunTableType) NewRecord() reform.Record { + return new(OmTopologyRun) +} + +// PKColumnIndex returns an index of primary key column for that table in SQL database. +func (v *omTopologyRunTableType) PKColumnIndex() uint { + return uint(v.s.PKFieldIndex) +} + +// OmTopologyRunTable represents om_topology_runs view or table in SQL database. +var OmTopologyRunTable = &omTopologyRunTableType{ + s: parse.StructInfo{ + Type: "OmTopologyRun", + SQLName: "om_topology_runs", + Fields: []parse.FieldInfo{ + {Name: "RunID", Type: "string", Column: "run_id"}, + {Name: "StartedAt", Type: "time.Time", Column: "started_at"}, + {Name: "FinishedAt", Type: "*time.Time", Column: "finished_at"}, + {Name: "Status", Type: "OmTopologyRunStatus", Column: "status"}, + {Name: "ServicesTotal", Type: "int32", Column: "services_total"}, + {Name: "ServicesResolved", Type: "int32", Column: "services_resolved"}, + {Name: "ServicesOrphaned", Type: "int32", Column: "services_orphaned"}, + {Name: "ProbesOK", Type: "int32", Column: "probes_ok"}, + {Name: "ServicesStale", Type: "int32", Column: "services_stale"}, + {Name: "OriginNode", Type: "string", Column: "origin_node"}, + {Name: "Sources", Type: "OmTopologySourceReports", Column: "sources"}, + {Name: "Errors", Type: "OmTopologyRunErrors", Column: "errors"}, + {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, + }, + PKFieldIndex: 0, + }, + z: new(OmTopologyRun).Values(), +} + +// String returns a string representation of this struct or record. +func (s OmTopologyRun) String() string { + res := make([]string, 13) + res[0] = "RunID: " + reform.Inspect(s.RunID, true) + res[1] = "StartedAt: " + reform.Inspect(s.StartedAt, true) + res[2] = "FinishedAt: " + reform.Inspect(s.FinishedAt, true) + res[3] = "Status: " + reform.Inspect(s.Status, true) + res[4] = "ServicesTotal: " + reform.Inspect(s.ServicesTotal, true) + res[5] = "ServicesResolved: " + reform.Inspect(s.ServicesResolved, true) + res[6] = "ServicesOrphaned: " + reform.Inspect(s.ServicesOrphaned, true) + res[7] = "ProbesOK: " + reform.Inspect(s.ProbesOK, true) + res[8] = "ServicesStale: " + reform.Inspect(s.ServicesStale, true) + res[9] = "OriginNode: " + reform.Inspect(s.OriginNode, true) + res[10] = "Sources: " + reform.Inspect(s.Sources, true) + res[11] = "Errors: " + reform.Inspect(s.Errors, true) + res[12] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true) + return strings.Join(res, ", ") +} + +// Values returns a slice of struct or record field values. +// Returned interface{} values are never untyped nils. +func (s *OmTopologyRun) Values() []interface{} { + return []interface{}{ + s.RunID, + s.StartedAt, + s.FinishedAt, + s.Status, + s.ServicesTotal, + s.ServicesResolved, + s.ServicesOrphaned, + s.ProbesOK, + s.ServicesStale, + s.OriginNode, + s.Sources, + s.Errors, + s.CreatedAt, + } +} + +// Pointers returns a slice of pointers to struct or record fields. +// Returned interface{} values are never untyped nils. +func (s *OmTopologyRun) Pointers() []interface{} { + return []interface{}{ + &s.RunID, + &s.StartedAt, + &s.FinishedAt, + &s.Status, + &s.ServicesTotal, + &s.ServicesResolved, + &s.ServicesOrphaned, + &s.ProbesOK, + &s.ServicesStale, + &s.OriginNode, + &s.Sources, + &s.Errors, + &s.CreatedAt, + } +} + +// View returns View object for that struct. +func (s *OmTopologyRun) View() reform.View { + return OmTopologyRunTable +} + +// Table returns Table object for that record. +func (s *OmTopologyRun) Table() reform.Table { + return OmTopologyRunTable +} + +// PKValue returns a value of primary key for that record. +// Returned interface{} value is never untyped nil. +func (s *OmTopologyRun) PKValue() interface{} { + return s.RunID +} + +// PKPointer returns a pointer to primary key field for that record. +// Returned interface{} value is never untyped nil. +func (s *OmTopologyRun) PKPointer() interface{} { + return &s.RunID +} + +// HasPK returns true if record has non-zero primary key set, false otherwise. +func (s *OmTopologyRun) HasPK() bool { + return s.RunID != OmTopologyRunTable.z[OmTopologyRunTable.s.PKFieldIndex] +} + +// SetPK sets record primary key, if possible. +// +// Deprecated: prefer direct field assignment where possible: s.RunID = pk. +func (s *OmTopologyRun) SetPK(pk interface{}) { + reform.SetPK(s, pk) +} + +// check interfaces +var ( + _ reform.View = OmTopologyRunTable + _ reform.Struct = (*OmTopologyRun)(nil) + _ reform.Table = OmTopologyRunTable + _ reform.Record = (*OmTopologyRun)(nil) + _ fmt.Stringer = (*OmTopologyRun)(nil) +) + +type omTopologySnapshotTableType struct { + s parse.StructInfo + z []interface{} +} + +// Schema returns a schema name in SQL database (""). +func (v *omTopologySnapshotTableType) Schema() string { + return v.s.SQLSchema +} + +// Name returns a view or table name in SQL database ("om_topology_snapshots"). +func (v *omTopologySnapshotTableType) Name() string { + return v.s.SQLName +} + +// Columns returns a new slice of column names for that view or table in SQL database. +func (v *omTopologySnapshotTableType) Columns() []string { + return []string{ + "run_id", + "generated_at", + "observed_at", + "stale", + "schema_version", + "document", + "created_at", + } +} + +// NewStruct makes a new struct for that view or table. +func (v *omTopologySnapshotTableType) NewStruct() reform.Struct { + return new(OmTopologySnapshot) +} + +// NewRecord makes a new record for that table. +func (v *omTopologySnapshotTableType) NewRecord() reform.Record { + return new(OmTopologySnapshot) +} + +// PKColumnIndex returns an index of primary key column for that table in SQL database. +func (v *omTopologySnapshotTableType) PKColumnIndex() uint { + return uint(v.s.PKFieldIndex) +} + +// OmTopologySnapshotTable represents om_topology_snapshots view or table in SQL database. +var OmTopologySnapshotTable = &omTopologySnapshotTableType{ + s: parse.StructInfo{ + Type: "OmTopologySnapshot", + SQLName: "om_topology_snapshots", + Fields: []parse.FieldInfo{ + {Name: "RunID", Type: "string", Column: "run_id"}, + {Name: "GeneratedAt", Type: "time.Time", Column: "generated_at"}, + {Name: "ObservedAt", Type: "*time.Time", Column: "observed_at"}, + {Name: "Stale", Type: "bool", Column: "stale"}, + {Name: "SchemaVersion", Type: "int32", Column: "schema_version"}, + {Name: "Document", Type: "[]uint8", Column: "document"}, + {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, + }, + PKFieldIndex: 0, + }, + z: new(OmTopologySnapshot).Values(), +} + +// String returns a string representation of this struct or record. +func (s OmTopologySnapshot) String() string { + res := make([]string, 7) + res[0] = "RunID: " + reform.Inspect(s.RunID, true) + res[1] = "GeneratedAt: " + reform.Inspect(s.GeneratedAt, true) + res[2] = "ObservedAt: " + reform.Inspect(s.ObservedAt, true) + res[3] = "Stale: " + reform.Inspect(s.Stale, true) + res[4] = "SchemaVersion: " + reform.Inspect(s.SchemaVersion, true) + res[5] = "Document: " + reform.Inspect(s.Document, true) + res[6] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true) + return strings.Join(res, ", ") +} + +// Values returns a slice of struct or record field values. +// Returned interface{} values are never untyped nils. +func (s *OmTopologySnapshot) Values() []interface{} { + return []interface{}{ + s.RunID, + s.GeneratedAt, + s.ObservedAt, + s.Stale, + s.SchemaVersion, + s.Document, + s.CreatedAt, + } +} + +// Pointers returns a slice of pointers to struct or record fields. +// Returned interface{} values are never untyped nils. +func (s *OmTopologySnapshot) Pointers() []interface{} { + return []interface{}{ + &s.RunID, + &s.GeneratedAt, + &s.ObservedAt, + &s.Stale, + &s.SchemaVersion, + &s.Document, + &s.CreatedAt, + } +} + +// View returns View object for that struct. +func (s *OmTopologySnapshot) View() reform.View { + return OmTopologySnapshotTable +} + +// Table returns Table object for that record. +func (s *OmTopologySnapshot) Table() reform.Table { + return OmTopologySnapshotTable +} + +// PKValue returns a value of primary key for that record. +// Returned interface{} value is never untyped nil. +func (s *OmTopologySnapshot) PKValue() interface{} { + return s.RunID +} + +// PKPointer returns a pointer to primary key field for that record. +// Returned interface{} value is never untyped nil. +func (s *OmTopologySnapshot) PKPointer() interface{} { + return &s.RunID +} + +// HasPK returns true if record has non-zero primary key set, false otherwise. +func (s *OmTopologySnapshot) HasPK() bool { + return s.RunID != OmTopologySnapshotTable.z[OmTopologySnapshotTable.s.PKFieldIndex] +} + +// SetPK sets record primary key, if possible. +// +// Deprecated: prefer direct field assignment where possible: s.RunID = pk. +func (s *OmTopologySnapshot) SetPK(pk interface{}) { + reform.SetPK(s, pk) +} + +// check interfaces +var ( + _ reform.View = OmTopologySnapshotTable + _ reform.Struct = (*OmTopologySnapshot)(nil) + _ reform.Table = OmTopologySnapshotTable + _ reform.Record = (*OmTopologySnapshot)(nil) + _ fmt.Stringer = (*OmTopologySnapshot)(nil) +) + +func init() { + parse.AssertUpToDate(&OmTopologyRunTable.s, new(OmTopologyRun)) + parse.AssertUpToDate(&OmTopologySnapshotTable.s, new(OmTopologySnapshot)) +} diff --git a/managed/services/grafana/auth_server.go b/managed/services/grafana/auth_server.go index afc83721fac..aa2c9c182ac 100644 --- a/managed/services/grafana/auth_server.go +++ b/managed/services/grafana/auth_server.go @@ -68,6 +68,22 @@ var rules = map[string]role{ "/server.v1.": admin, "/qan.v1.CollectorService.": viewer, "/qan.v1.QANService.": viewer, + // Reading OM over gRPC is a viewer's business; the writes are named exactly below. + // + // The HTTP methodRules cannot cover these: that table is keyed "METHOD /path" and a + // gRPC method name carries no verb, so /om.v1.OmService/DeleteInventoryHost would walk + // past every write rule and land here on viewer. A gRPC method name is unambiguous on + // its own, which is why these sit in `rules` rather than being method-qualified, the + // same as the agent and RTA endpoints above. + // + // The gateway reaches pmm-managed over HTTP, so in a normal deployment nothing uses + // these. They exist so the gRPC surface is not a way around the HTTP roles. + "/om.": viewer, + "/om.v1.OmService/TriggerInventoryRefresh": editor, + "/om.v1.OmService/DeleteInventoryHost": admin, + "/om.v1.OmService/DeleteInventoryService": admin, + "/om.v1.OmService/UpdateInventoryConfig": admin, + "/om.v1.OmService/DeleteInventoryConfigOverride": admin, "/v1/alerting": viewer, "/v1/alerting/rules": editor, @@ -106,6 +122,11 @@ var rules = map[string]role{ "/v1/qan": viewer, "/v1/qan:": viewer, + // Reading OM is a viewer's business. The writes are qualified by method in + // methodRules below -- /v1/om/inventory can forget rows, change the app's + // configuration and run code on database hosts, none of which a viewer may do. + "/v1/om": viewer, + "/prometheus": admin, "/victoriametrics": admin, "/nomad": admin, @@ -140,6 +161,40 @@ var methodRules = map[string]role{ http.MethodPost + " /v1/alerting/templates": editor, http.MethodPut + " /v1/alerting/templates/": editor, http.MethodDelete + " /v1/alerting/templates/": editor, + + // OM's inventory surface reads as viewer (see "/v1/om" above) but writes here. + // + // Refreshing is editor rather than admin. It runs SEP's fixed probe payload on the + // hosts it covers -- nothing the caller supplies, no database touched -- and the + // per-host refresh is the button beside a row that answers "I just fixed this, is it + // healthy now". Requiring admin for that would put the routine question behind the + // rarest role. + // The custom verb is part of the path, and it is the path that exists: there is no + // plain POST /v1/om/inventory/runs to gate. nextPrefix walks back past a colon, so a + // rule on the bare collection would match this too -- naming the real route instead + // keeps the rule readable as the thing it authorizes. + http.MethodPost + " /v1/om/inventory/runs:trigger": editor, + + // Forgetting a row and changing the app's configuration are both admin. A DELETE is + // not suppression -- the row returns on the next refresh if PMM still knows the + // entity -- but it is destructive to the annotations and history on that row. A + // configuration change sets the sweep schedule for the whole deployment, so it is + // the kind of thing one person does on everyone's behalf. + // + // The trailing slash on the id-bearing paths is not load-bearing: nextPrefix strips + // one as its own step, so the slash-less spelling would catch the same requests. + // It is kept because it reads as "everything under here" rather than as a path. + http.MethodDelete + " /v1/om/inventory/hosts/": admin, + http.MethodDelete + " /v1/om/inventory/services/": admin, + http.MethodPut + " /v1/om/inventory/config": admin, + + // Two rules for one route, on purpose. The first names the route that exists; the + // second is the backstop, because resolveRule walks longest prefix first and anything + // else that ever appears under config/ would otherwise fall through to the viewer rule + // at "/v1/om" -- which is the failure this table's test exists to catch. A DELETE + // anywhere under an app's configuration should default to admin, not to readable. + http.MethodDelete + " /v1/om/inventory/config/overrides/": admin, + http.MethodDelete + " /v1/om/inventory/config/": admin, } var lbacPrefixes = []string{ diff --git a/managed/services/grafana/auth_server_test.go b/managed/services/grafana/auth_server_test.go index a009ab5d185..601964ac7f8 100644 --- a/managed/services/grafana/auth_server_test.go +++ b/managed/services/grafana/auth_server_test.go @@ -76,6 +76,43 @@ func TestResolveRule(t *testing.T) { {http.MethodPut, "/v1/alerting/templates/foo", editor}, // UpdateTemplate {http.MethodDelete, "/v1/alerting/templates/foo", editor}, // DeleteTemplate {http.MethodPost, "/v1/alerting/rules", editor}, // CreateRule + + // OM: reading the estate is a viewer's, changing it is not. Asserted per path + // rather than trusted, because whether a write rule applies depends on how + // resolveRule walks prefixes, and that is not obvious from the rule table. It + // tries methodRules then rules at each prefix, and nextPrefix strips a trailing + // "/" as its own step -- so "/v1/om/inventory/hosts/" and + // "/v1/om/inventory/hosts" both catch a DELETE of an id under them. What would + // silently fall through to the viewer rule at "/v1/om" is a write path with no + // rule at all. + {http.MethodGet, "/v1/om/topology", viewer}, + {http.MethodGet, "/v1/om/inventory/hosts", viewer}, + {http.MethodGet, "/v1/om/inventory/hosts/node-1", viewer}, + {http.MethodGet, "/v1/om/inventory/services", viewer}, + {http.MethodGet, "/v1/om/inventory/config", viewer}, + {http.MethodPost, "/v1/om/inventory/runs:trigger", editor}, + {http.MethodDelete, "/v1/om/inventory/hosts/node-1", admin}, + {http.MethodDelete, "/v1/om/inventory/services/svc-1", admin}, + {http.MethodPut, "/v1/om/inventory/config", admin}, + {http.MethodDelete, "/v1/om/inventory/config/overrides/SCHEDULE__every", admin}, + // The backstop: no such route today, but a DELETE under an app's configuration + // must not degrade to the viewer rule at "/v1/om" if one is ever added. + {http.MethodDelete, "/v1/om/inventory/config/anything-else", admin}, + // PMM's own collection pass stays viewer: it recomputes a document from data PMM + // already holds and never reaches a host. + {http.MethodPost, "/v1/om/topology/runs:collect", viewer}, + + // The same surface over gRPC. methodRules cannot reach these -- a gRPC method + // name carries no HTTP verb -- so without exact entries every one of them walks + // past the write rules and lands on the viewer rule at "/om.". + {http.MethodPost, "/om.v1.OmService/GetTopology", viewer}, + {http.MethodPost, "/om.v1.OmService/ListInventoryHosts", viewer}, + {http.MethodPost, "/om.v1.OmService/TriggerInventoryRefresh", editor}, + {http.MethodPost, "/om.v1.OmService/DeleteInventoryHost", admin}, + {http.MethodPost, "/om.v1.OmService/DeleteInventoryService", admin}, + {http.MethodPost, "/om.v1.OmService/UpdateInventoryConfig", admin}, + {http.MethodPost, "/om.v1.OmService/DeleteInventoryConfigOverride", admin}, + // No matching rule falls back to grafanaAdmin. {http.MethodGet, "/v1/unknown", grafanaAdmin}, } { diff --git a/managed/services/ha/haservice.go b/managed/services/ha/haservice.go index 19de9cd0184..ec63fb11b86 100644 --- a/managed/services/ha/haservice.go +++ b/managed/services/ha/haservice.go @@ -600,6 +600,18 @@ func (s *Service) IsLeader() bool { return !s.params.Enabled || (s.raftNode != nil && s.raftNode.State() == raft.Leader) } +// LeaderID returns the current Raft leader's node ID, or "" when HA is disabled or no +// leader is known yet. +func (s *Service) LeaderID() string { + s.rw.RLock() + defer s.rw.RUnlock() + if !s.params.Enabled || s.raftNode == nil { + return "" + } + _, leaderID := s.raftNode.LeaderWithID() + return string(leaderID) +} + // Params returns HA parameters. func (s *Service) Params() *models.HAParams { return s.params diff --git a/managed/services/om/catalog.go b/managed/services/om/catalog.go new file mode 100644 index 00000000000..232a2beb0f8 --- /dev/null +++ b/managed/services/om/catalog.go @@ -0,0 +1,194 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "time" + + omv1 "github.com/percona/pmm/api/om/v1" +) + +// The signal catalog: exactly the queries the topology document needs, and nothing +// speculative. Every query aggregates or is keyed by service_id, which is the only safe +// join key -- a service name is reused across re-registrations while the superseded +// series live on until retention expires, so a name-keyed join silently mixes +// generations. +const ( + // The exporter's info metric: identity, running version, vendor and edition. + metricVersionInfo = "mongodb_version_info" + // The replSetGetStatus view as seen from the member itself -- its own member_state. + // The sibling mongodb_rs_members_state carries one series per peer; this one is a + // single series describing the node being asked. + metricMembersSelf = "mongodb_members_self" + // The exporter's own reachability flag. A service that is down produces no series at + // all rather than a 0, so absence is what the document reads as DOWN. + metricUp = "mongodb_up" + // Emitted only by a mongos, so its presence is the router test -- more reliable than + // the port convention, which only ever guessed. + metricMongosShards = "mongodb_mongos_sharding_shards_total" + // Seconds a peer trails the primary's optime. Several series per service, one per + // (reporting node, secondary peer), so it needs a reducer. The primary appears in no + // series by construction, and a single-member set emits nothing at all -- which is + // "not applicable" rather than "not collected". + metricReplicationLag = "mongodb_mongod_replset_member_replication_lag" + // Oplog bounds as epoch seconds; their difference is the window. One series per + // service each. A standalone emits neither -- no replica set, no oplog. + metricOplogHead = "mongodb_mongod_replset_oplog_head_timestamp" + metricOplogTail = "mongodb_mongod_replset_oplog_tail_timestamp" +) + +// Derived percentages. Neither exists as a series, so both are expressions. %[1]s is the +// series matcher -- the service_id set and highResolutionJob -- and %[2]s the freshness +// window; both aggregate by (service_id) so the result still joins back to a service. +// +// The CPU expression needs no last_over_time: irate over a 30s range already requires +// two raw samples inside it, so a service that stopped reporting drops out on its own. +const ( + queryCPUUsage = `100 * (1 - sum by (service_id) (irate(mongodb_sys_cpu_idle_ms{%[1]s}[30s]))` + + ` / (1000 * max by (service_id) (last_over_time(mongodb_sys_cpu_num_logical_cores{%[1]s}[%[2]s]))))` + queryConnectionsFree = `100 * max by (service_id) (last_over_time(mongodb_connections{%[1]s,state="available"}[%[2]s]))` + + ` / (max by (service_id) (last_over_time(mongodb_connections{%[1]s,state="current"}[%[2]s]))` + + ` + max by (service_id) (last_over_time(mongodb_connections{%[1]s,state="available"}[%[2]s])))` +) + +// metricsLookback is the window every query is read over. +// +// Deliberately long, and deliberately not the freshness rule. Without an explicit window +// this would be VictoriaMetrics' instant-query lookbehind of five minutes, so a query +// returns nothing whenever scraping paused -- indistinguishable from "no such service". +// Reading over a day instead means a since-unreachable node still contributes what it +// last reported, carrying the age that says so. Whether that age is too old to act on is +// a separate decision, made per field by volatileFields and volatileMaxAge. +const metricsLookback = "24h" + +// highResolutionJob narrows every query to the high-resolution scrape job, which is what +// makes volatileMaxAge meaningful. +// +// Each exporter is scraped once per resolution, so a metric it emits on every scrape +// regardless of collector flags arrives once per job. That is what mongodb_up is: an hr and +// an lr series per service. The lr series' age swings up to its own 60s interval, so a +// volatile fact read from it is stale for most of every minute while the hr sample is +// seconds old -- and sizing volatileMaxAge off lr instead would blunt every volatile field +// to minutes to accommodate one metric. The management package selects its own "up" metrics +// the same way. +// +// What this does not make true is "one series per service per metric", which nothing does: +// an exporter's label set changes over its own lifetime -- cluster_role appears once it can +// determine the role -- so it abandons a series and begins another under the same +// service_id. Pairing each sample with its own series' age is what handles that, not this +// matcher; see seriesSample.supersedes. +const highResolutionJob = `job=~".*_hr$"` + +// How old a volatile observation may be and still count as current. +// +// Sized against the scrape interval rather than picked: every query carries +// highResolutionJob, so the window is volatileMaxAgeFactor of PMM's configured high +// resolution, floored by minVolatileMaxAge. Four intervals tolerates several missed +// scrapes while still noticing a stopped database in well under a minute. +const ( + volatileMaxAgeFactor = 4 + minVolatileMaxAge = 30 * time.Second +) + +// sourceQueries names what the document was derived from, and is carried in the document +// so a reader can see that without reading this file. Ordered as the collector issues +// them. +var sourceQueries = []string{ + metricVersionInfo, + metricMembersSelf, + metricUp, + metricMongosShards, + "mongodb_sys_cpu_idle_ms", + "mongodb_connections", + metricReplicationLag, + metricOplogHead, + metricOplogTail, +} + +// The document fields sources set. Names match SEP's om_inventory app so a fact +// produced there needs no translation on the way in. +const ( + fieldHost = "host" + fieldServiceType = "service_type" + fieldCluster = "cluster" + fieldReplicationSet = "replication_set" + fieldEnvironment = "environment" + fieldVersion = "version" + fieldVendor = "vendor" + fieldEdition = "edition" + fieldState = "state" + fieldEndpoint = "endpoint" + fieldClusterRole = "cluster_role" + fieldExporterUp = "exporter_up" + fieldCPUUsage = "cpu_usage_percent" + fieldConnectionsFree = "connections_free_percent" + fieldIsMongos = "is_mongos" + fieldReplicationLag = "replication_lag_seconds" + fieldOplogHead = "oplog_head_timestamp" + fieldOplogTail = "oplog_tail_timestamp" + fieldInstalledVersion = "installed_version" + fieldConfigPath = "config_path" + fieldArgv = "argv" +) + +// volatileFields are the fields that describe now rather than describe the service. +// +// Everything is collected over metricsLookback and kept with its age, so the document can +// still say what a since-unreachable node last reported. But these fields are only +// meaningful while fresh: a replica-set state or an up flag from an hour ago is not a +// fact about the present, whereas an edition is. Reading one past volatileMaxAge yields +// nothing, which is what turns a stopped database into status DOWN instead of a +// confident, day-old UP. +var volatileFields = map[string]bool{ + fieldState: true, + fieldClusterRole: true, + fieldExporterUp: true, + fieldCPUUsage: true, + fieldConnectionsFree: true, + fieldIsMongos: true, + fieldReplicationLag: true, + fieldOplogHead: true, + fieldOplogTail: true, +} + +// clusterRoles maps the exporter's cl_role label onto the document's process_role. +// +// The label is the exporter's vocabulary and the enum is ours, so this is the only place +// the two meet. A label we do not recognise falls through to PROCESS_ROLE_MONGOD rather +// than UNSPECIFIED: an unlabelled mongod is the ordinary case, not a gap. +var clusterRoles = map[string]omv1.ProcessRole{ + "configsvr": omv1.ProcessRole_PROCESS_ROLE_CONFIGSVR, + "shardsvr": omv1.ProcessRole_PROCESS_ROLE_SHARDSVR, +} + +// unmeasured is the gauge sentinel: -1 rather than null so the field stays a number for +// every service, and rather than 0 because zero CPU is a legitimate reading. +const unmeasured = -1 + +// unspecified is the grouping key for a service whose environment or cluster is unset. +// Internal only -- the document emits null for it, because inventing the string +// "UNSPECIFIED" as a name would make it indistinguishable from a real environment +// called that. +const unspecified = "UNSPECIFIED" + +// schemaVersion is the version of the emitted document. Versioned so that a stored +// snapshot stays readable across changes. +// +// Starts at 1: nothing has shipped yet, so there is no prior version's snapshot a reader +// needs to keep distinguishing from this one. A dev database is one `./om reset data` +// away, which is what makes 1 the honest number rather than leftover numbering from +// development. +const schemaVersion = 1 diff --git a/managed/services/om/deps.go b/managed/services/om/deps.go new file mode 100644 index 00000000000..238ab420bee --- /dev/null +++ b/managed/services/om/deps.go @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "time" + + v1 "github.com/prometheus/client_golang/api/prometheus/v1" + "github.com/prometheus/common/model" +) + +// victoriaMetricsClient is a subset of methods of prometheus' API used by this package. +type victoriaMetricsClient interface { + Query(ctx context.Context, query string, ts time.Time, opts ...v1.Option) (model.Value, v1.Warnings, error) +} + +// haChecker reports HA leadership, so a write-triggering RPC can refuse on a follower +// rather than race the leader for the same collection. +// +// Optional like probe: a Service built without one (every test in this package but the +// ones that care) treats every node as the leader, which is the single-node default too. +type haChecker interface { + IsLeader() bool + LeaderID() string +} diff --git a/managed/services/om/facts.go b/managed/services/om/facts.go new file mode 100644 index 00000000000..886e8346198 --- /dev/null +++ b/managed/services/om/facts.go @@ -0,0 +1,359 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "slices" + "time" +) + +// The common currency every collection source deals in. +// +// Collection reads the same MongoDB estate from several places -- PMM's inventory, +// VictoriaMetrics, and (later) a SEP app running probes on Nomad clients -- and each +// knows a different, overlapping subset of the truth. Rather than special-case the +// sources against each other, every one of them emits the same thing: flat Fact records +// keyed by (service, field). Adding a source is then implementing one interface and +// changes nothing downstream. +// +// Merging is by declared precedence per field, never by call order. That is what makes +// "who wins" a piece of configuration rather than an accident of which source happened +// to run last, and it is why every merged field keeps its provenance: a document that +// cannot say where a version came from cannot distinguish "the node reports 7.0.39" from +// "the node reported 7.0.39 nine days ago and has been unreachable since". +// +// The field names and the precedence table are kept in step with om_inventory, whose +// facts merge here. + +// SourceStatus says how completely one source answered. +// +// Recorded per source on the run, so a thin document is legible rather than merely thin: +// a snapshot assembled with metrics=OK, probe=FAILED is still correct about every version +// and honest about reachability. +type SourceStatus string + +// The states a source can report. +const ( + // SourceOK means the source answered for every service asked about. + SourceOK SourceStatus = "ok" + // SourcePartial means it answered for some services but not all. + SourcePartial SourceStatus = "partial" + // SourceFailed means it answered for none, or errored. + SourceFailed SourceStatus = "failed" + // SourceDisabled means it was switched off and never ran. + SourceDisabled SourceStatus = "disabled" +) + +// Source keys. These are the strings the precedence table and the run receipt use, and +// they are part of the contract with anything that contributes facts. +const ( + sourceInventory = "inventory" + sourceMetrics = "metrics" + // The SEP inventory app's on-host facts -- argv, config paths, the installed binary + // version. Produced by probeSource in probe_source.go, which reads them off SEP's + // om_inventory app rather than probing anything itself; see that file for why. + sourceProbe = "probe" +) + +// Fact is keyed by PMM service, deliberately, not by host. +// +// A host with three mongods and no service PMM has registered -- the case this product +// exists to describe -- cannot contribute a fact the merge will keep, and neither can a +// naturally per-host probe attribute like repo_reachable or executor_reachable. That is a +// real gap and a decided one, not an oversight: host attributes live only on +// /v1/om/inventory/hosts (inventory.go), reached through a separate API rather than +// folded into this document. The alternative -- widening Fact with an optional node key +// so the merge becomes (node|service, field) -- was considered and deferred, because +// projection would then have to decide whether a host fact attaches to every service on +// that node or to some new slot, which is bigger than a fact-source addition. Until that +// lands, a naturally-per-host probe attribute must not be stuffed into every service row +// on its node: the copies would disagree the moment one of them changed. +// +// Fact carries one field about one service, as one source saw it. +type Fact struct { + // Service is the PMM service ID this is about. + Service string + // Field is the document field this sets, e.g. "version". + Field string + // Value is the observed value. + Value any + // Source is the source key that produced it. + Source string + // ObservedAt is when the underlying observation was taken, or nil for a source that + // is not time-bounded. Inventory is not time-bounded: it is current by definition. A + // metric sample very much is. + ObservedAt *time.Time +} + +// MergedField is one field after precedence has picked a winner, with its provenance. +type MergedField struct { + Value any + Source string + ObservedAt *time.Time +} + +// age returns how old the observation is at now, and whether it is datable at all. +func (m MergedField) age(now time.Time) (time.Duration, bool) { + if m.ObservedAt == nil { + return 0, false + } + return now.Sub(*m.ObservedAt), true +} + +// SourceResult reports everything one source produced in one collection run. +type SourceResult struct { + // Source is the source key. + Source string + // Status is how completely it answered. + Status SourceStatus + // Facts is every fact it produced. + Facts []Fact + // Detail holds source-specific counters and errors, and lands verbatim in the run + // receipt. This is what makes a thin snapshot legible. + Detail map[string]any + // Errors are per-service or per-query failures worth surfacing on the run. + Errors []RunError +} + +// RunError describes one thing that went wrong, scoped to whatever it concerns. +type RunError struct { + Scope string + ServiceName string + Code string + Message string +} + +// precedenceDefaultKey is the key under which the table holds the fallback ordering used +// by any field that does not name one of its own. +const precedenceDefaultKey = "default" + +// defaultPrecedence declares, per field, which sources may set it and in what order. +// +// A source not listed for a field is forbidden from setting it, which is the point: it +// makes "the probe must never override the exporter's idea of replica-set state" a line +// in a table rather than a convention someone has to remember. +// +// - version -- metrics first: mongodb_version_info is the running server's own report. +// The probe sees the same thing from the node and is the fallback. +// - installed_version -- probe only. The binary on disk is invisible to any metric, +// and it is the whole upgrade-readiness signal. +// - vendor / edition -- mongodb_version_info is the only source of either anywhere. +// - endpoint -- member_idx is how the replica set itself addresses the member, which +// beats inventory's record of where PMM reached the agent. Inventory stays the +// fallback, and is the only source for a mongos, which has no member_idx. +// - state -- metrics first, because a member's state as reported through the exporter +// covers services the probe cannot reach at all. +// - the exporter-only concepts -- reachability, load, role -- name metrics alone. +var defaultPrecedence = map[string][]string{ + precedenceDefaultKey: {sourceMetrics, sourceInventory, sourceProbe}, + + fieldVersion: {sourceMetrics, sourceProbe}, + fieldInstalledVersion: {sourceProbe}, + fieldConfigPath: {sourceProbe}, + fieldArgv: {sourceProbe}, + fieldVendor: {sourceMetrics}, + fieldEdition: {sourceMetrics}, + fieldEndpoint: {sourceMetrics, sourceInventory}, + fieldState: {sourceMetrics, sourceProbe}, + + fieldReplicationLag: {sourceMetrics}, + fieldOplogHead: {sourceMetrics}, + fieldOplogTail: {sourceMetrics}, + + fieldExporterUp: {sourceMetrics}, + fieldCPUUsage: {sourceMetrics}, + fieldConnectionsFree: {sourceMetrics}, + fieldClusterRole: {sourceMetrics}, + fieldIsMongos: {sourceMetrics}, +} + +// mergeFacts folds every source's facts into one merged view per service. +// +// For each (service, field) the winner is the fact from the earliest source listed for +// that field. Facts from a source the field does not list are dropped rather than +// silently accepted, and a nil value never wins: a source that looked and saw nothing +// must not shadow one that looked and saw something. +// +// Ties at the same rank are broken by recency, which matters more than it sounds. One +// service can carry several series of the same metric -- a replica-set reconfiguration +// leaves the superseded mongodb_members_self behind, and it survives in the lookback +// window alongside the live one. Measured here: one member reported PRIMARY at 0s, +// SECONDARY at 7500s and PRIMARY at 68477s, all under its current service_id. Without +// this rule the document takes whichever the query happened to return first, and calls a +// live primary a secondary. +func mergeFacts(results []SourceResult, precedence map[string][]string) map[string]map[string]MergedField { + merged := make(map[string]map[string]MergedField) + + for _, result := range results { + for _, fact := range result.Facts { + if fact.Value == nil || fact.Service == "" { + continue + } + order, ok := precedence[fact.Field] + if !ok { + order = precedence[precedenceDefaultKey] + } + rank := slices.Index(order, fact.Source) + if rank < 0 { + continue + } + + fields, ok := merged[fact.Service] + if !ok { + fields = make(map[string]MergedField) + merged[fact.Service] = fields + } + if held, ok := fields[fact.Field]; ok && !supersedes(fact, held, order, rank) { + continue + } + fields[fact.Field] = MergedField{ + Value: fact.Value, + Source: fact.Source, + ObservedAt: fact.ObservedAt, + } + } + } + return merged +} + +// supersedes reports whether an incoming fact should displace the one already held. +// +// Rank decides first. At equal rank -- the same source reporting the same field twice, +// which is what several series for one service look like -- the newer observation wins. +// An undatable fact never displaces a datable one, and never displaces its own kind: +// with nothing to compare, first seen stays. +func supersedes(fact Fact, held MergedField, order []string, rank int) bool { + heldRank := slices.Index(order, held.Source) + if heldRank != rank { + return heldRank > rank + } + if fact.ObservedAt == nil { + return false + } + if held.ObservedAt == nil { + return true + } + return fact.ObservedAt.After(*held.ObservedAt) +} + +// fieldSet is one service's merged fields plus the freshness rule to read them under. +// +// The rule travels with the data rather than sitting in a package variable: it is +// derived per run from PMM's configured scrape resolution, and a projection that read it +// from somewhere else could disagree with the collection it is projecting. +type fieldSet struct { + fields map[string]MergedField + now time.Time + maxAge time.Duration +} + +// str returns a string field, or "" when it is unset, stale, or of another type. +func (f fieldSet) str(field string) string { + value, ok := f.live(field) + if !ok { + return "" + } + s, _ := value.(string) + return s +} + +// f64 returns a float field, or nil when it is unset or stale. +func (f fieldSet) f64(field string) *float64 { + value, ok := f.live(field) + if !ok { + return nil + } + v, ok := value.(float64) + if !ok { + return nil + } + return &v +} + +// truthy reports whether a boolean field is set, fresh and true. +func (f fieldSet) truthy(field string) bool { + value, ok := f.live(field) + if !ok { + return false + } + v, _ := value.(bool) + return v +} + +// live returns a field's value, dropping it when it is a volatile field whose +// observation has aged out. +// +// This is the half SEP records but does not act on. Facts are collected over a long +// window and kept with their age -- that is what tells "this service is gone" apart from +// "this service has not been scraped since Tuesday" -- but a volatile fact past its age +// must not be read as current. A replica-set state or an up flag from an hour ago is not +// a fact about now; an edition is. +func (f fieldSet) live(field string) (any, bool) { + held, ok := f.fields[field] + if !ok { + return nil, false + } + if !volatileFields[field] { + return held.Value, true + } + age, datable := held.age(f.now) + if datable && age > f.maxAge { + return nil, false + } + return held.Value, true +} + +// newestObservedAt returns the most recent observation among this row's live fields, or +// nil when none of them carry one at all. +// +// This is the row's own provenance, as against Snapshot.observed_at which is the newest +// across the whole estate and so cannot tell "this row is current" from "this row merely +// did not drag the snapshot's headline age down". An inventory-only fact has no +// ObservedAt to begin with, and a volatile fact that aged out is excluded the same way +// live() excludes it from a read -- a fact too old to read as current should not read as +// current here either. +func (f fieldSet) newestObservedAt() *time.Time { + var newest *time.Time + for field, held := range f.fields { + if held.ObservedAt == nil { + continue + } + if volatileFields[field] { + if _, ok := f.live(field); !ok { + continue + } + } + if newest == nil || held.ObservedAt.After(*newest) { + newest = held.ObservedAt + } + } + return newest +} + +// staleVolatile counts the volatile fields dropped for age, which the run receipt reports +// so a thin document says why it is thin. +func (f fieldSet) staleVolatile() int { + stale := 0 + for field, held := range f.fields { + if !volatileFields[field] { + continue + } + if age, datable := held.age(f.now); datable && age > f.maxAge { + stale++ + } + } + return stale +} diff --git a/managed/services/om/facts_test.go b/managed/services/om/facts_test.go new file mode 100644 index 00000000000..8006b2ead9e --- /dev/null +++ b/managed/services/om/facts_test.go @@ -0,0 +1,244 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMergeFacts(t *testing.T) { + t.Parallel() + + now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC) + + t.Run("precedence decides, not call order", func(t *testing.T) { + t.Parallel() + + // The probe is listed after metrics for version, so it loses however late it runs. + merged := mergeFacts([]SourceResult{ + {Source: sourceProbe, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: "7.0.1", Source: sourceProbe}, + }}, + {Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: "7.0.39", Source: sourceMetrics, ObservedAt: new(now)}, + }}, + }, defaultPrecedence) + + require.Contains(t, merged, "s1") + assert.Equal(t, "7.0.39", merged["s1"][fieldVersion].Value) + assert.Equal(t, sourceMetrics, merged["s1"][fieldVersion].Source) + }) + + t.Run("the fallback source wins when the preferred one is silent", func(t *testing.T) { + t.Parallel() + + merged := mergeFacts([]SourceResult{ + {Source: sourceInventory, Facts: []Fact{ + {Service: "s1", Field: fieldEndpoint, Value: "host:27017", Source: sourceInventory}, + }}, + {Source: sourceMetrics, Facts: []Fact{}}, + }, defaultPrecedence) + + assert.Equal(t, "host:27017", merged["s1"][fieldEndpoint].Value) + assert.Equal(t, sourceInventory, merged["s1"][fieldEndpoint].Source) + }) + + t.Run("a source not listed for a field cannot set it", func(t *testing.T) { + t.Parallel() + + // exporter_up names metrics alone: reachability is not the probe's to assert. + merged := mergeFacts([]SourceResult{ + {Source: sourceProbe, Facts: []Fact{ + {Service: "s1", Field: fieldExporterUp, Value: 1.0, Source: sourceProbe}, + }}, + }, defaultPrecedence) + + assert.NotContains(t, merged["s1"], fieldExporterUp) + }) + + t.Run("probe-only fields are reserved and merge untouched", func(t *testing.T) { + t.Parallel() + + merged := mergeFacts([]SourceResult{ + {Source: sourceProbe, Facts: []Fact{ + {Service: "s1", Field: fieldInstalledVersion, Value: "7.0.40", Source: sourceProbe}, + }}, + {Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldInstalledVersion, Value: "nonsense", Source: sourceMetrics}, + }}, + }, defaultPrecedence) + + assert.Equal(t, "7.0.40", merged["s1"][fieldInstalledVersion].Value) + }) + + t.Run("a nil value never shadows a real one", func(t *testing.T) { + t.Parallel() + + merged := mergeFacts([]SourceResult{ + {Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: nil, Source: sourceMetrics}, + }}, + {Source: sourceProbe, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: "7.0.39", Source: sourceProbe}, + }}, + }, defaultPrecedence) + + assert.Equal(t, "7.0.39", merged["s1"][fieldVersion].Value) + }) + + t.Run("the freshest series wins when one service has several", func(t *testing.T) { + t.Parallel() + + // A replica-set reconfiguration leaves the superseded mongodb_members_self behind, + // and it survives in the lookback window under the same service_id. Measured in + // the sandbox: PRIMARY at 0s, SECONDARY at 7500s, PRIMARY at 68477s. Rank cannot + // separate them -- they are all the metrics source -- so recency has to. + fresh := now + stale := now.Add(-7500 * time.Second) + ancient := now.Add(-68477 * time.Second) + + for _, order := range [][]Fact{ + { + {Service: "s1", Field: fieldState, Value: "SECONDARY", Source: sourceMetrics, ObservedAt: new(stale)}, + {Service: "s1", Field: fieldState, Value: "PRIMARY", Source: sourceMetrics, ObservedAt: new(fresh)}, + {Service: "s1", Field: fieldState, Value: "PRIMARY", Source: sourceMetrics, ObservedAt: new(ancient)}, + }, + // The same facts the other way round: the answer must not depend on the order + // VictoriaMetrics happened to return them in. + { + {Service: "s1", Field: fieldState, Value: "PRIMARY", Source: sourceMetrics, ObservedAt: new(fresh)}, + {Service: "s1", Field: fieldState, Value: "SECONDARY", Source: sourceMetrics, ObservedAt: new(stale)}, + }, + } { + merged := mergeFacts([]SourceResult{{Source: sourceMetrics, Facts: order}}, defaultPrecedence) + assert.Equal(t, "PRIMARY", merged["s1"][fieldState].Value) + assert.Equal(t, fresh, *merged["s1"][fieldState].ObservedAt) + } + }) + + t.Run("a higher-precedence source still wins over a fresher low-precedence one", func(t *testing.T) { + t.Parallel() + + // Recency only breaks ties. It must not let the probe outrank metrics for version + // just by having looked more recently. + merged := mergeFacts([]SourceResult{ + {Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: "7.0.39", Source: sourceMetrics, ObservedAt: new(now.Add(-time.Hour))}, + }}, + {Source: sourceProbe, Facts: []Fact{ + {Service: "s1", Field: fieldVersion, Value: "7.0.1", Source: sourceProbe, ObservedAt: new(now)}, + }}, + }, defaultPrecedence) + + assert.Equal(t, "7.0.39", merged["s1"][fieldVersion].Value) + }) + + t.Run("provenance survives the merge", func(t *testing.T) { + t.Parallel() + + observed := now.Add(-90 * time.Second) + merged := mergeFacts([]SourceResult{ + {Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldState, Value: "PRIMARY", Source: sourceMetrics, ObservedAt: new(observed)}, + }}, + }, defaultPrecedence) + + held := merged["s1"][fieldState] + require.NotNil(t, held.ObservedAt) + assert.Equal(t, observed, *held.ObservedAt) + + age, datable := held.age(now) + assert.True(t, datable) + assert.Equal(t, 90*time.Second, age) + }) +} + +func TestFieldSetFreshness(t *testing.T) { + t.Parallel() + + now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC) + maxAge := 30 * time.Second + + newFields := func(age time.Duration) fieldSet { + observed := now.Add(-age) + return fieldSet{ + now: now, + maxAge: maxAge, + fields: map[string]MergedField{ + // Volatile: only meaningful while fresh. + fieldExporterUp: {Value: 1.0, Source: sourceMetrics, ObservedAt: new(observed)}, + fieldState: {Value: "PRIMARY", Source: sourceMetrics, ObservedAt: new(observed)}, + // Durable: describes the service, not the moment. + fieldVersion: {Value: "7.0.39", Source: sourceMetrics, ObservedAt: new(observed)}, + fieldEdition: {Value: "Community", Source: sourceMetrics, ObservedAt: new(observed)}, + }, + } + } + + t.Run("fresh volatile facts read through", func(t *testing.T) { + t.Parallel() + + fields := newFields(5 * time.Second) + assert.InDelta(t, 1.0, *fields.f64(fieldExporterUp), 0.001) + assert.Equal(t, "PRIMARY", fields.str(fieldState)) + assert.Zero(t, fields.staleVolatile()) + }) + + t.Run("stale volatile facts are dropped, durable ones are kept", func(t *testing.T) { + t.Parallel() + + // This is the case that made a stopped database report UP: the sample survives in + // the long lookback window, and only the age says it is not about now. + fields := newFields(10 * time.Minute) + assert.Nil(t, fields.f64(fieldExporterUp)) + assert.Empty(t, fields.str(fieldState)) + assert.Equal(t, "7.0.39", fields.str(fieldVersion), "a version does not go stale") + assert.Equal(t, "Community", fields.str(fieldEdition)) + assert.Equal(t, 2, fields.staleVolatile()) + }) + + t.Run("an undatable fact is never stale", func(t *testing.T) { + t.Parallel() + + // Inventory is current by definition and carries no observed_at. + fields := fieldSet{ + now: now, + maxAge: maxAge, + fields: map[string]MergedField{ + fieldEndpoint: {Value: "host:27017", Source: sourceInventory}, + }, + } + assert.Equal(t, "host:27017", fields.str(fieldEndpoint)) + }) + + t.Run("a missing or mistyped field reads as absent", func(t *testing.T) { + t.Parallel() + + fields := fieldSet{ + now: now, + maxAge: maxAge, + fields: map[string]MergedField{fieldVersion: {Value: 42, Source: sourceMetrics}}, + } + assert.Empty(t, fields.str(fieldVersion)) + assert.Empty(t, fields.str(fieldVendor)) + assert.Nil(t, fields.f64(fieldCPUUsage)) + assert.False(t, fields.truthy(fieldIsMongos)) + }) +} diff --git a/managed/services/om/inventory.go b/managed/services/om/inventory.go new file mode 100644 index 00000000000..36782fced10 --- /dev/null +++ b/managed/services/om/inventory.go @@ -0,0 +1,841 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "math" + "net/http" + "net/url" + "strconv" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" + + omv1 "github.com/percona/pmm/api/om/v1" +) + +// The /v1/om/inventory/* handlers: SEP's estate, served through PMM. +// +// Two different things are called a "run" one path segment apart, so they are mounted +// apart on purpose. /v1/om/topology/runs is PMM's *own* collection pass -- inventory +// plus VictoriaMetrics, a tenth of a second, never touches a host. /v1/om/inventory/runs +// dispatches a Nomad job per host and takes tens of seconds. Nothing but the path tells +// a caller which one they are about to start, which is why the surface does. +// +// The projection below is deliberately dull. Everything interesting about the estate -- +// what counts as failing, when a row is stale, which of three ways an executor is +// unusable -- was decided in the app, and re-deciding any of it here would give a reader +// two answers to the same question. + +// defaultInventoryRunLimit is what a caller who passes no limit gets, and +// maxInventoryRunLimit is the most one can ask for. The ceiling exists because the value +// is forwarded to SEP verbatim: without it a caller could ask the inventory app for an +// unbounded page and wait on it through this proxy. Matches the proto's own +// ListInventoryRunsRequest.limit validation (lte: 100) and SEP's le=100 -- any of the +// three drifting from the others makes one of them dead code, since the request has to +// clear all of them to reach the database. +const ( + defaultInventoryRunLimit = 20 + maxInventoryRunLimit = 100 +) + +// inventoryProbe returns the configured SEP client, or an error saying it is not. +// +// Reported as FailedPrecondition rather than Unimplemented or NotFound: the endpoints +// exist and work, the deployment has simply not been told where SEP is, and that is an +// operator's action rather than a missing feature. +// +// Returns sepApp, not *probeSource: the inventory handlers below only ever need to call +// against om_inventory, never any of probeSource's own factSource behaviour, and holding +// the narrower handle is what keeps this file from knowing probeSource exists at all. +func (s *Service) inventoryProbe() (sepApp, error) { + if s.probe == nil { + return sepApp{}, status.Error(codes.FailedPrecondition, + "SEP is not configured; set PMM_SEP_URL and PMM_SEP_TOKEN to reach the inventory app") + } + return s.probe.app, nil +} + +// ListInventoryHosts returns every host the inventory app has a row for. +func (s *Service) ListInventoryHosts(ctx context.Context, req *omv1.ListInventoryHostsRequest) (*omv1.ListInventoryHostsResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + query := url.Values{} + if req.HasService != nil { + query.Set("has_service", strconv.FormatBool(req.GetHasService())) + } + if req.Failing != nil { + query.Set("failing", strconv.FormatBool(req.GetFailing())) + } + if req.Executor != nil { + query.Set("executor", strconv.FormatBool(req.GetExecutor())) + } + + hosts := []sepHost{} + call := inventoryCall{method: http.MethodGet, path: "hosts", query: query} + err = probe.call(ctx, call, &hosts) + if err != nil { + return nil, err + } + + response := &omv1.ListInventoryHostsResponse{Hosts: make([]*omv1.InventoryHost, 0, len(hosts))} + for _, host := range hosts { + response.Hosts = append(response.Hosts, inventoryHostToProto(host)) + } + return response, nil +} + +// GetInventoryHost returns one host. +func (s *Service) GetInventoryHost(ctx context.Context, req *omv1.GetInventoryHostRequest) (*omv1.GetInventoryHostResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + host := sepHost{} + call := inventoryCall{method: http.MethodGet, path: inventoryPath("hosts", req.GetNodeId())} + err = probe.call(ctx, call, &host) + if err != nil { + return nil, err + } + return &omv1.GetInventoryHostResponse{Host: inventoryHostToProto(host)}, nil +} + +// DeleteInventoryHost forgets a host and the services on it. +// +// Not suppression: an entity PMM still knows about returns on the next refresh. It is +// for rows left behind when a node was replaced -- restarting a pmm-agent runs +// `setup --force`, which mints a new node ID, so OM gains a row and keeps the old one. +func (s *Service) DeleteInventoryHost(ctx context.Context, req *omv1.DeleteInventoryHostRequest) (*omv1.DeleteInventoryHostResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + call := inventoryCall{method: http.MethodDelete, path: inventoryPath("hosts", req.GetNodeId())} + err = probe.call(ctx, call, nil) + if err != nil { + return nil, err + } + return &omv1.DeleteInventoryHostResponse{}, nil +} + +// ListInventoryServices returns every service the inventory app has a row for. +func (s *Service) ListInventoryServices(ctx context.Context, req *omv1.ListInventoryServicesRequest) (*omv1.ListInventoryServicesResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + query := url.Values{} + if nodeID := req.GetNodeId(); nodeID != "" { + query.Set("node_id", nodeID) + } + if req.Failing != nil { + query.Set("failing", strconv.FormatBool(req.GetFailing())) + } + + services := []sepService{} + call := inventoryCall{method: http.MethodGet, path: "services", query: query} + err = probe.call(ctx, call, &services) + if err != nil { + return nil, err + } + + response := &omv1.ListInventoryServicesResponse{Services: make([]*omv1.InventoryService, 0, len(services))} + for _, service := range services { + response.Services = append(response.Services, inventoryServiceToProto(service)) + } + return response, nil +} + +// GetInventoryService returns one service. +func (s *Service) GetInventoryService(ctx context.Context, req *omv1.GetInventoryServiceRequest) (*omv1.GetInventoryServiceResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + service := sepService{} + call := inventoryCall{method: http.MethodGet, path: inventoryPath("services", req.GetServiceId())} + err = probe.call(ctx, call, &service) + if err != nil { + return nil, err + } + return &omv1.GetInventoryServiceResponse{Service: inventoryServiceToProto(service)}, nil +} + +// DeleteInventoryService forgets one service. +func (s *Service) DeleteInventoryService(ctx context.Context, req *omv1.DeleteInventoryServiceRequest) (*omv1.DeleteInventoryServiceResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + call := inventoryCall{method: http.MethodDelete, path: inventoryPath("services", req.GetServiceId())} + err = probe.call(ctx, call, nil) + if err != nil { + return nil, err + } + return &omv1.DeleteInventoryServiceResponse{}, nil +} + +// ListInventoryRuns returns the inventory app's refresh history. +func (s *Service) ListInventoryRuns(ctx context.Context, req *omv1.ListInventoryRunsRequest) (*omv1.ListInventoryRunsResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + since, until := req.GetSince(), req.GetUntil() + if since != nil && until != nil && until.AsTime().Before(since.AsTime()) { + return nil, status.Error(codes.InvalidArgument, "until must not be before since") + } + + limit := req.GetLimit() + switch { + case limit <= 0: + limit = defaultInventoryRunLimit + case limit > maxInventoryRunLimit: + limit = maxInventoryRunLimit + } + query := url.Values{"limit": []string{strconv.FormatInt(int64(limit), 10)}} + if since != nil { + query.Set("since", since.AsTime().UTC().Format(time.RFC3339Nano)) + } + if until != nil { + query.Set("until", until.AsTime().UTC().Format(time.RFC3339Nano)) + } + + runs := []sepRun{} + call := inventoryCall{method: http.MethodGet, path: "runs", query: query} + err = probe.call(ctx, call, &runs) + if err != nil { + return nil, err + } + + response := &omv1.ListInventoryRunsResponse{Runs: make([]*omv1.InventoryRun, 0, len(runs))} + for _, run := range runs { + response.Runs = append(response.Runs, inventoryRunToProto(run)) + } + return response, nil +} + +// GetInventoryRun returns one refresh. +func (s *Service) GetInventoryRun(ctx context.Context, req *omv1.GetInventoryRunRequest) (*omv1.GetInventoryRunResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + run := sepRun{} + call := inventoryCall{method: http.MethodGet, path: inventoryPath("runs", req.GetRunId())} + err = probe.call(ctx, call, &run) + if err != nil { + return nil, err + } + return &omv1.GetInventoryRunResponse{ + Run: inventoryRunToProto(run), + Entities: inventoryRunEntitiesToProto(run.Nodes), + }, nil +} + +// TriggerInventoryRefresh probes the estate, or the named hosts within it. +// +// Returns as soon as the refresh is accepted. Conflict is judged per host on the app's +// side, so a scoped refresh is not refused merely because the scheduled sweep happens to +// be running -- only because something else already holds one of the same hosts. +func (s *Service) TriggerInventoryRefresh(ctx context.Context, req *omv1.TriggerInventoryRefreshRequest) (*omv1.TriggerInventoryRefreshResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + // Node IDs pass through untranslated: PMM's node ID is also the app's key, which is + // the whole point of keying the estate on it. + // + // Materialised as an empty slice rather than passed through nil. Go marshals a nil + // slice as JSON `null`, and the app types the field `list[str]` with an empty + // default -- so `null` is a validation failure, not "no scope". Left as-is, every + // full-estate refresh through this proxy would have answered 422 while a scoped one + // worked, which is the shape of bug that gets diagnosed as "the trigger is broken + // sometimes". + nodeIDs := req.GetNodeIds() + if nodeIDs == nil { + nodeIDs = []string{} + } + body := map[string]any{"node_ids": nodeIDs} + + accepted := struct { + RunID string `json:"run_id"` + Status string `json:"status"` + StartedAt *string `json:"started_at"` + Scope []string `json:"scope"` + }{} + call := inventoryCall{method: http.MethodPost, path: "runs", body: body} + err = probe.call(ctx, call, &accepted) + if err != nil { + return nil, err + } + + response := &omv1.TriggerInventoryRefreshResponse{ + RunId: accepted.RunID, + Status: sepRunStatusToProto(accepted.Status), + Scope: accepted.Scope, + } + if accepted.StartedAt != nil { + if parsed := parseSepTime(*accepted.StartedAt); parsed != nil { + response.StartTime = parsed + } + } + return response, nil +} + +// GetInventoryConfig returns the inventory app's configuration. +func (s *Service) GetInventoryConfig(ctx context.Context, _ *omv1.GetInventoryConfigRequest) (*omv1.GetInventoryConfigResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + settings := []sepSetting{} + call := inventoryCall{method: http.MethodGet, path: "config"} + err = probe.call(ctx, call, &settings) + if err != nil { + return nil, err + } + return &omv1.GetInventoryConfigResponse{Settings: inventorySettingsToProto(settings)}, nil +} + +// Bounds on the shape of an update batch, not on its meaning. +// +// The app owns which keys exist and what values are legal, so these do not duplicate its +// rules -- they bound how much structure may cross the hop at all. Both are orders of +// magnitude above any real batch: the settings class this proxies has ten fields and +// nests one level, SCHEDULE and its children. +// +// They are needed because neither hop bounds them. Measured against this tree: +// protojson accepts 200k fields in a 2.3MB body, inside the 4MB default gRPC message +// size, and nests to just under 10k before refusing. The app on the far side is Python, +// where the default recursion limit is 1000, so forwarding either would make PMM the +// thing that broke SEP. This endpoint is admin-only, which makes it a footgun rather +// than an attack, but a 200k-key batch is an accident worth refusing by name. +const ( + maxConfigFields = 100 + maxConfigDepth = 10 +) + +// validateConfigValues refuses a batch that is empty, too wide, or too deeply nested. +func validateConfigValues(values *structpb.Struct) error { + fields := values.GetFields() + switch { + case len(fields) == 0: + return status.Error(codes.InvalidArgument, "values must name at least one field to change") + case len(fields) > maxConfigFields: + return status.Errorf(codes.InvalidArgument, + "values names %d fields, at most %d may change in one call", len(fields), maxConfigFields) + } + for key, value := range fields { + if exceedsDepth(value, maxConfigDepth-1) { + return status.Errorf(codes.InvalidArgument, + "values.%s nests deeper than %d levels", key, maxConfigDepth) + } + } + return nil +} + +// exceedsDepth reports whether value nests deeper than limit. +// +// It stops at the limit rather than measuring the true depth, so its own recursion is +// bounded by maxConfigDepth however deep the input goes. +func exceedsDepth(value *structpb.Value, limit int) bool { + if limit <= 0 { + return value.GetStructValue() != nil || value.GetListValue() != nil + } + for _, field := range value.GetStructValue().GetFields() { + if exceedsDepth(field, limit-1) { + return true + } + } + for _, element := range value.GetListValue().GetValues() { + if exceedsDepth(element, limit-1) { + return true + } + } + return false +} + +// UpdateInventoryConfig applies a batch of configuration changes. +// +// The batch is passed through as the app received it and the app decides what is valid, +// which is what keeps one set of validation rules rather than two. A single bad field +// rejects the whole batch there and nothing is written. Only the batch's shape is +// checked here, by validateConfigValues. +// +// PUT here, PATCH to the app below, deliberately. PMM's API guidelines require the +// standard Update method to be PUT and every other update in this repo is one; SEP +// reaches the same overrides through a generic settings router that PATCHes +// `/{setting_class}` for every app, so the verb there is not this app's to pick. +// Translating one method is what a proxy is for. +func (s *Service) UpdateInventoryConfig(ctx context.Context, req *omv1.UpdateInventoryConfigRequest) (*omv1.UpdateInventoryConfigResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + err = validateConfigValues(req.GetValues()) + if err != nil { + return nil, err + } + + applied := []sepSetting{} + call := inventoryCall{method: http.MethodPatch, path: "config", body: req.GetValues().AsMap()} + err = probe.call(ctx, call, &applied) + if err != nil { + return nil, err + } + + // Read the whole configuration back rather than returning the rows the app echoed. + // + // Two reasons, and the second is the one that matters. The guidelines require an + // Update to answer with the resource, not a diff. And the app answers with one row per + // key *named in the request*, which is misleading for a nested write: overriding + // SCHEDULE as a whole object changes what SCHEDULE__every effectively resolves to, and + // no row says so. A caller that trusted the echo would render a stale child beside a + // fresh parent. + // + // This also retires the rule the UI had to follow -- "re-read after a write, never + // echo the submitted value" -- by doing it once here, for every caller rather than + // only the ones that remembered. + current := []sepSetting{} + read := inventoryCall{method: http.MethodGet, path: "config"} + err = probe.call(ctx, read, ¤t) + if err != nil { + // The write landed; only the read-back failed. Reporting an error here would tell + // a caller to retry a change that already applied, so answer with the narrower + // body the app gave us and log the shortfall. + s.l.Warnf("inventory config updated, but reading it back failed: %s", err) + return &omv1.UpdateInventoryConfigResponse{Settings: inventorySettingsToProto(applied)}, nil + } + return &omv1.UpdateInventoryConfigResponse{Settings: inventorySettingsToProto(current)}, nil +} + +// DeleteInventoryConfigOverride reverts one field to its deployed value. +func (s *Service) DeleteInventoryConfigOverride( + ctx context.Context, req *omv1.DeleteInventoryConfigOverrideRequest, +) (*omv1.DeleteInventoryConfigOverrideResponse, error) { + probe, err := s.inventoryProbe() + if err != nil { + return nil, err + } + + call := inventoryCall{method: http.MethodDelete, path: inventoryPath("config", req.GetKey())} + err = probe.call(ctx, call, nil) + if err != nil { + return nil, err + } + return &omv1.DeleteInventoryConfigOverrideResponse{}, nil +} + +// inventoryHostToProto projects one host row for the wire. +func inventoryHostToProto(host sepHost) *omv1.InventoryHost { + out := &omv1.InventoryHost{ + NodeId: host.NodeID, + Name: host.Name, + Address: optionalString(host.Address), + ExecutorHost: optionalString(host.ExecutorHost), + Os: observedString(host.Observed, "os"), + Kernel: observedString(host.Observed, "kernel"), + Executor: executorToProto(host.Observed), + UnregisteredMongods: unregisteredMongodsToProto(host.Observed), + Observed: observedToStruct(host.Observed), + Freshness: freshnessToProto(host.sepFreshness), + Services: make([]*omv1.InventoryService, 0, len(host.Services)), + } + for _, service := range host.Services { + out.Services = append(out.Services, inventoryServiceToProto(service)) + } + return out +} + +// inventoryServiceToProto projects one service row for the wire. +func inventoryServiceToProto(service sepService) *omv1.InventoryService { + return &omv1.InventoryService{ + ServiceId: service.ServiceID, + NodeId: service.NodeID, + Name: service.Name, + Port: optionalInt32(service.Port), + Role: optionalString(service.Role), + InstalledVersion: observedString(service.Observed, "installed_version"), + RunningVersion: observedString(service.Observed, "version"), + ConfigPath: observedString(service.Observed, "config_path"), + Argv: observedString(service.Observed, "argv"), + ProbeStatus: observedString(service.Observed, "probe_status"), + ServerRunning: observedBool(service.Observed, "server_running"), + UptimeSeconds: observedDouble(service.Observed, "uptime_seconds"), + ReplicationSet: observedString(service.Observed, "replication_set"), + Observed: observedToStruct(service.Observed), + Freshness: freshnessToProto(service.sepFreshness), + } +} + +// inventoryRunToProto projects one refresh for the wire. +func inventoryRunToProto(run sepRun) *omv1.InventoryRun { + return &omv1.InventoryRun{ + RunId: run.RunID, + Status: sepRunStatusToProto(run.Status), + StartTime: optionalTimestamp(run.StartedAt), + EndTime: optionalTimestamp(run.FinishedAt), + Counts: &omv1.InventoryRunCounts{ + TotalServices: run.Counts.ServicesTotal, + ResolvedServices: run.Counts.ServicesResolved, + OrphanedServices: run.Counts.ServicesOrphaned, + AnsweredServices: run.Counts.ServicesAnswered, + TotalHosts: run.Counts.HostsTotal, + ProbeableHosts: run.Counts.HostsProbeable, + AnsweredHosts: run.Counts.HostsAnswered, + }, + Scope: run.Scope, + Error: optionalString(run.Error), + } +} + +// inventoryRunEntitiesToProto projects what a refresh attempted, one row per host. +// +// Host-oriented, because a refresh attempts hosts: a flat service list cannot show a +// machine carrying a PMM client and no database, which is the case OM most exists to +// describe. Each host carries the services on it, and empty is a meaningful answer. +// +// Outcomes only: which host, matched how, answered or not, how long, and the error. +// What the probe found belongs to the estate, which is upserted and stays current -- +// carrying it here as well would be a second copy that goes stale the moment the next +// refresh runs. TaskHistoryID is the one exception, and not a contradiction of that +// rule: it carries no observation, only a pointer to where the dispatch's raw output +// -- the observations that were deliberately *not* kept here -- can still be read. +func inventoryRunEntitiesToProto(nodes []sepRunNode) []*omv1.InventoryRunEntity { + entities := make([]*omv1.InventoryRunEntity, 0, len(nodes)) + for _, node := range nodes { + services := make([]*omv1.InventoryRunEntityService, 0, len(node.Services)) + for _, service := range node.Services { + services = append(services, &omv1.InventoryRunEntityService{ + ServiceId: optionalString(service.ServiceID), + ServiceName: optionalString(service.ServiceName), + Answered: service.Answered, + Error: optionalString(service.Error), + }) + } + entities = append(entities, &omv1.InventoryRunEntity{ + NodeId: node.NodeID, + HostName: optionalString(node.HostName), + ExecutorHost: optionalString(node.ExecutorHost), + Resolution: sepResolutionToProto(node.Resolution), + Answered: node.Answered, + DurationSeconds: optionalDouble(node.Duration), + TaskHistoryId: node.TaskHistoryID, + Error: optionalString(node.Error), + Services: services, + }) + } + return entities +} + +// inventorySettingsToProto projects the configuration rows for the wire. +func inventorySettingsToProto(settings []sepSetting) []*omv1.InventorySetting { + out := make([]*omv1.InventorySetting, 0, len(settings)) + for _, setting := range settings { + out = append(out, &omv1.InventorySetting{ + Key: setting.Key, + Value: anyToValue(setting.Value), + DefaultValue: anyToValue(setting.DefaultValue), + Type: setting.Type, + Reload: sepReloadToProto(setting.Reload), + HasOverride: setting.HasOverride, + IsAdvanced: setting.IsAdvanced, + Description: optionalString(setting.Description), + }) + } + return out +} + +// freshnessToProto projects the freshness block. +func freshnessToProto(f sepFreshness) *omv1.InventoryFreshness { + return &omv1.InventoryFreshness{ + FirstSeenAt: optionalTimestamp(f.FirstSeenAt), + LastAttemptAt: optionalTimestamp(f.LastAttemptAt), + LastSuccessAt: optionalTimestamp(f.LastSuccessAt), + FailingSince: optionalTimestamp(f.FailingSince), + ConsecutiveFailures: clampInt32(f.ConsecutiveFailures), + LastError: optionalString(f.LastError), + } +} + +// executorToProto lifts the executor block out of the host document. +// +// Returns nil when the app reported none, which is not the same as three false flags: +// absent means "this sweep did not say", while false means "SEP looked and the answer +// was no". +func executorToProto(observed map[string]any) *omv1.InventoryExecutor { + nested, ok := observed["executor"].(map[string]any) + if !ok { + return nil + } + out := &omv1.InventoryExecutor{} + if value, ok := nested["registered"].(bool); ok { + out.Registered = value + } + if value, ok := nested["reachable"].(bool); ok { + out.Reachable = value + } + if value, ok := nested["driver_healthy"].(bool); ok { + out.DriverHealthy = value + } + if value, ok := nested["detail"].(string); ok && value != "" { + out.Detail = &value + } + return out +} + +// unregisteredMongodsToProto lifts the stranger list out of the host document. +func unregisteredMongodsToProto(observed map[string]any) []*omv1.UnregisteredMongod { + entries, ok := observed["unregistered_mongods"].([]any) + if !ok { + return nil + } + out := make([]*omv1.UnregisteredMongod, 0, len(entries)) + for _, entry := range entries { + fields, ok := entry.(map[string]any) + if !ok { + continue + } + out = append(out, &omv1.UnregisteredMongod{ + Port: observedInt32(fields, "port"), + ConfigPath: observedString(fields, "config_path"), + Argv: observedString(fields, "argv"), + Program: observedString(fields, "program"), + Pid: observedInt32(fields, "pid"), + }) + } + return out +} + +// observedToStruct carries the whole document through untyped. +// +// The point of the app storing observations as JSON is that collecting a new attribute +// is a payload change rather than a schema change. Enumerating every attribute as a +// proto field would put that coupling back, so the fields above are the ones a table +// sorts by and this is everything: a new attribute shows up in a detail panel the day it +// is collected, and is promoted to a field only when something wants to sort by it. +// +// The collected_at key is dropped: it is metadata about the document rather than an observation, +// and the freshness block already carries the same instant with a name that says so. +func observedToStruct(observed map[string]any) *structpb.Struct { + if len(observed) == 0 { + return nil + } + filtered := make(map[string]any, len(observed)) + for key, value := range observed { + if key == observedCollectedAt { + continue + } + filtered[key] = value + } + encoded, err := structpb.NewStruct(filtered) + if err != nil { + // Not fatal: the typed fields above are already extracted, and losing the detail + // panel is better than failing the whole listing over one unrepresentable value. + return nil + } + return encoded +} + +// anyToValue wraps one decoded JSON value, or nil when it cannot be represented. +func anyToValue(value any) *structpb.Value { + encoded, err := structpb.NewValue(value) + if err != nil { + return nil + } + return encoded +} + +// observedString reads one string attribute out of a document. +// +// Empty and absent are deliberately merged: a missing key and a key holding "" both +// return nil, so the field is omitted from the response either way. For what these read +// -- a config path, an argv, an OS name -- an empty string carries no more information +// than no string at all, and collapsing them keeps the column from showing a blank cell +// that a reader has to interpret. +// +// The pointer is what makes that omission reachable at all: protojson drops an unset +// `optional` scalar entirely, even under EmitUnpopulated. +func observedString(observed map[string]any, key string) *string { + value, ok := observed[key].(string) + if !ok || value == "" { + return nil + } + return &value +} + +// clampInt32 narrows a count that arrived as a JSON number. +// +// SEP's counter is decoded into an int, which is 64-bit here, so a plain conversion could +// wrap and report a negative number of consecutive failures. Saturating instead keeps the +// column monotonic: a reader learns "very many", never "minus two billion". +func clampInt32(value int) int32 { + switch { + case value > math.MaxInt32: + return math.MaxInt32 + case value < math.MinInt32: + return math.MinInt32 + } + return int32(value) +} + +// observedBool reads one boolean attribute out of a document. +func observedBool(observed map[string]any, key string) *bool { + value, ok := observed[key].(bool) + if !ok { + return nil + } + return &value +} + +// observedDouble reads one numeric attribute out of a document. +func observedDouble(observed map[string]any, key string) *float64 { + value, ok := observed[key].(float64) + if !ok { + return nil + } + return &value +} + +// observedInt32 reads one integer attribute out of a document. +// +// JSON numbers decode as float64, so this narrows rather than asserts -- and a value that +// will not fit is dropped rather than wrapped. Both callers are a port and a PID, where a +// wrapped result reads as a plausible one: absent says "not collected", 4295 says a port +// something is listening on. +func observedInt32(observed map[string]any, key string) *int32 { + value, ok := observed[key].(float64) + if !ok { + return nil + } + if math.IsNaN(value) || value < math.MinInt32 || value > math.MaxInt32 { + return nil + } + narrowed := int32(value) + return &narrowed +} + +// optionalString wraps a nullable string. +func optionalString(value *string) *string { + if value == nil || *value == "" { + return nil + } + return value +} + +// optionalInt32 wraps a nullable integer. +func optionalInt32(value *int32) *int32 { + if value == nil { + return nil + } + return value +} + +// optionalTimestamp wraps a nullable instant. +func optionalTimestamp(value *time.Time) *timestamppb.Timestamp { + if value == nil { + return nil + } + return timestamppb.New(*value) +} + +// parseSepTime parses one of the app's timestamps, tolerating either spelling. +// +// The app serves RFC 3339, but whether the offset is `Z` or `+00:00` depends on which +// column it came from, and a run's started_at has been seen both ways. +func parseSepTime(stamp string) *timestamppb.Timestamp { + parsed, err := time.Parse(time.RFC3339, stamp) + if err != nil { + return nil + } + return timestamppb.New(parsed) +} + +// The app's vocabularies, mapped onto the wire enums. +// +// Separate from store.go's mappers even where the values coincide, because these translate +// a *different* system's strings: the app owns them, they arrive over HTTP, and a value OM +// has never heard of is a real possibility rather than a corrupted row. Every one of these +// falls through to UNSPECIFIED, which is how "the app said something new" reaches a caller +// as an unknown rather than as a plausible wrong answer. + +// sepRunStatusToProto maps the app's run status onto the wire enum. +func sepRunStatusToProto(status string) omv1.RunStatus { + switch status { + case "running": + return omv1.RunStatus_RUN_STATUS_RUNNING + case "success": + return omv1.RunStatus_RUN_STATUS_SUCCESS + case "partial": + return omv1.RunStatus_RUN_STATUS_PARTIAL + case "failed": + return omv1.RunStatus_RUN_STATUS_FAILED + case "skipped": + return omv1.RunStatus_RUN_STATUS_SKIPPED + default: + return omv1.RunStatus_RUN_STATUS_UNSPECIFIED + } +} + +// sepResolutionToProto maps how the app matched a host to an executor client. +func sepResolutionToProto(resolution string) omv1.ExecutorResolution { + switch resolution { + case "name": + return omv1.ExecutorResolution_EXECUTOR_RESOLUTION_NAME + case "address": + return omv1.ExecutorResolution_EXECUTOR_RESOLUTION_ADDRESS + case "orphaned": + return omv1.ExecutorResolution_EXECUTOR_RESOLUTION_ORPHANED + default: + return omv1.ExecutorResolution_EXECUTOR_RESOLUTION_UNSPECIFIED + } +} + +// sepReloadToProto maps a setting's reload class. +// +// Mirrors ReloadClassification in the app's settings registry one-for-one. Collapsing +// nested_only into "not overridable" was the tempting simplification and it is wrong: a +// nested parent rejects a whole-object write while its children accept one, so a form +// reading the parent would refuse to edit a leaf the API accepts. +func sepReloadToProto(reload string) omv1.SettingReload { + switch reload { + case "hot": + return omv1.SettingReload_SETTING_RELOAD_HOT + case "nested_only": + return omv1.SettingReload_SETTING_RELOAD_NESTED_ONLY + case "not_overridable": + return omv1.SettingReload_SETTING_RELOAD_NOT_OVERRIDABLE + default: + return omv1.SettingReload_SETTING_RELOAD_UNSPECIFIED + } +} diff --git a/managed/services/om/inventory_client.go b/managed/services/om/inventory_client.go new file mode 100644 index 00000000000..76d5fdc0d9e --- /dev/null +++ b/managed/services/om/inventory_client.go @@ -0,0 +1,252 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "strings" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// This file is the client half of the inventory proxy: the shapes SEP's om_inventory +// app serves, and the estate-specific decoding of its answers. The transport itself -- +// where SEP is, the bearer token, the request/response mechanics -- is sep_client.go, +// shared with every other SEP-backed source in this package. +// +// It exists because the browser must not hold a SEP bearer. A page that talks to SEP +// directly needs one minted from the PMM session, which means the page is gated on SEP +// being up, configured and willing to exchange the token -- and it fails closed, so a +// sick SEP blanks the page rather than showing an estate with an error on it. Proxying +// here costs a second hop and buys "SEP is unreachable" as an error *inside* a page +// that still renders. + +// inventoryRequestTimeout bounds a proxied request. +// +// Every path here is a database read on the other side; the one that starts work, +// POST /runs, returns as soon as the run row is written and does not wait for the Nomad +// jobs. So nothing behind this endpoint should take seconds, and one that does is a +// sign the app is unwell rather than busy. +const inventoryRequestTimeout = 15 * time.Second + +// sepFreshness is the freshness block both estate rows carry. +type sepFreshness struct { + FirstSeenAt *time.Time `json:"first_seen_at"` + LastAttemptAt *time.Time `json:"last_attempt_at"` + LastSuccessAt *time.Time `json:"last_success_at"` + FailingSince *time.Time `json:"failing_since"` + ConsecutiveFailures int `json:"consecutive_failures"` + LastError *string `json:"last_error"` +} + +// sepService is one row of GET /services, and of the `services` list on a host. +type sepService struct { + sepFreshness + + ServiceID string `json:"service_id"` + NodeID string `json:"node_id"` + Name string `json:"name"` + Port *int32 `json:"port"` + Role *string `json:"role"` + Observed map[string]any `json:"observed"` +} + +// sepHost is one row of GET /hosts. +type sepHost struct { + sepFreshness + + NodeID string `json:"node_id"` + Name string `json:"name"` + Address *string `json:"address"` + ExecutorHost *string `json:"executor_host"` + Observed map[string]any `json:"observed"` + Services []sepService `json:"services"` +} + +// sepRunCounts is what one refresh saw. +type sepRunCounts struct { + ServicesTotal int32 `json:"services_total"` + ServicesResolved int32 `json:"services_resolved"` + ServicesOrphaned int32 `json:"services_orphaned"` + ServicesAnswered int32 `json:"services_answered"` + HostsTotal int32 `json:"hosts_total"` + HostsProbeable int32 `json:"hosts_probeable"` + HostsAnswered int32 `json:"hosts_answered"` +} + +// sepRun is one row of GET /runs. +type sepRun struct { + RunID string `json:"run_id"` + Status string `json:"status"` + StartedAt *time.Time `json:"started_at"` + FinishedAt *time.Time `json:"finished_at"` + Counts sepRunCounts `json:"counts"` + Scope []string `json:"scope"` + Error *string `json:"error"` + // Only the detail endpoint fills this; the list omits it. + Nodes []sepRunNode `json:"nodes"` +} + +// sepRunNode is one host a refresh attempted, from GET /runs/{id}. +type sepRunNode struct { + NodeID string `json:"node_id"` + HostName *string `json:"host_name"` + ExecutorHost *string `json:"executor_host"` + Resolution string `json:"resolution"` + Answered bool `json:"answered"` + Duration *float64 `json:"duration_seconds"` + TaskHistoryID *int64 `json:"task_history_id"` + Error *string `json:"error"` + Services []sepRunNodeService `json:"services"` +} + +// sepRunNodeService is one service on such a host. +type sepRunNodeService struct { + ServiceID *string `json:"service_id"` + ServiceName *string `json:"service_name"` + Answered bool `json:"answered"` + Error *string `json:"error"` +} + +// sepSetting is one row of GET /config. +type sepSetting struct { + Key string `json:"key"` + Value any `json:"value"` + DefaultValue any `json:"default_value"` + Type string `json:"type"` + Reload string `json:"reload"` + HasOverride bool `json:"has_override"` + IsAdvanced bool `json:"is_advanced"` + Description *string `json:"description"` +} + +// sepError is FastAPI's error envelope. +// +// `detail` is a string for the app's own errors and a list of per-field objects for a +// validation failure, so it is decoded as `any` and rendered rather than typed. +type sepError struct { + Detail any `json:"detail"` +} + +// inventoryCall describes one proxied request. +type inventoryCall struct { + method string + path string + query url.Values + // body is marshalled as JSON when non-nil. A nil body on a POST still sends `{}` + // when sendEmptyBody is set, because the app's trigger endpoint takes an optional + // object and FastAPI rejects a bodyless POST against a typed body. + body any + sendEmptyBody bool +} + +// call performs one proxied request and decodes the answer into out. +// +// The out parameter may be nil for a DELETE, whose 204 carries none. Errors come back as gRPC status +// errors with the code the gateway will turn back into the status SEP gave, so a 404 +// from the app reaches the browser as a 404 rather than as a 500 about a 404. +func (a sepApp) call(ctx context.Context, c inventoryCall, out any) error { + ctx, cancel := context.WithTimeout(ctx, inventoryRequestTimeout) + defer cancel() + + req, err := a.request(ctx, c.method, c.path, c.query, c.body, c.sendEmptyBody) + if err != nil { + return status.Errorf(codes.Internal, "failed to build the request: %s", err) + } + + resp, err := a.client.http.Do(req) + if err != nil { + return status.Errorf(codes.Unavailable, "the inventory app is unreachable: %s", err) + } + defer resp.Body.Close() //nolint:errcheck + + if resp.StatusCode >= http.StatusBadRequest { + return sepStatusError(resp) + } + if out == nil || resp.StatusCode == http.StatusNoContent { + return nil + } + err = json.NewDecoder(resp.Body).Decode(out) + if err != nil { + return status.Errorf(codes.Internal, "failed to decode the inventory app's answer: %s", err) + } + return nil +} + +// sepStatusError turns the app's error response into a gRPC status error. +// +// The mapping is chosen so the gateway reproduces the app's own status where it can: +// 404 stays 404 and 409 stays 409, because "no such host" and "another refresh already +// holds this host" are both answers a caller acts on differently from a failure. +// +// The one exception is 422: gRPC has no code the gateway renders as 422, so a validation +// failure arrives as InvalidArgument and the browser sees 400. The app's per-field +// detail is carried through in the message rather than dropped, which is what the UI +// needs to render inline errors; only the status number is lost. +func sepStatusError(resp *http.Response) error { + detail := sepErrorDetail(resp) + switch resp.StatusCode { + case http.StatusNotFound: + return status.Error(codes.NotFound, detail) + case http.StatusConflict: + return status.Error(codes.Aborted, detail) + case http.StatusUnprocessableEntity, http.StatusBadRequest: + return status.Error(codes.InvalidArgument, detail) + case http.StatusUnauthorized, http.StatusForbidden: + // Deliberately not passed through as-is: a 401 from PMM's own gateway means the + // *caller* is unauthenticated, and reflecting the app's 401 would tell the + // browser to re-authenticate against PMM when what actually failed is PMM's + // credential for SEP. That is an operator's problem, so it reads as one. + return status.Errorf(codes.Internal, + "PMM's credential for the inventory app was rejected (%s): %s", resp.Status, detail) + default: + return status.Errorf(codes.Internal, "the inventory app answered %s: %s", resp.Status, detail) + } +} + +// sepErrorDetail extracts something readable from the app's error body. +func sepErrorDetail(resp *http.Response) string { + var envelope sepError + err := json.NewDecoder(resp.Body).Decode(&envelope) + if err != nil || envelope.Detail == nil { + return resp.Status + } + if text, ok := envelope.Detail.(string); ok { + return text + } + encoded, err := json.Marshal(envelope.Detail) + if err != nil { + return resp.Status + } + return string(encoded) +} + +// inventoryPath joins path segments under the app, escaping each one. +// +// Escaping matters: an ID reaching here is PMM's, not the app's, and nothing guarantees +// it is free of characters that would change which path it addresses. +func inventoryPath(segments ...string) string { + escaped := make([]string, 0, len(segments)) + for _, segment := range segments { + escaped = append(escaped, url.PathEscape(segment)) + } + return strings.Join(escaped, "/") +} diff --git a/managed/services/om/inventory_test.go b/managed/services/om/inventory_test.go new file mode 100644 index 00000000000..0ec4a76bb02 --- /dev/null +++ b/managed/services/om/inventory_test.go @@ -0,0 +1,841 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" + + omv1 "github.com/percona/pmm/api/om/v1" +) + +// hostsBody is one om_inventory GET /hosts answer. +// +// Two hosts on purpose, because the pair is the whole reason the host table exists. +// `n1` runs a registered database and reports an unregistered mongod beside it -- the +// arbiter case, which PMM registers no service for, so nothing else in OM would mention +// the process. `n2` carries a PMM client and no database at all, which is the case a +// service-keyed inventory cannot represent. +const hostsBody = `[ + { + "node_id": "n1", "name": "db00", "address": "10.0.0.1", "executor_host": "db00", + "observed": { + "collected_at": "2026-08-18T09:00:00+00:00", + "os": "Ubuntu 24.04.3 LTS", + "kernel": "6.17.0-35-generic", + "executor": {"registered": true, "reachable": true, "driver_healthy": true, "detail": null}, + "unregistered_mongods": [ + {"pid": 10, "port": 27018, "program": "mongod", + "argv": "/usr/bin/mongod --config /etc/mongod-node.conf", + "config_path": "/etc/mongod-node.conf"} + ] + }, + "first_seen_at": "2026-08-18T08:00:00Z", "last_attempt_at": "2026-08-18T09:00:00Z", + "last_success_at": "2026-08-18T09:00:00Z", "failing_since": null, + "consecutive_failures": 0, "last_error": null, + "services": [ + { + "service_id": "s1", "node_id": "n1", "name": "mongo-1", "port": 27017, "role": "PRIMARY", + "observed": { + "collected_at": "2026-08-18T09:00:00+00:00", + "installed_version": "7.0.40-22", "version": "7.0.39-21", + "config_path": "/etc/mongod-node.conf", + "argv": "/usr/bin/mongod --config /etc/mongod-node.conf", + "probe_status": "ok", "server_running": true, "uptime_seconds": 11699, + "replication_set": "rs0" + }, + "first_seen_at": "2026-08-18T08:00:00Z", "last_attempt_at": "2026-08-18T09:00:00Z", + "last_success_at": "2026-08-18T09:00:00Z", "failing_since": null, + "consecutive_failures": 0, "last_error": null + } + ] + }, + { + "node_id": "n2", "name": "pmm-client-node00", "address": "10.0.0.2", "executor_host": null, + "observed": {}, + "first_seen_at": "2026-08-18T08:00:00Z", "last_attempt_at": "2026-08-18T09:00:00Z", + "last_success_at": null, "failing_since": "2026-08-18T08:30:00Z", + "consecutive_failures": 3, "last_error": "no executor host", + "services": [] + } +]` + +// configBody is one om_inventory GET /config answer, trimmed to the two rows that make +// the point: a nested schedule leaf and a field the deployment owns outright. +const configBody = `[ + {"key": "SCHEDULE__every", "value": 10, "default_value": null, "type": "int", + "reload": "hot", "has_override": false, "is_advanced": false, "description": null}, + {"key": "CREDENTIALS_PATH", "value": null, "default_value": null, "type": "str", + "reload": "not_overridable", "has_override": false, "is_advanced": false, + "description": null} +]` + +// stubCall is one request the stub was asked to serve. +type stubCall struct { + method string + path string + query string + body string +} + +// sepStub stands in for the inventory app, recording what it was asked. +type sepStub struct { + server *httptest.Server + + method string + path string + query string + body string + + // calls records every request in order. The fields above keep only the last, which + // is enough for a handler that makes one call and wrong for one that writes and then + // reads back. + calls []stubCall + // bodies, when set, is served one entry per request so a read-after-write can be + // given a different answer from the write itself. The last entry repeats once + // exhausted. + bodies []string +} + +// newSEPStub serves one canned answer and records the request that fetched it. +func newSEPStub(t *testing.T, code int, body string) *sepStub { + t.Helper() + + return newSEPStubSeq(t, code, body) +} + +// newSEPStubSeq serves one canned answer per request, in order. +func newSEPStubSeq(t *testing.T, code int, bodies ...string) *sepStub { + t.Helper() + + stub := &sepStub{bodies: bodies} + stub.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + call := stubCall{method: r.Method, path: r.URL.Path, query: r.URL.RawQuery} + raw, err := io.ReadAll(r.Body) + if err == nil { + call.body = string(raw) + } + stub.method, stub.path, stub.query, stub.body = call.method, call.path, call.query, call.body + body := "" + if len(stub.bodies) > 0 { + body = stub.bodies[min(len(stub.calls), len(stub.bodies)-1)] + } + stub.calls = append(stub.calls, call) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _, _ = w.Write([]byte(body)) + })) + t.Cleanup(stub.server.Close) + return stub +} + +// service returns an OM service wired to the stub. +func (s *sepStub) service(t *testing.T) *Service { + t.Helper() + + svc := &Service{l: logrus.WithField("test", t.Name())} + return svc.WithProbeSource(s.server.URL, "test-token") +} + +func TestInventoryNotConfigured(t *testing.T) { + t.Parallel() + + // An unconfigured SEP is a deployment that has not been told where SEP is, not a + // missing feature and not a broken app. FailedPrecondition says so; NotFound would + // read as "there is no such endpoint" and send the reader looking for a version + // problem. + svc := &Service{l: logrus.WithField("test", t.Name())} + + _, err := svc.ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.FailedPrecondition, status.Code(err)) +} + +func TestListInventoryHosts(t *testing.T) { + t.Parallel() + + t.Run("projects both hosts", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + + require.NoError(t, err) + require.Len(t, response.GetHosts(), 2) + assert.Equal(t, "/api/apps/om_inventory/hosts", stub.path) + }) + + t.Run("promotes the attributes a table sorts by", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + host := response.GetHosts()[0] + assert.Equal(t, "n1", host.GetNodeId()) + assert.Equal(t, "Ubuntu 24.04.3 LTS", host.GetOs()) + assert.Equal(t, "6.17.0-35-generic", host.GetKernel()) + assert.Equal(t, "db00", host.GetExecutorHost()) + }) + + t.Run("carries the whole document for a detail panel", func(t *testing.T) { + t.Parallel() + + // The app stores observations as JSON so a new attribute is a payload change + // rather than a schema change. Enumerating every attribute as a proto field + // would put that coupling straight back, so anything without a field of its own + // still has to arrive. + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + observed := response.GetHosts()[0].GetObserved().GetFields() + assert.Contains(t, observed, "unregistered_mongods") + assert.NotContains(t, observed, observedCollectedAt, + "collected_at is metadata about the document; freshness already carries the instant") + }) + + t.Run("reports an unregistered mongod on its host", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + strangers := response.GetHosts()[0].GetUnregisteredMongods() + require.Len(t, strangers, 1) + assert.Equal(t, int32(27018), strangers[0].GetPort()) + assert.Equal(t, "/etc/mongod-node.conf", strangers[0].GetConfigPath()) + }) + + t.Run("splits the executor state three ways", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + executor := response.GetHosts()[0].GetExecutor() + require.NotNil(t, executor) + assert.True(t, executor.GetRegistered()) + assert.True(t, executor.GetReachable()) + assert.True(t, executor.GetDriverHealthy()) + }) + + t.Run("a host with no probe reports absent, not false", func(t *testing.T) { + t.Parallel() + + // Three false flags would claim SEP looked and the answer was no. A nil block + // says this sweep did not say, which is what an empty document means. + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + empty := response.GetHosts()[1] + assert.Nil(t, empty.GetExecutor()) + assert.Nil(t, empty.GetObserved()) + assert.Empty(t, empty.GetServices(), "a host with no database is a row, not an omission") + }) + + t.Run("a failing host carries why and since when", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + freshness := response.GetHosts()[1].GetFreshness() + assert.Equal(t, int32(3), freshness.GetConsecutiveFailures()) + assert.Equal(t, "no executor host", freshness.GetLastError()) + assert.NotNil(t, freshness.GetFailingSince()) + assert.Nil(t, freshness.GetLastSuccessAt(), + "never having answered is different from having answered nothing") + }) + + t.Run("passes the filters through", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, `[]`) + + // Addressable locals rather than a helper: these are proto3 `optional` bools, so + // what the request carries is a plain *bool, and false has to be distinguishable + // from unset -- which is the whole point of the three assertions below. + hasService, failing, executor := false, true, false + + _, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{ + HasService: &hasService, + Failing: &failing, + Executor: &executor, + }) + + require.NoError(t, err) + assert.Contains(t, stub.query, "has_service=false") + assert.Contains(t, stub.query, "failing=true") + // The app types this one bool as well: it filters on whether an executor is + // matched at all, not on which client. A host name here is a 422 from the app, + // which is what this assertion used to require. + assert.Contains(t, stub.query, "executor=false") + }) + + t.Run("an unset filter is not sent as false", func(t *testing.T) { + t.Parallel() + + // has_service=false means "only hosts with no database", which is a very + // different listing from the default. Sending it because the caller said nothing + // would silently hide every host that has one. + stub := newSEPStub(t, http.StatusOK, `[]`) + + _, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + + require.NoError(t, err) + assert.Empty(t, stub.query) + }) +} + +func TestInventoryServiceProjection(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, hostsBody) + + response, err := stub.service(t).ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + require.NoError(t, err) + + services := response.GetHosts()[0].GetServices() + require.Len(t, services, 1) + service := services[0] + + // installed_version against running version is the whole reason the probe exists: + // their divergence is the upgraded-but-not-restarted case, and no metric carries it. + assert.Equal(t, "7.0.40-22", service.GetInstalledVersion()) + assert.Equal(t, "7.0.39-21", service.GetRunningVersion()) + assert.Equal(t, "PRIMARY", service.GetRole()) + assert.Equal(t, int32(27017), service.GetPort()) + assert.Equal(t, "ok", service.GetProbeStatus()) + assert.True(t, service.GetServerRunning()) + assert.InDelta(t, 11699.0, service.GetUptimeSeconds(), 0.001) + assert.Equal(t, "rs0", service.GetReplicationSet()) +} + +func TestTriggerInventoryRefresh(t *testing.T) { + t.Parallel() + + t.Run("passes node ids through untranslated", func(t *testing.T) { + t.Parallel() + + // The whole argument for keying the estate on PMM's node ID is that no + // translation step exists. If one appeared here, it would be the bug that + // argument was meant to prevent. + stub := newSEPStub(t, http.StatusAccepted, + `{"run_id": "r1", "status": "running", "started_at": "2026-08-18T09:00:00Z", "scope": ["n1"]}`) + + response, err := stub.service(t).TriggerInventoryRefresh(t.Context(), + &omv1.TriggerInventoryRefreshRequest{NodeIds: []string{"n1"}}) + + require.NoError(t, err) + assert.Equal(t, "r1", response.GetRunId()) + assert.Equal(t, []string{"n1"}, response.GetScope()) + assert.JSONEq(t, `{"node_ids": ["n1"]}`, stub.body) + assert.Equal(t, http.MethodPost, stub.method) + }) + + t.Run("no scope means the whole estate", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusAccepted, + `{"run_id": "r2", "status": "running", "started_at": "2026-08-18T09:00:00Z", "scope": null}`) + + response, err := stub.service(t).TriggerInventoryRefresh(t.Context(), + &omv1.TriggerInventoryRefreshRequest{}) + + require.NoError(t, err) + assert.Empty(t, response.GetScope()) + assert.JSONEq(t, `{"node_ids": []}`, stub.body) + }) + + t.Run("a held host answers 409, not 500", func(t *testing.T) { + t.Parallel() + + // Conflict is an answer a caller acts on -- wait, or refresh something else -- + // so it has to survive the hop as a conflict. Aborted is the code the gateway + // renders as 409. + stub := newSEPStub(t, http.StatusConflict, + `{"detail": "Probe run abc is already refreshing n1"}`) + + _, err := stub.service(t).TriggerInventoryRefresh(t.Context(), + &omv1.TriggerInventoryRefreshRequest{NodeIds: []string{"n1"}}) + + require.Error(t, err) + assert.Equal(t, codes.Aborted, status.Code(err)) + assert.Contains(t, status.Convert(err).Message(), "already refreshing n1") + }) +} + +func TestInventoryErrorMapping(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + name string + code int + body string + want codes.Code + hides bool + }{ + { + name: "a missing host stays missing", + code: http.StatusNotFound, + body: `{"detail": "No host with node_id n9"}`, + want: codes.NotFound, + }, + { + name: "a validation failure is the caller's fault", + code: http.StatusUnprocessableEntity, + body: `{"detail": [{"loc": ["SCHEDULE__every"], "msg": "must be positive"}]}`, + want: codes.InvalidArgument, + }, + { + // PMM's credential being rejected is an operator's problem, not the + // browser's. Reflecting the app's 401 would tell the browser to + // re-authenticate against PMM, which would not fix anything. + name: "a rejected credential does not read as the caller's", + code: http.StatusUnauthorized, + body: `{"detail": "Not authenticated"}`, + want: codes.Internal, + hides: true, + }, + { + name: "anything else is internal", + code: http.StatusInternalServerError, + body: `{"detail": "boom"}`, + want: codes.Internal, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, tc.code, tc.body) + + _, err := stub.service(t).GetInventoryHost(t.Context(), + &omv1.GetInventoryHostRequest{NodeId: "n9"}) + + require.Error(t, err) + assert.Equal(t, tc.want, status.Code(err)) + if tc.hides { + assert.Contains(t, status.Convert(err).Message(), "PMM's credential") + } + }) + } +} + +func TestInventoryDeleteSendsDelete(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusNoContent, ``) + + _, err := stub.service(t).DeleteInventoryHost(t.Context(), + &omv1.DeleteInventoryHostRequest{NodeId: "n1"}) + + require.NoError(t, err) + assert.Equal(t, http.MethodDelete, stub.method) + assert.Equal(t, "/api/apps/om_inventory/hosts/n1", stub.path) +} + +func TestInventoryConfig(t *testing.T) { + t.Parallel() + + t.Run("reports every field and where its value came from", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, configBody) + + response, err := stub.service(t).GetInventoryConfig(t.Context(), &omv1.GetInventoryConfigRequest{}) + + require.NoError(t, err) + require.Len(t, response.GetSettings(), 2) + + schedule := response.GetSettings()[0] + assert.Equal(t, "SCHEDULE__every", schedule.GetKey()) + assert.InDelta(t, 10.0, schedule.GetValue().GetNumberValue(), 0.001) + assert.Equal(t, omv1.SettingReload_SETTING_RELOAD_HOT, schedule.GetReload()) + assert.False(t, schedule.GetHasOverride()) + + // A field the deployment owns outright is listed rather than hidden, so a UI can + // show it greyed out instead of leaving the reader to wonder where it went. + assert.Equal(t, omv1.SettingReload_SETTING_RELOAD_NOT_OVERRIDABLE, response.GetSettings()[1].GetReload()) + }) + + t.Run("a change is passed through as the app will validate it", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, configBody) + values, err := structpb.NewStruct(map[string]any{"SCHEDULE__every": 25}) + require.NoError(t, err) + + _, err = stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.NoError(t, err) + require.Len(t, stub.calls, 2, "the write, then the read-back") + assert.Equal(t, http.MethodPatch, stub.calls[0].method, "the app's own verb, not PMM's PUT") + assert.JSONEq(t, `{"SCHEDULE__every": 25}`, stub.calls[0].body) + }) + + t.Run("the answer is the whole configuration, not the submitted keys", func(t *testing.T) { + t.Parallel() + + // The app answers a PATCH with one row per key *named in the request*. That is + // misleading for a nested write -- overriding a parent moves what its children + // resolve to, and no row says so -- so the handler reads the configuration back + // and answers with that. The two canned bodies differ precisely so this asserts + // which one was returned. + applied := `[{"key": "SCHEDULE__every", "value": 25, "default_value": null, + "type": "int", "reload": "hot", "has_override": true, + "is_advanced": false, "description": null}]` + stub := newSEPStubSeq(t, http.StatusOK, applied, configBody) + values, err := structpb.NewStruct(map[string]any{"SCHEDULE__every": 25}) + require.NoError(t, err) + + response, err := stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.NoError(t, err) + require.Len(t, stub.calls, 2) + assert.Equal(t, http.MethodGet, stub.calls[1].method) + assert.Equal(t, "/api/apps/om_inventory/config", stub.calls[1].path) + // Two rows, from the read-back -- not the one row the write echoed. + require.Len(t, response.GetSettings(), 2) + assert.Equal(t, "CREDENTIALS_PATH", response.GetSettings()[1].GetKey()) + }) + + t.Run("a failed read-back does not report the write as failed", func(t *testing.T) { + t.Parallel() + + // The write landed. Answering with an error would tell a caller to retry a change + // that already applied, so the narrower body is served instead. + applied := `[{"key": "SCHEDULE__every", "value": 25, "default_value": null, + "type": "int", "reload": "hot", "has_override": true, + "is_advanced": false, "description": null}]` + stub := newSEPStubSeq(t, http.StatusOK, applied, `not json`) + values, err := structpb.NewStruct(map[string]any{"SCHEDULE__every": 25}) + require.NoError(t, err) + + response, err := stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.NoError(t, err) + require.Len(t, response.GetSettings(), 1) + assert.Equal(t, "SCHEDULE__every", response.GetSettings()[0].GetKey()) + }) + + t.Run("an empty batch is refused here", func(t *testing.T) { + t.Parallel() + + // Not forwarded: an empty PATCH would succeed on the app's side and change + // nothing, so a caller who built the body wrongly would see success. + stub := newSEPStub(t, http.StatusOK, configBody) + + _, err := stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assert.Empty(t, stub.method, "nothing should have been sent") + }) + + t.Run("a batch wider than the settings class is refused here", func(t *testing.T) { + t.Parallel() + + // Nothing bounds this on either hop: protojson takes 200k fields inside the 4MB + // gRPC default, and the app would then attempt every one of them. + stub := newSEPStub(t, http.StatusOK, configBody) + wide := map[string]any{} + for i := 0; i <= maxConfigFields; i++ { + wide["KEY_"+strconv.Itoa(i)] = i + } + values, err := structpb.NewStruct(wide) + require.NoError(t, err) + + _, err = stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.Error(t, err) + assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assert.Contains(t, err.Error(), "at most 100 may change in one call") + assert.Empty(t, stub.method, "nothing should have been sent") + }) + + t.Run("a batch nested deeper than the app can parse is refused here", func(t *testing.T) { + t.Parallel() + + // The app is Python, where the default recursion limit is 1000, while protojson + // accepts nesting just short of 10k. Forwarding that would make PMM the thing + // that broke SEP. + stub := newSEPStub(t, http.StatusOK, configBody) + nested := map[string]any{"leaf": 1} + for range maxConfigDepth + 1 { + nested = map[string]any{"SCHEDULE": nested} + } + values, err := structpb.NewStruct(nested) + require.NoError(t, err) + + _, err = stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.Error(t, err) + assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assert.Contains(t, err.Error(), "nests deeper than 10 levels") + assert.Empty(t, stub.method, "nothing should have been sent") + }) + + t.Run("the nesting a real batch uses is not refused", func(t *testing.T) { + t.Parallel() + + // The bounds must not touch what the settings class actually looks like: a + // whole-object write of SCHEDULE, which is the deepest legitimate shape. + stub := newSEPStub(t, http.StatusOK, configBody) + values, err := structpb.NewStruct(map[string]any{ + "SCHEDULE": map[string]any{"every": 25, "period": "seconds"}, + }) + require.NoError(t, err) + + _, err = stub.service(t).UpdateInventoryConfig(t.Context(), + &omv1.UpdateInventoryConfigRequest{Values: values}) + + require.NoError(t, err) + assert.JSONEq(t, `{"SCHEDULE": {"every": 25, "period": "seconds"}}`, stub.calls[0].body) + }) + + t.Run("a revert names the field in the path", func(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusNoContent, ``) + + _, err := stub.service(t).DeleteInventoryConfigOverride(t.Context(), + &omv1.DeleteInventoryConfigOverrideRequest{Key: "SCHEDULE__every"}) + + require.NoError(t, err) + assert.Equal(t, http.MethodDelete, stub.method) + assert.Equal(t, "/api/apps/om_inventory/config/SCHEDULE__every", stub.path) + }) +} + +func TestInventoryRunsDefaultLimit(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, `[]`) + + _, err := stub.service(t).ListInventoryRuns(t.Context(), &omv1.ListInventoryRunsRequest{}) + + require.NoError(t, err) + assert.Equal(t, "limit=20", stub.query) +} + +func TestInventoryRunsForwardsDateRange(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, `[]`) + since := timestamppb.New(mustParseTime(t, "2026-08-18T00:00:00Z")) + until := timestamppb.New(mustParseTime(t, "2026-08-25T00:00:00Z")) + + _, err := stub.service(t).ListInventoryRuns(t.Context(), &omv1.ListInventoryRunsRequest{ + Since: since, + Until: until, + }) + + require.NoError(t, err) + query, err := url.ParseQuery(stub.query) + require.NoError(t, err) + assert.Equal(t, "20", query.Get("limit")) + assert.Equal(t, "2026-08-18T00:00:00Z", query.Get("since")) + assert.Equal(t, "2026-08-25T00:00:00Z", query.Get("until")) +} + +func TestInventoryRunsRejectsInvertedDateRange(t *testing.T) { + t.Parallel() + + stub := newSEPStub(t, http.StatusOK, `[]`) + + _, err := stub.service(t).ListInventoryRuns(t.Context(), &omv1.ListInventoryRunsRequest{ + Since: timestamppb.New(mustParseTime(t, "2026-08-25T00:00:00Z")), + Until: timestamppb.New(mustParseTime(t, "2026-08-18T00:00:00Z")), + }) + + require.Error(t, err) + assert.Equal(t, codes.InvalidArgument, status.Code(err)) + assert.Empty(t, stub.query) +} + +func TestInventoryRunCarriesHostCounters(t *testing.T) { + t.Parallel() + + // A refresh attempts hosts as well as the services on them. Counting only + // services made a refresh of a host with no database read as "0 of 0", which is + // what a run that did nothing also looks like -- on the one kind of host OM most + // exists to describe. + stub := newSEPStub(t, http.StatusOK, `[{ + "run_id": "r1", "status": "success", + "started_at": "2026-08-18T12:00:00Z", "finished_at": "2026-08-18T12:00:30Z", + "counts": {"services_total": 0, "services_resolved": 0, "services_orphaned": 0, + "services_answered": 0, + "hosts_total": 3, "hosts_probeable": 2, "hosts_answered": 1}, + "scope": ["node-1"], "error": null + }]`) + + res, err := stub.service(t).ListInventoryRuns(t.Context(), &omv1.ListInventoryRunsRequest{}) + + require.NoError(t, err) + require.Len(t, res.GetRuns(), 1) + counts := res.GetRuns()[0].GetCounts() + assert.Equal(t, int32(3), counts.GetTotalHosts()) + assert.Equal(t, int32(2), counts.GetProbeableHosts()) + assert.Equal(t, int32(1), counts.GetAnsweredHosts()) + // Zero services is the honest answer for a host-only refresh, and the reason the + // host counters had to exist rather than the service ones being reinterpreted. + assert.Equal(t, int32(0), counts.GetTotalServices()) +} + +func TestInventoryRunDetailIsHostOriented(t *testing.T) { + t.Parallel() + + // A refresh attempts hosts, so the receipt lists hosts. A flat service list -- which + // this was -- cannot show a machine carrying a PMM client and no database, however + // many times it is probed, and that machine is the case OM most exists to describe. + stub := newSEPStub(t, http.StatusOK, `{ + "run_id": "r1", "status": "partial", + "started_at": "2026-08-19T12:00:00Z", "finished_at": "2026-08-19T12:00:30Z", + "counts": {"services_total": 1, "services_resolved": 1, "services_orphaned": 0, + "services_answered": 1, + "hosts_total": 3, "hosts_probeable": 2, "hosts_answered": 2}, + "scope": [], "error": null, + "nodes": [ + {"node_id": "n1", "host_name": "db00", "executor_host": "db00", + "resolution": "name", "answered": true, "duration_seconds": 12.5, + "task_history_id": 4711, "error": null, + "services": [{"service_id": "s1", "service_name": "mongo-1", + "answered": true, "error": null}]}, + {"node_id": "n2", "host_name": "pmm-client-node00", + "executor_host": "pmm-client-node00", "resolution": "name", + "answered": true, "duration_seconds": 8.0, "task_history_id": null, + "error": null, "services": []}, + {"node_id": "n3", "host_name": "stranded", "executor_host": null, + "resolution": "orphaned", "answered": false, "duration_seconds": null, + "task_history_id": null, "error": "no executor host", "services": []} + ] + }`) + + res, err := stub.service(t).GetInventoryRun(t.Context(), &omv1.GetInventoryRunRequest{RunId: "r1"}) + + require.NoError(t, err) + require.Len(t, res.GetEntities(), 3) + + withDatabase := res.GetEntities()[0] + assert.Equal(t, "db00", withDatabase.GetHostName()) + assert.True(t, withDatabase.GetAnswered()) + assert.InDelta(t, 12.5, withDatabase.GetDurationSeconds(), 0.001) + // The pointer to this attempt's raw output -- the observations deliberately not + // kept on the receipt itself. + assert.Equal(t, int64(4711), withDatabase.GetTaskHistoryId()) + require.Len(t, withDatabase.GetServices(), 1) + assert.Equal(t, "mongo-1", withDatabase.GetServices()[0].GetServiceName()) + + // The row a service-oriented receipt could not produce at all: probed, answered, + // and carrying no services because there is no database on it. + bare := res.GetEntities()[1] + assert.Equal(t, "pmm-client-node00", bare.GetHostName()) + assert.True(t, bare.GetAnswered()) + assert.Empty(t, bare.GetServices()) + + // An orphan keeps its row rather than being dropped: "2 of 3 answered" cannot say + // which one was missed, and the orphan is the one worth acting on. + orphan := res.GetEntities()[2] + assert.Equal(t, omv1.ExecutorResolution_EXECUTOR_RESOLUTION_ORPHANED, orphan.GetResolution()) + assert.False(t, orphan.GetAnswered()) + // Asserted on the fields rather than the getters: these are proto3 `optional` + // scalars, so the getter returns the zero value for an unset field and only the + // pointer distinguishes "no executor host" from "an empty one". protojson omits + // the key altogether, which is the wire form the UI reads as absent. + assert.Nil(t, orphan.ExecutorHost) + assert.Nil(t, orphan.DurationSeconds) + assert.Nil(t, orphan.TaskHistoryId) + assert.Equal(t, "no executor host", orphan.GetError()) +} + +func TestInventoryBearerIsSent(t *testing.T) { + t.Parallel() + + // The browser holds no SEP token -- that is the point of proxying -- so this hop is + // the only place the app's credential is presented. Without it every request is a + // 401 the page cannot explain. + var seen string + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + seen = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`[]`)) + })) + t.Cleanup(server.Close) + + svc := (&Service{l: logrus.WithField("test", t.Name())}).WithProbeSource(server.URL, "test-token") + + _, err := svc.ListInventoryHosts(t.Context(), &omv1.ListInventoryHostsRequest{}) + + require.NoError(t, err) + assert.Equal(t, "Bearer test-token", seen) +} + +func mustParseTime(t *testing.T, stamp string) time.Time { + t.Helper() + parsed, err := time.Parse(time.RFC3339, stamp) + require.NoError(t, err) + return parsed +} + +// ensure the canned bodies stay valid JSON as they are edited. +func TestInventoryFixturesAreValid(t *testing.T) { + t.Parallel() + + for name, body := range map[string]string{"hosts": hostsBody, "config": configBody} { + t.Run(name, func(t *testing.T) { + t.Parallel() + + var parsed []map[string]any + require.NoError(t, json.Unmarshal([]byte(body), &parsed)) + assert.NotEmpty(t, parsed) + }) + } +} diff --git a/managed/services/om/om_metrics.go b/managed/services/om/om_metrics.go new file mode 100644 index 00000000000..4b2df70be01 --- /dev/null +++ b/managed/services/om/om_metrics.go @@ -0,0 +1,105 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "time" + + prom "github.com/prometheus/client_golang/prometheus" +) + +const ( + prometheusNamespace = "pmm_managed" + prometheusSubsystem = "om" +) + +// MetricsCollector exposes OM's own collection health to Prometheus -- otherwise a +// degraded pass is visible only in the run history, which prunes at runHistory, and in a +// log line at Info. +// +// The following metrics are exposed: +// +// - pmm_managed_om_runs_total{status="success|partial|failed"} -- completed collection +// runs so far, by outcome. A rising "partial" or "failed" rate says collection itself +// is unhealthy, before any caller notices the document is stale. +// +// - pmm_managed_om_document_age_seconds -- how old the newest observation in the +// document PMM currently serves is. This is the same age Snapshot.Stale is computed +// from, exposed as a number so it can be alerted on rather than only rendered. Unset +// until the estate has been observed at least once. +// +// - pmm_managed_om_services{state="total|up|down"} -- how much of the estate the last +// collection pass saw, and how much of it answered. +type MetricsCollector struct { + svc *Service + + mRunsTotal *prom.Desc + mDocumentAge *prom.Desc + mServices *prom.Desc +} + +// NewMetricsCollector creates a new MetricsCollector backed by the given OM service. +func NewMetricsCollector(svc *Service) *MetricsCollector { + return &MetricsCollector{ + svc: svc, + mRunsTotal: prom.NewDesc( + prom.BuildFQName(prometheusNamespace, prometheusSubsystem, "runs_total"), + "Total number of OM topology collection runs, by outcome status.", + []string{"status"}, + nil, + ), + mDocumentAge: prom.NewDesc( + prom.BuildFQName(prometheusNamespace, prometheusSubsystem, "document_age_seconds"), + "Age, in seconds, of the newest observation in the topology document PMM currently serves.", + nil, + nil, + ), + mServices: prom.NewDesc( + prom.BuildFQName(prometheusNamespace, prometheusSubsystem, "services"), + "Services in the topology document PMM currently serves, by state.", + []string{"state"}, + nil, + ), + } +} + +// Describe implements prom.Collector. +func (c *MetricsCollector) Describe(ch chan<- *prom.Desc) { + prom.DescribeByCollect(c, ch) +} + +// Collect implements prom.Collector. +func (c *MetricsCollector) Collect(ch chan<- prom.Metric) { + ch <- prom.MustNewConstMetric(c.mRunsTotal, prom.CounterValue, float64(c.svc.runsSuccess.Load()), runStatusSuccess) + ch <- prom.MustNewConstMetric(c.mRunsTotal, prom.CounterValue, float64(c.svc.runsPartial.Load()), runStatusPartial) + ch <- prom.MustNewConstMetric(c.mRunsTotal, prom.CounterValue, float64(c.svc.runsFailed.Load()), runStatusFailed) + + snap := c.svc.snapshot() + if snap.GetSnapshot().GetObservedAt() == nil { + // Nothing has been observed yet -- a fresh estate whose leader has not completed + // its first pass. Reporting age 0 would read as "current" rather than "no data". + return + } + age := time.Since(snap.Snapshot.ObservedAt.AsTime()).Seconds() + ch <- prom.MustNewConstMetric(c.mDocumentAge, prom.GaugeValue, age) + + summary := snap.Summary + ch <- prom.MustNewConstMetric(c.mServices, prom.GaugeValue, float64(summary.GetTotalServices()), "total") + ch <- prom.MustNewConstMetric(c.mServices, prom.GaugeValue, float64(summary.GetUpServices()), "up") + ch <- prom.MustNewConstMetric(c.mServices, prom.GaugeValue, float64(summary.GetDownServices()), "down") +} + +var _ prom.Collector = (*MetricsCollector)(nil) diff --git a/managed/services/om/probe_source.go b/managed/services/om/probe_source.go new file mode 100644 index 00000000000..9639a4b4053 --- /dev/null +++ b/managed/services/om/probe_source.go @@ -0,0 +1,280 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/sirupsen/logrus" + + "github.com/percona/pmm/managed/models" +) + +// probeSource reads on-host facts from SEP's om_inventory app. +// +// The facts it contributes are the ones nothing on this side can answer: the command +// line a mongod was started with, the config file it read, and the *installed* binary +// version as against the *running* server the metrics report. Their divergence is the +// upgraded-but-not-restarted case, and no metric anywhere carries it. +// +// It pulls; it does not drive. The app sweeps its estate over Nomad on its own +// schedule and serves whatever the last completed sweep stored, so this is a database +// read on the other side rather than a fan-out waiting to happen. That is what keeps +// an OM run in the tenth-of-a-second range with a source attached whose own work +// takes tens of seconds. +// +// This is the only job a probeSource has. Where SEP is, how PMM authenticates to it and +// how a request against it is built are sepApp's and sepClient's, in sep_client.go -- +// shared with inventory.go's proxy handlers rather than duplicated for them, and ready +// for the next SEP-backed source to reuse the same way. +type probeSource struct { + // app is the zero value, with a nil client, when the source is not configured -- a + // normal state, reported as disabled rather than failed. See Service.WithProbeSource. + app sepApp + l *logrus.Entry +} + +// probeAppModule is where SEP mounts the inventory app: the module name under the +// `/api/apps/` convention every SEP app follows, and what Service.WithProbeSource +// hands to sepClient.app to build this source's handle. +const probeAppModule = "om_inventory" + +// probeServicesPath is the app's estate, flat. /hosts nests the same service rows +// under their host and carries host-level attributes besides, which this source has +// nothing to do with: the document it feeds is keyed by service. +const probeServicesPath = "services" + +func (probeSource) key() string { return sourceProbe } + +// probeService is one row of the app's GET /services contract. +// +// The app used to serve a flat fact list at GET /facts, assembled per sweep. It now +// keeps an estate -- a row per host and a row per service, upserted -- and the facts +// this source wants are the `observed` document on the service row. Reading the +// estate rather than the last sweep's output is what makes a service that has not +// been probed for a week still carry what it was running a week ago, with a timestamp +// saying so, instead of vanishing when a sweep misses it. +type probeService struct { + ServiceID string `json:"service_id"` + NodeID string `json:"node_id"` + Name string `json:"name"` + Observed map[string]any `json:"observed"` + + // LastSuccessAt is the age of everything in Observed. Null means this service has + // never answered a probe, which is different from having answered nothing. + LastSuccessAt *time.Time `json:"last_success_at"` + // FailingSince is the *first* failure after the last success, so it says "failing + // for three days" rather than "failed a minute ago". + FailingSince *time.Time `json:"failing_since"` + ConsecutiveFailures int `json:"consecutive_failures"` + LastError string `json:"last_error"` +} + +// observedCollectedAt is the key the app stamps on every document it stores. It is +// metadata about the document rather than a fact about the service, so it is used for +// the timestamp and never emitted as a field. +const observedCollectedAt = "collected_at" + +// probeRequestTimeout bounds the pull. +// +// Generous for a database read on the other side and far short of anything that would +// make an OM run feel slow. The app never probes on this path, so a request that takes +// longer than this is a sign the app is unwell rather than busy -- and the run reports +// the source as failed and carries on with the sources that answered. +const probeRequestTimeout = 10 * time.Second + +func (s probeSource) collect(ctx context.Context, services []*models.Service) SourceResult { + result := SourceResult{Source: sourceProbe, Status: SourceDisabled} + if s.app.client == nil { + result.Detail = map[string]any{"reason": "no SEP endpoint configured"} + return result + } + + known := make(map[string]bool, len(services)) + for _, service := range services { + known[service.ServiceID] = true + } + + answer, err := s.fetch(ctx) + if err != nil { + s.l.Warnf("probe source: %s", err) + return SourceResult{ + Source: sourceProbe, + Status: SourceFailed, + Errors: []RunError{{Scope: "source", Code: "probe_fetch_failed", Message: err.Error()}}, + Detail: map[string]any{"endpoint": s.app.endpoint(probeServicesPath)}, + } + } + + var ( + covered = make(map[string]bool) + unknown int + failing int + oldest float64 + failures []string + ) + now := time.Now() + + for _, service := range answer { + // A service the app knows and this PMM does not is not an error: the app reads + // its own inventory, which can be a moment ahead or behind. Counting them is + // enough -- merging them would put facts in the document for services it has no + // row for. + if !known[service.ServiceID] { + unknown++ + continue + } + + if service.FailingSince != nil { + failing++ + if len(failures) < probeFailuresReported { + failures = append(failures, service.failureSummary()) + } + } + + observedAt := service.observedAt() + if observedAt == nil || len(service.Observed) == 0 { + // Seen but never successfully probed. Not covered, and not a fact. + continue + } + covered[service.ServiceID] = true + if age := now.Sub(*observedAt).Seconds(); age > oldest { + oldest = age + } + + for field, value := range service.Observed { + if field == observedCollectedAt { + continue + } + at := *observedAt + result.Facts = append(result.Facts, Fact{ + Service: service.ServiceID, + Field: field, + Value: value, + Source: sourceProbe, + ObservedAt: &at, + }) + } + } + + // The estate's own condition is part of the answer, not a detail. Every service + // failing its probe means something is wrong on the probe side, and reporting that + // as "ok, 0 facts" reads as "there is nothing to probe here" -- the opposite of + // what happened. + switch { + case len(services) == 0: + // Nothing to cover. Not this source's failure, and not a partial answer. + result.Status = SourceOK + case len(covered) == 0 && failing > 0: + result.Status = SourceFailed + result.Errors = append(result.Errors, RunError{ + Scope: "source", + Code: "probe_all_failing", + Message: "no service answered its probe: " + strings.Join(failures, "; "), + }) + case len(covered) < len(services): + // The usual steady state, and not an alarm: a service whose node runs no + // healthy executor is a fact about the estate rather than a failure here. + result.Status = SourcePartial + default: + result.Status = SourceOK + } + + result.Detail = map[string]any{ + "endpoint": s.app.endpoint(probeServicesPath), + "services": len(services), + "services_covered": len(covered), + "services_unknown": unknown, + "services_failing": failing, + "oldest_age_seconds": int(oldest), + "facts": len(result.Facts), + } + s.l.Infof("probe source: %d/%d service(s) covered, %d failing, oldest %ds", + len(covered), len(services), failing, int(oldest)) + return result +} + +// probeFailuresReported bounds how many failures reach the run receipt. +// +// A whole estate failing the same way produces one message per service, and the +// receipt is meant to be read. The count is reported in full either way. +const probeFailuresReported = 3 + +// observedAt is when this service's document was collected. +// +// The last_success_at column is authoritative because the app maintains it; the document's own +// collected_at is the fallback for a row written before that column carried a value. +func (p probeService) observedAt() *time.Time { + if p.LastSuccessAt != nil { + return p.LastSuccessAt + } + stamp, ok := p.Observed[observedCollectedAt].(string) + if !ok { + return nil + } + parsed, err := time.Parse(time.RFC3339, stamp) + if err != nil { + return nil + } + return &parsed +} + +// failureSummary explains one failing service in the run's own receipt, so a reader is +// told the cause here rather than having to go and ask the other service. +func (p probeService) failureSummary() string { + name := p.Name + if name == "" { + name = p.ServiceID + } + if p.LastError == "" { + return fmt.Sprintf("%s failing since %s", name, p.FailingSince.Format(time.RFC3339)) + } + return fmt.Sprintf("%s: %s", name, p.LastError) +} + +// fetch reads the app's service estate. +func (s probeSource) fetch(ctx context.Context) ([]probeService, error) { + ctx, cancel := context.WithTimeout(ctx, probeRequestTimeout) + defer cancel() + + url := s.app.endpoint(probeServicesPath) + req, err := s.app.request(ctx, http.MethodGet, probeServicesPath, nil, nil, false) + if err != nil { + return nil, fmt.Errorf("failed to build the request: %w", err) + } + + resp, err := s.app.client.http.Do(req) + if err != nil { + return nil, fmt.Errorf("GET %s: %w", url, err) + } + defer resp.Body.Close() //nolint:errcheck + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("GET %s: unexpected status %s", url, resp.Status) + } + + answer := []probeService{} + err = json.NewDecoder(resp.Body).Decode(&answer) + if err != nil { + return nil, fmt.Errorf("GET %s: failed to decode the response: %w", url, err) + } + return answer, nil +} diff --git a/managed/services/om/probe_source_test.go b/managed/services/om/probe_source_test.go new file mode 100644 index 00000000000..31f46b786b9 --- /dev/null +++ b/managed/services/om/probe_source_test.go @@ -0,0 +1,331 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" +) + +// servicesBody is one om_inventory GET /services answer, shaped as the app sends it: +// a row per service PMM has registered, each carrying the document the last successful +// probe stored. `gone` is a service the app knows and this PMM does not. +const servicesBody = `[ + { + "service_id": "s1", "node_id": "n1", "name": "mongo-1", "port": 27017, "role": null, + "observed": { + "collected_at": "2026-08-11T11:32:30+00:00", + "installed_version": "7.0.40-22", + "config_path": "/etc/mongod-node.conf", + "argv": "/usr/bin/mongod --config /etc/mongod-node.conf", + "uptime_seconds": 10295, + "server_running": true + }, + "first_seen_at": "2026-08-11T10:00:00Z", "last_attempt_at": "2026-08-11T11:32:30Z", + "last_success_at": "2026-08-11T11:32:30Z", "failing_since": null, + "consecutive_failures": 0, "last_error": null + }, + { + "service_id": "gone", "node_id": "n9", "name": "mongo-9", "port": 27017, "role": null, + "observed": {"collected_at": "2026-08-11T11:32:30+00:00", "installed_version": "6.0.1"}, + "first_seen_at": "2026-08-11T10:00:00Z", "last_attempt_at": "2026-08-11T11:32:30Z", + "last_success_at": "2026-08-11T11:32:30Z", "failing_since": null, + "consecutive_failures": 0, "last_error": null + } +]` + +// unprobedBody is a service the app holds a row for and has never reached: an empty +// document and null timestamps, which is a normal state rather than an absence. +const unprobedBody = `[ + { + "service_id": "s1", "node_id": "n1", "name": "mongo-1", "port": 27017, "role": null, + "observed": {}, "first_seen_at": "2026-08-11T10:00:00Z", + "last_attempt_at": null, "last_success_at": null, "failing_since": null, + "consecutive_failures": 0, "last_error": null + } +]` + +func probeTestServices() []*models.Service { + return []*models.Service{ + mongoService("s1", "mongo-1", "cl1", "rs0", "prod"), + mongoService("s2", "mongo-2", "cl1", "rs0", "prod"), + } +} + +func newProbeSource(t *testing.T, handler http.HandlerFunc) probeSource { + t.Helper() + server := httptest.NewServer(handler) + t.Cleanup(server.Close) + client := &sepClient{baseURL: server.URL, token: "test-token", http: server.Client()} + return probeSource{ + app: client.app(probeAppModule), + l: logrus.WithField("test", t.Name()), + } +} + +func TestProbeSource(t *testing.T) { + t.Parallel() + + t.Run("facts arrive typed, with their own age", func(t *testing.T) { + t.Parallel() + + var gotAuth, gotPath string + source := newProbeSource(t, func(w http.ResponseWriter, r *http.Request) { + gotAuth, gotPath = r.Header.Get("Authorization"), r.URL.Path + _, _ = w.Write([]byte(servicesBody)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, "Bearer test-token", gotAuth) + // The caller configures where SEP is; this side appends the app path. A path of + // just "/services" would mean the app name had leaked into configuration. + assert.Equal(t, "/api/apps/"+probeAppModule+"/"+probeServicesPath, gotPath) + assert.Equal(t, SourcePartial, result.Status, "one of two services was covered") + + byField := make(map[string]any, len(result.Facts)) + for _, fact := range result.Facts { + assert.Equal(t, sourceProbe, fact.Source) + require.NotNil(t, fact.ObservedAt, "a probe fact has to be datable") + byField[fact.Field] = fact.Value + } + assert.Equal(t, "7.0.40-22", byField[fieldInstalledVersion]) + assert.Equal(t, "/etc/mongod-node.conf", byField[fieldConfigPath]) + assert.InDelta(t, 10295.0, byField["uptime_seconds"], 0.001, "a JSON number decodes to float64") + assert.Equal(t, true, byField["server_running"]) + // collected_at describes the document rather than the service, and the age it + // carries is already on every fact. + assert.NotContains(t, byField, observedCollectedAt) + }) + + t.Run("facts for services this PMM does not have are counted, not merged", func(t *testing.T) { + t.Parallel() + + // The app reads its own inventory, which can be a moment ahead or behind. A row + // for a service with none here has nothing to attach to. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(servicesBody)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + for _, fact := range result.Facts { + assert.NotEqual(t, "gone", fact.Service) + } + assert.Equal(t, "1", detailStrings(result.Detail)["services_unknown"]) + }) + + t.Run("an unconfigured source is disabled, not failed", func(t *testing.T) { + t.Parallel() + + // "No probe has run here" is a normal state of a PMM that has not enabled the + // app, and must not read as an error on the run. + source := probeSource{l: logrus.WithField("test", t.Name())} // zero-value app, no sepURL + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourceDisabled, result.Status) + assert.Empty(t, result.Facts) + assert.Empty(t, result.Errors) + }) + + t.Run("an unreachable app fails the source and not the run", func(t *testing.T) { + t.Parallel() + + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourceFailed, result.Status) + require.Len(t, result.Errors, 1) + assert.Equal(t, "probe_fetch_failed", result.Errors[0].Code) + assert.Empty(t, result.Facts) + }) + + t.Run("an estate with no rows is partial and empty", func(t *testing.T) { + t.Parallel() + + // The app is installed and has never swept. Not anybody's failure. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(`[]`)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourcePartial, result.Status, "nothing covered, but nothing failing either") + assert.Empty(t, result.Facts) + assert.Empty(t, result.Errors) + }) + + t.Run("a service seen but never probed contributes no facts", func(t *testing.T) { + t.Parallel() + + // An empty document is not a fact set of size zero to merge; it is the absence + // of a probe, and the row exists so the estate view can say so. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(unprobedBody)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Empty(t, result.Facts) + assert.Equal(t, SourcePartial, result.Status) + assert.Equal(t, "0", detailStrings(result.Detail)["services_covered"]) + }) + + t.Run("an estate that is entirely failing fails the source and says why", func(t *testing.T) { + t.Parallel() + + // The app is reachable and answering; every service it holds is failing its + // probe. Reporting that as "ok, 0 facts" reads as "there is nothing to probe + // here", which is the opposite of what happened. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(`[ + {"service_id":"s1","node_id":"n1","name":"mongo-1","observed":{}, + "first_seen_at":"2026-08-11T10:00:00Z","last_attempt_at":"2026-08-11T19:53:44Z", + "last_success_at":null,"failing_since":"2026-08-09T19:53:44Z", + "consecutive_failures":37,"last_error":"Cannot connect to host localhost:8000"}, + {"service_id":"s2","node_id":"n2","name":"mongo-2","observed":{}, + "first_seen_at":"2026-08-11T10:00:00Z","last_attempt_at":"2026-08-11T19:53:44Z", + "last_success_at":null,"failing_since":"2026-08-09T19:53:44Z", + "consecutive_failures":37,"last_error":"Cannot connect to host localhost:8000"}]`)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourceFailed, result.Status) + require.Len(t, result.Errors, 1) + assert.Equal(t, "probe_all_failing", result.Errors[0].Code) + // The cause travels with it, so the receipt is readable without going to ask + // the other service. + assert.Contains(t, result.Errors[0].Message, "Cannot connect to host") + assert.Contains(t, result.Errors[0].Message, "mongo-1") + assert.Equal(t, "2", detailStrings(result.Detail)["services_failing"]) + }) + + t.Run("a failure with no recorded reason still says since when", func(t *testing.T) { + t.Parallel() + + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(`[{"service_id":"s1","node_id":"n1","name":"mongo-1","observed":{}, + "first_seen_at":"2026-08-11T10:00:00Z","last_attempt_at":"2026-08-11T19:53:44Z", + "last_success_at":null,"failing_since":"2026-08-09T19:53:44Z", + "consecutive_failures":37,"last_error":null}]`)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourceFailed, result.Status) + require.Len(t, result.Errors, 1) + assert.Contains(t, result.Errors[0].Message, "failing since") + }) + + t.Run("some covered and some failing is partial", func(t *testing.T) { + t.Parallel() + + // The steady state of a real estate: one node unreachable, the rest answering. + // Not a failure of this source, and not a clean run either. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(`[ + {"service_id":"s1","node_id":"n1","name":"mongo-1", + "observed":{"collected_at":"2026-08-11T11:32:30+00:00","installed_version":"7.0.40-22"}, + "first_seen_at":"2026-08-11T10:00:00Z","last_attempt_at":"2026-08-11T11:32:30Z", + "last_success_at":"2026-08-11T11:32:30Z","failing_since":null, + "consecutive_failures":0,"last_error":null}, + {"service_id":"s2","node_id":"n2","name":"mongo-2","observed":{}, + "first_seen_at":"2026-08-11T10:00:00Z","last_attempt_at":"2026-08-11T11:32:30Z", + "last_success_at":null,"failing_since":"2026-08-11T11:00:00Z", + "consecutive_failures":2,"last_error":"unreachable"}]`)) + }) + + result := source.collect(context.Background(), probeTestServices()) + + assert.Equal(t, SourcePartial, result.Status) + assert.Len(t, result.Facts, 1) + assert.Equal(t, "1", detailStrings(result.Detail)["services_failing"]) + }) + + t.Run("garbage does not become facts", func(t *testing.T) { + t.Parallel() + + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte("this is not json")) + }) + + result := source.collect(context.Background(), probeTestServices()) + assert.Equal(t, SourceFailed, result.Status) + assert.Empty(t, result.Facts) + }) +} + +func TestProbeFactsReachTheDocument(t *testing.T) { + t.Parallel() + + // End to end through the seam: what the app serves, merged under the precedence + // table, projected into the document. + source := newProbeSource(t, func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(servicesBody)) + }) + services := probeTestServices() + observed := projectionNow.Add(-5 * time.Second) + + metrics := SourceResult{Source: sourceMetrics, Facts: []Fact{ + {Service: "s1", Field: fieldExporterUp, Value: 1.0, Source: sourceMetrics, ObservedAt: &observed}, + {Service: "s1", Field: fieldVersion, Value: "7.0.39-21", Source: sourceMetrics, ObservedAt: &observed}, + }} + probe := source.collect(context.Background(), services) + + merged := mergeFacts([]SourceResult{metrics, probe}, defaultPrecedence) + doc := buildDocument(services, merged, projectionNow, projectionMaxAge) + + var svc *omv1.TopologyService + for _, cluster := range doc.environments[0].Clusters { + for _, candidate := range cluster.Services { + if candidate.ServiceName == "mongo-1" { + svc = candidate + } + } + } + require.NotNil(t, svc) + + // The upgraded-but-not-restarted case, which is the whole reason the probe exists: + // the binary on disk is ahead of the server that is running. + assert.Equal(t, "7.0.40-22", svc.GetInstalledVersion()) + assert.Equal(t, "7.0.39-21", svc.GetVersion(), "metrics still own the running version") + assert.Equal(t, "/etc/mongod-node.conf", svc.GetConfigPath()) + assert.Contains(t, svc.GetArgv(), "mongod") + + // And the service the probe never reached carries nulls rather than another's facts. + for _, cluster := range doc.environments[0].Clusters { + for _, candidate := range cluster.Services { + if candidate.ServiceName == "mongo-2" { + assert.Nil(t, candidate.InstalledVersion) + assert.Nil(t, candidate.ConfigPath) + } + } + } +} diff --git a/managed/services/om/projection.go b/managed/services/om/projection.go new file mode 100644 index 00000000000..60921395afe --- /dev/null +++ b/managed/services/om/projection.go @@ -0,0 +1,347 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "cmp" + "crypto/sha256" + "encoding/hex" + "slices" + "time" + + "github.com/AlekSi/pointer" + "google.golang.org/protobuf/types/known/timestamppb" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" +) + +// Four rules the document shape enforces, all of them load-bearing for the UI: +// +// - A service that inventory knows and no source ever saw is still in the document, as +// status DOWN. Dropping it would shrink the estate every time something broke. +// - Grouping is by environment then cluster, where cluster falls back to the replica +// set. Both keys are emitted as null rather than the internal sentinel, so the +// document never invents a name. +// - Numeric gauges use -1 for "not measured", not 0 and not null. +// - Nothing here is a verdict. The document reports what was observed; health rules +// read it, they do not live here. + +// document is one assembled topology document plus what it took to assemble it. +type document struct { + summary *omv1.Summary + environments []*omv1.Environment + // observedAt is the newest observation behind the document, or the zero time when + // nothing datable went into it. + observedAt time.Time + // staleServices is how many services carry a volatile fact too old to read. + staleServices int +} + +// buildDocument folds inventory and the merged facts into the topology document. +func buildDocument(services []*models.Service, merged map[string]map[string]MergedField, now time.Time, maxAge time.Duration) document { + out := document{} + grouped := make(map[string]map[string][]*omv1.TopologyService) + + for _, service := range services { + fields := fieldSet{fields: merged[service.ServiceID], now: now, maxAge: maxAge} + if fields.fields == nil { + fields.fields = map[string]MergedField{} + } + if stale := fields.staleVolatile(); stale > 0 { + out.staleServices++ + } + for _, held := range fields.fields { + if held.ObservedAt != nil && held.ObservedAt.After(out.observedAt) { + out.observedAt = *held.ObservedAt + } + } + + env, cluster := groupingKeys(service, fields) + if _, ok := grouped[env]; !ok { + grouped[env] = make(map[string][]*omv1.TopologyService) + } + grouped[env][cluster] = append(grouped[env][cluster], serviceDocument(service, fields)) + } + + out.environments = make([]*omv1.Environment, 0, len(grouped)) + for _, env := range sortedKeys(grouped) { + clusters := make([]*omv1.Cluster, 0, len(grouped[env])) + for _, cluster := range sortedKeys(grouped[env]) { + svcs := grouped[env][cluster] + slices.SortFunc(svcs, func(a, b *omv1.TopologyService) int { + return cmp.Compare(a.ServiceName, b.ServiceName) + }) + clusters = append(clusters, &omv1.Cluster{ + Name: named(cluster), + Services: svcs, + Id: clusterID(env, cluster), + Type: clusterType(svcs), + }) + } + out.environments = append(out.environments, &omv1.Environment{EnvName: named(env), Clusters: clusters}) + } + + out.summary = buildSummary(out.environments) + return out +} + +// applyHealth evaluates advisories and rollup statuses over the assembled document. +// +// A separate pipeline stage so the observational projection above stays pure: buildDocument +// reports what was observed, and a verdict about what that means belongs downstream of it, +// not folded into the same pass. No-op today -- there are no health rules yet -- and kept as +// its own stage rather than an `if` bolted onto serviceDocument so the first rule has a place +// to land without restructuring the pipeline around it. +func applyHealth(doc document) document { + return doc +} + +// serviceDocument builds one service entry. +func serviceDocument(service *models.Service, fields fieldSet) *omv1.TopologyService { + host := fields.str(fieldHost) + if host == "" { + host = service.ServiceName + } + serviceType := fields.str(fieldServiceType) + if serviceType == "" { + serviceType = string(models.MongoDBServiceType) + } + + up := pointer.GetFloat64(fields.f64(fieldExporterUp)) == 1 + + return &omv1.TopologyService{ + ServiceName: service.ServiceName, + Host: optional(host), + Endpoint: optional(fields.str(fieldEndpoint)), + ServiceId: optional(service.ServiceID), + ServiceType: optional(serviceType), + Version: optional(fields.str(fieldVersion)), + Vendor: optional(fields.str(fieldVendor)), + Edition: optional(fields.str(fieldEdition)), + ReplicationSet: optional(fields.str(fieldReplicationSet)), + State: optional(fields.str(fieldState)), + Status: serviceStatus(up), + CpuUsagePercent: gauge(fields.f64(fieldCPUUsage), up), + ConnectionsFreePercent: gauge(fields.f64(fieldConnectionsFree), up), + ProcessRole: processRole(fields), + ReplicationLagSeconds: optionalDouble(fields.f64(fieldReplicationLag)), + OplogWindowSeconds: optionalDouble(oplogWindow(fields)), + + // Probe-only, and null wherever no probe has run. Not volatile: an installed + // binary and a config path are properties of the node, not of this moment, so + // they keep reporting what the last sweep found rather than blanking between + // sweeps that are minutes apart. + InstalledVersion: optional(fields.str(fieldInstalledVersion)), + ConfigPath: optional(fields.str(fieldConfigPath)), + Argv: optional(fields.str(fieldArgv)), + + // This row's own provenance, as against Snapshot.observed_at's estate-wide + // newest -- see fieldSet.newestObservedAt. + ObservedAt: observedAtTimestamp(fields.newestObservedAt()), + } +} + +// observedAtTimestamp adapts fieldSet.newestObservedAt's *time.Time to the wire's +// *timestamppb.Timestamp, nil to nil. +func observedAtTimestamp(t *time.Time) *timestamppb.Timestamp { + if t == nil { + return nil + } + return timestamppb.New(*t) +} + +// clusterID derives a stable, opaque id for one grouped service inventory. +// +// (environment, grouping key) is already the unique key buildDocument groups services +// under -- groupingKeys has already folded replication_set into it as cluster's fallback +// -- so hashing that pair is enough to give two clusters that happen to share a label +// (two generations of a sandbox both called "sharded-cluster") two different ids. +// Deterministic rather than random, so the same estate group derives the same id run +// over run without needing to be stored anywhere: id is a projection of the grouping, +// not new state. +func clusterID(env, groupKey string) string { + sum := sha256.Sum256([]byte(env + "\x00" + groupKey)) + return hex.EncodeToString(sum[:])[:16] +} + +// clusterType infers a grouped service inventory's shape from what is in the group. +// +// Inferred, not reconstructed -- this package does not walk a replica set's own config to +// discover its member list, it looks at what buildDocument already grouped: a mongos +// present, or more than one replication_set label sharing this cluster label, is SHARDED; +// exactly one replication_set and no mongos is REPLICA_SET; neither is STANDALONE. A +// later schema_version can grow an actual shard map without this needing to change -- +// the enum names a shape, it does not commit to having discovered one. +func clusterType(services []*omv1.TopologyService) omv1.ClusterType { + replicationSets := make(map[string]bool) + mongos := false + for _, svc := range services { + if svc.GetProcessRole() == omv1.ProcessRole_PROCESS_ROLE_MONGOS { + mongos = true + } + if rs := svc.GetReplicationSet(); rs != "" { + replicationSets[rs] = true + } + } + switch { + case mongos || len(replicationSets) > 1: + return omv1.ClusterType_CLUSTER_TYPE_SHARDED + case len(replicationSets) == 1: + return omv1.ClusterType_CLUSTER_TYPE_REPLICA_SET + default: + return omv1.ClusterType_CLUSTER_TYPE_STANDALONE + } +} + +// groupingKeys returns the (environment, cluster) keys a service groups under. +// +// Cluster falls back to the replica set, because a replica set registered without a +// --cluster= string is still a cluster and would otherwise land in one anonymous bucket +// with everything else. The merged fields already carry inventory as the fallback source +// for both, so this reads them once rather than re-deriving the precedence. +func groupingKeys(_ *models.Service, fields fieldSet) (string, string) { + env := firstNonEmpty(fields.str(fieldEnvironment), unspecified) + cluster := firstNonEmpty(fields.str(fieldCluster), fields.str(fieldReplicationSet), unspecified) + return env, cluster +} + +// processRole returns a service's process role. +// +// The mongodb_mongos_sharding_shards_total metric is emitted only by a router, so its +// presence is the test -- no port-convention guessing. Otherwise the exporter's cl_role +// names a config or shard server, and anything else is a plain mongod. +func processRole(fields fieldSet) omv1.ProcessRole { + if fields.truthy(fieldIsMongos) { + return omv1.ProcessRole_PROCESS_ROLE_MONGOS + } + if role, ok := clusterRoles[fields.str(fieldClusterRole)]; ok { + return role + } + return omv1.ProcessRole_PROCESS_ROLE_MONGOD +} + +// gauge returns a reading, or the unmeasured sentinel when there is none. +// +// A DOWN service reports the sentinel even if a reading survives in the query window: a +// CPU figure for a process that is not running would be read as current, and a number +// nobody can act on is worse than an explicit "not measured". +func gauge(value *float64, up bool) float64 { + if !up || value == nil { + return unmeasured + } + return *value +} + +// oplogWindow returns the oplog window in seconds, or nil when it cannot be computed. +// +// Head and tail come from the same scrape, so subtracting two separately queried values +// is safe in practice. The head >= tail guard still rejects the pathological case -- +// mismatched scrapes, clock skew -- as unknown rather than surfacing a negative duration. +func oplogWindow(fields fieldSet) *float64 { + head, tail := fields.f64(fieldOplogHead), fields.f64(fieldOplogTail) + if head == nil || tail == nil || *head < *tail { + return nil + } + window := *head - *tail + return &window +} + +// buildSummary builds the fleet-level counts the list view shows above the table. +// +// The down_services count is the honest headline and is a first-class field rather than +// something every caller re-derives. +// +// The process_role_counts map is keyed by the ProcessRole enum's name rather than its +// number, so it reads as itself in JSON instead of as {"1": 5}. +func buildSummary(environments []*omv1.Environment) *omv1.Summary { + summary := &omv1.Summary{ + Environments: int32(len(environments)), //nolint:gosec + ProcessRoleCounts: make(map[string]int32), + } + for _, env := range environments { + summary.Clusters += int32(len(env.Clusters)) //nolint:gosec + for _, cluster := range env.Clusters { + for _, service := range cluster.Services { + summary.TotalServices++ + if service.Status == omv1.ServiceStatus_SERVICE_STATUS_UP { + summary.UpServices++ + } else { + summary.DownServices++ + } + summary.ProcessRoleCounts[service.ProcessRole.String()]++ + } + } + } + return summary +} + +func serviceStatus(up bool) omv1.ServiceStatus { + if up { + return omv1.ServiceStatus_SERVICE_STATUS_UP + } + return omv1.ServiceStatus_SERVICE_STATUS_DOWN +} + +// named returns a grouping key as the document spells it: null for the internal +// sentinel, the key itself otherwise. +func named(key string) *string { + if key == unspecified { + return nil + } + return &key +} + +// optional returns nil for an empty string, so the document omits the key rather than +// carrying "". +// +// These fields were `google.protobuf.StringValue` originally, because protojson renders +// an unset message field as an explicit null while it omits an unset proto3 `optional` +// scalar entirely, even under EmitUnpopulated. The explicit null read better. It was not +// worth what it cost: protoc-gen-openapiv2 does not mark a wrapper field `x-nullable`, +// so the REST schema and the generated Go client both flattened to a value type and lost +// the distinction altogether -- `{}`, null and 0 arrived as 0. An absent key is a weaker +// signal than a null one, but it is a signal that survives the whole contract, and it is +// what every other proto in PMM does. +func optional(value string) *string { + if value == "" { + return nil + } + return &value +} + +// optionalDouble is optional's counterpart for a gauge that may not apply at all. +func optionalDouble(value *float64) *float64 { + return value +} + +func firstNonEmpty(values ...string) string { + for _, value := range values { + if value != "" { + return value + } + } + return "" +} + +func sortedKeys[V any](m map[string]V) []string { + keys := make([]string, 0, len(m)) + for key := range m { + keys = append(keys, key) + } + slices.Sort(keys) + return keys +} diff --git a/managed/services/om/projection_test.go b/managed/services/om/projection_test.go new file mode 100644 index 00000000000..8bcfa53ddb0 --- /dev/null +++ b/managed/services/om/projection_test.go @@ -0,0 +1,323 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "maps" + "testing" + "time" + + "github.com/AlekSi/pointer" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" +) + +var ( + projectionNow = time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC) + projectionMaxAge = 30 * time.Second +) + +func mongoService(id, name, cluster, replicationSet, environment string) *models.Service { + return &models.Service{ + ServiceID: id, + ServiceName: name, + ServiceType: models.MongoDBServiceType, + Cluster: cluster, + ReplicationSet: replicationSet, + Environment: environment, + NodeID: "node-" + id, + } +} + +// liveFacts is a healthy replica-set member as the metrics source would report it. +func liveFacts(state string, extra map[string]MergedField) map[string]MergedField { + observed := projectionNow.Add(-5 * time.Second) + fields := map[string]MergedField{ + fieldExporterUp: {Value: 1.0, Source: sourceMetrics, ObservedAt: &observed}, + fieldState: {Value: state, Source: sourceMetrics, ObservedAt: &observed}, + fieldVersion: {Value: "7.0.39-21", Source: sourceMetrics, ObservedAt: &observed}, + fieldVendor: {Value: "Percona", Source: sourceMetrics, ObservedAt: &observed}, + fieldEdition: {Value: "Community", Source: sourceMetrics, ObservedAt: &observed}, + fieldHost: {Value: "host-a", Source: sourceMetrics, ObservedAt: &observed}, + fieldEndpoint: {Value: "host-a:27017", Source: sourceMetrics, ObservedAt: &observed}, + fieldCPUUsage: {Value: 12.5, Source: sourceMetrics, ObservedAt: &observed}, + fieldConnectionsFree: {Value: 99.5, Source: sourceMetrics, ObservedAt: &observed}, + } + maps.Copy(fields, extra) + return fields +} + +func onlyService(t *testing.T, doc document) *omv1.TopologyService { + t.Helper() + require.Len(t, doc.environments, 1) + require.Len(t, doc.environments[0].Clusters, 1) + require.Len(t, doc.environments[0].Clusters[0].Services, 1) + return doc.environments[0].Clusters[0].Services[0] +} + +func TestBuildDocument(t *testing.T) { + t.Parallel() + + t.Run("a service no source saw is present and DOWN", func(t *testing.T) { + t.Parallel() + + // Dropping it would shrink the estate every time something broke. + services := []*models.Service{mongoService("s1", "mongo-1", "c1", "rs0", "prod")} + doc := buildDocument(services, map[string]map[string]MergedField{}, projectionNow, projectionMaxAge) + + svc := onlyService(t, doc) + assert.Equal(t, "mongo-1", svc.ServiceName) + assert.Equal(t, omv1.ServiceStatus_SERVICE_STATUS_DOWN, svc.Status) + assert.InDelta(t, float64(unmeasured), svc.CpuUsagePercent, 0.001) + assert.InDelta(t, float64(unmeasured), svc.ConnectionsFreePercent, 0.001) + assert.Nil(t, svc.Version) + assert.Equal(t, int32(1), doc.summary.TotalServices) + assert.Equal(t, int32(1), doc.summary.DownServices) + }) + + t.Run("a stopped service reads DOWN once its up flag ages out", func(t *testing.T) { + t.Parallel() + + // The regression that mattered: the sample survives the long lookback window, so + // only the age can tell that it is not a fact about now. + stale := projectionNow.Add(-10 * time.Minute) + fields := liveFacts("PRIMARY", nil) + for _, key := range []string{fieldExporterUp, fieldState, fieldCPUUsage, fieldConnectionsFree} { + held := fields[key] + held.ObservedAt = &stale + fields[key] = held + } + + services := []*models.Service{mongoService("s1", "mongo-1", "c1", "rs0", "prod")} + doc := buildDocument(services, map[string]map[string]MergedField{"s1": fields}, projectionNow, projectionMaxAge) + + svc := onlyService(t, doc) + assert.Equal(t, omv1.ServiceStatus_SERVICE_STATUS_DOWN, svc.Status) + assert.Nil(t, svc.State, "a replica-set state from ten minutes ago is not current") + assert.InDelta(t, float64(unmeasured), svc.CpuUsagePercent, 0.001) + assert.Equal(t, "7.0.39-21", svc.GetVersion(), "identity is still worth reporting") + assert.Equal(t, 1, doc.staleServices) + }) + + t.Run("gauges are suppressed for a service that is not up", func(t *testing.T) { + t.Parallel() + + fields := liveFacts("PRIMARY", nil) + delete(fields, fieldExporterUp) + + services := []*models.Service{mongoService("s1", "mongo-1", "c1", "rs0", "prod")} + doc := buildDocument(services, map[string]map[string]MergedField{"s1": fields}, projectionNow, projectionMaxAge) + + svc := onlyService(t, doc) + assert.Equal(t, omv1.ServiceStatus_SERVICE_STATUS_DOWN, svc.Status) + assert.InDelta(t, float64(unmeasured), svc.CpuUsagePercent, 0.001, "a CPU figure for a stopped process reads as current") + }) + + t.Run("the oplog window is the difference, and nil when it cannot be one", func(t *testing.T) { + t.Parallel() + + observed := projectionNow.Add(-5 * time.Second) + withOplog := func(head, tail float64) map[string]MergedField { + return liveFacts("PRIMARY", map[string]MergedField{ + fieldOplogHead: {Value: head, Source: sourceMetrics, ObservedAt: &observed}, + fieldOplogTail: {Value: tail, Source: sourceMetrics, ObservedAt: &observed}, + }) + } + services := []*models.Service{mongoService("s1", "mongo-1", "c1", "rs0", "prod")} + + doc := buildDocument(services, map[string]map[string]MergedField{"s1": withOplog(1000, 400)}, projectionNow, projectionMaxAge) + assert.InDelta(t, 600.0, onlyService(t, doc).GetOplogWindowSeconds(), 0.001) + + // head < tail is mismatched scrapes or clock skew: unknown, not a negative duration. + doc = buildDocument(services, map[string]map[string]MergedField{"s1": withOplog(400, 1000)}, projectionNow, projectionMaxAge) + assert.Nil(t, onlyService(t, doc).OplogWindowSeconds) + + // A standalone emits neither. + doc = buildDocument(services, map[string]map[string]MergedField{"s1": liveFacts("PRIMARY", nil)}, projectionNow, projectionMaxAge) + assert.Nil(t, onlyService(t, doc).OplogWindowSeconds) + }) + + t.Run("the process role comes from the exporter, not a port convention", func(t *testing.T) { + t.Parallel() + + observed := projectionNow.Add(-5 * time.Second) + services := []*models.Service{mongoService("s1", "mongo-1", "c1", "rs0", "prod")} + + for _, tc := range []struct { + name string + extra map[string]MergedField + want omv1.ProcessRole + }{ + {"plain mongod", nil, omv1.ProcessRole_PROCESS_ROLE_MONGOD}, + {"router", map[string]MergedField{ + fieldIsMongos: {Value: true, Source: sourceMetrics, ObservedAt: &observed}, + }, omv1.ProcessRole_PROCESS_ROLE_MONGOS}, + {"config server", map[string]MergedField{ + fieldClusterRole: {Value: "configsvr", Source: sourceMetrics, ObservedAt: &observed}, + }, omv1.ProcessRole_PROCESS_ROLE_CONFIGSVR}, + {"shard server", map[string]MergedField{ + fieldClusterRole: {Value: "shardsvr", Source: sourceMetrics, ObservedAt: &observed}, + }, omv1.ProcessRole_PROCESS_ROLE_SHARDSVR}, + } { + doc := buildDocument(services, + map[string]map[string]MergedField{"s1": liveFacts("PRIMARY", tc.extra)}, + projectionNow, projectionMaxAge) + assert.Equal(t, tc.want, onlyService(t, doc).ProcessRole, tc.name) + } + }) + + t.Run("grouping falls back replica set, then to null", func(t *testing.T) { + t.Parallel() + + observed := projectionNow.Add(-5 * time.Second) + inv := func(cluster, rs, env string) map[string]MergedField { + fields := map[string]MergedField{} + for key, value := range map[string]string{ + fieldCluster: cluster, fieldReplicationSet: rs, fieldEnvironment: env, + } { + if value != "" { + fields[key] = MergedField{Value: value, Source: sourceInventory, ObservedAt: &observed} + } + } + return fields + } + + services := []*models.Service{ + mongoService("s1", "a", "", "", ""), + mongoService("s2", "b", "", "rs0", "prod"), + mongoService("s3", "c", "cl1", "rs0", "prod"), + } + doc := buildDocument(services, map[string]map[string]MergedField{ + "s1": inv("", "", ""), + "s2": inv("", "rs0", "prod"), + "s3": inv("cl1", "rs0", "prod"), + }, projectionNow, projectionMaxAge) + + // Environments sort by the internal grouping key, so the unnamed bucket -- + // "UNSPECIFIED" -- sorts ahead of "prod" by codepoint. Matches SEP, whose + // sorted() orders the same way. + require.Len(t, doc.environments, 2) + assert.Nil(t, doc.environments[0].EnvName, "an unset environment is null, never invented") + assert.Equal(t, "prod", doc.environments[1].GetEnvName()) + + require.Len(t, doc.environments[0].Clusters, 1) + assert.Nil(t, doc.environments[0].Clusters[0].Name) + + require.Len(t, doc.environments[1].Clusters, 2) + assert.Equal(t, "cl1", doc.environments[1].Clusters[0].GetName()) + assert.Equal(t, "rs0", doc.environments[1].Clusters[1].GetName(), "cluster falls back to the replica set") + }) + + t.Run("services sort by name inside a cluster", func(t *testing.T) { + t.Parallel() + + services := []*models.Service{ + mongoService("s1", "mongo-c", "cl1", "rs0", "prod"), + mongoService("s2", "mongo-a", "cl1", "rs0", "prod"), + mongoService("s3", "mongo-b", "cl1", "rs0", "prod"), + } + merged := map[string]map[string]MergedField{} + for _, service := range services { + merged[service.ServiceID] = liveFacts("SECONDARY", nil) + } + doc := buildDocument(services, merged, projectionNow, projectionMaxAge) + + names := make([]string, 0, len(doc.environments[0].Clusters[0].Services)) + for _, svc := range doc.environments[0].Clusters[0].Services { + names = append(names, svc.ServiceName) + } + assert.Equal(t, []string{"mongo-a", "mongo-b", "mongo-c"}, names) + }) + + t.Run("the summary counts what the tree holds", func(t *testing.T) { + t.Parallel() + + observed := projectionNow.Add(-5 * time.Second) + services := []*models.Service{ + mongoService("s1", "mongo-1", "cl1", "rs0", "prod"), + mongoService("s2", "mongo-2", "cl1", "rs0", "prod"), + mongoService("s3", "router", "cl1", "", "prod"), + } + doc := buildDocument(services, map[string]map[string]MergedField{ + "s1": liveFacts("PRIMARY", nil), + "s2": {}, // never seen + "s3": liveFacts("", map[string]MergedField{ + fieldIsMongos: {Value: true, Source: sourceMetrics, ObservedAt: &observed}, + }), + }, projectionNow, projectionMaxAge) + + assert.Equal(t, int32(3), doc.summary.TotalServices) + assert.Equal(t, int32(2), doc.summary.UpServices) + assert.Equal(t, int32(1), doc.summary.DownServices) + // Keyed by the enum's name, not its number, so the map reads as itself in JSON. + assert.Equal(t, map[string]int32{ + omv1.ProcessRole_PROCESS_ROLE_MONGOD.String(): 2, + omv1.ProcessRole_PROCESS_ROLE_MONGOS.String(): 1, + }, doc.summary.ProcessRoleCounts) + }) + + t.Run("observed_at is the newest observation behind the document", func(t *testing.T) { + t.Parallel() + + newest := projectionNow.Add(-3 * time.Second) + older := projectionNow.Add(-20 * time.Second) + services := []*models.Service{ + mongoService("s1", "mongo-1", "cl1", "rs0", "prod"), + mongoService("s2", "mongo-2", "cl1", "rs0", "prod"), + } + doc := buildDocument(services, map[string]map[string]MergedField{ + "s1": {fieldExporterUp: {Value: 1.0, Source: sourceMetrics, ObservedAt: &older}}, + "s2": {fieldExporterUp: {Value: 1.0, Source: sourceMetrics, ObservedAt: &newest}}, + }, projectionNow, projectionMaxAge) + + assert.Equal(t, newest, doc.observedAt) + assert.False(t, isStale(doc, projectionNow)) + }) +} + +func TestInventoryEndpoint(t *testing.T) { + t.Parallel() + + service := mongoService("s1", "mongo-1", "cl1", "rs0", "prod") + service.Port = pointer.ToUint16(27017) + service.Address = new("127.0.0.1") + + t.Run("prefers the node over the service address", func(t *testing.T) { + t.Parallel() + + // A service address is where its own agent reaches it -- 127.0.0.1 for a local + // agent, which is true and useless to anyone else. + node := &models.Node{NodeName: "db-host-1", Address: "10.0.0.11"} + assert.Equal(t, "10.0.0.11:27017", inventoryEndpoint(service, node)) + }) + + t.Run("falls back to the node name, then the service address", func(t *testing.T) { + t.Parallel() + + assert.Equal(t, "db-host-1:27017", inventoryEndpoint(service, &models.Node{NodeName: "db-host-1"})) + assert.Equal(t, "127.0.0.1:27017", inventoryEndpoint(service, nil)) + }) + + t.Run("no port means no endpoint", func(t *testing.T) { + t.Parallel() + + portless := mongoService("s2", "mongo-2", "", "", "") + assert.Empty(t, inventoryEndpoint(portless, &models.Node{NodeName: "db-host-1"})) + }) +} diff --git a/managed/services/om/sep_client.go b/managed/services/om/sep_client.go new file mode 100644 index 00000000000..de13051bcb0 --- /dev/null +++ b/managed/services/om/sep_client.go @@ -0,0 +1,104 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "strings" +) + +// sepClient is where SEP is and how PMM authenticates to it: the base URL, the bearer +// token, the http.Client every SEP-backed source and proxy handler shares. +// +// It knows nothing about a specific app -- that is app()'s job. Splitting the two is what +// lets a second SEP-backed source (restart, upgrade, whatever om_actions turns out to +// need) get a client of its own by calling app() again on the one sepClient the Service +// already holds, rather than by copying the transport. Before this split, probeSource was +// three things at once: the on-host fact source, the transport to SEP, and (through +// inventory.go's use of it) half of the inventory REST surface. Only the first of those +// is a probeSource's business; the other two are this file's. +type sepClient struct { + baseURL string + token string + http *http.Client +} + +// app returns a handle addressed relative to /api/apps/, the mount every SEP app +// follows. Which app to ask is the caller's business, not the operator's: `--sep-url` +// points at SEP, not at an app, so the same setting serves every source this package +// gains. +func (c *sepClient) app(module string) sepApp { + return sepApp{client: c, path: "api/apps/" + module} +} + +// sepApp addresses one SEP app through a shared sepClient. Cheap to copy: it is a +// pointer and a path. +type sepApp struct { + client *sepClient + path string +} + +// endpoint builds an absolute URL for a path relative to this app. +func (a sepApp) endpoint(path string) string { + return strings.TrimSuffix(a.client.baseURL, "/") + "/" + a.path + "/" + strings.TrimPrefix(path, "/") +} + +// request builds one HTTP request against this app. +// +// Body is marshalled as JSON when non-nil, and when sendEmptyBody is set instead sends +// "{}" -- some proxied endpoints need that: the app's trigger endpoint takes an optional +// object and FastAPI rejects a bodyless POST against a typed body. +// +// The caller sets its own deadline on ctx and performs the request itself -- callers want +// different timeouts (a probe's own read of its estate is budgeted tighter than a proxied +// request the browser is waiting on) and different error mappings (a gRPC status for the +// inventory proxy, a plain error for a factSource's run receipt), and only the request +// itself -- the URL, the query, the body encoding, the bearer header -- is common to both. +func (a sepApp) request(ctx context.Context, method, path string, query url.Values, body any, sendEmptyBody bool) (*http.Request, error) { + endpoint := a.endpoint(path) + if len(query) > 0 { + endpoint += "?" + query.Encode() + } + + var payload []byte + switch { + case body != nil: + encoded, err := json.Marshal(body) + if err != nil { + return nil, fmt.Errorf("failed to encode the request: %w", err) + } + payload = encoded + case sendEmptyBody: + payload = []byte("{}") + } + + req, err := http.NewRequestWithContext(ctx, method, endpoint, bytes.NewReader(payload)) + if err != nil { + return nil, err //nolint:wrapcheck + } + if a.client.token != "" { + req.Header.Set("Authorization", "Bearer "+a.client.token) + } + if payload != nil { + req.Header.Set("Content-Type", "application/json") + } + return req, nil +} diff --git a/managed/services/om/service.go b/managed/services/om/service.go new file mode 100644 index 00000000000..5506e120655 --- /dev/null +++ b/managed/services/om/service.go @@ -0,0 +1,588 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Package om implements OM -- the OpenManager topology and health API. +// +// It groups the MongoDB estate from the sources PMM already owns: the inventory in +// PostgreSQL and the exporter metrics in VictoriaMetrics. PMM stores cluster and +// replication_set as flat string columns on a service and has no topology object; this +// service groups services that share a label, folds in reachability and load, and serves +// the result as one document. That is a grouped service inventory, not a reconstructed +// topology graph: a sharded cluster here is a flat list of mongos, configsvr and shardsvr +// rows that happen to share a label, not a shard map with a discovered member list. See +// ClusterType in api/om/v1/om.proto for the one thing inferred about a group's shape. +// +// It is the read half of a split: derivation over data PMM owns lives here, while work +// that has to run on a database host -- collecting argv and installed binary versions, +// restarts, upgrades, configuration changes -- lives in SEP apps driving Nomad clients. +// Those arrive here as another factSource, which is why the merge is by declared +// precedence rather than by which source ran last. +package om + +import ( + "context" + "errors" + "fmt" + "net/http" + "sync" + "sync/atomic" + "time" + + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" + "gopkg.in/reform.v1" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" +) + +const ( + // How often the leader's own ticker rebuilds the document. Collection is + // leader-driven, not request-driven -- see Run and GetTopology -- so this paces the + // ticker rather than gating a read. + refreshInterval = 30 * time.Second + + // How old the newest observation may be before the document declares itself stale. A + // stale document is still served -- the UI shows the age and lets the reader judge, + // which beats replacing data with an error. + staleAfter = 5 * time.Minute + + // How many runs the in-memory history keeps. + runHistory = 100 + + // What the UI asks for when it passes no limit, and the most a caller may ask for. + // The ceiling is runHistory: asking for more than the history keeps cannot return + // more rows, so a larger number is only a larger query. + defaultRunLimit = 25 + maxRunLimit = runHistory +) + +// Run statuses, as the run row stores them. A run whose sources all answered is a success +// even if some services were never seen: a service that inventory knows and metrics have +// not is a fact about the estate, not a failure of the run. +// +// Kept as strings because they are persisted. The wire carries omv1.RunStatus instead, and +// runStatusToProto in store.go is the only crossing -- a stored row stays legible in psql +// and survives a renumbering of the enum. +const ( + runStatusSuccess = "success" + runStatusPartial = "partial" + runStatusFailed = "failed" +) + +// Service provides the OM topology API. +type Service struct { + omv1.UnimplementedOmServiceServer + + db *reform.DB + vmClient victoriaMetricsClient + l *logrus.Entry + + // ha reports leadership, so TriggerTopologyCollection can refuse on a follower. Nil + // in most tests, which is read as "every node is the leader" -- the single-node + // default. + ha haChecker + + // probe is the on-host fact source, or nil when SEP's om_inventory app is not + // configured. Held rather than constructed per run so the HTTP client is reused. + probe *probeSource + + // restored guards the one-time read of the stored document on a cold start. + restored sync.Once + + // running serialises collection. One collection at a time is enough, and two + // concurrent ones would issue the same queries twice and race to publish. + running sync.Mutex + + mu sync.Mutex + latest *omv1.GetTopologyResponse + + // Completed-run tally by status, read by MetricsCollector on every Prometheus scrape + // and written once per run by recordRunOutcome. Atomic because a scrape can land while + // a collection is in flight. + runsSuccess atomic.Int64 + runsPartial atomic.Int64 + runsFailed atomic.Int64 +} + +// New returns a new OM service. +func New(db *reform.DB, vmClient victoriaMetricsClient, ha haChecker, l *logrus.Entry) *Service { + return &Service{ + db: db, + vmClient: vmClient, + ha: ha, + l: l, + } +} + +// WithProbeSource attaches SEP's om_inventory app as a fact source. +// +// Takes where SEP is, not where the app is: the app path is this package's business, +// and the sources that follow -- upgrade, restart -- will hang off the same SEP. +// +// Optional by design: an empty URL leaves the source off, and the document is built +// from PMM's own inventory and metrics alone. That is the difference between "no probe +// has run here" and "the probe failed", and the run receipt reports which. +func (s *Service) WithProbeSource(sepURL, token string) *Service { + if sepURL == "" { + s.l.Info("SEP is not configured; on-host facts will be absent") + return s + } + client := &sepClient{ + baseURL: sepURL, + token: token, + http: &http.Client{Timeout: probeRequestTimeout}, + } + probe := &probeSource{ + app: client.app(probeAppModule), + l: s.l.WithField("source", sourceProbe), + } + s.probe = probe + s.l.Infof("om_inventory estate at %s", probe.app.endpoint("")) + return s +} + +// GetTopology returns the whole MongoDB estate as one document. +// +// A pure read path: memory, then the stored snapshot, never a collection. Collection is +// leader-only (Run, TriggerTopologyCollection), and a request-triggered rebuild here +// would make every follower behind the load balancer a writer and a pruner racing the +// leader. Staleness is recomputed against the clock on every call rather than trusted +// from whenever the document was built or restored, so a follower that never collects +// still reports its document's true age. +func (s *Service) GetTopology(ctx context.Context, _ *omv1.GetTopologyRequest) (*omv1.GetTopologyResponse, error) { //nolint:unparam + s.restoreOnce(ctx) + if cached := s.snapshot(); cached != nil { + return withFreshStale(cached), nil + } + // Genuinely cold: no in-memory document and nothing stored yet, e.g. a fresh estate + // whose leader has not completed its first pass. An empty document with stale=true + // is the honest answer -- Unavailable would read as an error for a normal startup + // state, and blocking for the leader's first run would reintroduce the + // request-triggered wait this path exists to remove. + return emptyTopologyResponse(), nil +} + +// ListTopologyRuns returns the recorded runs, newest first. +func (s *Service) ListTopologyRuns(ctx context.Context, req *omv1.ListTopologyRunsRequest) (*omv1.ListTopologyRunsResponse, error) { + limit := int(req.GetLimit()) + switch { + case limit <= 0: + limit = defaultRunLimit + case limit > maxRunLimit: + limit = maxRunLimit + } + + runs, err := s.listRuns(ctx, limit) + if err != nil { + return nil, err + } + return &omv1.ListTopologyRunsResponse{Runs: runs}, nil +} + +// GetTopologyRun returns one recorded run. +func (s *Service) GetTopologyRun(ctx context.Context, req *omv1.GetTopologyRunRequest) (*omv1.GetTopologyRunResponse, error) { + run, err := s.getRun(ctx, req.GetRunId()) + if err != nil { + if errors.Is(err, models.ErrNotFound) { + return nil, status.Errorf(codes.NotFound, "Run %s not found.", req.GetRunId()) + } + return nil, err + } + return &omv1.GetTopologyRunResponse{Run: run}, nil +} + +// TriggerTopologyCollection rebuilds the topology document now and records the run. +// +// Synchronous, unlike SEP's, and it answers with a terminal status: there is no fan-out +// to remote executors to wait on here, so there is nothing to poll for. It refuses +// rather than queues while one is in flight -- two collections would issue the same +// queries twice and race to publish, and the caller wants the answer, not a second run. +// +// Refuses on a non-leader for the same reason: a follower that collected would persist a +// run and prune the shared history right alongside the leader's own pass. +// +//nolint:unparam +func (s *Service) TriggerTopologyCollection(ctx context.Context, _ *omv1.TriggerTopologyCollectionRequest) (*omv1.TriggerTopologyCollectionResponse, error) { + if s.ha != nil && !s.ha.IsLeader() { + if leader := s.ha.LeaderID(); leader != "" { + return nil, status.Errorf(codes.FailedPrecondition, + "This node is not the HA leader; %s is. Only the leader collects.", leader) + } + return nil, status.Error(codes.FailedPrecondition, + "This node is not the HA leader. Only the leader collects.") + } + + if !s.running.TryLock() { + // Aborted, not FailedPrecondition: the gateway maps it to 409 Conflict, which is + // what the UI's Sync button already treats as an expected outcome rather than a + // failure. + return nil, status.Error(codes.Aborted, "A collection run is already in flight.") + } + defer s.running.Unlock() + + _, run, err := s.collect(ctx) + if err != nil { + return nil, err + } + return &omv1.TriggerTopologyCollectionResponse{ + RunId: run.RunId, + Status: run.Status, + StartTime: run.StartTime, + }, nil +} + +// Run refreshes the document on a timer until ctx is cancelled. +// +// Collection is driven rather than left to whoever happens to read: the run history is +// only worth having if it exists when nobody is looking, and a document assembled purely +// on demand can say nothing about the interval since the last one. +func (s *Service) Run(ctx context.Context) { + ticker := time.NewTicker(refreshInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + _, err := s.discover(ctx) + if err != nil && ctx.Err() == nil { + s.l.Warnf("scheduled collection failed: %s", err) + } + } + } +} + +// discover rebuilds unless another caller is already doing it, in which case it waits for +// that one and serves what it published. Two collections of the same estate at the same +// moment differ only in cost. +func (s *Service) discover(ctx context.Context) (*omv1.GetTopologyResponse, error) { + if !s.running.TryLock() { + s.running.Lock() + s.running.Unlock() //nolint:staticcheck // waiting out the in-flight run, not guarding + if cached := s.snapshot(); cached != nil { + return cached, nil + } + return nil, status.Error(codes.Unavailable, "A collection is in flight and no document is available yet.") + } + defer s.running.Unlock() + + response, _, err := s.collect(ctx) + return response, err +} + +// collect reads every source, merges, builds the document and records the run. The caller +// must hold s.running. +func (s *Service) collect(ctx context.Context) (*omv1.GetTopologyResponse, *omv1.TopologyRun, error) { + startedAt := time.Now() + runID := uuid.New().String() + + services, nodes, originNode, maxAge, err := s.readInventory(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to read inventory: %w", err) + } + + sources := s.sources(nodes, startedAt) + results := make([]SourceResult, 0, len(sources)) + for _, source := range sources { + results = append(results, source.collect(ctx, services)) + } + + merged := mergeFacts(results, defaultPrecedence) + generatedAt := time.Now() + doc := applyHealth(buildDocument(services, merged, generatedAt, maxAge)) + + response := &omv1.GetTopologyResponse{ + Snapshot: &omv1.Snapshot{ + GeneratedAt: timestamppb.New(generatedAt), + ObservedAt: observedAt(doc), + Stale: isStale(doc, generatedAt), + SchemaVersion: schemaVersion, + RunId: runID, + }, + OriginNode: optional(originNode), + SourceQueries: sourceQueries, + Summary: doc.summary, + Environments: doc.environments, + } + run := buildRun(runID, startedAt, generatedAt, services, merged, doc, results) + s.recordRunOutcome(run.Status) + + s.mu.Lock() + s.latest = response + s.mu.Unlock() + + // Recorded after publishing, and never fatal: the document is already correct and + // already served, so losing the record of a collection is worth less than refusing to + // answer with it. + err = s.persist(ctx, response, run, originNode) + if err != nil { + s.l.Warnf("run %s: failed to record: %s", runID, err) + } + + s.l.Infof("run %s: %d service(s), %d up, %d cluster(s), %d stale, %s max age, status %s", + runID, doc.summary.TotalServices, doc.summary.UpServices, doc.summary.Clusters, + doc.staleServices, maxAge, run.Status) + + return response, run, nil +} + +// sources returns the fact sources one collection reads, in the order they run. +// +// Extracted so a test can see the set and its order without driving a whole collection: +// which sources are wired in, and whether probe is included, is exactly what review +// found untested. Both nodes and startedAt are per-run state the sources close over +// rather than package globals, so two overlapping calls (the ticker and a manual +// trigger racing, however briefly) never share one. +func (s *Service) sources(nodes map[string]*models.Node, startedAt time.Time) []factSource { + sources := []factSource{ + inventorySource{nodes: nodes}, + metricsSource{vm: s.vmClient, l: s.l, now: startedAt}, + } + if s.probe != nil { + sources = append(sources, *s.probe) + } + return sources +} + +// restoreOnce loads the newest stored document into memory the first time it is needed, +// so a restarted pmm-managed answers from the last known estate rather than nothing. +// +// Only "is there a document at all" is decided here. How fresh it is remains a question +// the read path answers itself, every time it is asked -- see withFreshStale -- rather +// than baking the answer in as of the moment this ran. +func (s *Service) restoreOnce(ctx context.Context) { + s.restored.Do(func() { + response, generatedAt, err := s.restore(ctx) + if err != nil { + s.l.Warnf("failed to restore the stored topology: %s", err) + return + } + if response == nil { + return + } + s.mu.Lock() + if s.latest == nil { + s.latest = response + } + s.mu.Unlock() + s.l.Infof("restored the topology document generated at %s (%s ago)", + generatedAt.Format(time.RFC3339), time.Since(generatedAt).Truncate(time.Second)) + }) +} + +// snapshot returns the published document, however old. +func (s *Service) snapshot() *omv1.GetTopologyResponse { + s.mu.Lock() + defer s.mu.Unlock() + return s.latest +} + +// withFreshStale returns response with Snapshot.Stale recomputed against the current +// time, leaving the rest of the message untouched. +// +// A document served from memory can sit there for a long time on a node that never +// collects -- every follower, once GetTopology stops triggering a collection of its own +// -- so staleness has to be a property of when it is read, not frozen as of whenever it +// was built or restored. Response is shared across concurrent readers, so this returns a +// shallow copy rather than mutating it in place. +func withFreshStale(response *omv1.GetTopologyResponse) *omv1.GetTopologyResponse { + if response == nil || response.Snapshot == nil { + return response + } + // Built field by field rather than copied (`clone := *response`): a proto message + // carries a sync.Mutex in its generated MessageState, and copying that by value is + // exactly the bug go vet's copylocks check exists to catch. + snapshot := &omv1.Snapshot{ + GeneratedAt: response.Snapshot.GeneratedAt, + ObservedAt: response.Snapshot.ObservedAt, + Stale: snapshotStale(response.Snapshot.ObservedAt), + SchemaVersion: response.Snapshot.SchemaVersion, + RunId: response.Snapshot.RunId, + } + return &omv1.GetTopologyResponse{ + Snapshot: snapshot, + OriginNode: response.OriginNode, + SourceQueries: response.SourceQueries, + Summary: response.Summary, + Environments: response.Environments, + } +} + +// emptyTopologyResponse is what GetTopology answers on a genuinely cold estate: nothing +// in memory, nothing stored yet. That is the normal state for the first moments of a +// fresh install, not an error -- observed_at stays unset and stale is true so the UI can +// render "collecting, no data yet" rather than a blank document that looks like an empty +// estate. +func emptyTopologyResponse() *omv1.GetTopologyResponse { + return &omv1.GetTopologyResponse{ + Snapshot: &omv1.Snapshot{ + Stale: true, + SchemaVersion: schemaVersion, + }, + SourceQueries: sourceQueries, + Summary: &omv1.Summary{ProcessRoleCounts: map[string]int32{}}, + Environments: []*omv1.Environment{}, + } +} + +// readInventory returns every MongoDB service, its nodes by ID, the PMM Server node name +// to record as the document's vantage point, and how old a volatile observation may be. +func (s *Service) readInventory(ctx context.Context) ([]*models.Service, map[string]*models.Node, string, time.Duration, error) { + var ( + services []*models.Service + nodesByID map[string]*models.Node + originNode string + maxAge time.Duration + ) + + serviceType := models.MongoDBServiceType + errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + var err error + services, err = models.FindServices(tx.Querier, models.ServiceFilters{ServiceType: &serviceType}) + if err != nil { + return err + } + + // The freshness rule follows whatever PMM is actually scraping at, rather than + // hardcoding an interval that a settings change would silently invalidate. + settings, err := models.GetSettings(tx) + if err != nil { + return err + } + maxAge = max(settings.MetricsResolutions.HR*volatileMaxAgeFactor, minVolatileMaxAge) + + nodes, err := models.FindNodes(tx.Querier, models.NodeFilters{}) + if err != nil { + return err + } + nodesByID = make(map[string]*models.Node, len(nodes)) + for _, node := range nodes { + nodesByID[node.NodeID] = node + if node.IsPMMServerNode { + originNode = node.NodeName + } + } + return nil + }) + if errTX != nil { + return nil, nil, "", 0, errTX + } + return services, nodesByID, originNode, maxAge, nil +} + +// buildRun records what one pass saw. +// +// The resolved_services versus successful_probes pair is the diagnostic split: the first says a +// source produced facts for the service at all, the second says it was observed as reachable. +// A run with resolved=9, successful=0 is a healthy join and nine unreachable databases. +func buildRun( + runID string, startedAt, finishedAt time.Time, + services []*models.Service, merged map[string]map[string]MergedField, + doc document, results []SourceResult, +) *omv1.TopologyRun { + counts := &omv1.TopologyRunCounts{TotalServices: int32(len(services))} //nolint:gosec + for _, service := range services { + if len(merged[service.ServiceID]) == 0 { + counts.OrphanedServices++ + continue + } + counts.ResolvedServices++ + } + counts.SuccessfulProbes = doc.summary.UpServices + counts.StaleServices = int32(doc.staleServices) //nolint:gosec + + run := &omv1.TopologyRun{ + RunId: runID, + Status: omv1.RunStatus_RUN_STATUS_SUCCESS, + StartTime: timestamppb.New(startedAt), + EndTime: timestamppb.New(finishedAt), + Counts: counts, + Sources: make([]*omv1.SourceReport, 0, len(results)), + Errors: []*omv1.TopologyRunError{}, + } + + failed := 0 + for _, result := range results { + run.Sources = append(run.Sources, &omv1.SourceReport{ + Source: result.Source, + Status: sourceStatusToProto(result.Status), + Facts: int32(len(result.Facts)), //nolint:gosec + Detail: detailStrings(result.Detail), + }) + for _, e := range result.Errors { + run.Errors = append(run.Errors, &omv1.TopologyRunError{ + Scope: e.Scope, + ServiceName: optional(e.ServiceName), + Code: e.Code, + Message: e.Message, + }) + } + if result.Status == SourceFailed { + failed++ + } + } + + switch { + case failed > 0 && failed == len(results): + run.Status = omv1.RunStatus_RUN_STATUS_FAILED + case len(run.Errors) > 0 || failed > 0: + run.Status = omv1.RunStatus_RUN_STATUS_PARTIAL + } + return run +} + +// recordRunOutcome tallies one completed run by status, for MetricsCollector's +// pmm_managed_om_runs_total counter. +func (s *Service) recordRunOutcome(status omv1.RunStatus) { + switch status { + case omv1.RunStatus_RUN_STATUS_SUCCESS: + s.runsSuccess.Add(1) + case omv1.RunStatus_RUN_STATUS_PARTIAL: + s.runsPartial.Add(1) + case omv1.RunStatus_RUN_STATUS_FAILED: + s.runsFailed.Add(1) + default: + // buildRun only ever sets one of the three above. + } +} + +// detailStrings renders a source's counters for the wire, which carries them as strings +// so a source can report whatever it has without the contract naming every counter. +func detailStrings(detail map[string]any) map[string]string { + out := make(map[string]string, len(detail)) + for key, value := range detail { + out[key] = fmt.Sprint(value) + } + return out +} + +func observedAt(doc document) *timestamppb.Timestamp { + if doc.observedAt.IsZero() { + return nil + } + return timestamppb.New(doc.observedAt) +} + +func isStale(doc document, generatedAt time.Time) bool { + if doc.observedAt.IsZero() { + return false + } + return generatedAt.Sub(doc.observedAt) > staleAfter +} diff --git a/managed/services/om/service_test.go b/managed/services/om/service_test.go new file mode 100644 index 00000000000..76bac0500ff --- /dev/null +++ b/managed/services/om/service_test.go @@ -0,0 +1,238 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "sync" + "testing" + "time" + + v1 "github.com/prometheus/client_golang/api/prometheus/v1" + "github.com/prometheus/common/model" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/utils/testdb" +) + +// panicVM fails the test the moment it is queried. GetTopology's whole point after the +// PMM-15326 read-path fix is that it never reaches VictoriaMetrics -- collection is +// leader-only and request-triggered nowhere -- so any test that exercises the read path +// wires this in and lets a query panic rather than silently succeed. +type panicVM struct{ t *testing.T } + +func (p panicVM) Query(context.Context, string, time.Time, ...v1.Option) (model.Value, v1.Warnings, error) { + p.t.Helper() + p.t.Fatal("GetTopology must not query VictoriaMetrics: it is a pure read path") + return nil, nil, nil +} + +// fakeHA is a haChecker double. +type fakeHA struct { + leader bool + leaderID string +} + +func (f fakeHA) IsLeader() bool { return f.leader } +func (f fakeHA) LeaderID() string { return f.leaderID } + +func serviceTestDB(t *testing.T) *reform.DB { + t.Helper() + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + return reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) +} + +// TestGetTopologyNeverCollects is the regression guard for PMM-15326's read-path fix: +// GetTopology must serve memory or the stored snapshot and never reach collect(), on a +// freshly restored service or on any later call. Before the fix, a restored document +// older than 30s missed the cache immediately and every request rebuilt it -- see +// service.go's package comment history in the PR for the mechanism. +func TestGetTopologyNeverCollects(t *testing.T) { + db := serviceTestDB(t) + + // Written by one Service instance, as if by a leader that has since gone away -- + // restored by a second, as pmm-managed does across a restart. + writer := &Service{db: db, l: logrus.WithField("test", t.Name())} + generatedAt := time.Now().Truncate(time.Microsecond) + response, run := testTopologyResponse("restored-run", generatedAt, generatedAt.Add(-2*time.Second)) + require.NoError(t, writer.persist(t.Context(), response, run, "pmm-server")) + + reader := &Service{db: db, vmClient: panicVM{t: t}, l: logrus.WithField("test", t.Name())} + + first, err := reader.GetTopology(t.Context(), &omv1.GetTopologyRequest{}) + require.NoError(t, err) + require.NotNil(t, first) + assert.Equal(t, "restored-run", first.Snapshot.RunId) + assert.False(t, first.Snapshot.Stale, "just-restored document should read as fresh") + + // The DB is gone from here on. sync.Once guarantees restoreOnce's own query never + // repeats, but this proves the read path holds that guarantee rather than assuming + // it -- a second GetTopology call has nothing to fall back on but memory. + require.NoError(t, db.DBInterface().(interface{ Close() error }).Close()) + + second, err := reader.GetTopology(t.Context(), &omv1.GetTopologyRequest{}) + require.NoError(t, err) + assert.Equal(t, first.Snapshot.RunId, second.Snapshot.RunId) +} + +// TestGetTopologyColdStart covers the estate that has never collected anywhere: no +// memory, nothing stored. GetTopology must answer with an empty, explicitly stale +// document rather than an error or a wait for a collection that GetTopology itself must +// never start. +func TestGetTopologyColdStart(t *testing.T) { + db := serviceTestDB(t) + svc := &Service{db: db, vmClient: panicVM{t: t}, l: logrus.WithField("test", t.Name())} + + response, err := svc.GetTopology(t.Context(), &omv1.GetTopologyRequest{}) + require.NoError(t, err) + require.NotNil(t, response) + assert.True(t, response.Snapshot.Stale) + assert.Nil(t, response.Snapshot.ObservedAt) + assert.Empty(t, response.Environments) +} + +// TestGetTopologyConcurrentReadsDoNotRace exercises the read path from many goroutines +// at once. Run with -race: the point is that GetTopology touches only s.mu and +// s.restored, never s.running, so concurrent readers never contend with each other or +// with a collection. +func TestGetTopologyConcurrentReadsDoNotRace(t *testing.T) { + db := serviceTestDB(t) + svc := &Service{db: db, vmClient: panicVM{t: t}, l: logrus.WithField("test", t.Name())} + + var wg sync.WaitGroup + for range 16 { + wg.Go(func() { + _, err := svc.GetTopology(t.Context(), &omv1.GetTopologyRequest{}) + assert.NoError(t, err) + }) + } + wg.Wait() +} + +func TestTriggerTopologyCollectionRefusesOnNonLeader(t *testing.T) { + svc := &Service{ha: fakeHA{leader: false, leaderID: "node-b"}, l: logrus.WithField("test", t.Name())} + + _, err := svc.TriggerTopologyCollection(t.Context(), &omv1.TriggerTopologyCollectionRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.FailedPrecondition, status.Code(err)) + assert.Contains(t, err.Error(), "node-b") +} + +func TestTriggerTopologyCollectionRefusesOnNonLeaderWithoutKnownLeader(t *testing.T) { + svc := &Service{ha: fakeHA{leader: false, leaderID: ""}, l: logrus.WithField("test", t.Name())} + + _, err := svc.TriggerTopologyCollection(t.Context(), &omv1.TriggerTopologyCollectionRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.FailedPrecondition, status.Code(err)) +} + +// TestTriggerTopologyCollectionAllowsLeaderOrNoHA covers the common cases: an explicit +// leader, and no ha wired in at all -- every test in this package but the ones above, and +// single-node PMM without HA enabled at all (ha.Service.IsLeader() is true when HA is +// disabled, so the same "every node is the leader" reading applies). +func TestTriggerTopologyCollectionAllowsLeaderOrNoHA(t *testing.T) { + for name, ha := range map[string]haChecker{"leader": fakeHA{leader: true}, "no ha wired in": nil} { + t.Run(name, func(t *testing.T) { + svc := &Service{ha: ha, l: logrus.WithField("test", t.Name())} + svc.running.Lock() // short-circuit before collect() needs a database. + defer svc.running.Unlock() + + _, err := svc.TriggerTopologyCollection(t.Context(), &omv1.TriggerTopologyCollectionRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.Aborted, status.Code(err), "should reach the in-flight check, not refuse as a follower") + }) + } +} + +func TestTriggerTopologyCollectionAbortsWhileRunInFlight(t *testing.T) { + svc := &Service{l: logrus.WithField("test", t.Name())} + svc.running.Lock() + defer svc.running.Unlock() + + _, err := svc.TriggerTopologyCollection(t.Context(), &omv1.TriggerTopologyCollectionRequest{}) + + require.Error(t, err) + assert.Equal(t, codes.Aborted, status.Code(err)) +} + +func TestSourcesOrdering(t *testing.T) { + t.Run("without a probe, just inventory and metrics", func(t *testing.T) { + svc := &Service{l: logrus.WithField("test", t.Name())} + sources := svc.sources(nil, time.Now()) + + require.Len(t, sources, 2) + assert.Equal(t, sourceInventory, sources[0].key()) + assert.Equal(t, sourceMetrics, sources[1].key()) + }) + + t.Run("with a probe configured, probe is appended last", func(t *testing.T) { + client := &sepClient{baseURL: "http://sep.example", http: nil} + svc := &Service{ + l: logrus.WithField("test", t.Name()), + probe: &probeSource{app: client.app(probeAppModule), l: logrus.WithField("source", sourceProbe)}, + } + sources := svc.sources(nil, time.Now()) + + require.Len(t, sources, 3) + assert.Equal(t, sourceInventory, sources[0].key()) + assert.Equal(t, sourceMetrics, sources[1].key()) + assert.Equal(t, sourceProbe, sources[2].key()) + }) +} + +// TestCollectPersistFailureStillReturnsDocument covers the run whose write fails: the +// document was already built and is already correct, so losing the run record must not +// turn into losing the response. +func TestCollectPersistFailureStillReturnsDocument(t *testing.T) { + db := serviceTestDB(t) + + node, err := models.CreateNode(db.Querier, models.GenericNodeType, &models.CreateNodeParams{NodeName: "node00"}) + require.NoError(t, err) + port := uint16(27017) + address := "127.0.0.1" + _, err = models.AddNewService(db.Querier, models.MongoDBServiceType, &models.AddDBMSServiceParams{ + ServiceName: "mongo-1", + NodeID: node.NodeID, + Address: &address, + Port: &port, + }) + require.NoError(t, err) + + // om_topology_runs is gone, so persist()'s INSERT fails -- collect() must log that + // and still hand back the response it already built and published. + _, err = db.Exec(`ALTER TABLE om_topology_runs RENAME TO om_topology_runs_test_gone`) + require.NoError(t, err) + + svc := &Service{db: db, vmClient: &recordingVM{}, l: logrus.WithField("test", t.Name())} + response, run, err := svc.collect(t.Context()) + + require.NoError(t, err, "a failed persist must not fail collect") + require.NotNil(t, response) + require.NotNil(t, run) + assert.Equal(t, int32(1), response.Summary.TotalServices) + assert.Same(t, response, svc.snapshot(), "the response collect returned is the one it published") +} diff --git a/managed/services/om/sources.go b/managed/services/om/sources.go new file mode 100644 index 00000000000..9a65aa09a1f --- /dev/null +++ b/managed/services/om/sources.go @@ -0,0 +1,434 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "fmt" + "net" + "slices" + "strconv" + "strings" + "time" + + "github.com/AlekSi/pointer" + "github.com/prometheus/common/model" + "github.com/sirupsen/logrus" + + "github.com/percona/pmm/managed/models" +) + +// factSource is one place collection reads the estate from. +// +// The interface is the extension point: the SEP inventory app's on-host facts arrive as +// another implementation of this and nothing downstream changes, because the merge +// resolves overlap by the precedence table rather than by which source ran. +type factSource interface { + // key is the source key every fact it produces carries. + key() string + // collect reads the estate. It reports rather than returns an error: a source that + // could not answer is a fact about the run, and losing the sources that did answer + // because one did not is the opposite of useful. + collect(ctx context.Context, services []*models.Service) SourceResult +} + +// inventorySource restates PMM's inventory as facts. +// +// Not time-bounded -- every fact carries a nil observed_at -- because inventory is +// current by definition. That is the distinction Fact.ObservedAt exists to keep: a +// version read from a metric sample can be nine days old, a cluster label read from the +// services table cannot. +type inventorySource struct { + nodes map[string]*models.Node +} + +func (inventorySource) key() string { return sourceInventory } + +func (s inventorySource) collect(_ context.Context, services []*models.Service) SourceResult { + result := SourceResult{Source: sourceInventory, Status: SourceOK} + for _, service := range services { + node := s.nodes[service.NodeID] + add := func(field string, value any) { + if value == nil || value == "" { + return + } + result.Facts = append(result.Facts, Fact{ + Service: service.ServiceID, + Field: field, + Value: value, + Source: sourceInventory, + }) + } + add(fieldServiceType, string(service.ServiceType)) + add(fieldCluster, service.Cluster) + add(fieldReplicationSet, service.ReplicationSet) + add(fieldEnvironment, service.Environment) + if node != nil { + add(fieldHost, node.NodeName) + } + add(fieldEndpoint, inventoryEndpoint(service, node)) + } + result.Detail = map[string]any{"services": len(services), "facts": len(result.Facts)} + return result +} + +// inventoryEndpoint builds the host:port inventory knows the service by. +// +// The node, not the service. A service's address is where its own pmm-agent reaches it, +// which for an agent on the same host is 127.0.0.1 -- true, and useless as an endpoint +// for anyone else. The node's address is the one that means something off the box. +func inventoryEndpoint(service *models.Service, node *models.Node) string { + var host string + if node != nil { + host = firstNonEmpty(node.Address, node.NodeName) + } + if host == "" { + host = pointer.GetString(service.Address) + } + if host == "" || service.Port == nil { + return "" + } + return net.JoinHostPort(host, strconv.Itoa(int(*service.Port))) +} + +// metricsSource reads the signal catalog out of VictoriaMetrics. +type metricsSource struct { + vm victoriaMetricsClient + l *logrus.Entry + now time.Time +} + +func (metricsSource) key() string { return sourceMetrics } + +// queryBatch is how many services are pinned per query. +// +// Each contributes a 37-byte UUID to a regex matcher, so this bounds the query string +// rather than the result set. Without it a few hundred services build a matcher tens of +// kilobytes long on every one of the queries below. +const queryBatch = 50 + +// labelSignal maps one series label onto one document field. +type labelSignal struct { + field string + label string +} + +// metricSignals says, per metric, which labels to read off it and whether its sample +// value is wanted too. +// +// The age query carries the labels, so a label-only metric costs one query. A metric +// whose value matters costs two, because lag()'s value is the age rather than the +// metric's own. +type metricSignal struct { + metric string + labels []labelSignal + valueField string + // presenceField is set from the series existing at all, whatever its value. + presenceField string + // reduceMax folds several series for one service into the largest. + reduceMax bool +} + +var metricSignals = []metricSignal{ + { + metric: metricVersionInfo, + labels: []labelSignal{ + {fieldHost, "node_name"}, + {fieldServiceType, "service_type"}, + {fieldCluster, "cluster"}, + {fieldReplicationSet, "replication_set"}, + {fieldEnvironment, "environment"}, + {fieldVersion, "mongodb"}, + {fieldVendor, "vendor"}, + {fieldEdition, "edition"}, + }, + }, + { + metric: metricMembersSelf, + labels: []labelSignal{ + {fieldState, "member_state"}, + // member_idx is the host:port the replica set itself knows the member by, + // which is a truer endpoint than inventory's address. + {fieldEndpoint, "member_idx"}, + {fieldClusterRole, "cl_role"}, + }, + }, + {metric: metricUp, valueField: fieldExporterUp}, + {metric: metricMongosShards, presenceField: fieldIsMongos}, + // Each member reports lag against every secondary, so the worst of them is "the worst + // lag this node saw". Double-counting is harmless under max. + {metric: metricReplicationLag, valueField: fieldReplicationLag, reduceMax: true}, + {metric: metricOplogHead, valueField: fieldOplogHead}, + {metric: metricOplogTail, valueField: fieldOplogTail}, +} + +// metricsRun is the mutable state of one pass over the catalog, kept out of collect so +// each stage stays readable on its own. +type metricsRun struct { + src metricsSource + result *SourceResult + covered map[string]bool + oldest float64 + queries int +} + +func (s metricsSource) collect(ctx context.Context, services []*models.Service) SourceResult { + result := SourceResult{Source: sourceMetrics, Status: SourceOK} + if len(services) == 0 { + return result + } + + ids := make([]string, 0, len(services)) + for _, service := range services { + ids = append(ids, service.ServiceID) + } + + run := &metricsRun{src: s, result: &result, covered: make(map[string]bool, len(ids))} + for batch := range slices.Chunk(ids, queryBatch) { + matcher := fmt.Sprintf(`service_id=~%q,%s`, strings.Join(batch, "|"), highResolutionJob) + for _, signal := range metricSignals { + run.signal(ctx, matcher, signal) + } + run.expressions(ctx, matcher) + } + + switch { + case len(result.Errors) > 0 && len(run.covered) == 0: + result.Status = SourceFailed + case len(result.Errors) > 0 || len(run.covered) < len(services): + result.Status = SourcePartial + } + result.Detail = map[string]any{ + "services": len(services), + "services_covered": len(run.covered), + "facts": len(result.Facts), + "queries": run.queries, + "oldest_age_seconds": int(run.oldest), + } + s.l.Infof("metrics source: %d/%d service(s) covered by %d queries, oldest sample %ds", + len(run.covered), len(services), run.queries, int(run.oldest)) + return result +} + +// signal reads one catalog entry: its age query, and its value query when the metric's +// own value is wanted. +func (r *metricsRun) signal(ctx context.Context, matcher string, signal metricSignal) { + ages := r.ages(ctx, matcher, signal) + if signal.valueField == "" { + return + } + + // The value query, issued only when the metric's own value is wanted, because lag()'s + // value is the age rather than the metric's. + query := fmt.Sprintf("last_over_time(%s{%s}[%s])", signal.metric, matcher, metricsLookback) + r.queries++ + values := make(map[string]seriesSample) + r.src.each(ctx, r.result, query, func(serviceID string, m model.Metric, v float64) { + age, dated := ages[seriesKey(m)] + sample := seriesSample{value: v, age: age, dated: dated} + if held, ok := values[serviceID]; ok && !sample.supersedes(held, signal.reduceMax) { + return + } + values[serviceID] = sample + }) + + for serviceID, sample := range values { + fact := Fact{Service: serviceID, Field: signal.valueField, Value: sample.value, Source: sourceMetrics} + // Dated by its own series' age, so a value read over a day-long window still knows + // how old it is -- and the fact that survives the reduction carries the age of the + // series it actually came from. + if sample.dated { + fact.ObservedAt = r.observedAt(sample.age) + } + r.result.Facts = append(r.result.Facts, fact) + } +} + +// seriesSample is one series' contribution to a valued signal: the sample the value query +// returned, and the age of that same series' last raw sample. +type seriesSample struct { + value float64 + age float64 + // dated is false when the age query returned no matching series, which leaves the + // fact undatable rather than pretending to an age of zero. + dated bool +} + +// supersedes reports whether this sample should displace the one already held for the +// service. +// +// Several series of one metric under one service_id is the ordinary case rather than a +// pathology, and the two kinds need different reducers: +// +// Under reduceMax the largest sample wins, which is the point of the reducer -- +// mongodb_mongod_replset_member_replication_lag emits one series per peer and the worst of +// them is what the node saw. The winner is then dated by its own series, so a stale maximum +// reads as stale and fieldSet.live drops it, rather than being reported as a statement about +// now. +// +// Otherwise the freshest series wins, because the series are successive generations of one +// reading rather than peers: an exporter that learns cluster_role only after startup +// abandons its first mongodb_up series and begins another under the same service_id, and the +// abandoned one is not evidence about the present. Dating the reduction from the oldest of +// them -- which is what this used to do -- made every such service report DOWN with its live +// sample seconds old. +// +// An undated sample never displaces a dated one, and never displaces its own kind: with no +// age to compare, first seen stays. +func (s seriesSample) supersedes(held seriesSample, reduceMax bool) bool { + if reduceMax && s.value != held.value { + return s.value > held.value + } + if !s.dated { + return false + } + if !held.dated { + return true + } + return s.age < held.age +} + +// seriesKey identifies one series across the two queries a valued signal issues. +// +// Every label except __name__, because the age query wraps the metric in lag() and a +// rollup need not carry the metric name through, while last_over_time() does. Keying on +// the rest pairs each sample with its own series' age, which is what a service carrying +// several series of one metric needs and what a per-service key cannot express. +func seriesKey(m model.Metric) model.Fingerprint { + if _, ok := m[model.MetricNameLabel]; !ok { + return m.Fingerprint() + } + trimmed := make(model.Metric, len(m)-1) + for name, value := range m { + if name != model.MetricNameLabel { + trimmed[name] = value + } + } + return trimmed.Fingerprint() +} + +// ages runs the age query, harvesting the labels it carries, and returns each series' age +// so the value query can date its own facts. +// +// Keyed per series rather than per service, because a service can carry several series of +// one metric and they do not share an age. Reducing them here -- to the oldest, which this +// used to do -- loses the pairing the value query needs: the sample that survives its own +// reduction then gets stamped with an age no series it came from ever reported. See +// seriesSample.supersedes for what each reducer does with the pairing. +// +// The label and presence facts below were always unaffected: each is dated with its own +// series' age inside the callback, because each comes from exactly one series. +// +// MetricsQL's lag() answers the seconds since the series' last raw sample and preserves +// every label, so one query yields both the labels the catalog reads and the staleness +// the run records. +// +// Wrapping timestamp() around a last_over_time() looks like it should do the same and +// does not: it reports the evaluation time rounded to the step, which reads as "fresh" +// for a series last scraped days ago -- the single most dangerous way to be wrong here. +func (r *metricsRun) ages(ctx context.Context, matcher string, signal metricSignal) map[model.Fingerprint]float64 { + query := fmt.Sprintf("lag(%s{%s}[%s])", signal.metric, matcher, metricsLookback) + r.queries++ + ages := make(map[model.Fingerprint]float64) + + r.src.each(ctx, r.result, query, func(serviceID string, m model.Metric, age float64) { + r.covered[serviceID] = true + if age > r.oldest { + r.oldest = age + } + ages[seriesKey(m)] = age + observedAt := r.observedAt(age) + + for _, label := range signal.labels { + if value := string(m[model.LabelName(label.label)]); value != "" { + r.result.Facts = append(r.result.Facts, Fact{ + Service: serviceID, Field: label.field, Value: value, + Source: sourceMetrics, ObservedAt: observedAt, + }) + } + } + if signal.presenceField != "" { + r.result.Facts = append(r.result.Facts, Fact{ + Service: serviceID, Field: signal.presenceField, Value: true, + Source: sourceMetrics, ObservedAt: observedAt, + }) + } + }) + return ages +} + +// expressions reads the two derived percentages. +// +// Neither exists as a series, so lag() has nothing to report on and their facts are dated +// to the run. That is safe because both are gauges the projection already suppresses for +// a service that is not up. +func (r *metricsRun) expressions(ctx context.Context, matcher string) { + for _, expr := range []struct { + query string + field string + }{ + {fmt.Sprintf(queryCPUUsage, matcher, metricsLookback), fieldCPUUsage}, + {fmt.Sprintf(queryConnectionsFree, matcher, metricsLookback), fieldConnectionsFree}, + } { + r.queries++ + r.src.each(ctx, r.result, expr.query, func(serviceID string, _ model.Metric, v float64) { + observedAt := r.src.now + r.result.Facts = append(r.result.Facts, Fact{ + Service: serviceID, Field: expr.field, Value: v, + Source: sourceMetrics, ObservedAt: &observedAt, + }) + }) + } +} + +// observedAt turns an age in seconds into the moment the sample was taken. +func (r *metricsRun) observedAt(age float64) *time.Time { + observed := r.src.now.Add(-time.Duration(age * float64(time.Second))) + return &observed +} + +// each runs one instant query and applies apply to every sample, keyed by service_id. +// +// A sample carrying no service_id label is skipped: it cannot be attributed to a service, +// and guessing from the instance label is how generations get mixed. +func (s metricsSource) each(ctx context.Context, result *SourceResult, query string, apply func(string, model.Metric, float64)) { + value, warnings, err := s.vm.Query(ctx, query, s.now) + if err != nil { + s.l.Warnf("query %q failed: %s", query, err) + result.Errors = append(result.Errors, RunError{ + Scope: "query", Code: "vm_query_failed", + Message: fmt.Sprintf("%s: %s", query, err), + }) + return + } + for _, w := range warnings { + s.l.Warnf("query %q: %s", query, w) + } + + vector, ok := value.(model.Vector) + if !ok { + result.Errors = append(result.Errors, RunError{ + Scope: "query", Code: "vm_unexpected_result", + Message: fmt.Sprintf("%s: unexpected result type %T", query, value), + }) + return + } + for _, sample := range vector { + if serviceID := string(sample.Metric["service_id"]); serviceID != "" { + apply(serviceID, sample.Metric, float64(sample.Value)) + } + } +} diff --git a/managed/services/om/sources_test.go b/managed/services/om/sources_test.go new file mode 100644 index 00000000000..bb560799293 --- /dev/null +++ b/managed/services/om/sources_test.go @@ -0,0 +1,226 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "strings" + "testing" + "time" + + v1 "github.com/prometheus/client_golang/api/prometheus/v1" + "github.com/prometheus/common/model" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/models" +) + +// stubVM answers the two queries metricsSource issues per signal: lag() for ages and +// last_over_time() for values. Keyed by metric name so one stub can cover a whole pass. +type stubVM struct { + lag map[string]model.Vector + values map[string]model.Vector +} + +func (s stubVM) Query(_ context.Context, query string, _ time.Time, _ ...v1.Option) (model.Value, v1.Warnings, error) { + for metric, vector := range s.lag { + if strings.HasPrefix(query, "lag("+metric+"{") { + return vector, nil, nil + } + } + for metric, vector := range s.values { + if strings.HasPrefix(query, "last_over_time("+metric+"{") { + return vector, nil, nil + } + } + return model.Vector{}, nil, nil +} + +// recordingVM answers nothing and keeps what it was asked, for the tests that are about +// the queries the catalog issues rather than about the samples they return. +type recordingVM struct { + queries []string +} + +func (r *recordingVM) Query(_ context.Context, query string, _ time.Time, _ ...v1.Option) (model.Value, v1.Warnings, error) { + r.queries = append(r.queries, query) + return model.Vector{}, nil, nil +} + +// testServiceID is the one service the sample helpers below build series for. +const testServiceID = "svc-1" + +// seriesLabels builds one series' label set: service_id plus the given name/value pairs, +// which is what distinguishes two series of the same metric under one service. +func seriesLabels(labels ...string) model.Metric { + m := model.Metric{"service_id": testServiceID} + for i := 0; i+1 < len(labels); i += 2 { + m[model.LabelName(labels[i])] = model.LabelValue(labels[i+1]) + } + return m +} + +// lagSample is a sample as the age query returns it: lag() is a rollup, so it carries no +// __name__ -- which is why seriesKey pairs the two queries on everything else. +func lagSample(age float64, labels ...string) *model.Sample { + return &model.Sample{Metric: seriesLabels(labels...), Value: model.SampleValue(age)} +} + +// valueSample is a sample as the value query returns it, __name__ included. +func valueSample(metric string, value float64, labels ...string) *model.Sample { + m := seriesLabels(labels...) + m[model.MetricNameLabel] = model.LabelValue(metric) + return &model.Sample{Metric: m, Value: model.SampleValue(value)} +} + +// factFor returns the last fact collected for a field, or nil. +func factFor(result SourceResult, field string) *Fact { + var found *Fact + for i := range result.Facts { + if result.Facts[i].Field == field { + found = &result.Facts[i] + } + } + return found +} + +// TestReducedValueCarriesItsOwnSeriesAge pins the pairing between a reduced value and the +// age it is stamped with. +// +// The value query folds every series for a service into one sample -- the largest, for +// replication lag -- and the fact has to carry the age of the series that sample came +// from. Dating it from the oldest series of the set instead reports an age no contributing +// series ever had, in whichever direction the set happens to be arranged. +func TestReducedValueCarriesItsOwnSeriesAge(t *testing.T) { + t.Parallel() + + now := time.Date(2026, 8, 21, 12, 0, 0, 0, time.UTC) + + // Two series for one service -- one per peer, as replication lag is emitted -- scraped + // 30s and 4h ago respectively. + lag := map[string]model.Vector{ + metricReplicationLag: { + lagSample(30, "member_idx", "peer-a"), + lagSample(4*60*60, "member_idx", "peer-b"), + }, + } + + t.Run("the max is fresh", func(t *testing.T) { + t.Parallel() + + vm := stubVM{lag: lag, values: map[string]model.Vector{ + metricReplicationLag: { + valueSample(metricReplicationLag, 900, "member_idx", "peer-a"), + valueSample(metricReplicationLag, 100, "member_idx", "peer-b"), + }, + }} + src := metricsSource{vm: vm, l: logrus.WithField("test", t.Name()), now: now} + fact := factFor(src.collect(t.Context(), []*models.Service{{ServiceID: testServiceID}}), fieldReplicationLag) + + require.NotNil(t, fact, "expected a replication-lag fact") + assert.InDelta(t, 900.0, fact.Value, 0.001) + require.NotNil(t, fact.ObservedAt) + assert.Equal(t, now.Add(-30*time.Second), fact.ObservedAt.UTC(), + "the largest lag came from the 30s-old series, so that is its age") + }) + + t.Run("the max is stale", func(t *testing.T) { + t.Parallel() + + vm := stubVM{lag: lag, values: map[string]model.Vector{ + metricReplicationLag: { + valueSample(metricReplicationLag, 100, "member_idx", "peer-a"), + valueSample(metricReplicationLag, 900, "member_idx", "peer-b"), + }, + }} + src := metricsSource{vm: vm, l: logrus.WithField("test", t.Name()), now: now} + fact := factFor(src.collect(t.Context(), []*models.Service{{ServiceID: testServiceID}}), fieldReplicationLag) + + require.NotNil(t, fact, "expected a replication-lag fact") + assert.InDelta(t, 900.0, fact.Value, 0.001) + require.NotNil(t, fact.ObservedAt) + + // Still reported, and still dated 4 hours old, so fieldSet.live drops it rather + // than the projection reading a stale maximum as a statement about now. + assert.Equal(t, now.Add(-4*time.Hour), fact.ObservedAt.UTC(), + "the largest lag came from the 4h-old series, so that is its age") + }) +} + +// TestAbandonedSeriesDoesNotStaleTheLiveOne pins the fix for a live service reporting DOWN. +// +// An exporter's label set changes over its own lifetime: mongodb_up is emitted without +// cluster_role until the exporter can determine the role, at which point the series is +// abandoned and another begins under the same service_id. Both stay inside metricsLookback, +// so both come back, and dating exporter_up from the oldest of them made the fact age out of +// volatileMaxAge while the live sample was seconds old. Measured against a 14-service +// sandbox: 6 of them DOWN, stably, every one of them up in PMM's own inventory. +func TestAbandonedSeriesDoesNotStaleTheLiveOne(t *testing.T) { + t.Parallel() + + now := time.Date(2026, 8, 21, 12, 0, 0, 0, time.UTC) + + vm := stubVM{ + lag: map[string]model.Vector{ + metricUp: { + lagSample(2, "cluster_role", "mongod"), + lagSample(540), + }, + }, + values: map[string]model.Vector{ + metricUp: { + valueSample(metricUp, 1, "cluster_role", "mongod"), + valueSample(metricUp, 1), + }, + }, + } + + src := metricsSource{vm: vm, l: logrus.WithField("test", t.Name()), now: now} + fact := factFor(src.collect(t.Context(), []*models.Service{{ServiceID: testServiceID}}), fieldExporterUp) + + require.NotNil(t, fact, "expected an exporter-up fact") + assert.InDelta(t, 1.0, fact.Value, 0.001) + require.NotNil(t, fact.ObservedAt) + assert.Equal(t, now.Add(-2*time.Second), fact.ObservedAt.UTC(), + "exporter_up must carry the live series' age, not the abandoned one's") +} + +// TestEveryQueryNarrowsToTheHighResolutionJob pins the other half of that pairing: the +// series a reduction may see. +// +// A mongodb_exporter is scraped at two resolutions, so a metric it emits on every scrape +// -- mongodb_up -- exists as an hr and an lr series per service. Reduced across both, +// exporter_up is dated by the lr series, whose age exceeds volatileMaxAge for most of every +// minute, and a healthy service reports DOWN half the time it is asked. +func TestEveryQueryNarrowsToTheHighResolutionJob(t *testing.T) { + t.Parallel() + + vm := &recordingVM{} + src := metricsSource{ + vm: vm, + l: logrus.WithField("test", t.Name()), + now: time.Date(2026, 8, 21, 12, 0, 0, 0, time.UTC), + } + src.collect(t.Context(), []*models.Service{{ServiceID: "svc-1"}}) + + require.NotEmpty(t, vm.queries, "expected the catalog to issue queries") + for _, query := range vm.queries { + assert.Contains(t, query, highResolutionJob, + "every query must select the high-resolution job") + } +} diff --git a/managed/services/om/store.go b/managed/services/om/store.go new file mode 100644 index 00000000000..851297f9558 --- /dev/null +++ b/managed/services/om/store.go @@ -0,0 +1,278 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "context" + "errors" + "fmt" + "time" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/timestamppb" + "gopkg.in/reform.v1" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" +) + +// documentJSON is how a snapshot is stored and read back. +// +// Deliberately protojson rather than encoding/json: the document is a protobuf message, +// and only protojson agrees with the wire format the API serves -- wrapper types as bare +// values or null, timestamps as RFC 3339. Round-tripping through encoding/json would +// store a differently-shaped document than the one the UI receives. +var ( + documentJSON = protojson.MarshalOptions{UseProtoNames: true, EmitUnpopulated: true} + documentJSONParse = protojson.UnmarshalOptions{DiscardUnknown: true} +) + +// persist writes one run and its document, then prunes the history. +// +// Both rows go in one transaction: a run without its document is not a state any reader +// should have to handle. Failure is reported but not fatal -- the document is already +// published in memory, and losing the record of a collection is worth less than refusing +// to serve the collection. +func (s *Service) persist(ctx context.Context, response *omv1.GetTopologyResponse, run *omv1.TopologyRun, originNode string) error { + document, err := documentJSON.Marshal(response) + if err != nil { + return fmt.Errorf("failed to marshal the topology document: %w", err) + } + + row := &models.OmTopologyRun{ + RunID: run.RunId, + StartedAt: run.StartTime.AsTime(), + Status: runStatusFromProto(run.Status), + ServicesTotal: run.Counts.TotalServices, + ServicesResolved: run.Counts.ResolvedServices, + ServicesOrphaned: run.Counts.OrphanedServices, + ProbesOK: run.Counts.SuccessfulProbes, + ServicesStale: run.Counts.StaleServices, + OriginNode: originNode, + Sources: make(models.OmTopologySourceReports, 0, len(run.Sources)), + Errors: make(models.OmTopologyRunErrors, 0, len(run.Errors)), + } + if run.EndTime != nil { + finished := run.EndTime.AsTime() + row.FinishedAt = &finished + } + for _, source := range run.Sources { + row.Sources = append(row.Sources, models.OmTopologySourceReport{ + Source: source.Source, Status: string(sourceStatusFromProto(source.Status)), + Facts: source.Facts, Detail: source.Detail, + }) + } + for _, e := range run.Errors { + row.Errors = append(row.Errors, models.OmTopologyRunError{ + Scope: e.Scope, ServiceName: e.GetServiceName(), + Code: e.Code, Message: e.Message, + }) + } + + snapshot := &models.OmTopologySnapshot{ + GeneratedAt: response.Snapshot.GeneratedAt.AsTime(), + Stale: response.Snapshot.Stale, + SchemaVersion: response.Snapshot.SchemaVersion, + Document: document, + } + if response.Snapshot.ObservedAt != nil { + observed := response.Snapshot.ObservedAt.AsTime() + snapshot.ObservedAt = &observed + } + + // InTransactionContext rather than InTransaction so a shutdown or a cancelled + // collection aborts the write instead of finishing it. managed/AGENTS.md prescribes + // this form, and it is what most of managed/services uses. + return s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + err := models.CreateOmTopologyRun(tx.Querier, row, snapshot) + if err != nil { + return err + } + return models.PruneOmTopologyRuns(tx.Querier, runHistory) + }) +} + +// restore loads the newest stored document, so a restarted pmm-managed can answer before +// it has collected anything of its own. +// +// A document read back from the database is re-staled against the clock rather than +// trusted: stale was computed when it was written, and the whole point of restoring one +// is that time has passed since. +func (s *Service) restore(ctx context.Context) (*omv1.GetTopologyResponse, time.Time, error) { + var snapshot *models.OmTopologySnapshot + errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + var err error + snapshot, err = models.FindLatestOmTopologySnapshot(tx.Querier) + return err + }) + if errTX != nil { + if errors.Is(errTX, models.ErrNotFound) { + return nil, time.Time{}, nil + } + return nil, time.Time{}, errTX + } + + response := &omv1.GetTopologyResponse{} + err := documentJSONParse.Unmarshal(snapshot.Document, response) + if err != nil { + return nil, time.Time{}, fmt.Errorf("failed to parse the stored topology document: %w", err) + } + if response.Snapshot != nil { + response.Snapshot.Stale = snapshotStale(response.Snapshot.ObservedAt) + } + return response, snapshot.GeneratedAt, nil +} + +// listRuns reads the run history back out of the database. +func (s *Service) listRuns(ctx context.Context, limit int) ([]*omv1.TopologyRun, error) { + var rows []*models.OmTopologyRun + errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + var err error + rows, err = models.FindOmTopologyRuns(tx.Querier, limit) + return err + }) + if errTX != nil { + return nil, errTX + } + runs := make([]*omv1.TopologyRun, 0, len(rows)) + for _, row := range rows { + runs = append(runs, runFromModel(row)) + } + return runs, nil +} + +// getRun reads one run back out of the database. +func (s *Service) getRun(ctx context.Context, runID string) (*omv1.TopologyRun, error) { + var row *models.OmTopologyRun + errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + var err error + row, err = models.FindOmTopologyRunByID(tx.Querier, runID) + return err + }) + if errTX != nil { + return nil, errTX + } + return runFromModel(row), nil +} + +func runFromModel(row *models.OmTopologyRun) *omv1.TopologyRun { + run := &omv1.TopologyRun{ + RunId: row.RunID, + Status: runStatusToProto(row.Status), + StartTime: timestamppb.New(row.StartedAt), + Counts: &omv1.TopologyRunCounts{ + TotalServices: row.ServicesTotal, + ResolvedServices: row.ServicesResolved, + OrphanedServices: row.ServicesOrphaned, + SuccessfulProbes: row.ProbesOK, + StaleServices: row.ServicesStale, + }, + Sources: make([]*omv1.SourceReport, 0, len(row.Sources)), + Errors: make([]*omv1.TopologyRunError, 0, len(row.Errors)), + } + if row.FinishedAt != nil { + run.EndTime = timestamppb.New(*row.FinishedAt) + } + for _, source := range row.Sources { + run.Sources = append(run.Sources, &omv1.SourceReport{ + Source: source.Source, Status: sourceStatusToProto(SourceStatus(source.Status)), + Facts: source.Facts, Detail: source.Detail, + }) + } + for _, e := range row.Errors { + run.Errors = append(run.Errors, &omv1.TopologyRunError{ + Scope: e.Scope, ServiceName: optional(e.ServiceName), + Code: e.Code, Message: e.Message, + }) + } + return run +} + +// snapshotStale reports whether an observation is older than the grace period. +func snapshotStale(observedAt *timestamppb.Timestamp) bool { + if observedAt == nil { + return false + } + return time.Since(observedAt.AsTime()) > staleAfter +} + +// The enum boundary. Statuses are stored as the collector's own lowercase strings and +// translated here, in one place, rather than persisted as enum numbers: a run row stays +// readable in psql, and renumbering the enum cannot silently reinterpret history. +// +// An unrecognised stored value maps to UNSPECIFIED rather than being guessed at. That is +// the honest answer for a row written by a newer version, and it is visible on the wire +// instead of masquerading as a status the caller knows. + +// runStatusToProto maps a stored run status onto the wire enum. +func runStatusToProto(status models.OmTopologyRunStatus) omv1.RunStatus { + switch string(status) { + case runStatusSuccess: + return omv1.RunStatus_RUN_STATUS_SUCCESS + case runStatusPartial: + return omv1.RunStatus_RUN_STATUS_PARTIAL + case runStatusFailed: + return omv1.RunStatus_RUN_STATUS_FAILED + default: + return omv1.RunStatus_RUN_STATUS_UNSPECIFIED + } +} + +// runStatusFromProto maps the wire enum back onto the stored representation. +func runStatusFromProto(status omv1.RunStatus) models.OmTopologyRunStatus { + switch status { + case omv1.RunStatus_RUN_STATUS_SUCCESS: + return models.OmTopologyRunStatus(runStatusSuccess) + case omv1.RunStatus_RUN_STATUS_PARTIAL: + return models.OmTopologyRunStatus(runStatusPartial) + case omv1.RunStatus_RUN_STATUS_FAILED: + return models.OmTopologyRunStatus(runStatusFailed) + default: + return "" + } +} + +// sourceStatusToProto maps a stored source status onto the wire enum. +func sourceStatusToProto(status SourceStatus) omv1.SourceStatus { + switch status { + case SourceOK: + return omv1.SourceStatus_SOURCE_STATUS_OK + case SourcePartial: + return omv1.SourceStatus_SOURCE_STATUS_PARTIAL + case SourceFailed: + return omv1.SourceStatus_SOURCE_STATUS_FAILED + case SourceDisabled: + return omv1.SourceStatus_SOURCE_STATUS_DISABLED + default: + return omv1.SourceStatus_SOURCE_STATUS_UNSPECIFIED + } +} + +// sourceStatusFromProto maps the wire enum back onto the stored representation. +func sourceStatusFromProto(status omv1.SourceStatus) SourceStatus { + switch status { + case omv1.SourceStatus_SOURCE_STATUS_OK: + return SourceOK + case omv1.SourceStatus_SOURCE_STATUS_PARTIAL: + return SourcePartial + case omv1.SourceStatus_SOURCE_STATUS_FAILED: + return SourceFailed + case omv1.SourceStatus_SOURCE_STATUS_DISABLED: + return SourceDisabled + default: + return "" + } +} diff --git a/managed/services/om/store_test.go b/managed/services/om/store_test.go new file mode 100644 index 00000000000..9b440ef3ac7 --- /dev/null +++ b/managed/services/om/store_test.go @@ -0,0 +1,214 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package om + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/timestamppb" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + omv1 "github.com/percona/pmm/api/om/v1" + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/utils/testdb" +) + +// storeTestDB opens a fresh test database and wraps it as a *reform.DB, the shape +// store.go's methods take. +func storeTestDB(t *testing.T) *reform.DB { + t.Helper() + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + return reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) +} + +// testTopologyResponse builds one document and the run that produced it, shaped like +// what collect() would have built, so a round trip through persist/restore has +// something realistic to preserve. +func testTopologyResponse(runID string, generatedAt, observedAt time.Time) (*omv1.GetTopologyResponse, *omv1.TopologyRun) { + response := &omv1.GetTopologyResponse{ + Snapshot: &omv1.Snapshot{ + GeneratedAt: timestamppb.New(generatedAt), + ObservedAt: timestamppb.New(observedAt), + Stale: false, + SchemaVersion: schemaVersion, + RunId: runID, + }, + OriginNode: optional("pmm-server"), + SourceQueries: sourceQueries, + Summary: &omv1.Summary{ + Environments: 1, + Clusters: 1, + TotalServices: 1, + UpServices: 1, + ProcessRoleCounts: map[string]int32{"PROCESS_ROLE_MONGOD": 1}, + }, + Environments: []*omv1.Environment{ + { + EnvName: optional("prod"), + Clusters: []*omv1.Cluster{ + { + Name: optional("rs0"), + Id: clusterID("prod", "rs0"), + Type: omv1.ClusterType_CLUSTER_TYPE_REPLICA_SET, + Services: []*omv1.TopologyService{ + { + ServiceName: "mongo-1", + ServiceId: optional("svc-1"), + Status: omv1.ServiceStatus_SERVICE_STATUS_UP, + ProcessRole: omv1.ProcessRole_PROCESS_ROLE_MONGOD, + ObservedAt: timestamppb.New(observedAt), + }, + }, + }, + }, + }, + }, + } + run := &omv1.TopologyRun{ + RunId: runID, + Status: omv1.RunStatus_RUN_STATUS_SUCCESS, + StartTime: timestamppb.New(generatedAt.Add(-time.Second)), + EndTime: timestamppb.New(generatedAt), + Counts: &omv1.TopologyRunCounts{ + TotalServices: 1, + ResolvedServices: 1, + SuccessfulProbes: 1, + }, + Sources: []*omv1.SourceReport{ + {Source: sourceMetrics, Status: omv1.SourceStatus_SOURCE_STATUS_OK, Facts: 3}, + }, + Errors: []*omv1.TopologyRunError{}, + } + return response, run +} + +func TestStorePersistRestoreRoundTrip(t *testing.T) { + db := storeTestDB(t) + svc := &Service{db: db, l: logrus.WithField("test", t.Name())} + + // Observed recently enough to restore as fresh: restore() recomputes Stale against + // the clock rather than trusting what was written (see + // TestStoreRestoreRestalesAgainstNow), so a round trip of the rest of the document + // needs the timestamp to still be within staleAfter by the time restore() runs. + // Truncated to microseconds because TopologyRun's StartTime/EndTime round-trip + // through plain timestamp columns rather than protojson, and Postgres does not + // keep more precision than that. + generatedAt := time.Now().Truncate(time.Microsecond) + observedAt := generatedAt.Add(-4 * time.Second) + runID := uuid.New().String() + response, run := testTopologyResponse(runID, generatedAt, observedAt) + + err := svc.persist(t.Context(), response, run, "pmm-server") + require.NoError(t, err) + + restored, restoredGeneratedAt, err := svc.restore(t.Context()) + require.NoError(t, err) + require.NotNil(t, restored) + assert.WithinDuration(t, generatedAt, restoredGeneratedAt, time.Millisecond) + + // protojson through the store is lossy about nothing: every field persist wrote + // comes back unchanged, down to the cluster id and the per-service observed_at + // this test exists to guard. + diff := cmp.Diff(response, restored, protocmp.Transform()) + assert.Empty(t, diff, "restored document should equal what was persisted") + + run2, err := svc.getRun(t.Context(), runID) + require.NoError(t, err) + assert.Empty(t, cmp.Diff(run, run2, protocmp.Transform())) +} + +func TestStoreRestoreRestalesAgainstNow(t *testing.T) { + db := storeTestDB(t) + svc := &Service{db: db, l: logrus.WithField("test", t.Name())} + + // Written as fresh (Stale: false), but observed long enough ago that restoring it + // now must recompute Stale as true. The written value is deliberately wrong, to + // prove restore() does not just trust what was stored -- see snapshotStale's own + // comment for why that recomputation exists. + generatedAt := time.Now().Add(-time.Hour) + observedAt := generatedAt + response, run := testTopologyResponse(uuid.New().String(), generatedAt, observedAt) + response.Snapshot.Stale = false + + require.NoError(t, svc.persist(t.Context(), response, run, "pmm-server")) + + restored, _, err := svc.restore(t.Context()) + require.NoError(t, err) + assert.True(t, restored.Snapshot.Stale, "an hour-old observation must restore as stale") +} + +func TestStoreRestoreNoSnapshot(t *testing.T) { + db := storeTestDB(t) + svc := &Service{db: db, l: logrus.WithField("test", t.Name())} + + response, generatedAt, err := svc.restore(t.Context()) + require.NoError(t, err) + assert.Nil(t, response) + assert.True(t, generatedAt.IsZero()) +} + +func TestPruneOmTopologyRunsKeepsExactlyKeep(t *testing.T) { + db := storeTestDB(t) + svc := &Service{db: db, l: logrus.WithField("test", t.Name())} + + const total = 5 + const keep = 3 + base := time.Date(2026, 8, 20, 9, 0, 0, 0, time.UTC) + runIDs := make([]string, 0, total) + for i := range total { + generatedAt := base.Add(time.Duration(i) * time.Minute) + runID := uuid.New().String() + runIDs = append(runIDs, runID) + response, run := testTopologyResponse(runID, generatedAt, generatedAt) + run.StartTime = timestamppb.New(generatedAt) + require.NoError(t, svc.persist(t.Context(), response, run, "pmm-server")) + } + + err := db.InTransactionContext(t.Context(), nil, func(tx *reform.TX) error { + return models.PruneOmTopologyRuns(tx.Querier, keep) + }) + require.NoError(t, err) + + runs, err := svc.listRuns(t.Context(), total) + require.NoError(t, err) + require.Len(t, runs, keep) + + // Newest first, and the newest `keep` of them: the last `keep` run IDs persisted, + // in reverse order. + gotIDs := make([]string, 0, len(runs)) + for _, r := range runs { + gotIDs = append(gotIDs, r.RunId) + } + wantIDs := []string{runIDs[4], runIDs[3], runIDs[2]} + assert.Equal(t, wantIDs, gotIDs) + + // The run row is gone, and so is its snapshot -- CreateOmTopologyRun writes both in + // one transaction, and a cascade that prunes the run but leaves its snapshot behind + // would leak one row per pruned run forever. + _, err = models.FindOmTopologyRunByID(db.Querier, runIDs[0]) + require.ErrorIs(t, err, models.ErrNotFound) + + _, err = db.FindByPrimaryKeyFrom(models.OmTopologySnapshotTable, runIDs[0]) + require.ErrorIs(t, err, reform.ErrNoRows) +} diff --git a/managed/utils/envvars/parser.go b/managed/utils/envvars/parser.go index ee5377f1a38..2393d017933 100644 --- a/managed/utils/envvars/parser.go +++ b/managed/utils/envvars/parser.go @@ -124,6 +124,9 @@ func ParseEnvVars(envs []string) (*models.ChangeSettingsParams, []error, []strin case "PMM_ENABLE_SEP", "PMM_SEP_POSTGRES_PASSWORD": // skip env variables consumed by the entrypoint to expose postgres to SEP continue + case "PMM_SEP_URL", "PMM_SEP_TOKEN": + // skip SEP connection settings, parsed separately + continue case "PERCONA_TELEMETRY_DISABLE": // skip the Pillars telemetry environment variable continue @@ -334,6 +337,12 @@ var secretEnvVarMarkers = []string{"PASSWORD", "SECRET", "TOKEN", "KEY"} // redactSecretEnvVar replaces the value of a credential-bearing environment variable. func redactSecretEnvVar(key, value string) string { + if key == "PMM_SEP_URL" { + // A URL can carry credentials in its userinfo, and none of the markers below + // match "URL". + return "" + } + for _, marker := range secretEnvVarMarkers { if strings.Contains(key, marker) { return "" diff --git a/managed/utils/envvars/parser_test.go b/managed/utils/envvars/parser_test.go index e0a40c42212..21ad0210f27 100644 --- a/managed/utils/envvars/parser_test.go +++ b/managed/utils/envvars/parser_test.go @@ -20,7 +20,10 @@ import ( "testing" "time" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/percona/pmm/managed/models" ) @@ -292,6 +295,66 @@ func TestEnvVarValidator(t *testing.T) { }) } +// TestSEPSecretsAreNotLogged pins the reason the SEP variables are a special case +// rather than two more entries in the skip list: their values must not reach a log +// at any level. The trace line that used to leak them carried the whole original +// assignment, forty lines before the switch that meant to ignore these keys. +// +// Not parallel. It raises the standard logger's level and installs a global hook, +// both of which are process-wide. +func TestSEPSecretsAreNotLogged(t *testing.T) { + const ( + token = "bearer-value-that-must-not-be-logged" + password = "userinfo-password-that-must-not-be-logged" + ) + + logger := logrus.StandardLogger() + + // Captured before NewGlobal, which appends to the global logger's hooks. Reset + // only clears the entries a hook has collected, so without restoring the set the + // hook would outlive this test and keep collecting for the rest of the binary. + // The slices are copied too, because Add appends to them. + previousHooks := logrus.LevelHooks{} + for level, hooks := range logger.Hooks { + previousHooks[level] = append([]logrus.Hook(nil), hooks...) + } + previousLevel := logger.GetLevel() + + hook := test.NewGlobal() + // Tracef is where the value leaked. + logger.SetLevel(logrus.TraceLevel) + + t.Cleanup(func() { + logger.SetLevel(previousLevel) + logger.ReplaceHooks(previousHooks) + }) + + envs := []string{ + "PMM_SEP_TOKEN=" + token, + // Credentials in the userinfo are why the URL is redacted alongside the token. + "PMM_SEP_URL=https://sep:" + password + "@sep.example.com:8000", + } + + gotEnvVars, gotErrs, gotWarns := ParseEnvVars(envs) + assert.Equal(t, &models.ChangeSettingsParams{}, gotEnvVars) + assert.Nil(t, gotErrs) + assert.Nil(t, gotWarns) + + entries := hook.AllEntries() + require.Len(t, entries, 2) + + for _, entry := range entries { + line, err := entry.String() + require.NoError(t, err) + assert.NotContains(t, line, token) + assert.NotContains(t, line, password) + } + + // Logged by name, which is what keeps the skip auditable at trace level. + assert.Contains(t, entries[0].Message, "PMM_SEP_TOKEN") + assert.Contains(t, entries[1].Message, "PMM_SEP_URL") +} + func TestRedactSecretEnvVar(t *testing.T) { t.Parallel() @@ -306,6 +369,8 @@ func TestRedactSecretEnvVar(t *testing.T) { {key: "GF_SECURITY_ADMIN_PASSWORD", value: "s3cret", expected: ""}, {key: "AWS_SECRET_KEY", value: "s3cret", expected: ""}, {key: "PMM_CLICKHOUSE_DATASOURCE_USER", value: "grafana", expected: "grafana"}, + {key: "PMM_SEP_TOKEN", value: "bearer-value", expected: ""}, + {key: "PMM_SEP_URL", value: "https://sep:pw@sep.example.com", expected: ""}, {key: "PMM_DATA_RETENTION", value: "72h", expected: "72h"}, } for _, tt := range tests { diff --git a/ui/.gitignore b/ui/.gitignore index ef7e3281a5f..5baf8f8b100 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -26,6 +26,7 @@ coverage out/ build dist +*.tsbuildinfo # Debug diff --git a/ui/apps/pmm/package.json b/ui/apps/pmm/package.json index 1b78067f1f0..fdc4006d727 100644 --- a/ui/apps/pmm/package.json +++ b/ui/apps/pmm/package.json @@ -30,6 +30,10 @@ "@percona/peak-ui": "1.0.25", "@pmm/shared": "workspace:*", "@reactour/tour": "^3.8.0", + "@sep/api": "workspace:*", + "@sep/framework": "workspace:*", + "@sep/plugins-atw": "workspace:*", + "@sep/plugins-om": "workspace:*", "@tanstack/react-query": "^5.100.7", "axios": "^1.13.5", "axios-case-converter": "^1.1.1", @@ -44,6 +48,7 @@ "react-markdown": "^9.0.1", "react-router": "^7.18.2", "react-router-dom": "^7.18.2", + "react-syntax-highlighter": "^16.1.0", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.0", "vite-plugin-svgr": "^5.2.0", @@ -54,6 +59,7 @@ "@testing-library/react": "^16.3.0", "@types/react": "^19.1.0", "@types/react-dom": "^19.1.0", + "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-basic-ssl": "^2.3.0", "@vitejs/plugin-react": "^6.0.5", "jsdom": "^29.1.1", diff --git a/ui/apps/pmm/src/components/page/Page.tsx b/ui/apps/pmm/src/components/page/Page.tsx index 029e9e3fd6b..cadece63fed 100644 --- a/ui/apps/pmm/src/components/page/Page.tsx +++ b/ui/apps/pmm/src/components/page/Page.tsx @@ -8,9 +8,9 @@ import { Divider, GlobalStyles, Link, - Stack, Typography, } from '@mui/material'; +import { PageContainer } from '@percona/peak-ui'; import { useUser } from 'contexts/user'; import { Messages } from './Page.messages'; import { PMM_HOME_URL } from 'lib/constants'; @@ -23,6 +23,7 @@ export const Page: FC = ({ topBar, footer, children, + maxWidth, fullWidth, surface, roles, @@ -30,6 +31,9 @@ export const Page: FC = ({ const { user } = useUser(); updateDocumentTitle(title); const hasAccess = !roles || roles?.some((role) => user?.orgRole === role); + // Back-compat: `fullWidth` predates `maxWidth`; treat it as `maxWidth="full"` + // unless an explicit `maxWidth` is provided. + const resolvedMaxWidth = maxWidth ?? (fullWidth ? 'full' : undefined); return ( <> @@ -45,24 +49,7 @@ export const Page: FC = ({ })} /> )} - + {topBar} {!!title && {title}} @@ -86,7 +73,7 @@ export const Page: FC = ({ {footer !== undefined ? footer :