diff --git a/api-tests/server/updates_test.go b/api-tests/server/updates_test.go index f506c966bb0..0749adf0c78 100644 --- a/api-tests/server/updates_test.go +++ b/api-tests/server/updates_test.go @@ -16,6 +16,7 @@ package server import ( + "net/url" "strings" "testing" "time" @@ -182,3 +183,33 @@ func TestListUpdates(t *testing.T) { pmmapitests.AssertAPIErrorf(t, err, 400, codes.FailedPrecondition, `PMM updates are disabled`) }) } + +// TestUpdateStatus covers the endpoint pre-3.9 clients poll after triggering an update: on a server +// that has finished initializing it must report the update as done, without authentication. +func TestUpdateStatus(t *testing.T) { + baseURL, err := url.Parse(pmmapitests.BaseURL.String()) + require.NoError(t, err) + baseURL.User = nil + noAuthClient := serverClient.New(pmmapitests.Transport(baseURL, true), nil) + + for _, tc := range []struct { + name string + body server.UpdateStatusBody + }{ + {"with a token issued by the previous instance", server.UpdateStatusBody{AuthToken: "unverifiable", LogOffset: 1024}}, + {"without a token", server.UpdateStatusBody{}}, + } { + t.Run(tc.name, func(t *testing.T) { + res, err := noAuthClient.ServerService.UpdateStatus(&server.UpdateStatusParams{ + Body: tc.body, + Context: pmmapitests.Context, + }) + require.NoError(t, err) + assert.True(t, res.Payload.Done) + // Pre-3.9 clients join log_lines unconditionally, so it must marshal as an empty array. + assert.NotNil(t, res.Payload.LogLines) + assert.Empty(t, res.Payload.LogLines) + assert.Zero(t, res.Payload.LogOffset) + }) + } +} diff --git a/api/descriptor.bin b/api/descriptor.bin index e66dfa7c6f4..e6481fc092b 100644 Binary files a/api/descriptor.bin and b/api/descriptor.bin differ diff --git a/api/server/v1/json/client/server_service/server_service_client.go b/api/server/v1/json/client/server_service/server_service_client.go index 4817c5653da..f67d198f937 100644 --- a/api/server/v1/json/client/server_service/server_service_client.go +++ b/api/server/v1/json/client/server_service/server_service_client.go @@ -93,6 +93,8 @@ type ClientService interface { Readiness(params *ReadinessParams, opts ...ClientOption) (*ReadinessOK, error) + UpdateStatus(params *UpdateStatusParams, opts ...ClientOption) (*UpdateStatusOK, error) + Version(params *VersionParams, opts ...ClientOption) (*VersionOK, error) SetTransport(transport runtime.ClientTransport) @@ -450,6 +452,50 @@ func (a *Client) Readiness(params *ReadinessParams, opts ...ClientOption) (*Read return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +UpdateStatus updates status + +Returns PMM Server initialization status. +*/ +func (a *Client) UpdateStatus(params *UpdateStatusParams, opts ...ClientOption) (*UpdateStatusOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUpdateStatusParams() + } + op := &runtime.ClientOperation{ + ID: "UpdateStatus", + Method: "POST", + PathPattern: "/v1/server/updates:getStatus", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &UpdateStatusReader{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.(*UpdateStatusOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*UpdateStatusDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* Version versions diff --git a/api/server/v1/json/client/server_service/update_status_parameters.go b/api/server/v1/json/client/server_service/update_status_parameters.go new file mode 100644 index 00000000000..56b7eb403d5 --- /dev/null +++ b/api/server/v1/json/client/server_service/update_status_parameters.go @@ -0,0 +1,141 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package server_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" +) + +// NewUpdateStatusParams creates a new UpdateStatusParams 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 NewUpdateStatusParams() *UpdateStatusParams { + return &UpdateStatusParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUpdateStatusParamsWithTimeout creates a new UpdateStatusParams object +// with the ability to set a timeout on a request. +func NewUpdateStatusParamsWithTimeout(timeout time.Duration) *UpdateStatusParams { + return &UpdateStatusParams{ + timeout: timeout, + } +} + +// NewUpdateStatusParamsWithContext creates a new UpdateStatusParams object +// with the ability to set a context for a request. +func NewUpdateStatusParamsWithContext(ctx context.Context) *UpdateStatusParams { + return &UpdateStatusParams{ + Context: ctx, + } +} + +// NewUpdateStatusParamsWithHTTPClient creates a new UpdateStatusParams object +// with the ability to set a custom HTTPClient for a request. +func NewUpdateStatusParamsWithHTTPClient(client *http.Client) *UpdateStatusParams { + return &UpdateStatusParams{ + HTTPClient: client, + } +} + +/* +UpdateStatusParams contains all the parameters to send to the API endpoint + + for the update status operation. + + Typically these are written to a http.Request. +*/ +type UpdateStatusParams struct { + // Body. + Body UpdateStatusBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the update status params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateStatusParams) WithDefaults() *UpdateStatusParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the update status params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateStatusParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the update status params +func (o *UpdateStatusParams) WithTimeout(timeout time.Duration) *UpdateStatusParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the update status params +func (o *UpdateStatusParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the update status params +func (o *UpdateStatusParams) WithContext(ctx context.Context) *UpdateStatusParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the update status params +func (o *UpdateStatusParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the update status params +func (o *UpdateStatusParams) WithHTTPClient(client *http.Client) *UpdateStatusParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the update status params +func (o *UpdateStatusParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the update status params +func (o *UpdateStatusParams) WithBody(body UpdateStatusBody) *UpdateStatusParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the update status params +func (o *UpdateStatusParams) SetBody(body UpdateStatusBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *UpdateStatusParams) 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/server/v1/json/client/server_service/update_status_responses.go b/api/server/v1/json/client/server_service/update_status_responses.go new file mode 100644 index 00000000000..7de58ea79ff --- /dev/null +++ b/api/server/v1/json/client/server_service/update_status_responses.go @@ -0,0 +1,661 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package server_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" +) + +// UpdateStatusReader is a Reader for the UpdateStatus structure. +type UpdateStatusReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UpdateStatusReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewUpdateStatusOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUpdateStatusDefault(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 + } +} + +// NewUpdateStatusOK creates a UpdateStatusOK with default headers values +func NewUpdateStatusOK() *UpdateStatusOK { + return &UpdateStatusOK{} +} + +/* +UpdateStatusOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type UpdateStatusOK struct { + Payload *UpdateStatusOKBody +} + +// IsSuccess returns true when this update status Ok response has a 2xx status code +func (o *UpdateStatusOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this update status Ok response has a 3xx status code +func (o *UpdateStatusOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this update status Ok response has a 4xx status code +func (o *UpdateStatusOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this update status Ok response has a 5xx status code +func (o *UpdateStatusOK) IsServerError() bool { + return false +} + +// IsCode returns true when this update status Ok response a status code equal to that given +func (o *UpdateStatusOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the update status Ok response +func (o *UpdateStatusOK) Code() int { + return 200 +} + +func (o *UpdateStatusOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/server/updates:getStatus][%d] updateStatusOk %s", 200, payload) +} + +func (o *UpdateStatusOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/server/updates:getStatus][%d] updateStatusOk %s", 200, payload) +} + +func (o *UpdateStatusOK) GetPayload() *UpdateStatusOKBody { + return o.Payload +} + +func (o *UpdateStatusOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateStatusOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewUpdateStatusDefault creates a UpdateStatusDefault with default headers values +func NewUpdateStatusDefault(code int) *UpdateStatusDefault { + return &UpdateStatusDefault{ + _statusCode: code, + } +} + +/* +UpdateStatusDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type UpdateStatusDefault struct { + _statusCode int + + Payload *UpdateStatusDefaultBody +} + +// IsSuccess returns true when this update status default response has a 2xx status code +func (o *UpdateStatusDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this update status default response has a 3xx status code +func (o *UpdateStatusDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this update status default response has a 4xx status code +func (o *UpdateStatusDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this update status default response has a 5xx status code +func (o *UpdateStatusDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this update status default response a status code equal to that given +func (o *UpdateStatusDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the update status default response +func (o *UpdateStatusDefault) Code() int { + return o._statusCode +} + +func (o *UpdateStatusDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/server/updates:getStatus][%d] UpdateStatus default %s", o._statusCode, payload) +} + +func (o *UpdateStatusDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/server/updates:getStatus][%d] UpdateStatus default %s", o._statusCode, payload) +} + +func (o *UpdateStatusDefault) GetPayload() *UpdateStatusDefaultBody { + return o.Payload +} + +func (o *UpdateStatusDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateStatusDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +UpdateStatusBody update status body +swagger:model UpdateStatusBody +*/ +type UpdateStatusBody struct { + // Authentication token. Accepted from pre-3.9 clients. + AuthToken string `json:"auth_token,omitempty"` + + // Progress log offset. Accepted from pre-3.9 clients but ignored. + LogOffset int64 `json:"log_offset,omitempty"` +} + +// Validate validates this update status body +func (o *UpdateStatusBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update status body based on context it is used +func (o *UpdateStatusBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateStatusBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateStatusBody) UnmarshalBinary(b []byte) error { + var res UpdateStatusBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateStatusDefaultBody update status default body +swagger:model UpdateStatusDefaultBody +*/ +type UpdateStatusDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*UpdateStatusDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this update status default body +func (o *UpdateStatusDefaultBody) 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 *UpdateStatusDefaultBody) 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("UpdateStatus default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateStatus default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update status default body based on the context it is used +func (o *UpdateStatusDefaultBody) 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 *UpdateStatusDefaultBody) 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("UpdateStatus default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateStatus default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateStatusDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateStatusDefaultBody) UnmarshalBinary(b []byte) error { + var res UpdateStatusDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateStatusDefaultBodyDetailsItems0 `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +swagger:model UpdateStatusDefaultBodyDetailsItems0 +*/ +type UpdateStatusDefaultBodyDetailsItems0 struct { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + AtType string `json:"@type,omitempty"` + + // update status default body details items0 + UpdateStatusDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *UpdateStatusDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv UpdateStatusDefaultBodyDetailsItems0 + + 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.UpdateStatusDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o UpdateStatusDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + 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.UpdateStatusDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.UpdateStatusDefaultBodyDetailsItems0) + 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 status default body details items0 +func (o *UpdateStatusDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update status default body details items0 based on context it is used +func (o *UpdateStatusDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateStatusDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateStatusDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res UpdateStatusDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateStatusOKBody update status OK body +swagger:model UpdateStatusOKBody +*/ +type UpdateStatusOKBody struct { + // Progress log lines. Always empty, kept so pre-3.9 clients can parse the response. + LogLines []string `json:"log_lines"` + + // Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response. + LogOffset int64 `json:"log_offset,omitempty"` + + // True once PMM Server has finished initializing. + Done bool `json:"done,omitempty"` +} + +// Validate validates this update status OK body +func (o *UpdateStatusOKBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update status OK body based on context it is used +func (o *UpdateStatusOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateStatusOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateStatusOKBody) UnmarshalBinary(b []byte) error { + var res UpdateStatusOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/server/v1/json/v1.json b/api/server/v1/json/v1.json index bd36d1ff478..5aa4dfa51b7 100644 --- a/api/server/v1/json/v1.json +++ b/api/server/v1/json/v1.json @@ -1005,6 +1005,101 @@ } } }, + "/v1/server/updates:getStatus": { + "post": { + "description": "Returns PMM Server initialization status.", + "tags": [ + "ServerService" + ], + "summary": "Update status", + "operationId": "UpdateStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "auth_token": { + "description": "Authentication token. Accepted from pre-3.9 clients.", + "type": "string", + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset. Accepted from pre-3.9 clients but ignored.", + "type": "integer", + "format": "int64", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "log_lines": { + "description": "Progress log lines. Always empty, kept so pre-3.9 clients can parse the response.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response.", + "type": "integer", + "format": "int64", + "x-order": 1 + }, + "done": { + "description": "True once PMM Server has finished initializing.", + "type": "boolean", + "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": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/server/version": { "get": { "description": "Returns PMM Server versions.", diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index a5e3364cd38..a9bb5efd5e3 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -19,6 +19,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" common "github.com/percona/pmm/api/common" + _ "github.com/percona/pmm/api/extensions/v1" ) const ( @@ -718,6 +719,135 @@ func (x *ListChangeLogsResponse) GetLastCheck() *timestamppb.Timestamp { return nil } +type UpdateStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Authentication token. Accepted from pre-3.9 clients. + // + // Deprecated: Marked as deprecated in server/v1/server.proto. + AuthToken string `protobuf:"bytes,1,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` + // Progress log offset. Accepted from pre-3.9 clients but ignored. + // + // Deprecated: Marked as deprecated in server/v1/server.proto. + LogOffset uint32 `protobuf:"varint,2,opt,name=log_offset,json=logOffset,proto3" json:"log_offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateStatusRequest) Reset() { + *x = UpdateStatusRequest{} + mi := &file_server_v1_server_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStatusRequest) ProtoMessage() {} + +func (x *UpdateStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_v1_server_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 UpdateStatusRequest.ProtoReflect.Descriptor instead. +func (*UpdateStatusRequest) Descriptor() ([]byte, []int) { + return file_server_v1_server_proto_rawDescGZIP(), []int{12} +} + +// Deprecated: Marked as deprecated in server/v1/server.proto. +func (x *UpdateStatusRequest) GetAuthToken() string { + if x != nil { + return x.AuthToken + } + return "" +} + +// Deprecated: Marked as deprecated in server/v1/server.proto. +func (x *UpdateStatusRequest) GetLogOffset() uint32 { + if x != nil { + return x.LogOffset + } + return 0 +} + +type UpdateStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Progress log lines. Always empty, kept so pre-3.9 clients can parse the response. + // + // Deprecated: Marked as deprecated in server/v1/server.proto. + LogLines []string `protobuf:"bytes,1,rep,name=log_lines,json=logLines,proto3" json:"log_lines,omitempty"` + // Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response. + // + // Deprecated: Marked as deprecated in server/v1/server.proto. + LogOffset uint32 `protobuf:"varint,2,opt,name=log_offset,json=logOffset,proto3" json:"log_offset,omitempty"` + // True once PMM Server has finished initializing. + Done bool `protobuf:"varint,3,opt,name=done,proto3" json:"done,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateStatusResponse) Reset() { + *x = UpdateStatusResponse{} + mi := &file_server_v1_server_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStatusResponse) ProtoMessage() {} + +func (x *UpdateStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_v1_server_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 UpdateStatusResponse.ProtoReflect.Descriptor instead. +func (*UpdateStatusResponse) Descriptor() ([]byte, []int) { + return file_server_v1_server_proto_rawDescGZIP(), []int{13} +} + +// Deprecated: Marked as deprecated in server/v1/server.proto. +func (x *UpdateStatusResponse) GetLogLines() []string { + if x != nil { + return x.LogLines + } + return nil +} + +// Deprecated: Marked as deprecated in server/v1/server.proto. +func (x *UpdateStatusResponse) GetLogOffset() uint32 { + if x != nil { + return x.LogOffset + } + return 0 +} + +func (x *UpdateStatusResponse) GetDone() bool { + if x != nil { + return x.Done + } + return false +} + // MetricsResolutions represents Prometheus exporters metrics resolutions. type MetricsResolutions struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -733,7 +863,7 @@ type MetricsResolutions struct { func (x *MetricsResolutions) Reset() { *x = MetricsResolutions{} - mi := &file_server_v1_server_proto_msgTypes[12] + mi := &file_server_v1_server_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -745,7 +875,7 @@ func (x *MetricsResolutions) String() string { func (*MetricsResolutions) ProtoMessage() {} func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[12] + mi := &file_server_v1_server_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -758,7 +888,7 @@ func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { // Deprecated: Use MetricsResolutions.ProtoReflect.Descriptor instead. func (*MetricsResolutions) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{12} + return file_server_v1_server_proto_rawDescGZIP(), []int{14} } func (x *MetricsResolutions) GetHr() *durationpb.Duration { @@ -797,7 +927,7 @@ type AdvisorRunIntervals struct { func (x *AdvisorRunIntervals) Reset() { *x = AdvisorRunIntervals{} - mi := &file_server_v1_server_proto_msgTypes[13] + mi := &file_server_v1_server_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -809,7 +939,7 @@ func (x *AdvisorRunIntervals) String() string { func (*AdvisorRunIntervals) ProtoMessage() {} func (x *AdvisorRunIntervals) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[13] + mi := &file_server_v1_server_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -822,7 +952,7 @@ func (x *AdvisorRunIntervals) ProtoReflect() protoreflect.Message { // Deprecated: Use AdvisorRunIntervals.ProtoReflect.Descriptor instead. func (*AdvisorRunIntervals) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{13} + return file_server_v1_server_proto_rawDescGZIP(), []int{15} } func (x *AdvisorRunIntervals) GetStandardInterval() *durationpb.Duration { @@ -889,7 +1019,7 @@ type Settings struct { func (x *Settings) Reset() { *x = Settings{} - mi := &file_server_v1_server_proto_msgTypes[14] + mi := &file_server_v1_server_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -901,7 +1031,7 @@ func (x *Settings) String() string { func (*Settings) ProtoMessage() {} func (x *Settings) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[14] + mi := &file_server_v1_server_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -914,7 +1044,7 @@ func (x *Settings) ProtoReflect() protoreflect.Message { // Deprecated: Use Settings.ProtoReflect.Descriptor instead. func (*Settings) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{14} + return file_server_v1_server_proto_rawDescGZIP(), []int{16} } func (x *Settings) GetUpdatesEnabled() bool { @@ -1070,7 +1200,7 @@ type ReadOnlySettings struct { func (x *ReadOnlySettings) Reset() { *x = ReadOnlySettings{} - mi := &file_server_v1_server_proto_msgTypes[15] + mi := &file_server_v1_server_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1082,7 +1212,7 @@ func (x *ReadOnlySettings) String() string { func (*ReadOnlySettings) ProtoMessage() {} func (x *ReadOnlySettings) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[15] + mi := &file_server_v1_server_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1095,7 +1225,7 @@ func (x *ReadOnlySettings) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadOnlySettings.ProtoReflect.Descriptor instead. func (*ReadOnlySettings) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{15} + return file_server_v1_server_proto_rawDescGZIP(), []int{17} } func (x *ReadOnlySettings) GetUpdatesEnabled() bool { @@ -1162,7 +1292,7 @@ type GetSettingsRequest struct { func (x *GetSettingsRequest) Reset() { *x = GetSettingsRequest{} - mi := &file_server_v1_server_proto_msgTypes[16] + mi := &file_server_v1_server_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1174,7 +1304,7 @@ func (x *GetSettingsRequest) String() string { func (*GetSettingsRequest) ProtoMessage() {} func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[16] + mi := &file_server_v1_server_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1187,7 +1317,7 @@ func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsRequest.ProtoReflect.Descriptor instead. func (*GetSettingsRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{16} + return file_server_v1_server_proto_rawDescGZIP(), []int{18} } type GetReadOnlySettingsRequest struct { @@ -1198,7 +1328,7 @@ type GetReadOnlySettingsRequest struct { func (x *GetReadOnlySettingsRequest) Reset() { *x = GetReadOnlySettingsRequest{} - mi := &file_server_v1_server_proto_msgTypes[17] + mi := &file_server_v1_server_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1210,7 +1340,7 @@ func (x *GetReadOnlySettingsRequest) String() string { func (*GetReadOnlySettingsRequest) ProtoMessage() {} func (x *GetReadOnlySettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[17] + mi := &file_server_v1_server_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1223,7 +1353,7 @@ func (x *GetReadOnlySettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetReadOnlySettingsRequest.ProtoReflect.Descriptor instead. func (*GetReadOnlySettingsRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{17} + return file_server_v1_server_proto_rawDescGZIP(), []int{19} } type GetSettingsResponse struct { @@ -1235,7 +1365,7 @@ type GetSettingsResponse struct { func (x *GetSettingsResponse) Reset() { *x = GetSettingsResponse{} - mi := &file_server_v1_server_proto_msgTypes[18] + mi := &file_server_v1_server_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1247,7 +1377,7 @@ func (x *GetSettingsResponse) String() string { func (*GetSettingsResponse) ProtoMessage() {} func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[18] + mi := &file_server_v1_server_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1260,7 +1390,7 @@ func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsResponse.ProtoReflect.Descriptor instead. func (*GetSettingsResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{18} + return file_server_v1_server_proto_rawDescGZIP(), []int{20} } func (x *GetSettingsResponse) GetSettings() *Settings { @@ -1279,7 +1409,7 @@ type GetReadOnlySettingsResponse struct { func (x *GetReadOnlySettingsResponse) Reset() { *x = GetReadOnlySettingsResponse{} - mi := &file_server_v1_server_proto_msgTypes[19] + mi := &file_server_v1_server_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1291,7 +1421,7 @@ func (x *GetReadOnlySettingsResponse) String() string { func (*GetReadOnlySettingsResponse) ProtoMessage() {} func (x *GetReadOnlySettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[19] + mi := &file_server_v1_server_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1304,7 +1434,7 @@ func (x *GetReadOnlySettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetReadOnlySettingsResponse.ProtoReflect.Descriptor instead. func (*GetReadOnlySettingsResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{19} + return file_server_v1_server_proto_rawDescGZIP(), []int{21} } func (x *GetReadOnlySettingsResponse) GetSettings() *ReadOnlySettings { @@ -1345,7 +1475,7 @@ type ChangeSettingsRequest struct { func (x *ChangeSettingsRequest) Reset() { *x = ChangeSettingsRequest{} - mi := &file_server_v1_server_proto_msgTypes[20] + mi := &file_server_v1_server_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1357,7 +1487,7 @@ func (x *ChangeSettingsRequest) String() string { func (*ChangeSettingsRequest) ProtoMessage() {} func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[20] + mi := &file_server_v1_server_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1370,7 +1500,7 @@ func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsRequest.ProtoReflect.Descriptor instead. func (*ChangeSettingsRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{20} + return file_server_v1_server_proto_rawDescGZIP(), []int{22} } func (x *ChangeSettingsRequest) GetEnableUpdates() bool { @@ -1480,7 +1610,7 @@ type ChangeSettingsResponse struct { func (x *ChangeSettingsResponse) Reset() { *x = ChangeSettingsResponse{} - mi := &file_server_v1_server_proto_msgTypes[21] + mi := &file_server_v1_server_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1492,7 +1622,7 @@ func (x *ChangeSettingsResponse) String() string { func (*ChangeSettingsResponse) ProtoMessage() {} func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[21] + mi := &file_server_v1_server_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1505,7 +1635,7 @@ func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsResponse.ProtoReflect.Descriptor instead. func (*ChangeSettingsResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{21} + return file_server_v1_server_proto_rawDescGZIP(), []int{23} } func (x *ChangeSettingsResponse) GetSettings() *Settings { @@ -1519,7 +1649,7 @@ var File_server_v1_server_proto protoreflect.FileDescriptor const file_server_v1_server_proto_rawDesc = "" + "\n" + - "\x16server/v1/server.proto\x12\tserver.v1\x1a\x13common/common.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\x84\x01\n" + + "\x16server/v1/server.proto\x12\tserver.v1\x1a\x13common/common.proto\x1a\x1aextensions/v1/redact.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\x84\x01\n" + "\vVersionInfo\x12\x18\n" + "\aversion\x18\x01 \x01(\tR\aversion\x12!\n" + "\ffull_version\x18\x02 \x01(\tR\vfullVersion\x128\n" + @@ -1555,7 +1685,17 @@ const file_server_v1_server_proto_rawDesc = "" + "\x16ListChangeLogsResponse\x126\n" + "\aupdates\x18\x01 \x03(\v2\x1c.server.v1.DockerVersionInfoR\aupdates\x129\n" + "\n" + - "last_check\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tlastCheck\"\x95\x01\n" + + "last_check\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tlastCheck\"_\n" + + "\x13UpdateStatusRequest\x12%\n" + + "\n" + + "auth_token\x18\x01 \x01(\tB\x06\x88\xb5\x18\x01\x18\x01R\tauthToken\x12!\n" + + "\n" + + "log_offset\x18\x02 \x01(\rB\x02\x18\x01R\tlogOffset\"n\n" + + "\x14UpdateStatusResponse\x12\x1f\n" + + "\tlog_lines\x18\x01 \x03(\tB\x02\x18\x01R\blogLines\x12!\n" + + "\n" + + "log_offset\x18\x02 \x01(\rB\x02\x18\x01R\tlogOffset\x12\x12\n" + + "\x04done\x18\x03 \x01(\bR\x04done\"\x95\x01\n" + "\x12MetricsResolutions\x12)\n" + "\x02hr\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\x02hr\x12)\n" + "\x02mr\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\x02mr\x12)\n" + @@ -1636,13 +1776,14 @@ const file_server_v1_server_proto_rawDesc = "" + "\x17DISTRIBUTION_METHOD_OVF\x10\x02\x12\x1b\n" + "\x17DISTRIBUTION_METHOD_AMI\x10\x03\x12\x1d\n" + "\x19DISTRIBUTION_METHOD_AZURE\x10\x04\x12\x1a\n" + - "\x16DISTRIBUTION_METHOD_DO\x10\x052\x89\r\n" + + "\x16DISTRIBUTION_METHOD_DO\x10\x052\xc1\x0e\n" + "\rServerService\x12\x86\x01\n" + "\aVersion\x12\x19.server.v1.VersionRequest\x1a\x1a.server.v1.VersionResponse\"D\x92A'\x12\aVersion\x1a\x1cReturns PMM Server versions.\x82\xd3\xe4\x93\x02\x14\x12\x12/v1/server/version\x12\xab\x02\n" + "\tReadiness\x12\x1b.server.v1.ReadinessRequest\x1a\x1c.server.v1.ReadinessResponse\"\xe2\x01\x92A\xc5\x01\x12\x16Check server readiness\x1a\xaa\x01Returns an error when Server components being restarted are not ready yet. Use this API for checking the health of Docker containers and for probing Kubernetes readiness.\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/server/readyz\x12\x81\x02\n" + "\x11LeaderHealthCheck\x12#.server.v1.LeaderHealthCheckRequest\x1a$.server.v1.LeaderHealthCheckResponse\"\xa0\x01\x92Ay\x12\x10Check Leadership\x1aeChecks if the instance is the leader in a cluster. Returns an error if the instance isn't the leader.\x82\xd3\xe4\x93\x02\x1e\x12\x1c/v1/server/leaderHealthCheck\x12\xa7\x01\n" + "\fCheckUpdates\x12\x1e.server.v1.CheckUpdatesRequest\x1a\x1f.server.v1.CheckUpdatesResponse\"V\x92A9\x12\rCheck updates\x1a(Checks for available PMM Server updates.\x82\xd3\xe4\x93\x02\x14\x12\x12/v1/server/updates\x12\xe9\x01\n" + - "\x0eListChangeLogs\x12 .server.v1.ListChangeLogsRequest\x1a!.server.v1.ListChangeLogsResponse\"\x91\x01\x92Ai\x12\x11Get the changelog\x1aTDisplay a changelog comparing the installed version to the latest available version.\x82\xd3\xe4\x93\x02\x1f\x12\x1d/v1/server/updates/changelogs\x12\xa0\x01\n" + + "\x0eListChangeLogs\x12 .server.v1.ListChangeLogsRequest\x1a!.server.v1.ListChangeLogsResponse\"\x91\x01\x92Ai\x12\x11Get the changelog\x1aTDisplay a changelog comparing the installed version to the latest available version.\x82\xd3\xe4\x93\x02\x1f\x12\x1d/v1/server/updates/changelogs\x12\xb5\x01\n" + + "\fUpdateStatus\x12\x1e.server.v1.UpdateStatusRequest\x1a\x1f.server.v1.UpdateStatusResponse\"d\x92A:\x12\rUpdate status\x1a)Returns PMM Server initialization status.\x82\xd3\xe4\x93\x02!:\x01*\"\x1c/v1/server/updates:getStatus\x12\xa0\x01\n" + "\vGetSettings\x12\x1d.server.v1.GetSettingsRequest\x1a\x1e.server.v1.GetSettingsResponse\"R\x92A4\x12\fGet settings\x1a$Returns current PMM Server settings.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/server/settings\x12\xd9\x01\n" + "\x13GetReadOnlySettings\x12%.server.v1.GetReadOnlySettingsRequest\x1a&.server.v1.GetReadOnlySettingsResponse\"s\x92AL\x12\x16Get read-only settings\x1a2Returns a stripped version of PMM Server settings.\x82\xd3\xe4\x93\x02\x1e\x12\x1c/v1/server/settings/readonly\x12\xa7\x01\n" + "\x0eChangeSettings\x12 .server.v1.ChangeSettingsRequest\x1a!.server.v1.ChangeSettingsResponse\"P\x92A/\x12\x0fChange settings\x1a\x1cChanges PMM Server settings.\x82\xd3\xe4\x93\x02\x18:\x01*\x1a\x13/v1/server/settingsB\x90\x01\n" + @@ -1663,7 +1804,7 @@ func file_server_v1_server_proto_rawDescGZIP() []byte { var ( file_server_v1_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) - file_server_v1_server_proto_msgTypes = make([]protoimpl.MessageInfo, 22) + file_server_v1_server_proto_msgTypes = make([]protoimpl.MessageInfo, 24) file_server_v1_server_proto_goTypes = []any{ DistributionMethod(0), // 0: server.v1.DistributionMethod (*VersionInfo)(nil), // 1: server.v1.VersionInfo @@ -1678,67 +1819,71 @@ var ( (*CheckUpdatesResponse)(nil), // 10: server.v1.CheckUpdatesResponse (*ListChangeLogsRequest)(nil), // 11: server.v1.ListChangeLogsRequest (*ListChangeLogsResponse)(nil), // 12: server.v1.ListChangeLogsResponse - (*MetricsResolutions)(nil), // 13: server.v1.MetricsResolutions - (*AdvisorRunIntervals)(nil), // 14: server.v1.AdvisorRunIntervals - (*Settings)(nil), // 15: server.v1.Settings - (*ReadOnlySettings)(nil), // 16: server.v1.ReadOnlySettings - (*GetSettingsRequest)(nil), // 17: server.v1.GetSettingsRequest - (*GetReadOnlySettingsRequest)(nil), // 18: server.v1.GetReadOnlySettingsRequest - (*GetSettingsResponse)(nil), // 19: server.v1.GetSettingsResponse - (*GetReadOnlySettingsResponse)(nil), // 20: server.v1.GetReadOnlySettingsResponse - (*ChangeSettingsRequest)(nil), // 21: server.v1.ChangeSettingsRequest - (*ChangeSettingsResponse)(nil), // 22: server.v1.ChangeSettingsResponse - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 24: google.protobuf.Duration - (*common.StringArray)(nil), // 25: common.StringArray + (*UpdateStatusRequest)(nil), // 13: server.v1.UpdateStatusRequest + (*UpdateStatusResponse)(nil), // 14: server.v1.UpdateStatusResponse + (*MetricsResolutions)(nil), // 15: server.v1.MetricsResolutions + (*AdvisorRunIntervals)(nil), // 16: server.v1.AdvisorRunIntervals + (*Settings)(nil), // 17: server.v1.Settings + (*ReadOnlySettings)(nil), // 18: server.v1.ReadOnlySettings + (*GetSettingsRequest)(nil), // 19: server.v1.GetSettingsRequest + (*GetReadOnlySettingsRequest)(nil), // 20: server.v1.GetReadOnlySettingsRequest + (*GetSettingsResponse)(nil), // 21: server.v1.GetSettingsResponse + (*GetReadOnlySettingsResponse)(nil), // 22: server.v1.GetReadOnlySettingsResponse + (*ChangeSettingsRequest)(nil), // 23: server.v1.ChangeSettingsRequest + (*ChangeSettingsResponse)(nil), // 24: server.v1.ChangeSettingsResponse + (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 26: google.protobuf.Duration + (*common.StringArray)(nil), // 27: common.StringArray } ) var file_server_v1_server_proto_depIdxs = []int32{ - 23, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 25, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo 1, // 2: server.v1.VersionResponse.managed:type_name -> server.v1.VersionInfo 0, // 3: server.v1.VersionResponse.distribution_method:type_name -> server.v1.DistributionMethod - 23, // 4: server.v1.DockerVersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 25, // 4: server.v1.DockerVersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 5: server.v1.CheckUpdatesResponse.installed:type_name -> server.v1.VersionInfo 9, // 6: server.v1.CheckUpdatesResponse.latest:type_name -> server.v1.DockerVersionInfo - 23, // 7: server.v1.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp + 25, // 7: server.v1.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp 9, // 8: server.v1.ListChangeLogsResponse.updates:type_name -> server.v1.DockerVersionInfo - 23, // 9: server.v1.ListChangeLogsResponse.last_check:type_name -> google.protobuf.Timestamp - 24, // 10: server.v1.MetricsResolutions.hr:type_name -> google.protobuf.Duration - 24, // 11: server.v1.MetricsResolutions.mr:type_name -> google.protobuf.Duration - 24, // 12: server.v1.MetricsResolutions.lr:type_name -> google.protobuf.Duration - 24, // 13: server.v1.AdvisorRunIntervals.standard_interval:type_name -> google.protobuf.Duration - 24, // 14: server.v1.AdvisorRunIntervals.rare_interval:type_name -> google.protobuf.Duration - 24, // 15: server.v1.AdvisorRunIntervals.frequent_interval:type_name -> google.protobuf.Duration - 13, // 16: server.v1.Settings.metrics_resolutions:type_name -> server.v1.MetricsResolutions - 24, // 17: server.v1.Settings.data_retention:type_name -> google.protobuf.Duration - 14, // 18: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 15, // 19: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings - 16, // 20: server.v1.GetReadOnlySettingsResponse.settings:type_name -> server.v1.ReadOnlySettings - 13, // 21: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions - 24, // 22: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration - 25, // 23: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray - 14, // 24: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 15, // 25: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings + 25, // 9: server.v1.ListChangeLogsResponse.last_check:type_name -> google.protobuf.Timestamp + 26, // 10: server.v1.MetricsResolutions.hr:type_name -> google.protobuf.Duration + 26, // 11: server.v1.MetricsResolutions.mr:type_name -> google.protobuf.Duration + 26, // 12: server.v1.MetricsResolutions.lr:type_name -> google.protobuf.Duration + 26, // 13: server.v1.AdvisorRunIntervals.standard_interval:type_name -> google.protobuf.Duration + 26, // 14: server.v1.AdvisorRunIntervals.rare_interval:type_name -> google.protobuf.Duration + 26, // 15: server.v1.AdvisorRunIntervals.frequent_interval:type_name -> google.protobuf.Duration + 15, // 16: server.v1.Settings.metrics_resolutions:type_name -> server.v1.MetricsResolutions + 26, // 17: server.v1.Settings.data_retention:type_name -> google.protobuf.Duration + 16, // 18: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 17, // 19: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings + 18, // 20: server.v1.GetReadOnlySettingsResponse.settings:type_name -> server.v1.ReadOnlySettings + 15, // 21: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions + 26, // 22: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration + 27, // 23: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray + 16, // 24: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 17, // 25: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings 2, // 26: server.v1.ServerService.Version:input_type -> server.v1.VersionRequest 4, // 27: server.v1.ServerService.Readiness:input_type -> server.v1.ReadinessRequest 6, // 28: server.v1.ServerService.LeaderHealthCheck:input_type -> server.v1.LeaderHealthCheckRequest 8, // 29: server.v1.ServerService.CheckUpdates:input_type -> server.v1.CheckUpdatesRequest 11, // 30: server.v1.ServerService.ListChangeLogs:input_type -> server.v1.ListChangeLogsRequest - 17, // 31: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest - 18, // 32: server.v1.ServerService.GetReadOnlySettings:input_type -> server.v1.GetReadOnlySettingsRequest - 21, // 33: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest - 3, // 34: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse - 5, // 35: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse - 7, // 36: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse - 10, // 37: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse - 12, // 38: server.v1.ServerService.ListChangeLogs:output_type -> server.v1.ListChangeLogsResponse - 19, // 39: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse - 20, // 40: server.v1.ServerService.GetReadOnlySettings:output_type -> server.v1.GetReadOnlySettingsResponse - 22, // 41: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse - 34, // [34:42] is the sub-list for method output_type - 26, // [26:34] is the sub-list for method input_type + 13, // 31: server.v1.ServerService.UpdateStatus:input_type -> server.v1.UpdateStatusRequest + 19, // 32: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest + 20, // 33: server.v1.ServerService.GetReadOnlySettings:input_type -> server.v1.GetReadOnlySettingsRequest + 23, // 34: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest + 3, // 35: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse + 5, // 36: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse + 7, // 37: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse + 10, // 38: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse + 12, // 39: server.v1.ServerService.ListChangeLogs:output_type -> server.v1.ListChangeLogsResponse + 14, // 40: server.v1.ServerService.UpdateStatus:output_type -> server.v1.UpdateStatusResponse + 21, // 41: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse + 22, // 42: server.v1.ServerService.GetReadOnlySettings:output_type -> server.v1.GetReadOnlySettingsResponse + 24, // 43: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse + 35, // [35:44] is the sub-list for method output_type + 26, // [26:35] is the sub-list for method input_type 26, // [26:26] is the sub-list for extension type_name 26, // [26:26] is the sub-list for extension extendee 0, // [0:26] is the sub-list for field type_name @@ -1749,14 +1894,14 @@ func file_server_v1_server_proto_init() { if File_server_v1_server_proto != nil { return } - file_server_v1_server_proto_msgTypes[20].OneofWrappers = []any{} + file_server_v1_server_proto_msgTypes[22].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_server_v1_server_proto_rawDesc), len(file_server_v1_server_proto_rawDesc)), NumEnums: 1, - NumMessages: 22, + NumMessages: 24, NumExtensions: 0, NumServices: 1, }, diff --git a/api/server/v1/server.pb.gw.go b/api/server/v1/server.pb.gw.go index 464f987dd7d..01b1e98aa90 100644 --- a/api/server/v1/server.pb.gw.go +++ b/api/server/v1/server.pb.gw.go @@ -168,6 +168,33 @@ func local_request_ServerService_ListChangeLogs_0(ctx context.Context, marshaler return msg, metadata, err } +func request_ServerService_UpdateStatus_0(ctx context.Context, marshaler runtime.Marshaler, client ServerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateStatusRequest + 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.UpdateStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_ServerService_UpdateStatus_0(ctx context.Context, marshaler runtime.Marshaler, server ServerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateStatusRequest + 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.UpdateStatus(ctx, &protoReq) + return msg, metadata, err +} + func request_ServerService_GetSettings_0(ctx context.Context, marshaler runtime.Marshaler, client ServerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq GetSettingsRequest @@ -343,6 +370,26 @@ func RegisterServerServiceHandlerServer(ctx context.Context, mux *runtime.ServeM } forward_ServerService_ListChangeLogs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_ServerService_UpdateStatus_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, "/server.v1.ServerService/UpdateStatus", runtime.WithHTTPPathPattern("/v1/server/updates:getStatus")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ServerService_UpdateStatus_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_ServerService_UpdateStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_ServerService_GetSettings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -528,6 +575,23 @@ func RegisterServerServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } forward_ServerService_ListChangeLogs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_ServerService_UpdateStatus_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, "/server.v1.ServerService/UpdateStatus", runtime.WithHTTPPathPattern("/v1/server/updates:getStatus")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ServerService_UpdateStatus_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_ServerService_UpdateStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_ServerService_GetSettings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -588,6 +652,7 @@ var ( pattern_ServerService_LeaderHealthCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "leaderHealthCheck"}, "")) pattern_ServerService_CheckUpdates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "updates"}, "")) pattern_ServerService_ListChangeLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "server", "updates", "changelogs"}, "")) + pattern_ServerService_UpdateStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "updates"}, "getStatus")) pattern_ServerService_GetSettings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "settings"}, "")) pattern_ServerService_GetReadOnlySettings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "server", "settings", "readonly"}, "")) pattern_ServerService_ChangeSettings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "settings"}, "")) @@ -599,6 +664,7 @@ var ( forward_ServerService_LeaderHealthCheck_0 = runtime.ForwardResponseMessage forward_ServerService_CheckUpdates_0 = runtime.ForwardResponseMessage forward_ServerService_ListChangeLogs_0 = runtime.ForwardResponseMessage + forward_ServerService_UpdateStatus_0 = runtime.ForwardResponseMessage forward_ServerService_GetSettings_0 = runtime.ForwardResponseMessage forward_ServerService_GetReadOnlySettings_0 = runtime.ForwardResponseMessage forward_ServerService_ChangeSettings_0 = runtime.ForwardResponseMessage diff --git a/api/server/v1/server.pb.validate.go b/api/server/v1/server.pb.validate.go index 7c9c52c587a..e6412a2bb8a 100644 --- a/api/server/v1/server.pb.validate.go +++ b/api/server/v1/server.pb.validate.go @@ -1554,6 +1554,220 @@ var _ interface { ErrorName() string } = ListChangeLogsResponseValidationError{} +// Validate checks the field values on UpdateStatusRequest 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 *UpdateStatusRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateStatusRequest 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 +// UpdateStatusRequestMultiError, or nil if none found. +func (m *UpdateStatusRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateStatusRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for AuthToken + + // no validation rules for LogOffset + + if len(errors) > 0 { + return UpdateStatusRequestMultiError(errors) + } + + return nil +} + +// UpdateStatusRequestMultiError is an error wrapping multiple validation +// errors returned by UpdateStatusRequest.ValidateAll() if the designated +// constraints aren't met. +type UpdateStatusRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateStatusRequestMultiError) 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 UpdateStatusRequestMultiError) AllErrors() []error { return m } + +// UpdateStatusRequestValidationError is the validation error returned by +// UpdateStatusRequest.Validate if the designated constraints aren't met. +type UpdateStatusRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateStatusRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateStatusRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateStatusRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateStatusRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateStatusRequestValidationError) ErrorName() string { + return "UpdateStatusRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateStatusRequestValidationError) 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 %sUpdateStatusRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateStatusRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateStatusRequestValidationError{} + +// Validate checks the field values on UpdateStatusResponse 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 *UpdateStatusResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateStatusResponse 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 +// UpdateStatusResponseMultiError, or nil if none found. +func (m *UpdateStatusResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateStatusResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for LogOffset + + // no validation rules for Done + + if len(errors) > 0 { + return UpdateStatusResponseMultiError(errors) + } + + return nil +} + +// UpdateStatusResponseMultiError is an error wrapping multiple validation +// errors returned by UpdateStatusResponse.ValidateAll() if the designated +// constraints aren't met. +type UpdateStatusResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateStatusResponseMultiError) 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 UpdateStatusResponseMultiError) AllErrors() []error { return m } + +// UpdateStatusResponseValidationError is the validation error returned by +// UpdateStatusResponse.Validate if the designated constraints aren't met. +type UpdateStatusResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateStatusResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateStatusResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateStatusResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateStatusResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateStatusResponseValidationError) ErrorName() string { + return "UpdateStatusResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateStatusResponseValidationError) 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 %sUpdateStatusResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateStatusResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateStatusResponseValidationError{} + // Validate checks the field values on MetricsResolutions 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. diff --git a/api/server/v1/server.proto b/api/server/v1/server.proto index 0fe88df85d9..8bd8f8948c6 100644 --- a/api/server/v1/server.proto +++ b/api/server/v1/server.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package server.v1; import "common/common.proto"; +import "extensions/v1/redact.proto"; import "google/api/annotations.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; @@ -100,6 +101,25 @@ message ListChangeLogsResponse { google.protobuf.Timestamp last_check = 2; } +message UpdateStatusRequest { + // Authentication token. Accepted from pre-3.9 clients. + string auth_token = 1 [ + deprecated = true, + (extensions.v1.sensitive) = REDACT_TYPE_FULL + ]; + // Progress log offset. Accepted from pre-3.9 clients but ignored. + uint32 log_offset = 2 [deprecated = true]; +} + +message UpdateStatusResponse { + // Progress log lines. Always empty, kept so pre-3.9 clients can parse the response. + repeated string log_lines = 1 [deprecated = true]; + // Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response. + uint32 log_offset = 2 [deprecated = true]; + // True once PMM Server has finished initializing. + bool done = 3; +} + // MetricsResolutions represents Prometheus exporters metrics resolutions. message MetricsResolutions { // High resolution. Should have a suffix in JSON: 1s, 1m, 1h. @@ -266,6 +286,20 @@ service ServerService { description: "Display a changelog comparing the installed version to the latest available version." }; } + // UpdateStatus returns PMM Server initialization status. + // + // It exists for pre-3.9 clients, which poll it after triggering an update to learn when the + // freshly started PMM Server has finished initializing. Only the "done" field is meaningful. + rpc UpdateStatus(UpdateStatusRequest) returns (UpdateStatusResponse) { + option (google.api.http) = { + post: "/v1/server/updates:getStatus" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Update status" + description: "Returns PMM Server initialization status." + }; + } // GetSettings returns current PMM Server settings. rpc GetSettings(GetSettingsRequest) returns (GetSettingsResponse) { option (google.api.http) = {get: "/v1/server/settings"}; diff --git a/api/server/v1/server_grpc.pb.go b/api/server/v1/server_grpc.pb.go index 3253c4d8b8f..0753a4ccba7 100644 --- a/api/server/v1/server_grpc.pb.go +++ b/api/server/v1/server_grpc.pb.go @@ -25,6 +25,7 @@ const ( ServerService_LeaderHealthCheck_FullMethodName = "/server.v1.ServerService/LeaderHealthCheck" ServerService_CheckUpdates_FullMethodName = "/server.v1.ServerService/CheckUpdates" ServerService_ListChangeLogs_FullMethodName = "/server.v1.ServerService/ListChangeLogs" + ServerService_UpdateStatus_FullMethodName = "/server.v1.ServerService/UpdateStatus" ServerService_GetSettings_FullMethodName = "/server.v1.ServerService/GetSettings" ServerService_GetReadOnlySettings_FullMethodName = "/server.v1.ServerService/GetReadOnlySettings" ServerService_ChangeSettings_FullMethodName = "/server.v1.ServerService/ChangeSettings" @@ -47,6 +48,11 @@ type ServerServiceClient interface { CheckUpdates(ctx context.Context, in *CheckUpdatesRequest, opts ...grpc.CallOption) (*CheckUpdatesResponse, error) // ListChangeLogs delivers the changelog. ListChangeLogs(ctx context.Context, in *ListChangeLogsRequest, opts ...grpc.CallOption) (*ListChangeLogsResponse, error) + // UpdateStatus returns PMM Server initialization status. + // + // It exists for pre-3.9 clients, which poll it after triggering an update to learn when the + // freshly started PMM Server has finished initializing. Only the "done" field is meaningful. + UpdateStatus(ctx context.Context, in *UpdateStatusRequest, opts ...grpc.CallOption) (*UpdateStatusResponse, error) // GetSettings returns current PMM Server settings. GetSettings(ctx context.Context, in *GetSettingsRequest, opts ...grpc.CallOption) (*GetSettingsResponse, error) // GetReadOnlySettings returns a limited number of PMM settings that is opened to authenticated users of all roles. @@ -113,6 +119,16 @@ func (c *serverServiceClient) ListChangeLogs(ctx context.Context, in *ListChange return out, nil } +func (c *serverServiceClient) UpdateStatus(ctx context.Context, in *UpdateStatusRequest, opts ...grpc.CallOption) (*UpdateStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateStatusResponse) + err := c.cc.Invoke(ctx, ServerService_UpdateStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *serverServiceClient) GetSettings(ctx context.Context, in *GetSettingsRequest, opts ...grpc.CallOption) (*GetSettingsResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetSettingsResponse) @@ -160,6 +176,11 @@ type ServerServiceServer interface { CheckUpdates(context.Context, *CheckUpdatesRequest) (*CheckUpdatesResponse, error) // ListChangeLogs delivers the changelog. ListChangeLogs(context.Context, *ListChangeLogsRequest) (*ListChangeLogsResponse, error) + // UpdateStatus returns PMM Server initialization status. + // + // It exists for pre-3.9 clients, which poll it after triggering an update to learn when the + // freshly started PMM Server has finished initializing. Only the "done" field is meaningful. + UpdateStatus(context.Context, *UpdateStatusRequest) (*UpdateStatusResponse, error) // GetSettings returns current PMM Server settings. GetSettings(context.Context, *GetSettingsRequest) (*GetSettingsResponse, error) // GetReadOnlySettings returns a limited number of PMM settings that is opened to authenticated users of all roles. @@ -196,6 +217,10 @@ func (UnimplementedServerServiceServer) ListChangeLogs(context.Context, *ListCha return nil, status.Error(codes.Unimplemented, "method ListChangeLogs not implemented") } +func (UnimplementedServerServiceServer) UpdateStatus(context.Context, *UpdateStatusRequest) (*UpdateStatusResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateStatus not implemented") +} + func (UnimplementedServerServiceServer) GetSettings(context.Context, *GetSettingsRequest) (*GetSettingsResponse, error) { return nil, status.Error(codes.Unimplemented, "method GetSettings not implemented") } @@ -318,6 +343,24 @@ func _ServerService_ListChangeLogs_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _ServerService_UpdateStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServerServiceServer).UpdateStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ServerService_UpdateStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServerServiceServer).UpdateStatus(ctx, req.(*UpdateStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ServerService_GetSettings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetSettingsRequest) if err := dec(in); err != nil { @@ -399,6 +442,10 @@ var ServerService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListChangeLogs", Handler: _ServerService_ListChangeLogs_Handler, }, + { + MethodName: "UpdateStatus", + Handler: _ServerService_UpdateStatus_Handler, + }, { MethodName: "GetSettings", Handler: _ServerService_GetSettings_Handler, diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index ac4a6f1a126..ecb52740824 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -33121,6 +33121,101 @@ } } }, + "/v1/server/updates:getStatus": { + "post": { + "description": "Returns PMM Server initialization status.", + "tags": [ + "ServerService" + ], + "summary": "Update status", + "operationId": "UpdateStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "auth_token": { + "description": "Authentication token. Accepted from pre-3.9 clients.", + "type": "string", + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset. Accepted from pre-3.9 clients but ignored.", + "type": "integer", + "format": "int64", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "log_lines": { + "description": "Progress log lines. Always empty, kept so pre-3.9 clients can parse the response.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response.", + "type": "integer", + "format": "int64", + "x-order": 1 + }, + "done": { + "description": "True once PMM Server has finished initializing.", + "type": "boolean", + "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": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/server/version": { "get": { "description": "Returns PMM Server versions.", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index c40c51e6c46..c507371e4f3 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -32148,6 +32148,101 @@ } } }, + "/v1/server/updates:getStatus": { + "post": { + "description": "Returns PMM Server initialization status.", + "tags": [ + "ServerService" + ], + "summary": "Update status", + "operationId": "UpdateStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "auth_token": { + "description": "Authentication token. Accepted from pre-3.9 clients.", + "type": "string", + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset. Accepted from pre-3.9 clients but ignored.", + "type": "integer", + "format": "int64", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "log_lines": { + "description": "Progress log lines. Always empty, kept so pre-3.9 clients can parse the response.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "log_offset": { + "description": "Progress log offset for the next request. Always zero, kept so pre-3.9 clients can parse the response.", + "type": "integer", + "format": "int64", + "x-order": 1 + }, + "done": { + "description": "True once PMM Server has finished initializing.", + "type": "boolean", + "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": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/server/version": { "get": { "description": "Returns PMM Server versions.", diff --git a/build/ansible/roles/initialization/tasks/main.yml b/build/ansible/roles/initialization/tasks/main.yml index 1d3c67ab939..9ef53c20e37 100644 --- a/build/ansible/roles/initialization/tasks/main.yml +++ b/build/ansible/roles/initialization/tasks/main.yml @@ -127,7 +127,8 @@ state: absent path: /usr/share/pmm-server/maintenance/maintenance.html -- name: Remove the file provisioned by 'getStatus' +# Written by 'updates:start' up to PMM 3.8; nothing uses it now, so clean it off upgraded volumes. +- name: Remove the update auth token file left by older PMM versions file: state: absent path: /srv/pmm-update.json diff --git a/build/ansible/roles/nginx/files/conf.d/pmm.conf b/build/ansible/roles/nginx/files/conf.d/pmm.conf index 6ae7efbe7bc..534912f346e 100644 --- a/build/ansible/roles/nginx/files/conf.d/pmm.conf +++ b/build/ansible/roles/nginx/files/conf.d/pmm.conf @@ -60,14 +60,14 @@ ssl_dhparam /srv/nginx/dhparam.pem; # this block checks for maintenance.html file and, if it exists, it redirects all requests to the maintenance page - # there are two exceptions for it /v1/updates/Status and /auth_request endpoints + # there are two exceptions for it /v1/server/updates:getStatus and /auth_request endpoints set $maintenance_mode 0; if (-f /usr/share/pmm-server/maintenance/maintenance.html) { set $maintenance_mode 1; } - if ($request_uri ~* "^/v1/updates/Status|^/auth_request") { + if ($request_uri ~* "^/v1/server/updates:getStatus|^/auth_request") { set $maintenance_mode 0; } diff --git a/documentation/docs/admin/roles/index.md b/documentation/docs/admin/roles/index.md index 5ee79073ca6..8c66f2806db 100644 --- a/documentation/docs/admin/roles/index.md +++ b/documentation/docs/admin/roles/index.md @@ -70,7 +70,6 @@ Use the matrix below to check which permissions users have based on their assign View backups | ✗ | ✗ | ✓ Manage backups | ✗ | ✗ | ✓ View update status | ✗ | ✗ | ✓ - Start updates | ✗ | ✗ | ✓ === "Data sources" Permission | Viewer | Editor | Admin @@ -92,7 +91,6 @@ Use the matrix below to check which permissions users have based on their assign `/v1/management/` | Admin | Server management functions `/v1/management/Jobs` | Viewer | View management jobs `/v1/server/updates` | Viewer | Check for updates - `/v1/server/updates:start` | Admin | Start update process `/v1/server/settings/readonly` | Viewer | View read-only settings `/v1/server/settings` | Admin | Configure server settings `/v1/platform:` | Admin | Platform management diff --git a/managed/services/grafana/auth_server.go b/managed/services/grafana/auth_server.go index 7bb9927c306..afc83721fac 100644 --- a/managed/services/grafana/auth_server.go +++ b/managed/services/grafana/auth_server.go @@ -60,6 +60,9 @@ var rules = map[string]role{ "/actions.": viewer, "/advisors.v1.": editor, "/server.v1.ServerService/CheckUpdates": viewer, + // Polled by pre-3.9 clients right after an update, when Grafana and PostgreSQL may still be + // migrating and cannot authenticate anyone. + "/server.v1.ServerService/UpdateStatus": none, "/server.v1.ServerService/AWSInstanceCheck": none, // special case - used before Grafana can be accessed "/server.": admin, // TODO: do we need it for older agents? "/server.v1.": admin, @@ -83,6 +86,7 @@ var rules = map[string]role{ "/v1/management/Jobs": viewer, "/v1/server/AWSInstance": none, // special case - used before Grafana can be accessed "/v1/server/updates": viewer, + "/v1/server/updates:getStatus": none, "/v1/server/settings": admin, "/v1/server/settings/readonly": viewer, "/v1/platform:": admin, diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index 5d1c510130b..5265ed8b3aa 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -77,6 +77,7 @@ type vmAlertExternalRules interface { // We use it instead of real type for testing and to avoid dependency cycle. type supervisordService interface { UpdateConfiguration(settings *models.Settings) error + ProgramRunning(program string) bool } // telemetryService is a subset of methods of telemetry.Service used by this package. diff --git a/managed/services/server/mock_supervisord_service_test.go b/managed/services/server/mock_supervisord_service_test.go index ec30c3eb54c..ce8c5bb0935 100644 --- a/managed/services/server/mock_supervisord_service_test.go +++ b/managed/services/server/mock_supervisord_service_test.go @@ -13,6 +13,24 @@ type mockSupervisordService struct { mock.Mock } +// ProgramRunning provides a mock function with given fields: program +func (_m *mockSupervisordService) ProgramRunning(program string) bool { + ret := _m.Called(program) + + if len(ret) == 0 { + panic("no return value specified for ProgramRunning") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(program) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // UpdateConfiguration provides a mock function with given fields: settings func (_m *mockSupervisordService) UpdateConfiguration(settings *models.Settings) error { ret := _m.Called(settings) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 199ee2bfed9..022afac7432 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -45,6 +45,9 @@ import ( "github.com/percona/pmm/version" ) +// pmmInitProgram is the supervisord program running PMM Server initialization and upgrade tasks. +const pmmInitProgram = "pmm-init" + // Server represents service for checking PMM Server status and changing settings. type Server struct { serverv1.UnimplementedServerServiceServer @@ -332,6 +335,17 @@ func (s *Server) ListChangeLogs(ctx context.Context, _ *serverv1.ListChangeLogsR return res, nil } +// UpdateStatus returns PMM Server initialization status. +// +// It exists for pre-3.9 clients: after triggering an update they keep polling it to learn when the +// freshly started PMM Server has finished initializing. Only the "done" field is meaningful. The +// progress log fields are left empty. +func (s *Server) UpdateStatus(_ context.Context, _ *serverv1.UpdateStatusRequest) (*serverv1.UpdateStatusResponse, error) { + return &serverv1.UpdateStatusResponse{ + Done: !s.supervisord.ProgramRunning(pmmInitProgram), + }, nil +} + // convertSettings merges database settings and settings from environment variables into API response. func (s *Server) convertSettings(settings *models.Settings, disableInternalPgQan bool) *serverv1.Settings { res := &serverv1.Settings{ diff --git a/managed/services/server/server_test.go b/managed/services/server/server_test.go index 7a3ed57a2ff..cdbe5ef64ab 100644 --- a/managed/services/server/server_test.go +++ b/managed/services/server/server_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -322,3 +323,42 @@ func TestConvertDefaultRoleID(t *testing.T) { }) } } + +func TestUpdateStatus(t *testing.T) { + newServer := func(t *testing.T, initRunning bool) *Server { + t.Helper() + + var sv mockSupervisordService + sv.Test(t) + sv.On("ProgramRunning", pmmInitProgram).Return(initRunning) + + return &Server{ + supervisord: &sv, + l: logrus.WithField("component", "server-test"), + } + } + + t.Run("done once pmm-init is no longer running", func(t *testing.T) { + res, err := newServer(t, false).UpdateStatus(t.Context(), &serverv1.UpdateStatusRequest{}) + require.NoError(t, err) + assert.True(t, res.Done) + }) + + t.Run("not done while pmm-init is running", func(t *testing.T) { + res, err := newServer(t, true).UpdateStatus(t.Context(), &serverv1.UpdateStatusRequest{}) + require.NoError(t, err) + assert.False(t, res.Done) + }) + + t.Run("deprecated fields are ignored and left at their defaults", func(t *testing.T) { + req := &serverv1.UpdateStatusRequest{} + req.AuthToken = "issued-by-the-previous-instance" //nolint:staticcheck + req.LogOffset = 1024 //nolint:staticcheck + + res, err := newServer(t, false).UpdateStatus(t.Context(), req) + require.NoError(t, err) + assert.True(t, res.Done, "an unverifiable auth token must still be accepted") + assert.Empty(t, res.LogLines, "the progress log is no longer served") //nolint:staticcheck + assert.Zero(t, res.LogOffset) //nolint:staticcheck + }) +} diff --git a/managed/services/supervisord/devcontainer_test.go b/managed/services/supervisord/devcontainer_test.go index 40e91e8e0da..27d63f771ae 100644 --- a/managed/services/supervisord/devcontainer_test.go +++ b/managed/services/supervisord/devcontainer_test.go @@ -57,7 +57,7 @@ func TestDevContainer(t *testing.T) { require.NoError(t, err) } // force update supervisor config - err = s.supervisorctl("update") + _, err = s.supervisorctl("update") require.NoError(t, err) }() @@ -78,3 +78,16 @@ func TestDevContainer(t *testing.T) { require.NoError(t, err) }) } + +func TestProgramRunning(t *testing.T) { + vmParams, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) + require.NoError(t, err) + + s := New("/etc/supervisord.d", &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}) + if s.supervisorctlPath == "" { + t.Skip("supervisorctl not found") + } + + assert.True(t, s.ProgramRunning("nginx")) + assert.False(t, s.ProgramRunning("no-such-program")) +} diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index 48833ed0e97..191db7bde33 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -234,12 +234,51 @@ func (s *Service) UpdateConfiguration(settings *models.Settings) error { // StartSupervisedService starts given service. func (s *Service) StartSupervisedService(serviceName string) error { - return s.supervisorctl("start", serviceName) + _, err := s.supervisorctl("start", serviceName) + return err } // StopSupervisedService stops given service. func (s *Service) StopSupervisedService(serviceName string) error { - return s.supervisorctl("stop", serviceName) + _, err := s.supervisorctl("stop", serviceName) + return err +} + +// ProgramRunning returns true if the given supervisord program is running or is going to be +// restarted, false if it is not running, has exited as expected, or has failed for good. +func (s *Service) ProgramRunning(program string) bool { + // First check with the status command in case we missed that event during maintail + // or a pmm-managed restart. See http://supervisord.org/subprocess.html#process-states + b, err := s.supervisorctl("status", program) + if err != nil { + // supervisorctl exits with a non-zero code when the program is not running, + // so the output is still worth parsing. + s.l.Debugf("Status command for '%s' failed: %s", program, err) + } + if status := parseStatus(string(b)); status != nil { + return *status + } + + s.eventsM.Lock() + lastEvent := s.lastEvents[program] + s.eventsM.Unlock() + + s.l.Debugf("Status result for '%s' not parsed, inspecting last event '%s'.", program, lastEvent) + switch lastEvent { + case stopping, starting, running: + return true + case exitedUnexpected: // will be restarted + return true + case exitedExpected, fatal: // will not be restarted + return false + case stopped: // we don't know + fallthrough + default: + // A run-once program that exited before this pmm-managed started reports EXITED with no + // event recorded, so this is an expected state rather than something worth warning about. + s.l.Debugf("Unhandled status result for '%s' (last event '%s'), assuming it is not running.", program, lastEvent) + return false + } } var templates = template.Must(template.New("").Option("missingkey=error").Parse(` @@ -408,20 +447,20 @@ redirect_stderr = true {{end}} `)) -func (s *Service) supervisorctl(args ...string) error { +func (s *Service) supervisorctl(args ...string) ([]byte, error) { if s.supervisorctlPath == "" { - return errors.New("supervisorctl not found") + return nil, errors.New("supervisorctl not found") } cmd := exec.Command(s.supervisorctlPath, args...) //nolint:gosec,noctx cmdLine := strings.Join(cmd.Args, " ") s.l.Debugf("Running %q...", cmdLine) pdeathsig.Set(cmd, unix.SIGKILL) - _, err := cmd.Output() + b, err := cmd.Output() if err != nil { - return fmt.Errorf("%s failed: %w", cmdLine, err) + return b, fmt.Errorf("%s failed: %w", cmdLine, err) } - return nil + return b, nil } // parseStatus parses `supervisorctl status ` output, returns true if is running, @@ -444,7 +483,7 @@ func parseStatus(status string) *bool { // reload asks supervisord to reload configuration. func (s *Service) reload(name string) error { - err := s.supervisorctl("reread") + _, err := s.supervisorctl("reread") if err != nil { s.l.Warn(err) } @@ -456,7 +495,8 @@ func (s *Service) reload(name string) error { return nil } - return s.supervisorctl("update", name) + _, err = s.supervisorctl("update", name) + return err } // marshalConfig marshals supervisord program configuration.