From 9da3fd8370e036f5c449eed89331c809d9cd4829 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Sat, 17 Feb 2024 02:29:39 +0300 Subject: [PATCH 01/33] PMM-11261 Update PMM via watchtower --- .../client/server/start_update_parameters.go | 12 +- .../client/server/start_update_responses.go | 37 ++ api/serverpb/json/serverpb.json | 8 +- api/serverpb/server.pb.go | 601 +++++++++--------- api/serverpb/server.pb.validate.go | 2 + api/serverpb/server.proto | 4 +- api/swagger/swagger-dev.json | 8 +- api/swagger/swagger.json | 8 +- docker-compose.yml | 2 + managed/cmd/pmm-managed/main.go | 15 + managed/services/server/server.go | 20 +- managed/services/server/updater.go | 192 ++++++ managed/services/supervisord/supervisord.go | 2 +- .../victoriametrics/victoriametrics.go | 2 +- version/update.go | 9 + 15 files changed, 604 insertions(+), 318 deletions(-) create mode 100644 managed/services/server/updater.go diff --git a/api/serverpb/json/client/server/start_update_parameters.go b/api/serverpb/json/client/server/start_update_parameters.go index 514a1b9d38..ce4f9ac87d 100644 --- a/api/serverpb/json/client/server/start_update_parameters.go +++ b/api/serverpb/json/client/server/start_update_parameters.go @@ -61,7 +61,7 @@ StartUpdateParams contains all the parameters to send to the API endpoint */ type StartUpdateParams struct { // Body. - Body interface{} + Body StartUpdateBody timeout time.Duration Context context.Context @@ -117,13 +117,13 @@ func (o *StartUpdateParams) SetHTTPClient(client *http.Client) { } // WithBody adds the body to the start update params -func (o *StartUpdateParams) WithBody(body interface{}) *StartUpdateParams { +func (o *StartUpdateParams) WithBody(body StartUpdateBody) *StartUpdateParams { o.SetBody(body) return o } // SetBody adds the body to the start update params -func (o *StartUpdateParams) SetBody(body interface{}) { +func (o *StartUpdateParams) SetBody(body StartUpdateBody) { o.Body = body } @@ -133,10 +133,8 @@ func (o *StartUpdateParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.R return err } var res []error - if o.Body != nil { - if err := r.SetBodyParam(o.Body); err != nil { - return err - } + if err := r.SetBodyParam(o.Body); err != nil { + return err } if len(res) > 0 { diff --git a/api/serverpb/json/client/server/start_update_responses.go b/api/serverpb/json/client/server/start_update_responses.go index 17763683ec..433d595027 100644 --- a/api/serverpb/json/client/server/start_update_responses.go +++ b/api/serverpb/json/client/server/start_update_responses.go @@ -118,6 +118,43 @@ func (o *StartUpdateDefault) readResponse(response runtime.ClientResponse, consu return nil } +/* +StartUpdateBody start update body +swagger:model StartUpdateBody +*/ +type StartUpdateBody struct { + // new image + NewImage string `json:"new_image,omitempty"` +} + +// Validate validates this start update body +func (o *StartUpdateBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this start update body based on context it is used +func (o *StartUpdateBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *StartUpdateBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *StartUpdateBody) UnmarshalBinary(b []byte) error { + var res StartUpdateBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + /* StartUpdateDefaultBody start update default body swagger:model StartUpdateDefaultBody diff --git a/api/serverpb/json/serverpb.json b/api/serverpb/json/serverpb.json index 43543926c0..3c3baa749c 100644 --- a/api/serverpb/json/serverpb.json +++ b/api/serverpb/json/serverpb.json @@ -805,7 +805,13 @@ "in": "body", "required": true, "schema": { - "type": "object" + "type": "object", + "properties": { + "new_image": { + "type": "string", + "x-order": 0 + } + } } } ], diff --git a/api/serverpb/server.pb.go b/api/serverpb/server.pb.go index a83fcc1765..ead8dcae93 100644 --- a/api/serverpb/server.pb.go +++ b/api/serverpb/server.pb.go @@ -572,6 +572,8 @@ type StartUpdateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + NewImage string `protobuf:"bytes,1,opt,name=new_image,json=newImage,proto3" json:"new_image,omitempty"` } func (x *StartUpdateRequest) Reset() { @@ -606,6 +608,13 @@ func (*StartUpdateRequest) Descriptor() ([]byte, []int) { return file_serverpb_server_proto_rawDescGZIP(), []int{9} } +func (x *StartUpdateRequest) GetNewImage() string { + if x != nil { + return x.NewImage + } + return "" +} + type StartUpdateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1615,306 +1624,308 @@ var file_serverpb_server_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x6c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x53, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x22, 0x53, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, - 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, - 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, - 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x66, 0x0a, 0x14, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1d, - 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, - 0x65, 0x22, 0x95, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x02, 0x68, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x02, 0x68, 0x72, 0x12, 0x29, 0x0a, 0x02, 0x6d, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6d, 0x72, 0x12, 0x29, - 0x0a, 0x02, 0x6c, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6c, 0x72, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x53, 0x54, - 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, - 0x46, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x61, 0x72, 0x65, 0x5f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x72, 0x61, 0x72, 0x65, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x46, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x66, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, - 0xe7, 0x06, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x10, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x44, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x10, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, - 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, - 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x74, 0x74, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x61, - 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, - 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, - 0x3a, 0x0a, 0x19, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x17, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x15, 0x61, - 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x7a, 0x75, 0x72, - 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, - 0x5f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x13, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x12, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x15, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, - 0x64, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, - 0x0d, 0x10, 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x43, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x22, 0xce, 0x08, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, - 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, - 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, - 0x0a, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x12, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, + 0x6c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x22, 0x31, 0x0a, 0x12, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x53, 0x0a, 0x13, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x22, 0x53, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, + 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, + 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x66, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, + 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, + 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x22, 0x95, + 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x02, 0x68, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x68, 0x72, + 0x12, 0x29, 0x0a, 0x02, 0x6d, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6d, 0x72, 0x12, 0x29, 0x0a, 0x02, 0x6c, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x02, 0x6c, 0x72, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x53, 0x54, 0x54, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x46, 0x0a, 0x11, + 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x10, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, - 0x0a, 0x0e, 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x73, 0x74, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x53, 0x74, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x73, 0x74, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x53, 0x74, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, - 0x0a, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, - 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x72, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x5f, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x50, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x31, 0x0a, - 0x14, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x12, 0x33, 0x0a, 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, - 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x14, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x72, 0x61, 0x72, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x12, 0x46, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, + 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xe7, 0x06, 0x0a, + 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x10, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x72, 0x65, 0x73, + 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, + 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x77, 0x73, + 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x74, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x6c, 0x65, 0x72, + 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x3a, 0x0a, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, - 0x34, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x14, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, - 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, - 0x0f, 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, - 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0x46, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x43, 0x0a, - 0x17, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x49, 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x66, - 0x0a, 0x12, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, - 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, - 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x56, 0x46, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4d, - 0x49, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, 0x06, - 0x0a, 0x02, 0x44, 0x4f, 0x10, 0x05, 0x32, 0xe5, 0x0c, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x79, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x92, - 0x41, 0x27, 0x12, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x52, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, - 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x9e, 0x02, 0x0a, - 0x09, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, - 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0xdb, 0x01, 0x92, 0x41, 0xc5, 0x01, 0x12, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x1a, 0xaa, - 0x01, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x6f, - 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x72, - 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x79, 0x65, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x65, - 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x20, 0x6f, 0x66, 0x20, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, - 0x6f, 0x62, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x7a, 0x12, 0xf7, 0x01, - 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, + 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x17, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x7a, 0x75, 0x72, + 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x32, 0x0a, + 0x15, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x73, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, + 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x4a, 0x04, + 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, + 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x22, 0xce, 0x08, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1c, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x72, + 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, + 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x74, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x74, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x74, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, + 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x70, + 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, + 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, + 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x18, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x34, 0x0a, 0x16, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, + 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, + 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, + 0x10, 0x13, 0x22, 0x46, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x43, 0x0a, 0x17, 0x41, 0x57, + 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, + 0x02, 0x10, 0x01, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, + 0x1a, 0x0a, 0x18, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x66, 0x0a, 0x12, 0x44, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, 0x01, 0x12, 0x07, + 0x0a, 0x03, 0x4f, 0x56, 0x46, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4d, 0x49, 0x10, 0x03, + 0x12, 0x09, 0x0a, 0x05, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, 0x06, 0x0a, 0x02, 0x44, + 0x4f, 0x10, 0x05, 0x32, 0xe5, 0x0c, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x79, + 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x92, 0x41, 0x27, 0x12, + 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, + 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x9e, 0x02, 0x0a, 0x09, 0x52, 0x65, + 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, + 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdb, 0x01, 0x92, + 0x41, 0xc5, 0x01, 0x12, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x1a, 0xaa, 0x01, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x77, + 0x68, 0x65, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x79, 0x20, 0x79, 0x65, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, + 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x20, 0x6f, 0x66, + 0x20, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x62, 0x69, + 0x6e, 0x67, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, + 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x7a, 0x12, 0xf7, 0x01, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x92, 0x41, 0x79, 0x12, 0x10, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x1a, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, - 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa3, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x58, 0x92, 0x41, 0x39, 0x12, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x28, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x50, 0x4d, - 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x92, 0x41, 0x79, 0x12, 0x10, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x20, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x65, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x20, 0x69, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, + 0x76, 0x31, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa3, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x58, 0x92, 0x41, 0x39, 0x12, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x1a, 0x28, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x2f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x90, 0x01, 0x0a, 0x0b, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x48, 0x92, 0x41, 0x29, 0x12, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x19, 0x53, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x50, + 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x90, 0x01, - 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x92, 0x41, 0x29, 0x12, 0x0c, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x19, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, - 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x12, 0x9d, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x9d, 0x01, + 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, - 0x32, 0x12, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x1a, 0x21, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x76, - 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x9a, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x34, 0x12, 0x0c, - 0x47, 0x65, 0x74, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x24, 0x52, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x50, 0x4d, - 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, 0x31, - 0x2f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x47, 0x65, 0x74, 0x12, 0xa1, 0x01, - 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x50, 0x92, 0x41, 0x2f, 0x12, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x50, - 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x76, - 0x31, 0x2f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x12, 0xaa, 0x01, 0x0a, 0x10, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x92, 0x41, 0x31, 0x12, 0x12, - 0x41, 0x57, 0x53, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x63, 0x68, 0x65, - 0x63, 0x6b, 0x1a, 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x41, 0x57, 0x53, 0x20, 0x45, - 0x43, 0x32, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x49, 0x44, 0x2e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x41, 0x57, - 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x76, - 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x0b, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x23, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, - 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, - 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, - 0x02, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x32, 0x12, 0x0d, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x21, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x9a, 0x01, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x34, 0x12, 0x0c, 0x47, 0x65, 0x74, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x24, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x47, 0x65, 0x74, 0x12, 0xa1, 0x01, 0x0a, 0x0e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1d, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50, 0x92, 0x41, + 0x2f, 0x12, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x1a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0xaa, + 0x01, 0x0a, 0x10, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x57, 0x53, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x57, + 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x92, 0x41, 0x31, 0x12, 0x12, 0x41, 0x57, 0x53, + 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x1a, + 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x41, 0x57, 0x53, 0x20, 0x45, 0x43, 0x32, 0x20, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x49, 0x44, 0x2e, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x41, 0x57, 0x53, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x76, 0x0a, 0x0a, 0x63, + 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0xa2, 0x02, 0x03, + 0x53, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, 0x02, 0x06, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/serverpb/server.pb.validate.go b/api/serverpb/server.pb.validate.go index c0d73da0e4..3bba154397 100644 --- a/api/serverpb/server.pb.validate.go +++ b/api/serverpb/server.pb.validate.go @@ -1158,6 +1158,8 @@ func (m *StartUpdateRequest) validate(all bool) error { var errors []error + // no validation rules for NewImage + if len(errors) > 0 { return StartUpdateRequestMultiError(errors) } diff --git a/api/serverpb/server.proto b/api/serverpb/server.proto index cbdf514b70..629d06b9a8 100644 --- a/api/serverpb/server.proto +++ b/api/serverpb/server.proto @@ -79,7 +79,9 @@ message CheckUpdatesResponse { google.protobuf.Timestamp last_check = 5; } -message StartUpdateRequest {} +message StartUpdateRequest { + string new_image = 1; +} message StartUpdateResponse { // Authentication token for getting update statuses. diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 20ed4e0ed1..7872ee314a 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -3649,7 +3649,13 @@ "in": "body", "required": true, "schema": { - "type": "object" + "type": "object", + "properties": { + "new_image": { + "type": "string", + "x-order": 0 + } + } } } ], diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 436a77390a..7df74b3f1b 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -805,7 +805,13 @@ "in": "body", "required": true, "schema": { - "type": "object" + "type": "object", + "properties": { + "new_image": { + "type": "string", + "x-order": 0 + } + } } } ], diff --git a/docker-compose.yml b/docker-compose.yml index ac67bd09ed..de218e9602 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,8 @@ services: - ENABLE_RBAC=${ENABLE_RBAC:-0} - LESS_LOG_NOISE=1 - PERCONA_TEST_VERSION_SERVICE_URL=${PERCONA_TEST_VERSION_SERVICE_URL} + - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://host.docker.internal:8080} + - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-123} # - PERCONA_TEST_PLATFORM_ADDRESS=https://check.localhost # - PERCONA_TEST_PLATFORM_INSECURE=1 # - PERCONA_TEST_PLATFORM_PUBLIC_KEY= diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 9c1585503e..3b4368e5e0 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -969,6 +969,20 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) + // Get the hostname from the environment variable + watchtowerHostname := os.Getenv("PMM_WATCHTOWER_HOSTNAME") + if watchtowerHostname == "" { + watchtowerHostname = "http://watchtower:8080" + } + + // Create a URL with the images and new image name as query parameters + u, err := url.Parse(watchtowerHostname) + if err != nil { + l.Fatalf("Failed to parse watchtower hostname: %s", err) + } + + updater := server.NewUpdater(supervisord, u) + serverParams := &server.Params{ DB: db, VMDB: vmdb, @@ -981,6 +995,7 @@ func main() { //nolint:cyclop,maintidx AwsInstanceChecker: awsInstanceChecker, GrafanaClient: grafanaClient, VMAlertExternalRules: externalRules, + Updater: updater, } server, err := server.NewServer(serverParams) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 7f30ca880c..051666e77b 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -60,6 +60,7 @@ type Server struct { awsInstanceChecker *AWSInstanceChecker grafanaClient grafanaClient haService haService + updater *Updater l *logrus.Entry @@ -91,6 +92,7 @@ type Params struct { TelemetryService telemetryService AwsInstanceChecker *AWSInstanceChecker GrafanaClient grafanaClient + Updater *Updater } // NewServer returns new server for Server service. @@ -113,6 +115,7 @@ func NewServer(params *Params) (*Server, error) { telemetryService: params.TelemetryService, awsInstanceChecker: params.AwsInstanceChecker, grafanaClient: params.GrafanaClient, + updater: params.Updater, l: logrus.WithField("component", "server"), pmmUpdateAuthFile: path, envSettings: &models.ChangeSettingsParams{}, @@ -258,16 +261,16 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesReq s.envRW.RUnlock() if req.OnlyInstalledVersion { - return s.onlyInstalledVersionResponse(ctx), nil + return s.updater.onlyInstalledVersionResponse(), nil } if req.Force { - if err := s.supervisord.ForceCheckUpdates(ctx); err != nil { + if err := s.updater.ForceCheckUpdates(ctx); err != nil { return nil, err } } - v, lastCheck := s.supervisord.LastCheckUpdatesResult(ctx) + v, lastCheck := s.updater.LastCheckUpdatesResult(ctx) if v == nil { return nil, status.Error(codes.Unavailable, "failed to check for updates") } @@ -281,7 +284,7 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesReq Version: v.Latest.Version, FullVersion: v.Latest.FullVersion, }, - UpdateAvailable: v.UpdateAvailable, + UpdateAvailable: true, LatestNewsUrl: v.LatestNewsURL, } @@ -314,19 +317,16 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverpb.StartUpdateReque return nil, status.Error(codes.FailedPrecondition, "Updates are disabled via DISABLE_UPDATES environment variable.") } - offset, err := s.supervisord.StartUpdate() - if err != nil { - return nil, err - } + s.updater.StartUpdate(ctx, req.NewImage) authToken := uuid.New().String() - if err = s.writeUpdateAuthToken(authToken); err != nil { + if err := s.writeUpdateAuthToken(authToken); err != nil { return nil, err } return &serverpb.StartUpdateResponse{ AuthToken: authToken, - LogOffset: offset, + LogOffset: 0, }, nil } diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go new file mode 100644 index 0000000000..6539bd2c49 --- /dev/null +++ b/managed/services/server/updater.go @@ -0,0 +1,192 @@ +package server + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "os" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/percona/pmm/api/serverpb" + "github.com/percona/pmm/version" +) + +type Updater struct { + l *logrus.Entry + supervisord supervisordService + watchtowerHostname *url.URL +} + +func NewUpdater(supervisord supervisordService, watchtowerHostname *url.URL) *Updater { + return &Updater{ + l: logrus.WithField("service", "updater"), + supervisord: supervisord, + watchtowerHostname: watchtowerHostname, + } +} + +func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName string) error { + hostname, err := os.Hostname() + if err != nil { + return errors.Wrap(err, "failed to get hostname") + } + + u, err := s.watchtowerHostname.Parse("/v1/update") + if err != nil { + return errors.Wrap(err, "failed to parse URL") + } + q := u.Query() + q.Set("hostname", hostname) + q.Set("newImageName", newImageName) + u.RawQuery = q.Encode() + + // Create a new request + req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) + if err != nil { + return errors.Wrap(err, "failed to create request") + } + + // Add the token to the request header + token := os.Getenv("PMM_WATCHTOWER_TOKEN") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + + // Send the request + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return errors.Wrap(err, "failed to send request") + } + defer resp.Body.Close() + + // Check the response + if resp.StatusCode != http.StatusOK { + return errors.Errorf("received non-OK response: %v", resp.StatusCode) + } + + s.l.Info("Successfully triggered update") + return nil +} + +func (s *Updater) currentVersion() string { + return version.Version +} + +func (s *Updater) StartUpdate(ctx context.Context, newImageName string) error { + if newImageName == "" { + latest, err := s.latest() + if err != nil { + s.l.WithError(err).Error("Failed to get latest version") + newImageName = "perconalab/pmm-server:3-dev-latest" + } else { + newImageName = fmt.Sprintf("%s:%s", latest.Repo, latest.Version) + } + } + + if err := s.sendRequestToWatchtower(ctx, newImageName); err != nil { + s.l.WithError(err).Error("Failed to trigger update") + return errors.Wrap(err, "failed to trigger update") + } + return nil +} + +func (s *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse { + return &serverpb.CheckUpdatesResponse{ + Installed: &serverpb.VersionInfo{ + Version: s.currentVersion(), + }, + } +} + +func (s *Updater) ForceCheckUpdates(ctx context.Context) error { + return nil +} + +type TagsResponse struct { + Results []struct { + Name string `json:"name"` + } `json:"results"` +} + +func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { + buildTime, err := version.Time() + if err != nil { + s.l.WithError(err).Error("Failed to get build time") + return nil, time.Now() + } + latest, err := s.latest() + if err != nil { + s.l.WithError(err).Error("Failed to get latest version") + return nil, time.Now() + } + return &version.UpdateCheckResult{ + Installed: version.PackageInfo{ + Version: s.currentVersion(), + FullVersion: version.PMMVersion, + BuildTime: &buildTime, + Repo: "local", + }, + Latest: *latest, + UpdateAvailable: true, + LatestNewsURL: "", + }, time.Now() +} + +func (s *Updater) latest() (*version.PackageInfo, error) { + fileName := "/etc/pmm-server-update-version.json" + content, err := os.ReadFile(fileName) + switch { + case err == nil: + info := version.PackageInfo{} + err = json.Unmarshal(content, &info) + if err != nil { + s.l.WithError(err).Error("Failed to unmarshal file") + return nil, errors.Wrap(err, "failed to unmarshal file") + } + return &info, nil + case err != nil && !os.IsNotExist(err): + s.l.WithError(err).Error("Failed to read file") + return nil, errors.Wrap(err, "failed to read file") + case os.Getenv("PMM_SERVER_UPDATE_VERSION") != "": + return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil + default: // os.IsNotExist(err) + // File does not exist, get the latest tag from DockerHub + resp, err := http.Get("https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/") + if err != nil { + s.l.WithError(err).Error("Failed to get tags from DockerHub") + return nil, errors.Wrap(err, "failed to get tags from DockerHub") + } + defer resp.Body.Close() + + var tagsResponse TagsResponse + if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { + s.l.WithError(err).Error("Failed to decode response") + return nil, errors.Wrap(err, "failed to decode response") + } + + if len(tagsResponse.Results) > 0 { + // Assuming the first tag is the latest + return s.parseDockerTag(tagsResponse.Results[0].Name), nil + } + return nil, errors.New("no tags found") + } +} + +func (s *Updater) parseDockerTag(tag string) *version.PackageInfo { + splitTag := strings.Split(tag, ":") + if len(splitTag) != 2 { + return nil + } + return &version.PackageInfo{ + Version: splitTag[1], + FullVersion: tag, + Repo: splitTag[0], + } +} diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index d3a5c310fd..788470f0ed 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -627,7 +627,7 @@ command = --search.maxQueryDuration=90s --promscrape.streamParse=true --http.pathPrefix=/prometheus - --envflag.enable + --envflag.enable=true --envflag.prefix=VM_ user = pmm autorestart = true diff --git a/managed/services/victoriametrics/victoriametrics.go b/managed/services/victoriametrics/victoriametrics.go index b6356899f0..c3e6cd3763 100644 --- a/managed/services/victoriametrics/victoriametrics.go +++ b/managed/services/victoriametrics/victoriametrics.go @@ -258,7 +258,7 @@ func (svc *Service) validateConfig(ctx context.Context, cfg []byte) error { } svc.l.Debugf("%s", b) - args = append(args, "-promscrape.config.strictParse", "true") + args = append(args, "-promscrape.config.strictParse=true") cmd = exec.CommandContext(ctx, "victoriametrics", args...) //nolint:gosec pdeathsig.Set(cmd, unix.SIGKILL) diff --git a/version/update.go b/version/update.go index 5441043343..5ff6d19dbd 100644 --- a/version/update.go +++ b/version/update.go @@ -25,6 +25,15 @@ type PackageInfo struct { Repo string `json:"repo"` } +/* +{ + "version": "3.0.0", + "full_version": "3-dev-container", + "build_time": "2024-02-16T12:00:00Z", + "repo": "percona/pmm-server" +} +*/ + // UpdateInstalledResult represents `pmm-update -installed` result. type UpdateInstalledResult struct { Installed PackageInfo `json:"installed"` From 185ee21e4d59c94bae668c984ce553a06a5eeb40 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Fri, 8 Mar 2024 17:44:33 +0300 Subject: [PATCH 02/33] PMM-11261 address comments and fix linter --- docker-compose.yml | 18 +++++++++++++++++- managed/cmd/pmm-managed/main.go | 8 ++++---- managed/services/server/updater.go | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index de218e9602..902be06014 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: - ENABLE_RBAC=${ENABLE_RBAC:-0} - LESS_LOG_NOISE=1 - PERCONA_TEST_VERSION_SERVICE_URL=${PERCONA_TEST_VERSION_SERVICE_URL} - - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://host.docker.internal:8080} + - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://watchtower:8080} - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-123} # - PERCONA_TEST_PLATFORM_ADDRESS=https://check.localhost # - PERCONA_TEST_PLATFORM_INSECURE=1 @@ -96,6 +96,22 @@ services: # /opt/entrypoint.sh # " +# docker run -v /var/run/docker.sock:/var/run/docker.sock -e WATCHTOWER_HTTP_API_UPDATE=1 -e WATCHTOWER_HTTP_API_TOKEN=123 --hostname=watchtower --network=pmm_default docker.io/bupychuk/watchtower + watchtower: + profiles: + - pmm + image: ${WATCHTOWER_IMAGE:-bupychuk/watchtower} + container_name: watchtower + environment: + - WATCHTOWER_HTTP_LISTEN_PORT=8080 + - WATCHTOWER_HTTP_API_UPDATE=1 + - WATCHTOWER_HTTP_API_TOKEN=${PMM_WATCHTOWER_TOKEN:-123} + hostname: watchtower + networks: + - ${NETWORK:-default} + volumes: + - /var/run/docker.sock:${DOCKER_PATH:-/var/run/docker.sock} + # PMM with external DBs ch: profiles: diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 3b4368e5e0..ef748a79a0 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -970,13 +970,13 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) // Get the hostname from the environment variable - watchtowerHostname := os.Getenv("PMM_WATCHTOWER_HOSTNAME") - if watchtowerHostname == "" { - watchtowerHostname = "http://watchtower:8080" + watchtowerHost := os.Getenv("PMM_WATCHTOWER_HOST") + if watchtowerHost == "" { + watchtowerHost = "http://watchtower:8080" } // Create a URL with the images and new image name as query parameters - u, err := url.Parse(watchtowerHostname) + u, err := url.Parse(watchtowerHost) if err != nil { l.Fatalf("Failed to parse watchtower hostname: %s", err) } diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 6539bd2c49..acc3150e4e 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -1,3 +1,18 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + package server import ( From dd60f3b0fec98c1e14f6cb041f412af4438d4bad Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Fri, 8 Mar 2024 18:04:32 +0300 Subject: [PATCH 03/33] PMM-11261 fix linters and tests. --- managed/services/server/server.go | 5 ++++- managed/services/server/updater.go | 25 +++++++++++++++------ managed/services/supervisord/supervisord.go | 2 +- version/update.go | 9 -------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 296c917e23..7f0ac40c9e 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -317,7 +317,10 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverpb.StartUpdateReque return nil, status.Error(codes.FailedPrecondition, "Updates are disabled via DISABLE_UPDATES environment variable.") } - s.updater.StartUpdate(ctx, req.NewImage) + err := s.updater.StartUpdate(ctx, req.NewImage) + if err != nil { + return nil, err + } authToken := uuid.New().String() if err := s.writeUpdateAuthToken(authToken); err != nil { diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index acc3150e4e..f693666229 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -32,12 +32,14 @@ import ( "github.com/percona/pmm/version" ) +// Updater is a service to check for updates and trigger the update process. type Updater struct { l *logrus.Entry supervisord supervisordService watchtowerHostname *url.URL } +// NewUpdater creates a new Updater service. func NewUpdater(supervisord supervisordService, watchtowerHostname *url.URL) *Updater { return &Updater{ l: logrus.WithField("service", "updater"), @@ -62,7 +64,7 @@ func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName stri u.RawQuery = q.Encode() // Create a new request - req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { return errors.Wrap(err, "failed to create request") } @@ -79,7 +81,7 @@ func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName stri if err != nil { return errors.Wrap(err, "failed to send request") } - defer resp.Body.Close() + defer resp.Body.Close() //nolint:errcheck // Check the response if resp.StatusCode != http.StatusOK { @@ -94,6 +96,7 @@ func (s *Updater) currentVersion() string { return version.Version } +// StartUpdate triggers the update process. func (s *Updater) StartUpdate(ctx context.Context, newImageName string) error { if newImageName == "" { latest, err := s.latest() @@ -120,10 +123,12 @@ func (s *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse } } -func (s *Updater) ForceCheckUpdates(ctx context.Context) error { +func (s *Updater) ForceCheckUpdates(_ context.Context) error { + // TODO: PMM-11261 Implement this method return nil } +// TagsResponse is a response from DockerHub. type TagsResponse struct { Results []struct { Name string `json:"name"` @@ -136,7 +141,7 @@ func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCh s.l.WithError(err).Error("Failed to get build time") return nil, time.Now() } - latest, err := s.latest() + latest, err := s.latest(ctx) if err != nil { s.l.WithError(err).Error("Failed to get latest version") return nil, time.Now() @@ -154,7 +159,7 @@ func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCh }, time.Now() } -func (s *Updater) latest() (*version.PackageInfo, error) { +func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { fileName := "/etc/pmm-server-update-version.json" content, err := os.ReadFile(fileName) switch { @@ -173,12 +178,18 @@ func (s *Updater) latest() (*version.PackageInfo, error) { return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil default: // os.IsNotExist(err) // File does not exist, get the latest tag from DockerHub - resp, err := http.Get("https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/") + u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + s.l.WithError(err).Error("Failed to create request") + return nil, errors.Wrap(err, "failed to create request") + } + resp, err := http.DefaultClient.Do(req) if err != nil { s.l.WithError(err).Error("Failed to get tags from DockerHub") return nil, errors.Wrap(err, "failed to get tags from DockerHub") } - defer resp.Body.Close() + defer resp.Body.Close() //nolint:errcheck var tagsResponse TagsResponse if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index f174e4a4d2..2d94414418 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -652,7 +652,7 @@ command = --search.maxQueryDuration={{ .VMSearchMaxQueryDuration }} --promscrape.streamParse={{ .VMPromscrapeStreamParse }} --http.pathPrefix=/prometheus - --envflag.enable=true + --envflag.enable --envflag.prefix=VM_ user = pmm autorestart = true diff --git a/version/update.go b/version/update.go index 5ff6d19dbd..5441043343 100644 --- a/version/update.go +++ b/version/update.go @@ -25,15 +25,6 @@ type PackageInfo struct { Repo string `json:"repo"` } -/* -{ - "version": "3.0.0", - "full_version": "3-dev-container", - "build_time": "2024-02-16T12:00:00Z", - "repo": "percona/pmm-server" -} -*/ - // UpdateInstalledResult represents `pmm-update -installed` result. type UpdateInstalledResult struct { Installed PackageInfo `json:"installed"` From 5cd04a0f887ed14404780ad5a6c5e39177efae05 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Fri, 8 Mar 2024 18:17:35 +0300 Subject: [PATCH 04/33] PMM-11261 fix linters and tests. --- managed/services/server/updater.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index f693666229..4ae05bcfa8 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -99,7 +99,7 @@ func (s *Updater) currentVersion() string { // StartUpdate triggers the update process. func (s *Updater) StartUpdate(ctx context.Context, newImageName string) error { if newImageName == "" { - latest, err := s.latest() + latest, err := s.latest(ctx) if err != nil { s.l.WithError(err).Error("Failed to get latest version") newImageName = "perconalab/pmm-server:3-dev-latest" @@ -123,6 +123,7 @@ func (s *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse } } +// ForceCheckUpdates forces an update check. func (s *Updater) ForceCheckUpdates(_ context.Context) error { // TODO: PMM-11261 Implement this method return nil @@ -135,6 +136,7 @@ type TagsResponse struct { } `json:"results"` } +// LastCheckUpdatesResult returns the result of the last update check. func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { buildTime, err := version.Time() if err != nil { From 036dffb85fc8e5738f9d52f8668128487a7ac5a1 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Wed, 13 Mar 2024 14:49:47 +0300 Subject: [PATCH 05/33] PMM-11261 fix linters. --- managed/services/server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 7f0ac40c9e..e60fe04ef4 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -317,7 +317,7 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverpb.StartUpdateReque return nil, status.Error(codes.FailedPrecondition, "Updates are disabled via DISABLE_UPDATES environment variable.") } - err := s.updater.StartUpdate(ctx, req.NewImage) + err := s.updater.StartUpdate(ctx, req.GetNewImage()) if err != nil { return nil, err } From ed7bcfed7af3288b993a5b86908f98941c5a7722 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Wed, 13 Mar 2024 15:13:37 +0300 Subject: [PATCH 06/33] PMM-11261 fix linters. --- managed/services/server/server.go | 19 ------------------- managed/services/server/updater.go | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index e60fe04ef4..dc4d9634d1 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -235,25 +235,6 @@ func (s *Server) LeaderHealthCheck(ctx context.Context, req *serverpb.LeaderHeal return nil, status.Error(codes.FailedPrecondition, "this PMM Server isn't the leader") } -func (s *Server) onlyInstalledVersionResponse(ctx context.Context) *serverpb.CheckUpdatesResponse { - v := s.supervisord.InstalledPMMVersion(ctx) - r := &serverpb.CheckUpdatesResponse{ - Installed: &serverpb.VersionInfo{ - Version: v.Version, - FullVersion: v.FullVersion, - }, - } - - if v.BuildTime != nil { - t := v.BuildTime.UTC().Truncate(24 * time.Hour) // return only date - r.Installed.Timestamp = timestamppb.New(t) - } - - r.LastCheck = timestamppb.New(time.Now()) - - return r -} - // CheckUpdates checks PMM Server updates availability. func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesRequest) (*serverpb.CheckUpdatesResponse, error) { s.envRW.RLock() diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 4ae05bcfa8..1feb750109 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -199,7 +199,7 @@ func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { return nil, errors.Wrap(err, "failed to decode response") } - if len(tagsResponse.Results) > 0 { + if len(tagsResponse.Results) != 0 { // Assuming the first tag is the latest return s.parseDockerTag(tagsResponse.Results[0].Name), nil } From 7111d842fb08ebbfd76d504736f1c0c796541816 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 19 Mar 2024 13:30:18 +0300 Subject: [PATCH 07/33] Update managed/cmd/pmm-managed/main.go Co-authored-by: Alex Demidoff --- managed/cmd/pmm-managed/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 7b1ce15070..86eab55f51 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -969,7 +969,7 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) - // Get the hostname from the environment variable + // Get the host from the environment variable watchtowerHost := os.Getenv("PMM_WATCHTOWER_HOST") if watchtowerHost == "" { watchtowerHost = "http://watchtower:8080" From 8178764d4bffb6bb5f0e0375c942e37eee9eed03 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 19 Mar 2024 13:30:35 +0300 Subject: [PATCH 08/33] Update managed/cmd/pmm-managed/main.go Co-authored-by: Alex Demidoff --- managed/cmd/pmm-managed/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 86eab55f51..c023843e1c 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -978,7 +978,7 @@ func main() { //nolint:cyclop,maintidx // Create a URL with the images and new image name as query parameters u, err := url.Parse(watchtowerHost) if err != nil { - l.Fatalf("Failed to parse watchtower hostname: %s", err) + l.Fatalf("Failed to parse watchtower host: %s", err) } updater := server.NewUpdater(supervisord, u) From d66bea84caaab4724a0795667f0c8c78031a7fc7 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 19 Mar 2024 13:49:16 +0300 Subject: [PATCH 09/33] PMM-11261 Address comments. --- managed/cmd/pmm-managed/main.go | 15 ++++----------- managed/services/server/updater.go | 21 ++++++++++++--------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index c023843e1c..a673214dcb 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -723,6 +723,8 @@ func main() { //nolint:cyclop,maintidx clickHouseDatabaseF := kingpin.Flag("clickhouse-name", "Clickhouse database name").Default("pmm").Envar("PERCONA_TEST_PMM_CLICKHOUSE_DATABASE").String() clickhouseAddrF := kingpin.Flag("clickhouse-addr", "Clickhouse database address").Default("127.0.0.1:9000").Envar("PERCONA_TEST_PMM_CLICKHOUSE_ADDR").String() + watchtowerHostF := kingpin.Flag("watchtower-host", "Watchtower host").Default("http://watchtower:8080").Envar("PMM_WATCHTOWER_HOST").URL() + kingpin.Parse() logger.SetupGlobalLogger() @@ -969,20 +971,11 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) - // Get the host from the environment variable - watchtowerHost := os.Getenv("PMM_WATCHTOWER_HOST") - if watchtowerHost == "" { - watchtowerHost = "http://watchtower:8080" - } - - // Create a URL with the images and new image name as query parameters - u, err := url.Parse(watchtowerHost) + updater, err := server.NewUpdater(supervisord, *watchtowerHostF) if err != nil { - l.Fatalf("Failed to parse watchtower host: %s", err) + l.Panicf("Could not create updater: %s", err) } - updater := server.NewUpdater(supervisord, u) - serverParams := &server.Params{ DB: db, VMDB: vmdb, diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 1feb750109..3d374a6e87 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -32,19 +32,22 @@ import ( "github.com/percona/pmm/version" ) +// defaultLatestPMMImage is the default image name to use when the latest version cannot be determined. +const defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" + // Updater is a service to check for updates and trigger the update process. type Updater struct { - l *logrus.Entry - supervisord supervisordService - watchtowerHostname *url.URL + l *logrus.Entry + supervisord supervisordService + watchtowerHost *url.URL } // NewUpdater creates a new Updater service. -func NewUpdater(supervisord supervisordService, watchtowerHostname *url.URL) *Updater { +func NewUpdater(supervisord supervisordService, watchtowerHost *url.URL) *Updater { return &Updater{ - l: logrus.WithField("service", "updater"), - supervisord: supervisord, - watchtowerHostname: watchtowerHostname, + l: logrus.WithField("service", "updater"), + supervisord: supervisord, + watchtowerHost: watchtowerHost, } } @@ -54,7 +57,7 @@ func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName stri return errors.Wrap(err, "failed to get hostname") } - u, err := s.watchtowerHostname.Parse("/v1/update") + u, err := s.watchtowerHost.Parse("/v1/update") if err != nil { return errors.Wrap(err, "failed to parse URL") } @@ -102,7 +105,7 @@ func (s *Updater) StartUpdate(ctx context.Context, newImageName string) error { latest, err := s.latest(ctx) if err != nil { s.l.WithError(err).Error("Failed to get latest version") - newImageName = "perconalab/pmm-server:3-dev-latest" + newImageName = defaultLatestPMMImage } else { newImageName = fmt.Sprintf("%s:%s", latest.Repo, latest.Version) } From 1c3600a7c19120441b11ceb6b5af2f12fa4d7b0f Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 19 Mar 2024 16:50:17 +0300 Subject: [PATCH 10/33] PMM-11261 fix build. --- managed/cmd/pmm-managed/main.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index a673214dcb..a5a5cf3c0c 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -971,10 +971,7 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) - updater, err := server.NewUpdater(supervisord, *watchtowerHostF) - if err != nil { - l.Panicf("Could not create updater: %s", err) - } + updater := server.NewUpdater(supervisord, *watchtowerHostF) serverParams := &server.Params{ DB: db, From 19672634e51ce0f0e63bb68c9fde42dc71909fd8 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Wed, 27 Mar 2024 12:24:35 +0300 Subject: [PATCH 11/33] Update docker-compose.yml --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 902be06014..da9f201fce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,7 +100,7 @@ services: watchtower: profiles: - pmm - image: ${WATCHTOWER_IMAGE:-bupychuk/watchtower} + image: ${WATCHTOWER_IMAGE:-perconalab/watchtower} container_name: watchtower environment: - WATCHTOWER_HTTP_LISTEN_PORT=8080 From f78a642e0b39c0f4d2c093fee88f1e2d3e8cb1d6 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 2 Apr 2024 13:08:24 +0300 Subject: [PATCH 12/33] Update docker-compose.yml Co-authored-by: Alex Demidoff --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index da9f201fce..03b6257500 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: - LESS_LOG_NOISE=1 - PERCONA_TEST_VERSION_SERVICE_URL=${PERCONA_TEST_VERSION_SERVICE_URL} - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://watchtower:8080} - - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-123} + - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-INSECURE_TOKEN} # - PERCONA_TEST_PLATFORM_ADDRESS=https://check.localhost # - PERCONA_TEST_PLATFORM_INSECURE=1 # - PERCONA_TEST_PLATFORM_PUBLIC_KEY= From cc7bb6f337ccecf4048e205cf7d972c6a8ca3f3b Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 2 Apr 2024 13:08:32 +0300 Subject: [PATCH 13/33] Update docker-compose.yml Co-authored-by: Alex Demidoff --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 03b6257500..0195e96f9f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -105,7 +105,7 @@ services: environment: - WATCHTOWER_HTTP_LISTEN_PORT=8080 - WATCHTOWER_HTTP_API_UPDATE=1 - - WATCHTOWER_HTTP_API_TOKEN=${PMM_WATCHTOWER_TOKEN:-123} + - WATCHTOWER_HTTP_API_TOKEN=${PMM_WATCHTOWER_TOKEN:-INSECURE_TOKEN} hostname: watchtower networks: - ${NETWORK:-default} From 7bd962bb0d544d70d0da1425493d15e0ad3b80d8 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Wed, 3 Apr 2024 12:12:48 +0300 Subject: [PATCH 14/33] PMM-12762 Get notified about new version. --- managed/cmd/pmm-managed/main.go | 18 +- managed/services/server/deps.go | 23 +- .../services/{supervisord => server}/logs.go | 8 +- .../{supervisord => server}/logs_test.go | 11 +- .../pmm_update_checker.go | 68 +---- .../{supervisord => server}/pprof_config.go | 2 +- managed/services/server/server.go | 33 ++- managed/services/server/updater.go | 245 +++++++++++++--- managed/services/server/updater_test.go | 269 ++++++++++++++++++ managed/services/supervisord/deps.go | 9 - .../services/supervisord/devcontainer_test.go | 240 +++++----------- managed/services/supervisord/supervisord.go | 180 ++---------- .../services/supervisord/supervisord_test.go | 9 +- 13 files changed, 615 insertions(+), 500 deletions(-) rename managed/services/{supervisord => server}/logs.go (97%) rename managed/services/{supervisord => server}/logs_test.go (95%) rename managed/services/{supervisord => server}/pmm_update_checker.go (65%) rename managed/services/{supervisord => server}/pprof_config.go (97%) create mode 100644 managed/services/server/updater_test.go diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index a5a5cf3c0c..91e47207d2 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -137,7 +137,7 @@ const ( var pprofSemaphore = semaphore.NewWeighted(1) -func addLogsHandler(mux *http.ServeMux, logs *supervisord.Logs) { +func addLogsHandler(mux *http.ServeMux, logs *server.Logs) { l := logrus.WithField("component", "logs.zip") mux.HandleFunc("/logs.zip", func(rw http.ResponseWriter, req *http.Request) { @@ -147,7 +147,7 @@ func addLogsHandler(mux *http.ServeMux, logs *supervisord.Logs) { if err != nil { l.Debug("Unable to read 'pprof' query param. Using default: pprof=false") } - var pprofConfig *supervisord.PprofConfig + var pprofConfig *server.PprofConfig if pprofQueryParameter { if !pprofSemaphore.TryAcquire(1) { rw.WriteHeader(http.StatusLocked) @@ -160,7 +160,7 @@ func addLogsHandler(mux *http.ServeMux, logs *supervisord.Logs) { defer pprofSemaphore.Release(1) contextTimeout += pProfProfileDuration + pProfTraceDuration - pprofConfig = &supervisord.PprofConfig{ + pprofConfig = &server.PprofConfig{ ProfileDuration: pProfProfileDuration, TraceDuration: pProfTraceDuration, } @@ -334,7 +334,7 @@ func runGRPCServer(ctx context.Context, deps *gRPCServerDeps) { } type http1ServerDeps struct { - logs *supervisord.Logs + logs *server.Logs authServer *grafana.AuthServer } @@ -875,13 +875,12 @@ func main() { //nolint:cyclop,maintidx connectionCheck := agents.NewConnectionChecker(agentsRegistry) serviceInfoBroker := agents.NewServiceInfoBroker(agentsRegistry) - pmmUpdateCheck := supervisord.NewPMMUpdateChecker(logrus.WithField("component", "supervisord/pmm-update-checker")) + updater := server.NewUpdater(*watchtowerHostF, gRPCMessageMaxSize) - logs := supervisord.NewLogs(version.FullInfo(), pmmUpdateCheck, vmParams) + logs := server.NewLogs(version.FullInfo(), updater, vmParams) supervisord := supervisord.New( *supervisordConfigDirF, - pmmUpdateCheck, &models.Params{ VMParams: vmParams, PGParams: &models.PGParams{ @@ -895,8 +894,7 @@ func main() { //nolint:cyclop,maintidx SSLCertPath: *postgresSSLCertPathF, }, HAParams: haParams, - }, - gRPCMessageMaxSize) + }) haService.AddLeaderService(ha.NewStandardService("pmm-agent-runner", func(ctx context.Context) error { return supervisord.StartSupervisedService("pmm-agent") @@ -971,8 +969,6 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) - updater := server.NewUpdater(supervisord, *watchtowerHostF) - serverParams := &server.Params{ DB: db, VMDB: vmdb, diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index b675fba85d..20bdca6661 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -17,11 +17,11 @@ package server import ( "context" + "net/url" "time" "github.com/percona/pmm/api/serverpb" "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/version" ) // healthChecker interface wraps all services that implements the IsReady method to report the @@ -73,13 +73,13 @@ type vmAlertExternalRules interface { // supervisordService is a subset of methods of supervisord.Service used by this package. // We use it instead of real type for testing and to avoid dependency cycle. type supervisordService interface { - InstalledPMMVersion(ctx context.Context) *version.PackageInfo - LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) - ForceCheckUpdates(ctx context.Context) error - - StartUpdate() (uint32, error) - UpdateRunning() bool - UpdateLog(offset uint32) ([]string, uint32, error) + //InstalledPMMVersion(ctx context.Context) *version.PackageInfo + //LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) + //ForceCheckUpdates(ctx context.Context) error + // + //StartUpdate() (uint32, error) + //UpdateRunning() bool + //UpdateLog(offset uint32) ([]string, uint32, error) UpdateConfiguration(settings *models.Settings, ssoDetails *models.PerconaSSODetails) error } @@ -108,3 +108,10 @@ type templatesService interface { type haService interface { IsLeader() bool } + +// victoriaMetricsParams is a subset of methods of models.VMParams used by this package. +// We use it instead of real type to avoid dependency cycle. +type victoriaMetricsParams interface { + ExternalVM() bool + URLFor(path string) (*url.URL, error) +} diff --git a/managed/services/supervisord/logs.go b/managed/services/server/logs.go similarity index 97% rename from managed/services/supervisord/logs.go rename to managed/services/server/logs.go index 207a69947d..a32735e503 100644 --- a/managed/services/supervisord/logs.go +++ b/managed/services/server/logs.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package supervisord +package server import ( "archive/zip" @@ -56,12 +56,12 @@ type fileContent struct { // Logs is responsible for interactions with logs. type Logs struct { pmmVersion string - pmmUpdateChecker *PMMUpdateChecker + pmmUpdateChecker *Updater vmParams victoriaMetricsParams } // NewLogs creates a new Logs service. -func NewLogs(pmmVersion string, pmmUpdateChecker *PMMUpdateChecker, vmParams victoriaMetricsParams) *Logs { +func NewLogs(pmmVersion string, pmmUpdateChecker *Updater, vmParams victoriaMetricsParams) *Logs { return &Logs{ pmmVersion: pmmVersion, pmmUpdateChecker: pmmUpdateChecker, @@ -204,7 +204,7 @@ func (l *Logs) files(ctx context.Context, pprofConfig *PprofConfig) []fileConten }) // update checker installed info - b, err = json.Marshal(l.pmmUpdateChecker.Installed(ctx)) + b, err = json.Marshal(l.pmmUpdateChecker.InstalledPMMVersion()) files = append(files, fileContent{ Name: "installed.json", Data: b, diff --git a/managed/services/supervisord/logs_test.go b/managed/services/server/logs_test.go similarity index 95% rename from managed/services/supervisord/logs_test.go rename to managed/services/server/logs_test.go index 8fb6f2a7aa..2085f632cb 100644 --- a/managed/services/supervisord/logs_test.go +++ b/managed/services/server/logs_test.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package supervisord +package server import ( "archive/zip" @@ -27,7 +27,6 @@ import ( "testing" "time" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -143,10 +142,10 @@ func TestAddAdminSummary(t *testing.T) { } func TestFiles(t *testing.T) { - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) + updater := &Updater{} params, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) require.NoError(t, err) - l := NewLogs("2.4.5", checker, params) + l := NewLogs("2.4.5", updater, params) ctx := logger.Set(context.Background(), t.Name()) files := l.files(ctx, nil) @@ -184,10 +183,10 @@ func TestFiles(t *testing.T) { func TestZip(t *testing.T) { t.Skip("FIXME") - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) + updater := &Updater{} params, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) require.NoError(t, err) - l := NewLogs("2.4.5", checker, params) + l := NewLogs("2.4.5", updater, params) ctx := logger.Set(context.Background(), t.Name()) var buf bytes.Buffer diff --git a/managed/services/supervisord/pmm_update_checker.go b/managed/services/server/pmm_update_checker.go similarity index 65% rename from managed/services/supervisord/pmm_update_checker.go rename to managed/services/server/pmm_update_checker.go index fe062da7fe..5cc2b4ff93 100644 --- a/managed/services/supervisord/pmm_update_checker.go +++ b/managed/services/server/pmm_update_checker.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package supervisord +package server import ( "bytes" @@ -24,7 +24,6 @@ import ( "sync" "time" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -55,28 +54,9 @@ type PMMUpdateChecker struct { // NewPMMUpdateChecker returns a PMMUpdateChecker instance that can be shared across different parts of the code. // Since this is used inside this package, it could be a singleton, but it would make things mode difficult to test. -func NewPMMUpdateChecker(l *logrus.Entry) *PMMUpdateChecker { +func NewPMMUpdateChecker() *PMMUpdateChecker { return &PMMUpdateChecker{ - l: l, - } -} - -// run runs check for updates loop until ctx is canceled. -func (p *PMMUpdateChecker) run(ctx context.Context) { - p.l.Info("Starting...") - ticker := time.NewTicker(updateCheckInterval) - defer ticker.Stop() - - for { - _ = p.check(ctx) - - select { - case <-ticker.C: - // continue with next loop iteration - case <-ctx.Done(): - p.l.Info("Done.") - return - } + l: logrus.WithField("component", "pmm-update-checker"), } } @@ -126,45 +106,3 @@ func (p *PMMUpdateChecker) cmdRun(ctx context.Context, cmdLine string) ([]byte, p.cmdMutex.Unlock() return b, stderr, err } - -// checkResult returns last `pmm-update -check` result and check time. -// It may force re-check if last result is empty or too old. -func (p *PMMUpdateChecker) checkResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { - p.checkRW.RLock() - defer p.checkRW.RUnlock() - - if time.Since(p.lastCheckTime) > updateCheckResultFresh { - p.checkRW.RUnlock() - _ = p.check(ctx) - p.checkRW.RLock() - } - - return p.lastCheckResult, p.lastCheckTime -} - -// check calls `pmm-update -check` and fills lastInstalledPackageInfo/lastCheckResult/lastCheckTime on success. -func (p *PMMUpdateChecker) check(ctx context.Context) error { - p.checkRW.Lock() - defer p.checkRW.Unlock() - - cmdLine := "pmm-update -check" - b, stderr, err := p.cmdRun(ctx, cmdLine) - if err != nil { - p.l.Errorf("%s output: %s. Error: %s", cmdLine, stderr.Bytes(), err) - return errors.WithStack(err) - } - - var res version.UpdateCheckResult - if err = json.Unmarshal(b, &res); err != nil { - p.l.Errorf("%s output: %s", cmdLine, stderr.Bytes()) - return errors.WithStack(err) - } - - p.l.Debugf("%s output: %s", cmdLine, stderr.Bytes()) - p.installedRW.Lock() - p.lastInstalledPackageInfo = &res.Installed - p.installedRW.Unlock() - p.lastCheckResult = &res - p.lastCheckTime = time.Now() - return nil -} diff --git a/managed/services/supervisord/pprof_config.go b/managed/services/server/pprof_config.go similarity index 97% rename from managed/services/supervisord/pprof_config.go rename to managed/services/server/pprof_config.go index 52ab238389..9697cb8108 100644 --- a/managed/services/supervisord/pprof_config.go +++ b/managed/services/server/pprof_config.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package supervisord +package server import "time" diff --git a/managed/services/server/server.go b/managed/services/server/server.go index dc4d9634d1..1e2828e9d0 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -189,15 +189,14 @@ func (s *Server) Version(ctx context.Context, req *serverpb.VersionRequest) (*se res.Managed.Timestamp = timestamppb.New(t) } - if v := s.supervisord.InstalledPMMVersion(ctx); v != nil { - res.Version = v.Version - res.Server = &serverpb.VersionInfo{ - Version: v.Version, - FullVersion: v.FullVersion, - } - if v.BuildTime != nil { - res.Server.Timestamp = timestamppb.New(*v.BuildTime) - } + v := s.updater.InstalledPMMVersion() + res.Version = v.Version + res.Server = &serverpb.VersionInfo{ + Version: v.Version, + FullVersion: v.FullVersion, + } + if v.BuildTime != nil { + res.Server.Timestamp = timestamppb.New(*v.BuildTime) } return res, nil @@ -298,7 +297,17 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverpb.StartUpdateReque return nil, status.Error(codes.FailedPrecondition, "Updates are disabled via DISABLE_UPDATES environment variable.") } - err := s.updater.StartUpdate(ctx, req.GetNewImage()) + newImage := req.GetNewImage() + if newImage == "" { + latest, err := s.updater.latest(ctx) + if err != nil { + s.l.WithError(err).Error("Failed to get latest version") + newImage = defaultLatestPMMImage + } else { + newImage = fmt.Sprintf("%s:%s", latest.Repo, latest.Version) + } + } + err := s.updater.StartUpdate(ctx, newImage) if err != nil { return nil, err } @@ -331,13 +340,13 @@ func (s *Server) UpdateStatus(ctx context.Context, req *serverpb.UpdateStatusReq ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() for ctx.Err() == nil { - done = !s.supervisord.UpdateRunning() + done = !s.updater.IsRunning() if done { // give supervisord a second to flush logs to file time.Sleep(time.Second) } - lines, newOffset, err = s.supervisord.UpdateLog(req.LogOffset) + lines, newOffset, err = s.updater.UpdateLog(req.LogOffset) if err != nil { s.l.Warn(err) } diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 3d374a6e87..08735eaaa4 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -16,13 +16,15 @@ package server import ( + "bufio" "context" "encoding/json" - "fmt" + "io" "net/http" "net/url" "os" "strings" + "sync" "time" "github.com/pkg/errors" @@ -34,30 +36,57 @@ import ( // defaultLatestPMMImage is the default image name to use when the latest version cannot be determined. const defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" +const pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" // Updater is a service to check for updates and trigger the update process. type Updater struct { - l *logrus.Entry - supervisord supervisordService - watchtowerHost *url.URL + l *logrus.Entry + watchtowerHost *url.URL + gRPCMessageMaxSize uint32 + + performM sync.Mutex + running bool + + checkRW sync.RWMutex + lastCheckResult *version.PackageInfo + lastCheckTime time.Time } // NewUpdater creates a new Updater service. -func NewUpdater(supervisord supervisordService, watchtowerHost *url.URL) *Updater { +func NewUpdater(watchtowerHost *url.URL, gRPCMessageMaxSize uint32) *Updater { return &Updater{ - l: logrus.WithField("service", "updater"), - supervisord: supervisord, - watchtowerHost: watchtowerHost, + l: logrus.WithField("service", "updater"), + watchtowerHost: watchtowerHost, + gRPCMessageMaxSize: gRPCMessageMaxSize, + } +} + +// run runs check for updates loop until ctx is canceled. +func (up *Updater) run(ctx context.Context) { + up.l.Info("Starting...") + ticker := time.NewTicker(updateCheckInterval) + defer ticker.Stop() + + for { + _ = up.check(ctx) + + select { + case <-ticker.C: + // continue with next loop iteration + case <-ctx.Done(): + up.l.Info("Done.") + return + } } } -func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName string) error { +func (up *Updater) sendRequestToWatchtower(ctx context.Context, newImageName string) error { hostname, err := os.Hostname() if err != nil { return errors.Wrap(err, "failed to get hostname") } - u, err := s.watchtowerHost.Parse("/v1/update") + u, err := up.watchtowerHost.Parse("/v1/update") if err != nil { return errors.Wrap(err, "failed to parse URL") } @@ -91,69 +120,73 @@ func (s *Updater) sendRequestToWatchtower(ctx context.Context, newImageName stri return errors.Errorf("received non-OK response: %v", resp.StatusCode) } - s.l.Info("Successfully triggered update") + up.l.Info("Successfully triggered update") return nil } -func (s *Updater) currentVersion() string { +func (up *Updater) currentVersion() string { return version.Version } // StartUpdate triggers the update process. -func (s *Updater) StartUpdate(ctx context.Context, newImageName string) error { +func (up *Updater) StartUpdate(ctx context.Context, newImageName string) error { + up.performM.Lock() + defer up.performM.Unlock() + if up.running { + return errors.New("update already in progress") + } + up.running = true + up.performM.Unlock() if newImageName == "" { - latest, err := s.latest(ctx) - if err != nil { - s.l.WithError(err).Error("Failed to get latest version") - newImageName = defaultLatestPMMImage - } else { - newImageName = fmt.Sprintf("%s:%s", latest.Repo, latest.Version) - } + return errors.New("newImageName is empty") } - if err := s.sendRequestToWatchtower(ctx, newImageName); err != nil { - s.l.WithError(err).Error("Failed to trigger update") + if err := up.sendRequestToWatchtower(ctx, newImageName); err != nil { + up.l.WithError(err).Error("Failed to trigger update") return errors.Wrap(err, "failed to trigger update") } return nil } -func (s *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse { +func (up *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse { return &serverpb.CheckUpdatesResponse{ Installed: &serverpb.VersionInfo{ - Version: s.currentVersion(), + Version: up.currentVersion(), }, } } // ForceCheckUpdates forces an update check. -func (s *Updater) ForceCheckUpdates(_ context.Context) error { +func (up *Updater) ForceCheckUpdates(_ context.Context) error { // TODO: PMM-11261 Implement this method return nil } +type result struct { + Name string `json:"name"` +} + +type versionInfo struct { + Version version.Parsed `json:"version"` + DockerImage string `json:"docker_image"` +} + // TagsResponse is a response from DockerHub. type TagsResponse struct { - Results []struct { - Name string `json:"name"` - } `json:"results"` + Results []result `json:"results"` } // LastCheckUpdatesResult returns the result of the last update check. -func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { +func (up *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { buildTime, err := version.Time() if err != nil { - s.l.WithError(err).Error("Failed to get build time") - return nil, time.Now() - } - latest, err := s.latest(ctx) - if err != nil { - s.l.WithError(err).Error("Failed to get latest version") + up.l.WithError(err).Error("Failed to get build time") return nil, time.Now() } + latest, lastCheckTime := up.checkResult(ctx) return &version.UpdateCheckResult{ Installed: version.PackageInfo{ - Version: s.currentVersion(), + Version: up.currentVersion(), FullVersion: version.PMMVersion, BuildTime: &buildTime, Repo: "local", @@ -161,10 +194,10 @@ func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCh Latest: *latest, UpdateAvailable: true, LatestNewsURL: "", - }, time.Now() + }, lastCheckTime } -func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { +func (up *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { fileName := "/etc/pmm-server-update-version.json" content, err := os.ReadFile(fileName) switch { @@ -172,45 +205,55 @@ func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { info := version.PackageInfo{} err = json.Unmarshal(content, &info) if err != nil { - s.l.WithError(err).Error("Failed to unmarshal file") + up.l.WithError(err).Error("Failed to unmarshal file") return nil, errors.Wrap(err, "failed to unmarshal file") } return &info, nil case err != nil && !os.IsNotExist(err): - s.l.WithError(err).Error("Failed to read file") + up.l.WithError(err).Error("Failed to read file") return nil, errors.Wrap(err, "failed to read file") case os.Getenv("PMM_SERVER_UPDATE_VERSION") != "": - return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil + return up.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil default: // os.IsNotExist(err) // File does not exist, get the latest tag from DockerHub u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { - s.l.WithError(err).Error("Failed to create request") + up.l.WithError(err).Error("Failed to create request") return nil, errors.Wrap(err, "failed to create request") } resp, err := http.DefaultClient.Do(req) if err != nil { - s.l.WithError(err).Error("Failed to get tags from DockerHub") + up.l.WithError(err).Error("Failed to get tags from DockerHub") return nil, errors.Wrap(err, "failed to get tags from DockerHub") } defer resp.Body.Close() //nolint:errcheck var tagsResponse TagsResponse if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { - s.l.WithError(err).Error("Failed to decode response") + up.l.WithError(err).Error("Failed to decode response") return nil, errors.Wrap(err, "failed to decode response") } if len(tagsResponse.Results) != 0 { - // Assuming the first tag is the latest - return s.parseDockerTag(tagsResponse.Results[0].Name), nil + currentVersion, err := version.Parse(up.currentVersion()) + if err != nil { + up.l.WithError(err).Error("Failed to parse current version") + return nil, errors.Wrap(err, "failed to parse current version") + } + + update, err := up.next(*currentVersion, tagsResponse.Results) + if err != nil { + up.l.WithError(err).Error("Failed to get latest minor version") + return nil, errors.Wrap(err, "failed to get latest minor version") + } + return up.parseDockerTag(update.DockerImage), nil } return nil, errors.New("no tags found") } } -func (s *Updater) parseDockerTag(tag string) *version.PackageInfo { +func (up *Updater) parseDockerTag(tag string) *version.PackageInfo { splitTag := strings.Split(tag, ":") if len(splitTag) != 2 { return nil @@ -221,3 +264,111 @@ func (s *Updater) parseDockerTag(tag string) *version.PackageInfo { Repo: splitTag[0], } } + +func (up *Updater) next(currentVersion version.Parsed, results []result) (*versionInfo, error) { + latest := versionInfo{ + Version: currentVersion, + } + for _, result := range results { + splitTag := strings.Split(result.Name, ":") + if len(splitTag) != 2 { + continue + } + v, err := version.Parse(splitTag[1]) + if err != nil { + up.l.Debugf("Failed to parse version: %s", splitTag[1]) + continue + } + if v.Major == currentVersion.Major && v.Minor > currentVersion.Minor { + latest = versionInfo{ + Version: *v, + DockerImage: result.Name, + } + } else if v.Major > currentVersion.Major && v.Major < latest.Version.Major { + latest = versionInfo{ + Version: *v, + DockerImage: result.Name, + } + } + } + return &latest, nil +} + +func (up *Updater) InstalledPMMVersion() version.PackageInfo { + t, _ := version.Time() + return version.PackageInfo{ + Version: up.currentVersion(), + FullVersion: version.PMMVersion, + BuildTime: &t, + Repo: "local", + } +} + +func (up *Updater) IsRunning() bool { + up.performM.Lock() + defer up.performM.Unlock() + return up.running +} + +func (up *Updater) UpdateLog(offset uint32) ([]string, uint32, error) { + up.performM.Lock() + defer up.performM.Unlock() + + f, err := os.Open(pmmUpdatePerformLog) + if err != nil { + return nil, 0, errors.WithStack(err) + } + defer f.Close() //nolint:errcheck,gosec,nolintlint + + if _, err = f.Seek(int64(offset), io.SeekStart); err != nil { + return nil, 0, errors.WithStack(err) + } + + lines := make([]string, 0, 10) + reader := bufio.NewReader(f) + newOffset := offset + for { + line, err := reader.ReadString('\n') + if err == nil { + newOffset += uint32(len(line)) + if newOffset-offset > up.gRPCMessageMaxSize { + return lines, newOffset - uint32(len(line)), nil + } + lines = append(lines, strings.TrimSuffix(line, "\n")) + continue + } + if err == io.EOF { + err = nil + } + return lines, newOffset, errors.WithStack(err) + } +} + +// checkResult returns last `pmm-update -check` result and check time. +// It may force re-check if last result is empty or too old. +func (up *Updater) checkResult(ctx context.Context) (*version.PackageInfo, time.Time) { + up.checkRW.RLock() + defer up.checkRW.RUnlock() + + if time.Since(up.lastCheckTime) > updateCheckResultFresh { + up.checkRW.RUnlock() + _ = up.check(ctx) + up.checkRW.RLock() + } + + return up.lastCheckResult, up.lastCheckTime +} + +// check calls `pmm-update -check` and fills lastInstalledPackageInfo/lastCheckResult/lastCheckTime on success. +func (up *Updater) check(ctx context.Context) error { + up.checkRW.Lock() + defer up.checkRW.Unlock() + + latest, err := up.latest(ctx) + if err != nil { + return errors.Wrap(err, "failed to get latest version") + } + up.lastCheckResult = latest + up.lastCheckTime = time.Now() + return nil +} diff --git a/managed/services/server/updater_test.go b/managed/services/server/updater_test.go new file mode 100644 index 0000000000..f56e2d6c2f --- /dev/null +++ b/managed/services/server/updater_test.go @@ -0,0 +1,269 @@ +package server + +import ( + "context" + "github.com/percona/pmm/version" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "net/url" + "strings" + "testing" + "time" +) + +func TestUpdater(t *testing.T) { + + gRPCMessageMaxSize := uint32(100 * 1024 * 1024) + gaReleaseDate := time.Date(2019, 9, 18, 0, 0, 0, 0, time.UTC) + watchtowerURL, _ := url.Parse("http://watchtower:8080") + + t.Run("TestNextVersion", func(t *testing.T) { + type args struct { + currentVersion string + results []result + } + type versionInfo struct { + Version string + DockerImage string + } + tests := []struct { + name string + args args + want *versionInfo + wantErr assert.ErrorAssertionFunc + }{ + { + name: "no results", + args: args{ + currentVersion: "3.0.0", + results: nil, + }, + want: &versionInfo{ + Version: "3.0.0", + DockerImage: "", + }, + wantErr: nil, + }, + { + name: "no new version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.0.0"}, + }, + }, + want: &versionInfo{ + Version: "3.0.0", + DockerImage: "", + }, + wantErr: nil, + }, + { + name: "new minor version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.1.0"}, + {Name: "percona/pmm-server:3.0.0"}, + }, + }, + want: &versionInfo{ + Version: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", + }, + wantErr: nil, + }, + { + name: "new major version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:4.0.0"}, + {Name: "percona/pmm-server:3.0.0"}, + }, + }, + want: &versionInfo{ + Version: "4.0.0", + DockerImage: "percona/pmm-server:4.0.0", + }, + wantErr: nil, + }, + { + name: "new major version with minor version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:4.1.0"}, + {Name: "percona/pmm-server:4.0.0"}, + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:3.1.0"}, + }, + }, + want: &versionInfo{ + Version: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", + }, + wantErr: nil, + }, + { + name: "invalid version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:3.1.0"}, + {Name: "percona/pmm-server:invalid"}, + }, + }, + want: &versionInfo{ + Version: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", + }, + wantErr: nil, + }, + { + name: "non semver version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:3.1"}, + }, + }, + want: &versionInfo{ + Version: "3.0.0", + DockerImage: "", + }, + wantErr: nil, + }, + { + name: "rc version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:3.1.0-rc"}, + {Name: "percona/pmm-server:3.1.0-rc757"}, + }, + }, + want: &versionInfo{ + Version: "3.1.0-rc757", + DockerImage: "percona/pmm-server:3.1.0-rc757", + }, + wantErr: nil, + }, + { + name: "rc version and release version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:3.1.0-rc"}, + {Name: "percona/pmm-server:3.1.0-rc757"}, + {Name: "percona/pmm-server:3.1.0"}, + }, + }, + want: &versionInfo{ + Version: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", + }, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + u := NewUpdater(nil, gRPCMessageMaxSize) + parsed, err := version.Parse(tt.args.currentVersion) + require.NoError(t, err) + next, err := u.next(*parsed, tt.args.results) + if tt.wantErr != nil { + tt.wantErr(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want.Version, next.Version.String()) + assert.Equal(t, tt.want.DockerImage, next.DockerImage) + }) + } + }) + + t.Run("Installed", func(t *testing.T) { + checker := NewUpdater(watchtowerURL, gRPCMessageMaxSize) + + info := checker.InstalledPMMVersion() + require.NotNil(t, info) + + assert.True(t, strings.HasPrefix(info.Version, "3."), "version should start with `3.`. Actual value is: %s", info.Version) + fullVersion, _ := normalizeFullversion(&info) + assert.True(t, strings.HasPrefix(fullVersion, "3."), "full version should start with `3.`. Actual value is: %s", fullVersion) + require.NotEmpty(t, info.BuildTime) + assert.True(t, info.BuildTime.After(gaReleaseDate), "BuildTime = %s", info.BuildTime) + }) + + t.Run("Check", func(t *testing.T) { + t.Skip("This test is to be deprecated or completely rewritten") + + ctx := context.TODO() + checker := NewUpdater(watchtowerURL, gRPCMessageMaxSize) + + res, resT := checker.LastCheckUpdatesResult(ctx) + assert.WithinDuration(t, time.Now(), resT, time.Second) + + assert.True(t, strings.HasPrefix(res.Installed.Version, "3."), "installed version should start with `3.`. Actual value is: %s", res.Installed.Version) + installedFullVersion, _ := normalizeFullversion(&res.Installed) + assert.True(t, strings.HasPrefix(installedFullVersion, "3."), "installed full version should start with `3.`. Actual value is: %s", installedFullVersion) + require.NotEmpty(t, res.Installed.BuildTime) + assert.True(t, res.Installed.BuildTime.After(gaReleaseDate), "Installed.BuildTime = %s", res.Installed.BuildTime) + assert.Equal(t, "local", res.Installed.Repo) + + assert.True(t, strings.HasPrefix(res.Latest.Version, "3."), "The latest available version should start with `3.`. Actual value is: %s", res.Latest.Version) + latestFullVersion, isFeatureBranch := normalizeFullversion(&res.Latest) + if isFeatureBranch { + t.Skip("Skipping check latest version.") + } + assert.True(t, strings.HasPrefix(latestFullVersion, "3."), "The latest available versions full value should start with `3.`. Actual value is: %s", latestFullVersion) + require.NotEmpty(t, res.Latest.BuildTime) + assert.True(t, res.Latest.BuildTime.After(gaReleaseDate), "Latest.BuildTime = %s", res.Latest.BuildTime) + assert.NotEmpty(t, res.Latest.Repo) + + // We assume that the latest perconalab/pmm-server:3-dev-latest image + // always contains the latest pmm-update package versions. + // If this test fails, re-pull them and recreate devcontainer. + t.Log("Assuming the latest pmm-update version.") + assert.False(t, res.UpdateAvailable, "update should not be available") + assert.Empty(t, res.LatestNewsURL, "latest_news_url should be empty") + assert.Equal(t, res.Installed, res.Latest, "version should be the same (latest)") + assert.Equal(t, *res.Installed.BuildTime, *res.Latest.BuildTime, "build times should be the same") + assert.Equal(t, "local", res.Latest.Repo) + + // cached result + res2, resT2 := checker.checkResult(ctx) + assert.Equal(t, res, res2) + assert.Equal(t, resT, resT2) + + time.Sleep(100 * time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), updateDefaultTimeout) + defer cancel() + go checker.run(ctx) + time.Sleep(100 * time.Millisecond) + + // should block and wait for run to finish one iteration + res3, resT3 := checker.checkResult(ctx) + assert.Equal(t, res2, res3) + assert.NotEqual(t, resT2, resT3, "%s", resT2) + assert.WithinDuration(t, resT2, resT3, 10*time.Second) + }) +} + +func normalizeFullversion(info *version.PackageInfo) (version string, isFeatureBranch bool) { + fullVersion := info.FullVersion + + epochPrefix := "1:" // set by RPM_EPOCH in PMM Server build scripts + isFeatureBranch = strings.HasPrefix(fullVersion, epochPrefix) + if isFeatureBranch { + fullVersion = strings.TrimPrefix(fullVersion, epochPrefix) + } + + return fullVersion, isFeatureBranch +} diff --git a/managed/services/supervisord/deps.go b/managed/services/supervisord/deps.go index 9de477c334..9176f8b1bb 100644 --- a/managed/services/supervisord/deps.go +++ b/managed/services/supervisord/deps.go @@ -14,12 +14,3 @@ // along with this program. If not, see . package supervisord - -import "net/url" - -// victoriaMetricsParams is a subset of methods of models.VMParams used by this package. -// We use it instead of real type to avoid dependency cycle. -type victoriaMetricsParams interface { - ExternalVM() bool - URLFor(path string) (*url.URL, error) -} diff --git a/managed/services/supervisord/devcontainer_test.go b/managed/services/supervisord/devcontainer_test.go index e7b688c011..2c71f50445 100644 --- a/managed/services/supervisord/devcontainer_test.go +++ b/managed/services/supervisord/devcontainer_test.go @@ -19,105 +19,23 @@ import ( "context" "os" "path/filepath" - "strconv" - "strings" "testing" "time" - "github.com/sirupsen/logrus" + "github.com/percona/pmm/managed/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/version" ) // TODO move tests to other files and remove this one. func TestDevContainer(t *testing.T) { - gRPCMessageMaxSize := uint32(100 * 1024 * 1024) - gaReleaseDate := time.Date(2019, 9, 18, 0, 0, 0, 0, time.UTC) - - t.Run("Installed", func(t *testing.T) { - ctx := context.TODO() - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) - - info := checker.Installed(ctx) - require.NotNil(t, info) - - assert.True(t, strings.HasPrefix(info.Version, "3."), "version should start with `3.`. Actual value is: %s", info.Version) - fullVersion, _ := normalizeFullversion(info) - assert.True(t, strings.HasPrefix(fullVersion, "3."), "full version should start with `3.`. Actual value is: %s", fullVersion) - require.NotEmpty(t, info.BuildTime) - assert.True(t, info.BuildTime.After(gaReleaseDate), "BuildTime = %s", info.BuildTime) - assert.Equal(t, "local", info.Repo) - - info2 := checker.Installed(ctx) - assert.Equal(t, info, info2) - }) - - t.Run("Check", func(t *testing.T) { - t.Skip("This test is to be deprecated or completely rewritten") - - ctx := context.TODO() - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) - - res, resT := checker.checkResult(ctx) - assert.WithinDuration(t, time.Now(), resT, time.Second) - - assert.True(t, strings.HasPrefix(res.Installed.Version, "3."), "installed version should start with `3.`. Actual value is: %s", res.Installed.Version) - installedFullVersion, _ := normalizeFullversion(&res.Installed) - assert.True(t, strings.HasPrefix(installedFullVersion, "3."), "installed full version should start with `3.`. Actual value is: %s", installedFullVersion) - require.NotEmpty(t, res.Installed.BuildTime) - assert.True(t, res.Installed.BuildTime.After(gaReleaseDate), "Installed.BuildTime = %s", res.Installed.BuildTime) - assert.Equal(t, "local", res.Installed.Repo) - - assert.True(t, strings.HasPrefix(res.Latest.Version, "3."), "The latest available version should start with `3.`. Actual value is: %s", res.Latest.Version) - latestFullVersion, isFeatureBranch := normalizeFullversion(&res.Latest) - if isFeatureBranch { - t.Skip("Skipping check latest version.") - } - assert.True(t, strings.HasPrefix(latestFullVersion, "3."), "The latest available versions full value should start with `3.`. Actual value is: %s", latestFullVersion) - require.NotEmpty(t, res.Latest.BuildTime) - assert.True(t, res.Latest.BuildTime.After(gaReleaseDate), "Latest.BuildTime = %s", res.Latest.BuildTime) - assert.NotEmpty(t, res.Latest.Repo) - - // We assume that the latest perconalab/pmm-server:3-dev-latest image - // always contains the latest pmm-update package versions. - // If this test fails, re-pull them and recreate devcontainer. - t.Log("Assuming the latest pmm-update version.") - assert.False(t, res.UpdateAvailable, "update should not be available") - assert.Empty(t, res.LatestNewsURL, "latest_news_url should be empty") - assert.Equal(t, res.Installed, res.Latest, "version should be the same (latest)") - assert.Equal(t, *res.Installed.BuildTime, *res.Latest.BuildTime, "build times should be the same") - assert.Equal(t, "local", res.Latest.Repo) - - // cached result - res2, resT2 := checker.checkResult(ctx) - assert.Equal(t, res, res2) - assert.Equal(t, resT, resT2) - - time.Sleep(100 * time.Millisecond) - ctx, cancel := context.WithTimeout(context.Background(), updateDefaultTimeout) - defer cancel() - go checker.run(ctx) - time.Sleep(100 * time.Millisecond) - - // should block and wait for run to finish one iteration - res3, resT3 := checker.checkResult(ctx) - assert.Equal(t, res2, res3) - assert.NotEqual(t, resT2, resT3, "%s", resT2) - assert.WithinDuration(t, resT2, resT3, 10*time.Second) - }) t.Run("UpdateConfiguration", func(t *testing.T) { // logrus.SetLevel(logrus.DebugLevel) - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) vmParams, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) require.NoError(t, err) - s := New("/etc/supervisord.d", checker, &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) + s := New("/etc/supervisord.d", &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}) require.NotEmpty(t, s.supervisorctlPath) ctx, cancel := context.WithCancel(context.Background()) @@ -160,87 +78,75 @@ func TestDevContainer(t *testing.T) { require.NoError(t, err) }) - t.Run("Update", func(t *testing.T) { - // This test can be run only once as it breaks assumptions of other tests. - // It also should be the last test in devcontainer. - if ok, _ := strconv.ParseBool(os.Getenv("PMM_TEST_RUN_UPDATE")); !ok { - t.Skip("skipping update test") - } - - // logrus.SetLevel(logrus.DebugLevel) - checker := NewPMMUpdateChecker(logrus.WithField("test", t.Name())) - vmParams := &models.VictoriaMetricsParams{} - s := New("/etc/supervisord.d", checker, &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) - require.NotEmpty(t, s.supervisorctlPath) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go s.Run(ctx) - - require.Equal(t, false, s.UpdateRunning()) - - offset, err := s.StartUpdate() - require.NoError(t, err) - assert.Zero(t, offset) - - assert.True(t, s.UpdateRunning()) - - _, err = s.StartUpdate() - assert.Equal(t, status.Errorf(codes.FailedPrecondition, "Update is already running."), err) - - // get logs as often as possible to increase a chance for race detector to spot something - var lastLine string - for { - done := s.UpdateRunning() - if done { - // give supervisord a second to flush logs to file - time.Sleep(time.Second) - } - - lines, newOffset, err := s.UpdateLog(offset) - require.NoError(t, err) - if newOffset == offset { - assert.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) - if done { - continue - } - break - } - - assert.NotEmpty(t, lines) - t.Logf("%s", strings.Join(lines, "\n")) - lastLine = lines[len(lines)-1] - - assert.NotZero(t, newOffset) - assert.True(t, newOffset > offset, "expected newOffset = %d > offset = %d", newOffset, offset) - offset = newOffset - } - - t.Logf("lastLine = %q", lastLine) - assert.Contains(t, lastLine, "Waiting for Grafana dashboards update to finish...") - - // extra checks that we did not miss `pmp-update -perform` self-update and restart by supervisord - const wait = 3 * time.Second - const delay = 200 * time.Millisecond - for i := 0; i < int(wait/delay); i++ { - time.Sleep(delay) - require.False(t, s.UpdateRunning()) - lines, newOffset, err := s.UpdateLog(offset) - require.NoError(t, err) - require.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) - require.Equal(t, offset, newOffset, "offset = %d, newOffset = %d", offset, newOffset) - } - }) -} - -func normalizeFullversion(info *version.PackageInfo) (version string, isFeatureBranch bool) { - fullVersion := info.FullVersion - - epochPrefix := "1:" // set by RPM_EPOCH in PMM Server build scripts - isFeatureBranch = strings.HasPrefix(fullVersion, epochPrefix) - if isFeatureBranch { - fullVersion = strings.TrimPrefix(fullVersion, epochPrefix) - } - - return fullVersion, isFeatureBranch + //t.Run("Update", func(t *testing.T) { + // // This test can be run only once as it breaks assumptions of other tests. + // // It also should be the last test in devcontainer. + // if ok, _ := strconv.ParseBool(os.Getenv("PMM_TEST_RUN_UPDATE")); !ok { + // t.Skip("skipping update test") + // } + // + // // logrus.SetLevel(logrus.DebugLevel) + // checker := NewPMMUpdateChecker() + // vmParams := &models.VictoriaMetricsParams{} + // s := New("/etc/supervisord.d", &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) + // require.NotEmpty(t, s.supervisorctlPath) + // + // ctx, cancel := context.WithCancel(context.Background()) + // defer cancel() + // go s.Run(ctx) + // + // require.Equal(t, false, s.UpdateRunning()) + // + // offset, err := s.StartUpdate() + // require.NoError(t, err) + // assert.Zero(t, offset) + // + // assert.True(t, s.UpdateRunning()) + // + // _, err = s.StartUpdate() + // assert.Equal(t, status.Errorf(codes.FailedPrecondition, "Update is already running."), err) + // + // // get logs as often as possible to increase a chance for race detector to spot something + // var lastLine string + // for { + // done := s.UpdateRunning() + // if done { + // // give supervisord a second to flush logs to file + // time.Sleep(time.Second) + // } + // + // lines, newOffset, err := s.UpdateLog(offset) + // require.NoError(t, err) + // if newOffset == offset { + // assert.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) + // if done { + // continue + // } + // break + // } + // + // assert.NotEmpty(t, lines) + // t.Logf("%s", strings.Join(lines, "\n")) + // lastLine = lines[len(lines)-1] + // + // assert.NotZero(t, newOffset) + // assert.True(t, newOffset > offset, "expected newOffset = %d > offset = %d", newOffset, offset) + // offset = newOffset + // } + // + // t.Logf("lastLine = %q", lastLine) + // assert.Contains(t, lastLine, "Waiting for Grafana dashboards update to finish...") + // + // // extra checks that we did not miss `pmp-update -perform` self-update and restart by supervisord + // const wait = 3 * time.Second + // const delay = 200 * time.Millisecond + // for i := 0; i < int(wait/delay); i++ { + // time.Sleep(delay) + // require.False(t, s.UpdateRunning()) + // lines, newOffset, err := s.UpdateLog(offset) + // require.NoError(t, err) + // require.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) + // require.Equal(t, offset, newOffset, "offset = %d, newOffset = %d", offset, newOffset) + // } + //}) } diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index 2d94414418..2036914ca7 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -21,7 +21,6 @@ import ( "bytes" "context" "fmt" - "io" "io/fs" "net/url" "os" @@ -35,16 +34,12 @@ import ( "time" "github.com/AlekSi/pointer" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/utils/envvars" "github.com/percona/pmm/utils/pdeathsig" - "github.com/percona/pmm/version" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) const ( @@ -63,18 +58,15 @@ const ( // Service is responsible for interactions with Supervisord via supervisorctl. type Service struct { - configDir string - supervisorctlPath string - gRPCMessageMaxSize uint32 - l *logrus.Entry - pmmUpdateCheck *PMMUpdateChecker + configDir string + supervisorctlPath string + l *logrus.Entry eventsM sync.Mutex subs map[chan *event]sub lastEvents map[string]eventType - pmmUpdatePerformLogM sync.Mutex - supervisordConfigsM sync.Mutex + supervisordConfigsM sync.Mutex vmParams *models.VictoriaMetricsParams pgParams *models.PGParams @@ -88,25 +80,21 @@ type sub struct { // values from supervisord configuration. const ( - pmmUpdatePerformProgram = "pmm-update-perform" - pmmUpdatePerformLog = "/srv/logs/pmm-update-perform.log" - pmmConfig = "/etc/supervisord.d/pmm.ini" + pmmConfig = "/etc/supervisord.d/pmm.ini" ) // New creates new service. -func New(configDir string, pmmUpdateCheck *PMMUpdateChecker, params *models.Params, gRPCMessageMaxSize uint32) *Service { +func New(configDir string, params *models.Params, ) *Service { path, _ := exec.LookPath("supervisorctl") return &Service{ - configDir: configDir, - supervisorctlPath: path, - gRPCMessageMaxSize: gRPCMessageMaxSize, - l: logrus.WithField("component", "supervisord"), - pmmUpdateCheck: pmmUpdateCheck, - subs: make(map[chan *event]sub), - lastEvents: make(map[string]eventType), - vmParams: params.VMParams, - pgParams: params.PGParams, - haParams: params.HAParams, + configDir: configDir, + supervisorctlPath: path, + l: logrus.WithField("component", "supervisord"), + subs: make(map[chan *event]sub), + lastEvents: make(map[string]eventType), + vmParams: params.VMParams, + pgParams: params.PGParams, + haParams: params.HAParams, } } @@ -114,24 +102,6 @@ func New(configDir string, pmmUpdateCheck *PMMUpdateChecker, params *models.Para func (s *Service) Run(ctx context.Context) { var wg sync.WaitGroup wg.Add(1) - go func() { - defer wg.Done() - - // pre-set installed packages info to cache it. - s.pmmUpdateCheck.Installed(ctx) - - // Do not check for updates for the first 10 minutes. - // That solves PMM Server building problems when we start pmm-managed. - // TODO https://jira.percona.com/browse/PMM-4429 - sleepCtx, sleepCancel := context.WithTimeout(ctx, 10*time.Minute) - <-sleepCtx.Done() - sleepCancel() - if ctx.Err() != nil { - return - } - - s.pmmUpdateCheck.run(ctx) - }() defer wg.Wait() if s.supervisorctlPath == "" { @@ -210,21 +180,6 @@ func (s *Service) Run(ctx context.Context) { } } -// InstalledPMMVersion returns currently installed PMM version information. -func (s *Service) InstalledPMMVersion(ctx context.Context) *version.PackageInfo { - return s.pmmUpdateCheck.Installed(ctx) -} - -// LastCheckUpdatesResult returns last PMM update check result and last check time. -func (s *Service) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { - return s.pmmUpdateCheck.checkResult(ctx) -} - -// ForceCheckUpdates forces check for PMM updates. Result can be obtained via LastCheckUpdatesResult. -func (s *Service) ForceCheckUpdates(ctx context.Context) error { - return s.pmmUpdateCheck.check(ctx) -} - func (s *Service) subscribe(program string, eventTypes ...eventType) chan *event { ch := make(chan *event, 1) s.eventsM.Lock() @@ -249,66 +204,6 @@ func (s *Service) supervisorctl(args ...string) ([]byte, error) { return b, errors.Wrapf(err, "%s failed", cmdLine) } -// StartUpdate starts pmm-update-perform supervisord program with some preparations. -// It returns initial log file offset. -func (s *Service) StartUpdate() (uint32, error) { - if s.UpdateRunning() { - return 0, status.Errorf(codes.FailedPrecondition, "Update is already running.") - } - - // We need to remove and reopen log file for UpdateStatus API to be able to read it without it being rotated. - // Additionally, SIGUSR2 is expected by our Ansible playbook. - - s.pmmUpdatePerformLogM.Lock() - defer s.pmmUpdatePerformLogM.Unlock() - - // remove existing log file - err := os.Remove(pmmUpdatePerformLog) - if err != nil && errors.Is(err, fs.ErrNotExist) { - err = nil - } - if err != nil { - s.l.Warn(err) - } - - // send SIGUSR2 to supervisord and wait for it to reopen log file - ch := s.subscribe("supervisord", logReopen) - b, err := s.supervisorctl("pid") - if err != nil { - return 0, err - } - pid, err := strconv.Atoi(strings.TrimSpace(string(b))) - if err != nil { - return 0, errors.WithStack(err) - } - p, err := os.FindProcess(pid) - if err != nil { - return 0, errors.WithStack(err) - } - if err = p.Signal(unix.SIGUSR2); err != nil { - s.l.Warnf("Failed to send SIGUSR2: %s", err) - } - s.l.Debug("Waiting for log reopen...") - <-ch - - var offset uint32 - fi, err := os.Stat(pmmUpdatePerformLog) - switch { - case err == nil: - if fi.Size() != 0 { - s.l.Warnf("Unexpected log file size: %+v", fi) - } - offset = uint32(fi.Size()) - case errors.Is(err, fs.ErrNotExist): - // that's expected as we remove this file above - default: - s.l.Warn(err) - } - - _, err = s.supervisorctl("start", pmmUpdatePerformProgram) - return offset, err -} - // parseStatus parses `supervisorctl status ` output, returns true if is running, // false if definitely not, and nil if status can't be determined. func parseStatus(status string) *bool { @@ -327,11 +222,6 @@ func parseStatus(status string) *bool { return nil } -// UpdateRunning returns true if pmm-update-perform is not done yet. -func (s *Service) UpdateRunning() bool { - return s.programRunning(pmmUpdatePerformProgram) -} - // UpdateRunning returns true if given supervisord program is running or being restarted, // false if it is not running / failed. func (s *Service) programRunning(program string) bool { @@ -367,42 +257,6 @@ func (s *Service) programRunning(program string) bool { } } -// UpdateLog returns some lines and a new offset from pmm-update-perform log starting from the given offset. -// It may return zero lines and the same offset. Caller is expected to handle this. -func (s *Service) UpdateLog(offset uint32) ([]string, uint32, error) { - s.pmmUpdatePerformLogM.Lock() - defer s.pmmUpdatePerformLogM.Unlock() - - f, err := os.Open(pmmUpdatePerformLog) - if err != nil { - return nil, 0, errors.WithStack(err) - } - defer f.Close() //nolint:errcheck,gosec,nolintlint - - if _, err = f.Seek(int64(offset), io.SeekStart); err != nil { - return nil, 0, errors.WithStack(err) - } - - lines := make([]string, 0, 10) - reader := bufio.NewReader(f) - newOffset := offset - for { - line, err := reader.ReadString('\n') - if err == nil { - newOffset += uint32(len(line)) - if newOffset-offset > s.gRPCMessageMaxSize { - return lines, newOffset - uint32(len(line)), nil - } - lines = append(lines, strings.TrimSuffix(line, "\n")) - continue - } - if err == io.EOF { - err = nil - } - return lines, newOffset, errors.WithStack(err) - } -} - // reload asks supervisord to reload configuration. func (s *Service) reload(name string) error { if _, err := s.supervisorctl("reread"); err != nil { diff --git a/managed/services/supervisord/supervisord_test.go b/managed/services/supervisord/supervisord_test.go index b0fe8ef8b3..c576042826 100644 --- a/managed/services/supervisord/supervisord_test.go +++ b/managed/services/supervisord/supervisord_test.go @@ -22,19 +22,15 @@ import ( "time" "github.com/AlekSi/pointer" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/percona/pmm/managed/models" ) -const gRPCMessageMaxSize = uint32(100 * 1024 * 1024) - func TestConfig(t *testing.T) { t.Parallel() - pmmUpdateCheck := NewPMMUpdateChecker(logrus.WithField("component", "supervisord/pmm-update-checker_logs")) configDir := filepath.Join("..", "..", "testdata", "supervisord.d") vmParams, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) require.NoError(t, err) @@ -48,7 +44,7 @@ func TestConfig(t *testing.T) { SSLKeyPath: "path-to-key", SSLCertPath: "path-to-cert", } - s := New(configDir, pmmUpdateCheck, &models.Params{VMParams: vmParams, PGParams: pgParams, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) + s := New(configDir, &models.Params{VMParams: vmParams, PGParams: pgParams, HAParams: &models.HAParams{}}) settings := &models.Settings{ DataRetention: 30 * 24 * time.Hour, PMMPublicAddress: "192.168.0.42:8443", @@ -73,7 +69,6 @@ func TestConfig(t *testing.T) { } func TestConfigVictoriaMetricsEnvvars(t *testing.T) { - pmmUpdateCheck := NewPMMUpdateChecker(logrus.WithField("component", "supervisord/pmm-update-checker_logs")) configDir := filepath.Join("..", "..", "testdata", "supervisord.d") vmParams, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) require.NoError(t, err) @@ -87,7 +82,7 @@ func TestConfigVictoriaMetricsEnvvars(t *testing.T) { SSLKeyPath: "path-to-key", SSLCertPath: "path-to-cert", } - s := New(configDir, pmmUpdateCheck, &models.Params{VMParams: vmParams, PGParams: pgParams, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) + s := New(configDir, &models.Params{VMParams: vmParams, PGParams: pgParams, HAParams: &models.HAParams{}}) settings := &models.Settings{ DataRetention: 30 * 24 * time.Hour, PMMPublicAddress: "192.168.0.42:8443", From 4104986dd4ca90bd2eae83a1da39c3dd20da81a7 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 8 Apr 2024 12:48:12 +0300 Subject: [PATCH 15/33] PMM-11261 Replace switch with if-else --- managed/services/server/updater.go | 62 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 3d374a6e87..6b2f9c24d4 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -165,10 +165,14 @@ func (s *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCh } func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { + // Read from file, if it's not exist read from ENV variable, if it's not exist get the latest tag from DockerHub. fileName := "/etc/pmm-server-update-version.json" content, err := os.ReadFile(fileName) - switch { - case err == nil: + if err != nil && !os.IsNotExist(err) { + s.l.WithError(err).Error("Failed to read file") + return nil, errors.Wrap(err, "failed to read file") + } + if err == nil { info := version.PackageInfo{} err = json.Unmarshal(content, &info) if err != nil { @@ -176,38 +180,36 @@ func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { return nil, errors.Wrap(err, "failed to unmarshal file") } return &info, nil - case err != nil && !os.IsNotExist(err): - s.l.WithError(err).Error("Failed to read file") - return nil, errors.Wrap(err, "failed to read file") - case os.Getenv("PMM_SERVER_UPDATE_VERSION") != "": + } + if os.Getenv("PMM_SERVER_UPDATE_VERSION") != "" { return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil - default: // os.IsNotExist(err) - // File does not exist, get the latest tag from DockerHub - u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) - if err != nil { - s.l.WithError(err).Error("Failed to create request") - return nil, errors.Wrap(err, "failed to create request") - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - s.l.WithError(err).Error("Failed to get tags from DockerHub") - return nil, errors.Wrap(err, "failed to get tags from DockerHub") - } - defer resp.Body.Close() //nolint:errcheck + } - var tagsResponse TagsResponse - if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { - s.l.WithError(err).Error("Failed to decode response") - return nil, errors.Wrap(err, "failed to decode response") - } + // File does not exist, ENV variable doesn't provided, get the latest tag from DockerHub + u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + s.l.WithError(err).Error("Failed to create request") + return nil, errors.Wrap(err, "failed to create request") + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + s.l.WithError(err).Error("Failed to get tags from DockerHub") + return nil, errors.Wrap(err, "failed to get tags from DockerHub") + } + defer resp.Body.Close() //nolint:errcheck - if len(tagsResponse.Results) != 0 { - // Assuming the first tag is the latest - return s.parseDockerTag(tagsResponse.Results[0].Name), nil - } - return nil, errors.New("no tags found") + var tagsResponse TagsResponse + if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { + s.l.WithError(err).Error("Failed to decode response") + return nil, errors.Wrap(err, "failed to decode response") + } + + if len(tagsResponse.Results) != 0 { + // Assuming the first tag is the latest + return s.parseDockerTag(tagsResponse.Results[0].Name), nil } + return nil, errors.New("no tags found") } func (s *Updater) parseDockerTag(tag string) *version.PackageInfo { From 018ded1e61e231103bd335c56a6108ec37536f62 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 8 Apr 2024 18:16:41 +0300 Subject: [PATCH 16/33] PMM-12762 Fix conflicts, tests and linters. --- .../server/mock_supervisord_service_test.go | 155 ------------------ managed/services/server/updater.go | 40 +++-- managed/services/server/updater_test.go | 43 ++++- .../services/supervisord/devcontainer_test.go | 4 +- managed/services/supervisord/supervisord.go | 9 +- 5 files changed, 71 insertions(+), 180 deletions(-) diff --git a/managed/services/server/mock_supervisord_service_test.go b/managed/services/server/mock_supervisord_service_test.go index b958fc55b3..792e5987f1 100644 --- a/managed/services/server/mock_supervisord_service_test.go +++ b/managed/services/server/mock_supervisord_service_test.go @@ -3,13 +3,9 @@ package server import ( - context "context" - time "time" - mock "github.com/stretchr/testify/mock" models "github.com/percona/pmm/managed/models" - version "github.com/percona/pmm/version" ) // mockSupervisordService is an autogenerated mock type for the supervisordService type @@ -17,102 +13,6 @@ type mockSupervisordService struct { mock.Mock } -// ForceCheckUpdates provides a mock function with given fields: ctx -func (_m *mockSupervisordService) ForceCheckUpdates(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for ForceCheckUpdates") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// InstalledPMMVersion provides a mock function with given fields: ctx -func (_m *mockSupervisordService) InstalledPMMVersion(ctx context.Context) *version.PackageInfo { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for InstalledPMMVersion") - } - - var r0 *version.PackageInfo - if rf, ok := ret.Get(0).(func(context.Context) *version.PackageInfo); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*version.PackageInfo) - } - } - - return r0 -} - -// LastCheckUpdatesResult provides a mock function with given fields: ctx -func (_m *mockSupervisordService) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for LastCheckUpdatesResult") - } - - var r0 *version.UpdateCheckResult - var r1 time.Time - if rf, ok := ret.Get(0).(func(context.Context) (*version.UpdateCheckResult, time.Time)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *version.UpdateCheckResult); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*version.UpdateCheckResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) time.Time); ok { - r1 = rf(ctx) - } else { - r1 = ret.Get(1).(time.Time) - } - - return r0, r1 -} - -// StartUpdate provides a mock function with given fields: -func (_m *mockSupervisordService) StartUpdate() (uint32, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for StartUpdate") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func() (uint32, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // UpdateConfiguration provides a mock function with given fields: settings, ssoDetails func (_m *mockSupervisordService) UpdateConfiguration(settings *models.Settings, ssoDetails *models.PerconaSSODetails) error { ret := _m.Called(settings, ssoDetails) @@ -131,61 +31,6 @@ func (_m *mockSupervisordService) UpdateConfiguration(settings *models.Settings, return r0 } -// UpdateLog provides a mock function with given fields: offset -func (_m *mockSupervisordService) UpdateLog(offset uint32) ([]string, uint32, error) { - ret := _m.Called(offset) - - if len(ret) == 0 { - panic("no return value specified for UpdateLog") - } - - var r0 []string - var r1 uint32 - var r2 error - if rf, ok := ret.Get(0).(func(uint32) ([]string, uint32, error)); ok { - return rf(offset) - } - if rf, ok := ret.Get(0).(func(uint32) []string); ok { - r0 = rf(offset) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(uint32) uint32); ok { - r1 = rf(offset) - } else { - r1 = ret.Get(1).(uint32) - } - - if rf, ok := ret.Get(2).(func(uint32) error); ok { - r2 = rf(offset) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// UpdateRunning provides a mock function with given fields: -func (_m *mockSupervisordService) UpdateRunning() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for UpdateRunning") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - // newMockSupervisordService creates a new instance of mockSupervisordService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func newMockSupervisordService(t interface { diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 71a18f317d..2095c518fe 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -35,8 +35,10 @@ import ( ) // defaultLatestPMMImage is the default image name to use when the latest version cannot be determined. -const defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" -const pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" +const ( + defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" + pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" +) // Updater is a service to check for updates and trigger the update process. type Updater struct { @@ -202,7 +204,7 @@ func (up *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { fileName := "/etc/pmm-server-update-version.json" content, err := os.ReadFile(fileName) if err != nil && !os.IsNotExist(err) { - s.l.WithError(err).Error("Failed to read file") + up.l.WithError(err).Error("Failed to read file") return nil, errors.Wrap(err, "failed to read file") } if err == nil { @@ -215,19 +217,27 @@ func (up *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { return &info, nil } if os.Getenv("PMM_SERVER_UPDATE_VERSION") != "" { - return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil + return up.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil } // File does not exist, ENV variable doesn't provided, get the latest tag from DockerHub + return up.latestAvailableFromDockerHub(ctx, err) +} + +// latestAvailableFromDockerHub returns the latest available version from DockerHub. +// It returns the latest minor version for the current major version. +// If the current version is the latest minor version, it returns the next major version. +// If the current version is the latest version, it returns the current version. +func (up *Updater) latestAvailableFromDockerHub(ctx context.Context, err error) (*version.PackageInfo, error) { u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { - s.l.WithError(err).Error("Failed to create request") + up.l.WithError(err).Error("Failed to create request") return nil, errors.Wrap(err, "failed to create request") } resp, err := http.DefaultClient.Do(req) if err != nil { - s.l.WithError(err).Error("Failed to get tags from DockerHub") + up.l.WithError(err).Error("Failed to get tags from DockerHub") return nil, errors.Wrap(err, "failed to get tags from DockerHub") } defer resp.Body.Close() //nolint:errcheck @@ -240,16 +250,16 @@ func (up *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { if len(tagsResponse.Results) != 0 { currentVersion, err := version.Parse(up.currentVersion()) - if err != nil { - up.l.WithError(err).Error("Failed to parse current version") - return nil, errors.Wrap(err, "failed to parse current version") - } + if err != nil { + up.l.WithError(err).Error("Failed to parse current version") + return nil, errors.Wrap(err, "failed to parse current version") + } - update, err := up.next(*currentVersion, tagsResponse.Results) - if err != nil { - up.l.WithError(err).Error("Failed to get latest minor version") - return nil, errors.Wrap(err, "failed to get latest minor version") - } + update, err := up.next(*currentVersion, tagsResponse.Results) + if err != nil { + up.l.WithError(err).Error("Failed to get latest minor version") + return nil, errors.Wrap(err, "failed to get latest minor version") + } return up.parseDockerTag(update.DockerImage), nil } return nil, errors.New("no tags found") diff --git a/managed/services/server/updater_test.go b/managed/services/server/updater_test.go index f56e2d6c2f..5271a1493f 100644 --- a/managed/services/server/updater_test.go +++ b/managed/services/server/updater_test.go @@ -2,17 +2,18 @@ package server import ( "context" - "github.com/percona/pmm/version" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "net/url" "strings" "testing" "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/version" ) func TestUpdater(t *testing.T) { - gRPCMessageMaxSize := uint32(100 * 1024 * 1024) gaReleaseDate := time.Date(2019, 9, 18, 0, 0, 0, 0, time.UTC) watchtowerURL, _ := url.Parse("http://watchtower:8080") @@ -88,6 +89,39 @@ func TestUpdater(t *testing.T) { }, wantErr: nil, }, + { + name: "new major version with rc version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "percona/pmm-server:4.0.0"}, + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:4.0.0-rc"}, + }, + }, + want: &versionInfo{ + Version: "4.0.0", + DockerImage: "percona/pmm-server:4.0.0", + }, + wantErr: nil, + }, + { + name: "multiple new major versions", + args: args{ + currentVersion: "3.3.0", + results: []result{ + {Name: "percona/pmm-server:4.0.0"}, + {Name: "percona/pmm-server:3.0.0"}, + {Name: "percona/pmm-server:4.1.0"}, + {Name: "percona/pmm-server:5.1.0"}, + }, + }, + want: &versionInfo{ + Version: "4.1.0", + DockerImage: "percona/pmm-server:4.1.0", + }, + wantErr: nil, + }, { name: "new major version with minor version", args: args{ @@ -189,6 +223,7 @@ func TestUpdater(t *testing.T) { }) t.Run("Installed", func(t *testing.T) { + t.Skip("This test is to be deprecated or completely rewritten") checker := NewUpdater(watchtowerURL, gRPCMessageMaxSize) info := checker.InstalledPMMVersion() diff --git a/managed/services/supervisord/devcontainer_test.go b/managed/services/supervisord/devcontainer_test.go index 2c71f50445..0d91c7fb4b 100644 --- a/managed/services/supervisord/devcontainer_test.go +++ b/managed/services/supervisord/devcontainer_test.go @@ -22,14 +22,14 @@ import ( "testing" "time" - "github.com/percona/pmm/managed/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/models" ) // TODO move tests to other files and remove this one. func TestDevContainer(t *testing.T) { - t.Run("UpdateConfiguration", func(t *testing.T) { // logrus.SetLevel(logrus.DebugLevel) vmParams, err := models.NewVictoriaMetricsParams(models.BasePrometheusConfigPath, models.VMBaseURL) diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index 2036914ca7..f91d6bc76e 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -34,12 +34,13 @@ import ( "time" "github.com/AlekSi/pointer" - "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/utils/envvars" - "github.com/percona/pmm/utils/pdeathsig" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/utils/envvars" + "github.com/percona/pmm/utils/pdeathsig" ) const ( @@ -84,7 +85,7 @@ const ( ) // New creates new service. -func New(configDir string, params *models.Params, ) *Service { +func New(configDir string, params *models.Params) *Service { path, _ := exec.LookPath("supervisorctl") return &Service{ configDir: configDir, From 2e7228b12752d2cbc31b2bed67248ff52b1e780f Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 8 Apr 2024 19:26:06 +0300 Subject: [PATCH 17/33] PMM-12762 Add license header. --- managed/services/server/updater_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/managed/services/server/updater_test.go b/managed/services/server/updater_test.go index 5271a1493f..980a4e0ba4 100644 --- a/managed/services/server/updater_test.go +++ b/managed/services/server/updater_test.go @@ -1,3 +1,18 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + package server import ( From 42baca0bcb219ab74f0ae85da65f59edca82ca09 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 15 Apr 2024 14:35:50 +0300 Subject: [PATCH 18/33] PMM-12762 Get notified about new version. --- api-tests/server/updates_test.go | 8 +- .../client/server/check_updates_responses.go | 10 +- api/serverpb/json/serverpb.json | 9 +- api/serverpb/server.pb.go | 948 ++++++++++-------- api/serverpb/server.pb.validate.go | 135 +++ api/serverpb/server.proto | 11 +- api/swagger/swagger-dev.json | 9 +- api/swagger/swagger.json | 9 +- descriptor.bin | Bin 704549 -> 705024 bytes managed/cmd/pmm-managed/main.go | 6 + managed/services/server/deps.go | 8 - managed/services/server/pmm_update_checker.go | 108 -- managed/services/server/server.go | 24 +- managed/services/server/updater.go | 201 ++-- managed/services/server/updater_test.go | 223 ++-- .../services/supervisord/devcontainer_test.go | 72 -- managed/services/supervisord/maintail_test.go | 12 - managed/services/supervisord/pmm_config.go | 16 - .../services/supervisord/supervisord_test.go | 4 +- .../supervisord.d/pmm-db_disabled.ini | 16 - .../testdata/supervisord.d/pmm-db_enabled.ini | 16 - update/main.go | 92 -- update/pkg/yum/info.go | 117 --- update/pkg/yum/info_test.go | 683 ------------- update/pkg/yum/yum.go | 154 --- update/pkg/yum/yum_test.go | 100 -- version/parsed.go | 12 + version/update.go | 15 +- 28 files changed, 924 insertions(+), 2094 deletions(-) delete mode 100644 managed/services/server/pmm_update_checker.go delete mode 100644 update/pkg/yum/info.go delete mode 100644 update/pkg/yum/info_test.go delete mode 100644 update/pkg/yum/yum.go delete mode 100644 update/pkg/yum/yum_test.go diff --git a/api-tests/server/updates_test.go b/api-tests/server/updates_test.go index f4b8c68336..4285182f17 100644 --- a/api-tests/server/updates_test.go +++ b/api-tests/server/updates_test.go @@ -67,7 +67,6 @@ func TestCheckUpdates(t *testing.T) { require.NotEmpty(t, res.Payload.Latest) assert.True(t, strings.HasPrefix(res.Payload.Latest.Version, "2."), "latest.version = %q should have '2.' prefix", res.Payload.Latest.Version) - assert.NotEmpty(t, res.Payload.Latest.FullVersion) require.NotEmpty(t, res.Payload.Latest.Timestamp) ts = time.Time(res.Payload.Latest.Timestamp) hour, min, _ = ts.Clock() @@ -75,12 +74,13 @@ func TestCheckUpdates(t *testing.T) { assert.Zero(t, min, "latest.timestamp should contain only date") if res.Payload.UpdateAvailable { - assert.NotEqual(t, res.Payload.Installed.FullVersion, res.Payload.Latest.FullVersion) + assert.NotEmpty(t, res.Payload.Latest.Tag) + assert.NotEqual(t, res.Payload.Installed.FullVersion, res.Payload.Latest.Version) assert.NotEqual(t, res.Payload.Installed.Timestamp, res.Payload.Latest.Timestamp) assert.True(t, strings.HasPrefix(res.Payload.LatestNewsURL, "https://per.co.na/pmm/2."), "latest_news_url = %q", res.Payload.LatestNewsURL) } else { - assert.Equal(t, res.Payload.Installed.FullVersion, res.Payload.Latest.FullVersion) assert.Equal(t, res.Payload.Installed.Timestamp, res.Payload.Latest.Timestamp) + assert.Empty(t, res.Payload.Installed.FullVersion, res.Payload.Latest.Version) assert.Empty(t, res.Payload.LatestNewsURL, "latest_news_url should be empty") } assert.NotEmpty(t, res.Payload.LastCheck) @@ -108,7 +108,7 @@ func TestCheckUpdates(t *testing.T) { require.NoError(t, err) assert.Equal(t, res.Payload.Installed, resForce.Payload.Installed) - assert.Equal(t, resForce.Payload.Installed.FullVersion != resForce.Payload.Latest.FullVersion, resForce.Payload.UpdateAvailable) + assert.Equal(t, resForce.Payload.Latest.Tag != "", resForce.Payload.UpdateAvailable) assert.NotEqual(t, res.Payload.LastCheck, resForce.Payload.LastCheck) }) } diff --git a/api/serverpb/json/client/server/check_updates_responses.go b/api/serverpb/json/client/server/check_updates_responses.go index 93cda62aae..fb791b2c07 100644 --- a/api/serverpb/json/client/server/check_updates_responses.go +++ b/api/serverpb/json/client/server/check_updates_responses.go @@ -637,17 +637,17 @@ func (o *CheckUpdatesOKBodyInstalled) UnmarshalBinary(b []byte) error { } /* -CheckUpdatesOKBodyLatest VersionInfo describes component version, or PMM Server as a whole. +CheckUpdatesOKBodyLatest check updates OK body latest swagger:model CheckUpdatesOKBodyLatest */ type CheckUpdatesOKBodyLatest struct { - // User-visible version. + // PMM Version. Version string `json:"version,omitempty"` - // Full version for debugging. - FullVersion string `json:"full_version,omitempty"` + // Docker image tag. + Tag string `json:"tag,omitempty"` - // Build or release date. + // Release date. // Format: date-time Timestamp strfmt.DateTime `json:"timestamp,omitempty"` } diff --git a/api/serverpb/json/serverpb.json b/api/serverpb/json/serverpb.json index 3c3baa749c..f425d7fc35 100644 --- a/api/serverpb/json/serverpb.json +++ b/api/serverpb/json/serverpb.json @@ -720,22 +720,21 @@ "x-order": 4 }, "latest": { - "description": "VersionInfo describes component version, or PMM Server as a whole.", "type": "object", "properties": { - "full_version": { - "description": "Full version for debugging.", + "tag": { + "description": "Docker image tag.", "type": "string", "x-order": 1 }, "timestamp": { - "description": "Build or release date.", + "description": "Release date.", "type": "string", "format": "date-time", "x-order": 2 }, "version": { - "description": "User-visible version.", + "description": "PMM Version.", "type": "string", "x-order": 0 } diff --git a/api/serverpb/server.pb.go b/api/serverpb/server.pb.go index ead8dcae93..5798f6e814 100644 --- a/api/serverpb/server.pb.go +++ b/api/serverpb/server.pb.go @@ -484,6 +484,72 @@ func (x *CheckUpdatesRequest) GetOnlyInstalledVersion() bool { return false } +type DockerVersionInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // PMM Version. + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + // Docker image tag. + Tag string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"` + // Release date. + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *DockerVersionInfo) Reset() { + *x = DockerVersionInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_serverpb_server_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DockerVersionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DockerVersionInfo) ProtoMessage() {} + +func (x *DockerVersionInfo) ProtoReflect() protoreflect.Message { + mi := &file_serverpb_server_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DockerVersionInfo.ProtoReflect.Descriptor instead. +func (*DockerVersionInfo) Descriptor() ([]byte, []int) { + return file_serverpb_server_proto_rawDescGZIP(), []int{8} +} + +func (x *DockerVersionInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *DockerVersionInfo) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *DockerVersionInfo) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + type CheckUpdatesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -492,7 +558,7 @@ type CheckUpdatesResponse struct { // Currently installed PMM Server version. Installed *VersionInfo `protobuf:"bytes,1,opt,name=installed,proto3" json:"installed,omitempty"` // Latest available PMM Server version. - Latest *VersionInfo `protobuf:"bytes,2,opt,name=latest,proto3" json:"latest,omitempty"` + Latest *DockerVersionInfo `protobuf:"bytes,2,opt,name=latest,proto3" json:"latest,omitempty"` // True if there is a PMM Server update available. UpdateAvailable bool `protobuf:"varint,3,opt,name=update_available,json=updateAvailable,proto3" json:"update_available,omitempty"` // Latest available PMM Server release announcement URL. @@ -504,7 +570,7 @@ type CheckUpdatesResponse struct { func (x *CheckUpdatesResponse) Reset() { *x = CheckUpdatesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[8] + mi := &file_serverpb_server_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -517,7 +583,7 @@ func (x *CheckUpdatesResponse) String() string { func (*CheckUpdatesResponse) ProtoMessage() {} func (x *CheckUpdatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[8] + mi := &file_serverpb_server_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -530,7 +596,7 @@ func (x *CheckUpdatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckUpdatesResponse.ProtoReflect.Descriptor instead. func (*CheckUpdatesResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{8} + return file_serverpb_server_proto_rawDescGZIP(), []int{9} } func (x *CheckUpdatesResponse) GetInstalled() *VersionInfo { @@ -540,7 +606,7 @@ func (x *CheckUpdatesResponse) GetInstalled() *VersionInfo { return nil } -func (x *CheckUpdatesResponse) GetLatest() *VersionInfo { +func (x *CheckUpdatesResponse) GetLatest() *DockerVersionInfo { if x != nil { return x.Latest } @@ -579,7 +645,7 @@ type StartUpdateRequest struct { func (x *StartUpdateRequest) Reset() { *x = StartUpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[9] + mi := &file_serverpb_server_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -592,7 +658,7 @@ func (x *StartUpdateRequest) String() string { func (*StartUpdateRequest) ProtoMessage() {} func (x *StartUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[9] + mi := &file_serverpb_server_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -605,7 +671,7 @@ func (x *StartUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartUpdateRequest.ProtoReflect.Descriptor instead. func (*StartUpdateRequest) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{9} + return file_serverpb_server_proto_rawDescGZIP(), []int{10} } func (x *StartUpdateRequest) GetNewImage() string { @@ -629,7 +695,7 @@ type StartUpdateResponse struct { func (x *StartUpdateResponse) Reset() { *x = StartUpdateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[10] + mi := &file_serverpb_server_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -642,7 +708,7 @@ func (x *StartUpdateResponse) String() string { func (*StartUpdateResponse) ProtoMessage() {} func (x *StartUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[10] + mi := &file_serverpb_server_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -655,7 +721,7 @@ func (x *StartUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartUpdateResponse.ProtoReflect.Descriptor instead. func (*StartUpdateResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{10} + return file_serverpb_server_proto_rawDescGZIP(), []int{11} } func (x *StartUpdateResponse) GetAuthToken() string { @@ -686,7 +752,7 @@ type UpdateStatusRequest struct { func (x *UpdateStatusRequest) Reset() { *x = UpdateStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[11] + mi := &file_serverpb_server_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -699,7 +765,7 @@ func (x *UpdateStatusRequest) String() string { func (*UpdateStatusRequest) ProtoMessage() {} func (x *UpdateStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[11] + mi := &file_serverpb_server_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -712,7 +778,7 @@ func (x *UpdateStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateStatusRequest.ProtoReflect.Descriptor instead. func (*UpdateStatusRequest) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{11} + return file_serverpb_server_proto_rawDescGZIP(), []int{12} } func (x *UpdateStatusRequest) GetAuthToken() string { @@ -745,7 +811,7 @@ type UpdateStatusResponse struct { func (x *UpdateStatusResponse) Reset() { *x = UpdateStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[12] + mi := &file_serverpb_server_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -758,7 +824,7 @@ func (x *UpdateStatusResponse) String() string { func (*UpdateStatusResponse) ProtoMessage() {} func (x *UpdateStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[12] + mi := &file_serverpb_server_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -771,7 +837,7 @@ func (x *UpdateStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateStatusResponse.ProtoReflect.Descriptor instead. func (*UpdateStatusResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{12} + return file_serverpb_server_proto_rawDescGZIP(), []int{13} } func (x *UpdateStatusResponse) GetLogLines() []string { @@ -812,7 +878,7 @@ type MetricsResolutions struct { func (x *MetricsResolutions) Reset() { *x = MetricsResolutions{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[13] + mi := &file_serverpb_server_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -825,7 +891,7 @@ func (x *MetricsResolutions) String() string { func (*MetricsResolutions) ProtoMessage() {} func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[13] + mi := &file_serverpb_server_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -838,7 +904,7 @@ func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { // Deprecated: Use MetricsResolutions.ProtoReflect.Descriptor instead. func (*MetricsResolutions) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{13} + return file_serverpb_server_proto_rawDescGZIP(), []int{14} } func (x *MetricsResolutions) GetHr() *durationpb.Duration { @@ -879,7 +945,7 @@ type STTCheckIntervals struct { func (x *STTCheckIntervals) Reset() { *x = STTCheckIntervals{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[14] + mi := &file_serverpb_server_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -892,7 +958,7 @@ func (x *STTCheckIntervals) String() string { func (*STTCheckIntervals) ProtoMessage() {} func (x *STTCheckIntervals) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[14] + mi := &file_serverpb_server_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -905,7 +971,7 @@ func (x *STTCheckIntervals) ProtoReflect() protoreflect.Message { // Deprecated: Use STTCheckIntervals.ProtoReflect.Descriptor instead. func (*STTCheckIntervals) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{14} + return file_serverpb_server_proto_rawDescGZIP(), []int{15} } func (x *STTCheckIntervals) GetStandardInterval() *durationpb.Duration { @@ -970,7 +1036,7 @@ type Settings struct { func (x *Settings) Reset() { *x = Settings{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[15] + mi := &file_serverpb_server_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -983,7 +1049,7 @@ func (x *Settings) String() string { func (*Settings) ProtoMessage() {} func (x *Settings) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[15] + mi := &file_serverpb_server_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -996,7 +1062,7 @@ func (x *Settings) ProtoReflect() protoreflect.Message { // Deprecated: Use Settings.ProtoReflect.Descriptor instead. func (*Settings) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{15} + return file_serverpb_server_proto_rawDescGZIP(), []int{16} } func (x *Settings) GetUpdatesDisabled() bool { @@ -1127,7 +1193,7 @@ type GetSettingsRequest struct { func (x *GetSettingsRequest) Reset() { *x = GetSettingsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[16] + mi := &file_serverpb_server_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1140,7 +1206,7 @@ func (x *GetSettingsRequest) String() string { func (*GetSettingsRequest) ProtoMessage() {} func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[16] + mi := &file_serverpb_server_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1153,7 +1219,7 @@ func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsRequest.ProtoReflect.Descriptor instead. func (*GetSettingsRequest) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{16} + return file_serverpb_server_proto_rawDescGZIP(), []int{17} } type GetSettingsResponse struct { @@ -1167,7 +1233,7 @@ type GetSettingsResponse struct { func (x *GetSettingsResponse) Reset() { *x = GetSettingsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[17] + mi := &file_serverpb_server_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1180,7 +1246,7 @@ func (x *GetSettingsResponse) String() string { func (*GetSettingsResponse) ProtoMessage() {} func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[17] + mi := &file_serverpb_server_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1193,7 +1259,7 @@ func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsResponse.ProtoReflect.Descriptor instead. func (*GetSettingsResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{17} + return file_serverpb_server_proto_rawDescGZIP(), []int{18} } func (x *GetSettingsResponse) GetSettings() *Settings { @@ -1247,7 +1313,7 @@ type ChangeSettingsRequest struct { func (x *ChangeSettingsRequest) Reset() { *x = ChangeSettingsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[18] + mi := &file_serverpb_server_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1260,7 +1326,7 @@ func (x *ChangeSettingsRequest) String() string { func (*ChangeSettingsRequest) ProtoMessage() {} func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[18] + mi := &file_serverpb_server_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1273,7 +1339,7 @@ func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsRequest.ProtoReflect.Descriptor instead. func (*ChangeSettingsRequest) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{18} + return file_serverpb_server_proto_rawDescGZIP(), []int{19} } func (x *ChangeSettingsRequest) GetEnableUpdates() bool { @@ -1434,7 +1500,7 @@ type ChangeSettingsResponse struct { func (x *ChangeSettingsResponse) Reset() { *x = ChangeSettingsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[19] + mi := &file_serverpb_server_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1447,7 +1513,7 @@ func (x *ChangeSettingsResponse) String() string { func (*ChangeSettingsResponse) ProtoMessage() {} func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[19] + mi := &file_serverpb_server_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1460,7 +1526,7 @@ func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsResponse.ProtoReflect.Descriptor instead. func (*ChangeSettingsResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{19} + return file_serverpb_server_proto_rawDescGZIP(), []int{20} } func (x *ChangeSettingsResponse) GetSettings() *Settings { @@ -1482,7 +1548,7 @@ type AWSInstanceCheckRequest struct { func (x *AWSInstanceCheckRequest) Reset() { *x = AWSInstanceCheckRequest{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[20] + mi := &file_serverpb_server_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1495,7 +1561,7 @@ func (x *AWSInstanceCheckRequest) String() string { func (*AWSInstanceCheckRequest) ProtoMessage() {} func (x *AWSInstanceCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[20] + mi := &file_serverpb_server_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1508,7 +1574,7 @@ func (x *AWSInstanceCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AWSInstanceCheckRequest.ProtoReflect.Descriptor instead. func (*AWSInstanceCheckRequest) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{20} + return file_serverpb_server_proto_rawDescGZIP(), []int{21} } func (x *AWSInstanceCheckRequest) GetInstanceId() string { @@ -1527,7 +1593,7 @@ type AWSInstanceCheckResponse struct { func (x *AWSInstanceCheckResponse) Reset() { *x = AWSInstanceCheckResponse{} if protoimpl.UnsafeEnabled { - mi := &file_serverpb_server_proto_msgTypes[21] + mi := &file_serverpb_server_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1540,7 +1606,7 @@ func (x *AWSInstanceCheckResponse) String() string { func (*AWSInstanceCheckResponse) ProtoMessage() {} func (x *AWSInstanceCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_serverpb_server_proto_msgTypes[21] + mi := &file_serverpb_server_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1553,7 +1619,7 @@ func (x *AWSInstanceCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AWSInstanceCheckResponse.ProtoReflect.Descriptor instead. func (*AWSInstanceCheckResponse) Descriptor() ([]byte, []int) { - return file_serverpb_server_proto_rawDescGZIP(), []int{21} + return file_serverpb_server_proto_rawDescGZIP(), []int{22} } var File_serverpb_server_proto protoreflect.FileDescriptor @@ -1608,324 +1674,332 @@ var file_serverpb_server_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6f, 0x6e, 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0x84, 0x02, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x2b, - 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x76, 0x61, - 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x5f, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x55, 0x72, 0x6c, 0x12, 0x39, - 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x6c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x22, 0x31, 0x0a, 0x12, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x53, 0x0a, 0x13, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x22, 0x53, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, - 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, - 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x66, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, - 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, - 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, - 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x22, 0x95, - 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x02, 0x68, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x68, 0x72, - 0x12, 0x29, 0x0a, 0x02, 0x6d, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, + 0x6f, 0x6e, 0x22, 0x79, 0x0a, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x74, 0x61, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x8a, 0x02, + 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x6c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x55, 0x72, 0x6c, 0x12, + 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x22, 0x31, 0x0a, 0x12, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x53, 0x0a, + 0x13, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x22, 0x53, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, + 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, + 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x6f, + 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x66, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, + 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x22, + 0x95, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x02, 0x68, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x68, + 0x72, 0x12, 0x29, 0x0a, 0x02, 0x6d, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6d, 0x72, 0x12, 0x29, 0x0a, 0x02, + 0x6c, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6c, 0x72, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x53, 0x54, 0x54, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x46, 0x0a, + 0x11, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6d, 0x72, 0x12, 0x29, 0x0a, 0x02, 0x6c, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x02, 0x6c, 0x72, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x53, 0x54, 0x54, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x46, 0x0a, 0x11, - 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x72, 0x61, 0x72, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x46, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xe7, 0x06, + 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x10, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x10, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x72, 0x61, 0x72, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x12, 0x46, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x66, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xe7, 0x06, 0x0a, - 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x10, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x72, 0x65, 0x73, - 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, - 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, - 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x77, 0x73, - 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x74, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x6c, 0x65, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x3a, 0x0a, 0x19, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x17, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x7a, 0x75, 0x72, - 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x32, 0x0a, - 0x15, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x73, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, - 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x4a, 0x04, - 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, - 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x22, 0xce, 0x08, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1c, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x72, - 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, - 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x74, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, - 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x74, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, - 0x74, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, - 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, - 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x13, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x70, - 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, - 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, - 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x18, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x34, 0x0a, 0x16, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, - 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, - 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, - 0x10, 0x13, 0x22, 0x46, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x43, 0x0a, 0x17, 0x41, 0x57, - 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, - 0x1a, 0x0a, 0x18, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x66, 0x0a, 0x12, 0x44, - 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, 0x01, 0x12, 0x07, - 0x0a, 0x03, 0x4f, 0x56, 0x46, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4d, 0x49, 0x10, 0x03, - 0x12, 0x09, 0x0a, 0x05, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, 0x06, 0x0a, 0x02, 0x44, - 0x4f, 0x10, 0x05, 0x32, 0xe5, 0x0c, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x79, - 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x92, 0x41, 0x27, 0x12, - 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, - 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x9e, 0x02, 0x0a, 0x09, 0x52, 0x65, - 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, - 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdb, 0x01, 0x92, - 0x41, 0xc5, 0x01, 0x12, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x1a, 0xaa, 0x01, 0x52, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x77, - 0x68, 0x65, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x79, 0x20, 0x79, 0x65, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, - 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x20, 0x6f, 0x66, - 0x20, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x62, 0x69, - 0x6e, 0x67, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, - 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x7a, 0x12, 0xf7, 0x01, 0x0a, 0x11, 0x4c, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x12, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x92, 0x41, 0x79, 0x12, 0x10, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x20, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x65, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x20, 0x69, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, - 0x76, 0x31, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa3, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x58, 0x92, 0x41, 0x39, 0x12, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x1a, 0x28, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x2f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x90, 0x01, 0x0a, 0x0b, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x48, 0x92, 0x41, 0x29, 0x12, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x19, 0x53, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x50, - 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x9d, 0x01, - 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x32, 0x12, 0x0d, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x21, 0x52, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x9a, 0x01, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x34, 0x12, 0x0c, 0x47, 0x65, 0x74, - 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x24, 0x52, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x47, 0x65, 0x74, 0x12, 0xa1, 0x01, 0x0a, 0x0e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1d, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50, 0x92, 0x41, - 0x2f, 0x12, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x1a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, + 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x77, + 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x74, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x6c, 0x65, + 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x3a, 0x0a, + 0x19, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x17, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x7a, 0x75, + 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x32, + 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x12, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x4a, + 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0d, 0x10, + 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, + 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x22, 0xce, 0x08, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x12, 0x4b, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, + 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x12, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x40, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, + 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, + 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x74, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, + 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x53, 0x74, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, + 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, + 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x50, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x49, 0x0a, 0x13, 0x73, 0x74, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x54, 0x54, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x73, 0x74, 0x74, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x33, + 0x0a, 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3a, 0x0a, + 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x34, 0x0a, + 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, + 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0f, 0x10, + 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, + 0x12, 0x10, 0x13, 0x22, 0x46, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, + 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x43, 0x0a, 0x17, 0x41, + 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, + 0x22, 0x1a, 0x0a, 0x18, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x66, 0x0a, 0x12, + 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, + 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, 0x01, 0x12, + 0x07, 0x0a, 0x03, 0x4f, 0x56, 0x46, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4d, 0x49, 0x10, + 0x03, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, 0x06, 0x0a, 0x02, + 0x44, 0x4f, 0x10, 0x05, 0x32, 0xe5, 0x0c, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, + 0x79, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x92, 0x41, 0x27, + 0x12, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, + 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x9e, 0x02, 0x0a, 0x09, 0x52, + 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, + 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdb, 0x01, + 0x92, 0x41, 0xc5, 0x01, 0x12, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x1a, 0xaa, 0x01, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, + 0x77, 0x68, 0x65, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x79, 0x20, 0x79, 0x65, 0x74, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x20, 0x6f, + 0x66, 0x20, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x62, + 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, + 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x7a, 0x12, 0xf7, 0x01, 0x0a, 0x11, + 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x12, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x92, 0x41, 0x79, 0x12, 0x10, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x20, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x65, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x2e, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, + 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa3, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x58, 0x92, 0x41, 0x39, 0x12, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x28, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x50, 0x4d, 0x4d, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x90, 0x01, 0x0a, 0x0b, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x92, 0x41, 0x29, 0x12, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x19, 0x53, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, + 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, + 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x9d, + 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x32, 0x12, + 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x21, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x9a, + 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x92, 0x41, 0x34, 0x12, 0x0c, 0x47, 0x65, + 0x74, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x24, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x50, 0x4d, 0x4d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0xaa, - 0x01, 0x0a, 0x10, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x57, 0x53, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x57, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x47, 0x65, 0x74, 0x12, 0xa1, 0x01, 0x0a, 0x0e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1d, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50, 0x92, + 0x41, 0x2f, 0x12, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x1a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x50, 0x4d, 0x4d, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, + 0xaa, 0x01, 0x0a, 0x10, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x92, 0x41, 0x31, 0x12, 0x12, 0x41, 0x57, 0x53, - 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x1a, - 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x41, 0x57, 0x53, 0x20, 0x45, 0x43, 0x32, 0x20, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x49, 0x44, 0x2e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x41, 0x57, 0x53, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x76, 0x0a, 0x0a, 0x63, - 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0xa2, 0x02, 0x03, - 0x53, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, 0x02, 0x06, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, + 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x92, 0x41, 0x31, 0x12, 0x12, 0x41, 0x57, + 0x53, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x1a, 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x20, 0x41, 0x57, 0x53, 0x20, 0x45, 0x43, 0x32, + 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x49, 0x44, 0x2e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x41, 0x57, 0x53, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x76, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x0b, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, + 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0xa2, 0x02, + 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, 0x02, 0x06, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1942,7 +2016,7 @@ func file_serverpb_server_proto_rawDescGZIP() []byte { var ( file_serverpb_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) - file_serverpb_server_proto_msgTypes = make([]protoimpl.MessageInfo, 22) + file_serverpb_server_proto_msgTypes = make([]protoimpl.MessageInfo, 23) file_serverpb_server_proto_goTypes = []interface{}{ (DistributionMethod)(0), // 0: server.DistributionMethod (*VersionInfo)(nil), // 1: server.VersionInfo @@ -1953,70 +2027,72 @@ var ( (*LeaderHealthCheckRequest)(nil), // 6: server.LeaderHealthCheckRequest (*LeaderHealthCheckResponse)(nil), // 7: server.LeaderHealthCheckResponse (*CheckUpdatesRequest)(nil), // 8: server.CheckUpdatesRequest - (*CheckUpdatesResponse)(nil), // 9: server.CheckUpdatesResponse - (*StartUpdateRequest)(nil), // 10: server.StartUpdateRequest - (*StartUpdateResponse)(nil), // 11: server.StartUpdateResponse - (*UpdateStatusRequest)(nil), // 12: server.UpdateStatusRequest - (*UpdateStatusResponse)(nil), // 13: server.UpdateStatusResponse - (*MetricsResolutions)(nil), // 14: server.MetricsResolutions - (*STTCheckIntervals)(nil), // 15: server.STTCheckIntervals - (*Settings)(nil), // 16: server.Settings - (*GetSettingsRequest)(nil), // 17: server.GetSettingsRequest - (*GetSettingsResponse)(nil), // 18: server.GetSettingsResponse - (*ChangeSettingsRequest)(nil), // 19: server.ChangeSettingsRequest - (*ChangeSettingsResponse)(nil), // 20: server.ChangeSettingsResponse - (*AWSInstanceCheckRequest)(nil), // 21: server.AWSInstanceCheckRequest - (*AWSInstanceCheckResponse)(nil), // 22: server.AWSInstanceCheckResponse - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 24: google.protobuf.Duration + (*DockerVersionInfo)(nil), // 9: server.DockerVersionInfo + (*CheckUpdatesResponse)(nil), // 10: server.CheckUpdatesResponse + (*StartUpdateRequest)(nil), // 11: server.StartUpdateRequest + (*StartUpdateResponse)(nil), // 12: server.StartUpdateResponse + (*UpdateStatusRequest)(nil), // 13: server.UpdateStatusRequest + (*UpdateStatusResponse)(nil), // 14: server.UpdateStatusResponse + (*MetricsResolutions)(nil), // 15: server.MetricsResolutions + (*STTCheckIntervals)(nil), // 16: server.STTCheckIntervals + (*Settings)(nil), // 17: server.Settings + (*GetSettingsRequest)(nil), // 18: server.GetSettingsRequest + (*GetSettingsResponse)(nil), // 19: server.GetSettingsResponse + (*ChangeSettingsRequest)(nil), // 20: server.ChangeSettingsRequest + (*ChangeSettingsResponse)(nil), // 21: server.ChangeSettingsResponse + (*AWSInstanceCheckRequest)(nil), // 22: server.AWSInstanceCheckRequest + (*AWSInstanceCheckResponse)(nil), // 23: server.AWSInstanceCheckResponse + (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 25: google.protobuf.Duration } ) var file_serverpb_server_proto_depIdxs = []int32{ - 23, // 0: server.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 24, // 0: server.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.VersionResponse.server:type_name -> server.VersionInfo 1, // 2: server.VersionResponse.managed:type_name -> server.VersionInfo 0, // 3: server.VersionResponse.distribution_method:type_name -> server.DistributionMethod - 1, // 4: server.CheckUpdatesResponse.installed:type_name -> server.VersionInfo - 1, // 5: server.CheckUpdatesResponse.latest:type_name -> server.VersionInfo - 23, // 6: server.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp - 24, // 7: server.MetricsResolutions.hr:type_name -> google.protobuf.Duration - 24, // 8: server.MetricsResolutions.mr:type_name -> google.protobuf.Duration - 24, // 9: server.MetricsResolutions.lr:type_name -> google.protobuf.Duration - 24, // 10: server.STTCheckIntervals.standard_interval:type_name -> google.protobuf.Duration - 24, // 11: server.STTCheckIntervals.rare_interval:type_name -> google.protobuf.Duration - 24, // 12: server.STTCheckIntervals.frequent_interval:type_name -> google.protobuf.Duration - 14, // 13: server.Settings.metrics_resolutions:type_name -> server.MetricsResolutions - 24, // 14: server.Settings.data_retention:type_name -> google.protobuf.Duration - 15, // 15: server.Settings.stt_check_intervals:type_name -> server.STTCheckIntervals - 16, // 16: server.GetSettingsResponse.settings:type_name -> server.Settings - 14, // 17: server.ChangeSettingsRequest.metrics_resolutions:type_name -> server.MetricsResolutions - 24, // 18: server.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration - 15, // 19: server.ChangeSettingsRequest.stt_check_intervals:type_name -> server.STTCheckIntervals - 16, // 20: server.ChangeSettingsResponse.settings:type_name -> server.Settings - 2, // 21: server.Server.Version:input_type -> server.VersionRequest - 4, // 22: server.Server.Readiness:input_type -> server.ReadinessRequest - 6, // 23: server.Server.LeaderHealthCheck:input_type -> server.LeaderHealthCheckRequest - 8, // 24: server.Server.CheckUpdates:input_type -> server.CheckUpdatesRequest - 10, // 25: server.Server.StartUpdate:input_type -> server.StartUpdateRequest - 12, // 26: server.Server.UpdateStatus:input_type -> server.UpdateStatusRequest - 17, // 27: server.Server.GetSettings:input_type -> server.GetSettingsRequest - 19, // 28: server.Server.ChangeSettings:input_type -> server.ChangeSettingsRequest - 21, // 29: server.Server.AWSInstanceCheck:input_type -> server.AWSInstanceCheckRequest - 3, // 30: server.Server.Version:output_type -> server.VersionResponse - 5, // 31: server.Server.Readiness:output_type -> server.ReadinessResponse - 7, // 32: server.Server.LeaderHealthCheck:output_type -> server.LeaderHealthCheckResponse - 9, // 33: server.Server.CheckUpdates:output_type -> server.CheckUpdatesResponse - 11, // 34: server.Server.StartUpdate:output_type -> server.StartUpdateResponse - 13, // 35: server.Server.UpdateStatus:output_type -> server.UpdateStatusResponse - 18, // 36: server.Server.GetSettings:output_type -> server.GetSettingsResponse - 20, // 37: server.Server.ChangeSettings:output_type -> server.ChangeSettingsResponse - 22, // 38: server.Server.AWSInstanceCheck:output_type -> server.AWSInstanceCheckResponse - 30, // [30:39] is the sub-list for method output_type - 21, // [21:30] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 24, // 4: server.DockerVersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 1, // 5: server.CheckUpdatesResponse.installed:type_name -> server.VersionInfo + 9, // 6: server.CheckUpdatesResponse.latest:type_name -> server.DockerVersionInfo + 24, // 7: server.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp + 25, // 8: server.MetricsResolutions.hr:type_name -> google.protobuf.Duration + 25, // 9: server.MetricsResolutions.mr:type_name -> google.protobuf.Duration + 25, // 10: server.MetricsResolutions.lr:type_name -> google.protobuf.Duration + 25, // 11: server.STTCheckIntervals.standard_interval:type_name -> google.protobuf.Duration + 25, // 12: server.STTCheckIntervals.rare_interval:type_name -> google.protobuf.Duration + 25, // 13: server.STTCheckIntervals.frequent_interval:type_name -> google.protobuf.Duration + 15, // 14: server.Settings.metrics_resolutions:type_name -> server.MetricsResolutions + 25, // 15: server.Settings.data_retention:type_name -> google.protobuf.Duration + 16, // 16: server.Settings.stt_check_intervals:type_name -> server.STTCheckIntervals + 17, // 17: server.GetSettingsResponse.settings:type_name -> server.Settings + 15, // 18: server.ChangeSettingsRequest.metrics_resolutions:type_name -> server.MetricsResolutions + 25, // 19: server.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration + 16, // 20: server.ChangeSettingsRequest.stt_check_intervals:type_name -> server.STTCheckIntervals + 17, // 21: server.ChangeSettingsResponse.settings:type_name -> server.Settings + 2, // 22: server.Server.Version:input_type -> server.VersionRequest + 4, // 23: server.Server.Readiness:input_type -> server.ReadinessRequest + 6, // 24: server.Server.LeaderHealthCheck:input_type -> server.LeaderHealthCheckRequest + 8, // 25: server.Server.CheckUpdates:input_type -> server.CheckUpdatesRequest + 11, // 26: server.Server.StartUpdate:input_type -> server.StartUpdateRequest + 13, // 27: server.Server.UpdateStatus:input_type -> server.UpdateStatusRequest + 18, // 28: server.Server.GetSettings:input_type -> server.GetSettingsRequest + 20, // 29: server.Server.ChangeSettings:input_type -> server.ChangeSettingsRequest + 22, // 30: server.Server.AWSInstanceCheck:input_type -> server.AWSInstanceCheckRequest + 3, // 31: server.Server.Version:output_type -> server.VersionResponse + 5, // 32: server.Server.Readiness:output_type -> server.ReadinessResponse + 7, // 33: server.Server.LeaderHealthCheck:output_type -> server.LeaderHealthCheckResponse + 10, // 34: server.Server.CheckUpdates:output_type -> server.CheckUpdatesResponse + 12, // 35: server.Server.StartUpdate:output_type -> server.StartUpdateResponse + 14, // 36: server.Server.UpdateStatus:output_type -> server.UpdateStatusResponse + 19, // 37: server.Server.GetSettings:output_type -> server.GetSettingsResponse + 21, // 38: server.Server.ChangeSettings:output_type -> server.ChangeSettingsResponse + 23, // 39: server.Server.AWSInstanceCheck:output_type -> server.AWSInstanceCheckResponse + 31, // [31:40] is the sub-list for method output_type + 22, // [22:31] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_serverpb_server_proto_init() } @@ -2122,7 +2198,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckUpdatesResponse); i { + switch v := v.(*DockerVersionInfo); i { case 0: return &v.state case 1: @@ -2134,7 +2210,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StartUpdateRequest); i { + switch v := v.(*CheckUpdatesResponse); i { case 0: return &v.state case 1: @@ -2146,7 +2222,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StartUpdateResponse); i { + switch v := v.(*StartUpdateRequest); i { case 0: return &v.state case 1: @@ -2158,7 +2234,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateStatusRequest); i { + switch v := v.(*StartUpdateResponse); i { case 0: return &v.state case 1: @@ -2170,7 +2246,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateStatusResponse); i { + switch v := v.(*UpdateStatusRequest); i { case 0: return &v.state case 1: @@ -2182,7 +2258,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MetricsResolutions); i { + switch v := v.(*UpdateStatusResponse); i { case 0: return &v.state case 1: @@ -2194,7 +2270,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*STTCheckIntervals); i { + switch v := v.(*MetricsResolutions); i { case 0: return &v.state case 1: @@ -2206,7 +2282,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Settings); i { + switch v := v.(*STTCheckIntervals); i { case 0: return &v.state case 1: @@ -2218,7 +2294,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSettingsRequest); i { + switch v := v.(*Settings); i { case 0: return &v.state case 1: @@ -2230,7 +2306,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSettingsResponse); i { + switch v := v.(*GetSettingsRequest); i { case 0: return &v.state case 1: @@ -2242,7 +2318,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChangeSettingsRequest); i { + switch v := v.(*GetSettingsResponse); i { case 0: return &v.state case 1: @@ -2254,7 +2330,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChangeSettingsResponse); i { + switch v := v.(*ChangeSettingsRequest); i { case 0: return &v.state case 1: @@ -2266,7 +2342,7 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AWSInstanceCheckRequest); i { + switch v := v.(*ChangeSettingsResponse); i { case 0: return &v.state case 1: @@ -2278,6 +2354,18 @@ func file_serverpb_server_proto_init() { } } file_serverpb_server_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AWSInstanceCheckRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_serverpb_server_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AWSInstanceCheckResponse); i { case 0: return &v.state @@ -2296,7 +2384,7 @@ func file_serverpb_server_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_serverpb_server_proto_rawDesc, NumEnums: 1, - NumMessages: 22, + NumMessages: 23, NumExtensions: 0, NumServices: 1, }, diff --git a/api/serverpb/server.pb.validate.go b/api/serverpb/server.pb.validate.go index 3bba154397..7b80039780 100644 --- a/api/serverpb/server.pb.validate.go +++ b/api/serverpb/server.pb.validate.go @@ -943,6 +943,141 @@ var _ interface { ErrorName() string } = CheckUpdatesRequestValidationError{} +// Validate checks the field values on DockerVersionInfo 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 *DockerVersionInfo) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DockerVersionInfo 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 +// DockerVersionInfoMultiError, or nil if none found. +func (m *DockerVersionInfo) ValidateAll() error { + return m.validate(true) +} + +func (m *DockerVersionInfo) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Version + + // no validation rules for Tag + + if all { + switch v := interface{}(m.GetTimestamp()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, DockerVersionInfoValidationError{ + field: "Timestamp", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, DockerVersionInfoValidationError{ + field: "Timestamp", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetTimestamp()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return DockerVersionInfoValidationError{ + field: "Timestamp", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return DockerVersionInfoMultiError(errors) + } + + return nil +} + +// DockerVersionInfoMultiError is an error wrapping multiple validation errors +// returned by DockerVersionInfo.ValidateAll() if the designated constraints +// aren't met. +type DockerVersionInfoMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DockerVersionInfoMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DockerVersionInfoMultiError) AllErrors() []error { return m } + +// DockerVersionInfoValidationError is the validation error returned by +// DockerVersionInfo.Validate if the designated constraints aren't met. +type DockerVersionInfoValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DockerVersionInfoValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DockerVersionInfoValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DockerVersionInfoValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DockerVersionInfoValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DockerVersionInfoValidationError) ErrorName() string { + return "DockerVersionInfoValidationError" +} + +// Error satisfies the builtin error interface +func (e DockerVersionInfoValidationError) 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 %sDockerVersionInfo.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = DockerVersionInfoValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DockerVersionInfoValidationError{} + // Validate checks the field values on CheckUpdatesResponse 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/serverpb/server.proto b/api/serverpb/server.proto index 629d06b9a8..284d2ed481 100644 --- a/api/serverpb/server.proto +++ b/api/serverpb/server.proto @@ -66,11 +66,20 @@ message CheckUpdatesRequest { bool only_installed_version = 2; } +message DockerVersionInfo { + // PMM Version. + string version = 1; + // Docker image tag. + string tag = 2; + // Release date. + google.protobuf.Timestamp timestamp = 3; +} + message CheckUpdatesResponse { // Currently installed PMM Server version. VersionInfo installed = 1; // Latest available PMM Server version. - VersionInfo latest = 2; + DockerVersionInfo latest = 2; // True if there is a PMM Server update available. bool update_available = 3; // Latest available PMM Server release announcement URL. diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 022804ab9e..4138831107 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -3558,21 +3558,20 @@ "x-order": 0 }, "latest": { - "description": "VersionInfo describes component version, or PMM Server as a whole.", "type": "object", "properties": { "version": { - "description": "User-visible version.", + "description": "PMM Version.", "type": "string", "x-order": 0 }, - "full_version": { - "description": "Full version for debugging.", + "tag": { + "description": "Docker image tag.", "type": "string", "x-order": 1 }, "timestamp": { - "description": "Build or release date.", + "description": "Release date.", "type": "string", "format": "date-time", "x-order": 2 diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 1c94bfe76a..2bf78a2b0a 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -714,21 +714,20 @@ "x-order": 0 }, "latest": { - "description": "VersionInfo describes component version, or PMM Server as a whole.", "type": "object", "properties": { "version": { - "description": "User-visible version.", + "description": "PMM Version.", "type": "string", "x-order": 0 }, - "full_version": { - "description": "Full version for debugging.", + "tag": { + "description": "Docker image tag.", "type": "string", "x-order": 1 }, "timestamp": { - "description": "Build or release date.", + "description": "Release date.", "type": "string", "format": "date-time", "x-order": 2 diff --git a/descriptor.bin b/descriptor.bin index 353a1e60c3ea368c699ab88e230f6d4fca515127..7b7ff4d9aebb8bc9a0d9a9e2f2eda82ed7c1ec5d 100644 GIT binary patch delta 6231 zcmZu#eQcH09lpPF-@f6#dtWq5`p5g6 z^Lu{hIbXl$^zK`E$I4FpQK#sPcRHO#oo;8MGufHyk;k5mpI%8vPCP69cfQF{#@Ta=eBJZWu>QbwmQ9D|?EsaZa9ZPjUaYLU`9l7>p zx%N>u#h5m^r(v}8<}Ph)UpjBeGl-p&d+vD9q9?7N_ zk`XgfB{mr$+0?R(tkKDY7oRSMXUl>)xt3gGM=s#$7ZM4VyQ?izAkXxgx)34H^r6Er zPvN9IXJ+hsX3i-@rDrB<Xi_cdtt&!FFlyIPMzFjCF zu;$kcwk!v%`NM|mg_54LAohe=D2b>A$*e3!Hp%O>P#Adt5V6pT07Brxl&8}HA>G2t zUOHW|=R6sEy2j)yM%a_dYWV>26?48tqAEK^U0N$ERry*uupW)byU6AR0%1|gEGrQ5 zF6z}=4%BpXEmqa*WZk62g?L{0#f5l2M~e~9`(NTYx!CuOj1olUAY%~nl(38@bz!Xx z>hX=yn`|~9#5LJ$K*-i)M=#;MYUa^v^Y{j@=~Xto+kJ*OqsVKkH?ss%@I z05p`chE@?|D}zVc+nU;Q9UVbSTT{@|+?wmKCmk`^%~oM9BM`=HEiRWOb-0^=NY{#D zz&8~LgSPgomE(1CbS+Vzu9IWyOSRM`Rw@v8S*bu^ErHabnuT-Pt|qOQgTUf*+HTJ& z5LoSrVmlU})An?koQFkDd(N`hi>hnAob9C%wG3xx8nUH%g3Hyd_42`beB&f87v^>V zA#QnfU!4sI*_H?WDjl)s?*C$jF6)> zS$NJ*NG;eThZ-{GgoXkclL9P^j9CF<d0Ht0|e0eHoxA zu2ElYlG%JFg$b^q;u0+Z2ywSVXwa|(iZZC5K-hDhI?%VEjzzDD)u`OJu`G5CMbP$+ zv%%25hAMm8V3f9RKpl);UegTk$a?kBW;tvOzKZ||CsZrqGX;oJY9Z3DC)83yMCV2| zc#9mC&+vV4Hbz9A%0^05St4)5MnXB&QxO<{6N!*x_9E!Xj!EhH*!rvt@+$q<6Nh2Xcy>c?09^G*cGjs3t|@~ zJWF&z>>||vC-puhJZBq;zS&3Ab5ErDDDj%S4?C7X3N(k)NFc>FN`*U?K#FaYt&t;i zilpakSI@mBhk}>{aeFj2-YKi$YAZSg z;tuK;=sTAYaKW8w+AcW~M2V^IB$&HdCYT~%#gGt!xRZvDkay`3;di^$%UyCbh{YIj zcO(_=2bc)gw;06TG_X!KXd(=1kNToZjsmd+#61xaeg&AQu_Km%xQA-{%ZZu@SJ|tk zD|tVNr6BH&h%gzz0+Y2{@g9*6{R5j_wIC1~ekD?>$sy3Xz|}v+x^G$D-H7VvBmHrk~Br<>GcIyu86C7z^A(!2lb~ zCE|9d6QkF}qD1u2pusklYr*YM$D&uq@;)9Wykq%b_`2`|n!=w42KO)}OtA#SQXJ;# z87?}HkTCbi*R>zeZ~=91!Y&)Xh7jDx93P)+|Ivtw2NA=N%KLGY5_wa;5De~7HXJi7 z&@og%D;dvsh9Q@?=U8YtzQ6+>&{~ddDY?0Kq&-)^U8U^`}C|0YV-?Q>p<$Jrz0*AgHH8$MFTW z@^t7pK+q33!Q3-oq&gke6+omq9XbvmQk`bU8KLE)>Yq_hy^gBy>#BbyS~RZuXDDHu z3%wwo;S>rSZ9JyTvTuEk^?|wpST!FV4t{1iSSmlPh4d6Lo^XSaY=o>OAZ8)ed1C? zWS_Vc8Vq_tyhJdVVVVf1xU3%CE$cum2k~-5WaGF@iCViP<^+3;?;=A#&I>0%9r&jOErsA;W^jT z<8R0T*xCvZuSLWP5U)`ptREF1UgOHj-c;eaA5-kl)|)u;V@meZyI#Si@{`c=fUsA9 z<|G3m_LI=@0Fm_*cDy=HTj{xby*%eLiVf86-3ysMqhuhb zNa4mj_jAJUSCpL)%+pn%MF>#pnmEh&V*NES#Sry%7<&B5b1(!BMXYXKg`5T#K+xM(AhCqn}^1l4OXeC^T*cYt?8~VOzC0wN6 zFPyguB3vuNHX0Eebx=5O7eu&Pgl)oeA1jgY+-@O`LBz;FojM@L<-3KeO9gjAM7O9M zZnuM<0^Q=S8FoAHj&R=9e^NN_7epkj2-|2xaMT&${H7oxsYRHk e#qN^!wxw-jV4k9YjVMDFPyyQUoa_gb*5SERDv{nzo@fZD?zg8cf>sTl?&D4))iaZ?E<3 z_3g*`)|tDmII4TysC7jus$#mRizUUNm?>t9x%c_R67{F&dp}shHEAl^8SOlybQA~A zELhpLVr4&Nm$h@f{Y5+PsH8ii|Y!i=Z$tnVGddwpUR@8bPfj7NxKfcTHlu18mC%nvefTc6w$4ci+dRA(H+ol|nW@YQ~tTY=vJN0O|eT?zh*#@49A}rfC z$DZxrJ6rG!X>+_ZAmq)-)wm)+C^Dx{UmoIE2+g%)U*V?dtO%^RF-taYZp@O+n+uj` zC^h=A)Z?LsQe-^_4MQSa=Wp>6Htfp_5rTIZT!?6%*x3_QM2f&iopgm@Z^7fb|%G<%3?pRR1%pTst_kyLsS{AcJ z`LdWL%9lBo(iKLpN}!>!yjUS3{c%(~jo3WVI% z4Wr!(fH3RoaVaRpgPB{B=yDjp!uIiuH+>NmJ5|8U#V_UGCb z<)3`I?U_X@AD-_tWQ^{xAMW7CK+J&Hk%-TL*g?7I zoH8JGP<^9&vno~A=uX>ec{qq!5Id8K=)r*T0cSz%6yiu%5%0hjyLm4U12G5UmZT!O z5@4>uOU;3}g$CyNW=BMy+O}gSj{%Rd-fg7(eOBmNfVDSy9)q`yMvms&91p!^yM1CO z-wa|Y3T{u7qSXLqqD?IYaXSrZ=35*QZNb`eJ9#XKWgyywh%Nz`Y4jD#K(y2}i0^Sk z`0y^Wf%~v0xepbXXAi~K0R{?2MA_E2bKj?D3otm6O)!{1zxu=M{gr5h_y%ahQzF?VOwQYLgqKy1Z9SzgFR z@TX`Vo-1Y#7;=q#8v$ngw#mm4VE^#y7%}@p300gFFrvzN9HLAibS@-=dq_G=SQhAA zQUiQhd~yqnxNd`!lnX-Jq8fe!%>d`tO571G?^DjE|`cs zYW3^IQ}Wun|^?25Kkrh zERKIF>P?7(cuIOxc&Fg_r%4U-$0?o<7~LuH{L@jFF-koDv~(G1YevEI&$zaRN1XJT zsI38lcP46UfZ&~xwl>W1;PGc|@eLk~MT*CtO$v&~pQTLnR*J`;6|M3$Z4}Jm|Zan!80Iu zq+X8h93V0;Q!X?ZKumg>@N`$&GQ4Sf|Ln9C;WUu^^@|m+m=7qwmiQAf9&D?Ji&ZU*$VmfBuGJ7aD~(#?brMH zw!#$(%B8T3qskSkaKd$5~7EL^3){lg=1h`35s?$b>mL|mm&cX|;75q~Cq zs~16Dgc}M)AS3va^j~8Uq(y`u`mWQUOmL0V*U)f(zO`+^BKw!OxV3PN0@qnkRr=61 z>eu3{N~5_(lON%*1lmRLchX;>M2*`E70QSPldOM{{&y@yIU#=N0VgDFg6pJSQ0e-K zdHep`e9z?T_)peXO+&>xU+~vPdZ^)nVHY@Px@l6*z-O35|+HWrlhI8WoFb+%#Vi9uurrdIM$-m#uBf z0aTRnjY_{9SJbYeAHpwAn7PCRol5PrO+9?~NUL!s|g3U^A ziz}AcFQlT3zpAv2E0(y5erTGj7?@zUQg7N%d-$Hh?qrPtD(+6!D1CKzvc>>2?@{{o zxMJXs)(?h9D_LDi?~CgPuD&0_7dKX%F+sOd@8W33. - -package server - -import ( - "bytes" - "context" - "encoding/json" - "os/exec" - "strings" - "sync" - "time" - - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" - - "github.com/percona/pmm/utils/pdeathsig" - "github.com/percona/pmm/version" -) - -const ( - updateCheckInterval = 24 * time.Hour - updateCheckResultFresh = updateCheckInterval + 10*time.Minute - updateDefaultTimeout = 30 * time.Second -) - -// PMMUpdateChecker wraps `pmm-update -installed` and `pmm-update -check` with caching. -// -// We almost could use `supervisorctl start pmm-update-check` and then get output from stdout log file, -// but that is too painful, and, unlike with `pmm-update -perform`, we don't have to do it. -type PMMUpdateChecker struct { - l *logrus.Entry - - checkRW sync.RWMutex - installedRW sync.RWMutex - cmdMutex sync.Mutex - lastInstalledPackageInfo *version.PackageInfo - lastCheckResult *version.UpdateCheckResult - lastCheckTime time.Time -} - -// NewPMMUpdateChecker returns a PMMUpdateChecker instance that can be shared across different parts of the code. -// Since this is used inside this package, it could be a singleton, but it would make things mode difficult to test. -func NewPMMUpdateChecker() *PMMUpdateChecker { - return &PMMUpdateChecker{ - l: logrus.WithField("component", "pmm-update-checker"), - } -} - -// Installed returns currently installed version information. -// It is always cached since pmm-update RPM package is always updated before pmm-managed update/restart. -func (p *PMMUpdateChecker) Installed(ctx context.Context) *version.PackageInfo { - p.installedRW.RLock() - if p.lastInstalledPackageInfo != nil { - res := p.lastInstalledPackageInfo - p.installedRW.RUnlock() - return res - } - p.installedRW.RUnlock() - - // use -installed since it is much faster - cmdLine := "pmm-update -installed" - b, stderr, err := p.cmdRun(ctx, cmdLine) - if err != nil { - p.l.Errorf("%s output: %s. Error: %s", cmdLine, stderr.Bytes(), err) - return nil - } - - var res version.UpdateInstalledResult - if err = json.Unmarshal(b, &res); err != nil { - p.l.Errorf("%s output: %s", cmdLine, stderr.Bytes()) - return nil - } - - p.installedRW.Lock() - p.lastInstalledPackageInfo = &res.Installed - p.installedRW.Unlock() - - return &res.Installed -} - -func (p *PMMUpdateChecker) cmdRun(ctx context.Context, cmdLine string) ([]byte, bytes.Buffer, error) { - args := strings.Split(cmdLine, " ") - p.cmdMutex.Lock() - timeoutCtx, cancel := context.WithTimeout(ctx, updateDefaultTimeout) - defer cancel() - cmd := exec.CommandContext(timeoutCtx, args[0], args[1:]...) //nolint:gosec - var stderr bytes.Buffer - cmd.Stderr = &stderr - pdeathsig.Set(cmd, unix.SIGKILL) - - b, err := cmd.Output() - p.cmdMutex.Unlock() - return b, stderr, err -} diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 1e2828e9d0..b54dd67cc4 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -241,7 +241,14 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesReq s.envRW.RUnlock() if req.OnlyInstalledVersion { - return s.updater.onlyInstalledVersionResponse(), nil + installedPMMVersion := s.updater.InstalledPMMVersion() + return &serverpb.CheckUpdatesResponse{ + Installed: &serverpb.VersionInfo{ + Version: installedPMMVersion.Version, + FullVersion: installedPMMVersion.FullVersion, + Timestamp: timestamppb.New(*installedPMMVersion.BuildTime), + }, + }, nil } if req.Force { @@ -259,12 +266,13 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesReq Installed: &serverpb.VersionInfo{ Version: v.Installed.Version, FullVersion: v.Installed.FullVersion, + Timestamp: timestamppb.New(*v.Installed.BuildTime), }, - Latest: &serverpb.VersionInfo{ - Version: v.Latest.Version, - FullVersion: v.Latest.FullVersion, + Latest: &serverpb.DockerVersionInfo{ + Version: v.Latest.Version.String(), + Tag: v.Latest.DockerImage, }, - UpdateAvailable: true, + UpdateAvailable: v.Latest.DockerImage != "", LatestNewsUrl: v.LatestNewsURL, } @@ -279,7 +287,7 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverpb.CheckUpdatesReq res.Installed.Timestamp = timestamppb.New(t) } - if v.Latest.BuildTime != nil { + if v.Latest.DockerImage != "" { t := v.Latest.BuildTime.UTC().Truncate(24 * time.Hour) // return only date res.Latest.Timestamp = timestamppb.New(t) } @@ -304,7 +312,7 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverpb.StartUpdateReque s.l.WithError(err).Error("Failed to get latest version") newImage = defaultLatestPMMImage } else { - newImage = fmt.Sprintf("%s:%s", latest.Repo, latest.Version) + newImage = latest.DockerImage } } err := s.updater.StartUpdate(ctx, newImage) @@ -346,7 +354,7 @@ func (s *Server) UpdateStatus(ctx context.Context, req *serverpb.UpdateStatusReq time.Sleep(time.Second) } - lines, newOffset, err = s.updater.UpdateLog(req.LogOffset) + lines, newOffset, err = s.updater.UpdateLog(req.GetLogOffset()) if err != nil { s.l.Warn(err) } diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 2095c518fe..d4093d7d81 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -19,6 +19,7 @@ import ( "bufio" "context" "encoding/json" + "fmt" "io" "net/http" "net/url" @@ -30,16 +31,20 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/percona/pmm/api/serverpb" "github.com/percona/pmm/version" ) // defaultLatestPMMImage is the default image name to use when the latest version cannot be determined. const ( - defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" - pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" + defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" + pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" + updateCheckInterval = 24 * time.Hour + updateCheckResultFresh = updateCheckInterval + 10*time.Minute + updateDefaultTimeout = 30 * time.Second ) +var fileName = "/etc/pmm-server-update-version.json" + // Updater is a service to check for updates and trigger the update process. type Updater struct { l *logrus.Entry @@ -50,21 +55,22 @@ type Updater struct { running bool checkRW sync.RWMutex - lastCheckResult *version.PackageInfo + lastCheckResult *version.DockerVersionInfo lastCheckTime time.Time } // NewUpdater creates a new Updater service. func NewUpdater(watchtowerHost *url.URL, gRPCMessageMaxSize uint32) *Updater { - return &Updater{ + u := &Updater{ l: logrus.WithField("service", "updater"), watchtowerHost: watchtowerHost, gRPCMessageMaxSize: gRPCMessageMaxSize, } + return u } -// run runs check for updates loop until ctx is canceled. -func (up *Updater) run(ctx context.Context) { +// Run runs check for updates loop until ctx is canceled. +func (up *Updater) Run(ctx context.Context) { up.l.Info("Starting...") ticker := time.NewTicker(updateCheckInterval) defer ticker.Stop() @@ -126,8 +132,8 @@ func (up *Updater) sendRequestToWatchtower(ctx context.Context, newImageName str return nil } -func (up *Updater) currentVersion() string { - return version.Version +func (up *Updater) currentVersion() *version.Parsed { + return version.MustParse(version.Version) } // StartUpdate triggers the update process. @@ -150,86 +156,78 @@ func (up *Updater) StartUpdate(ctx context.Context, newImageName string) error { return nil } -func (up *Updater) onlyInstalledVersionResponse() *serverpb.CheckUpdatesResponse { - return &serverpb.CheckUpdatesResponse{ - Installed: &serverpb.VersionInfo{ - Version: up.currentVersion(), - }, - } -} - // ForceCheckUpdates forces an update check. -func (up *Updater) ForceCheckUpdates(_ context.Context) error { - // TODO: PMM-11261 Implement this method - return nil -} - -type result struct { - Name string `json:"name"` -} - -type versionInfo struct { - Version version.Parsed `json:"version"` - DockerImage string `json:"docker_image"` -} - -// TagsResponse is a response from DockerHub. -type TagsResponse struct { - Results []result `json:"results"` +func (up *Updater) ForceCheckUpdates(ctx context.Context) error { + return up.check(ctx) } // LastCheckUpdatesResult returns the result of the last update check. func (up *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) { - buildTime, err := version.Time() - if err != nil { - up.l.WithError(err).Error("Failed to get build time") - return nil, time.Now() - } + installed := up.InstalledPMMVersion() latest, lastCheckTime := up.checkResult(ctx) return &version.UpdateCheckResult{ - Installed: version.PackageInfo{ - Version: up.currentVersion(), - FullVersion: version.PMMVersion, - BuildTime: &buildTime, - Repo: "local", - }, + Installed: installed, Latest: *latest, - UpdateAvailable: true, - LatestNewsURL: "", + UpdateAvailable: latest.DockerImage != "", + LatestNewsURL: "https://per.co.na/pmm/" + latest.Version.String(), }, lastCheckTime } -func (up *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { +func (up *Updater) latest(ctx context.Context) (*version.DockerVersionInfo, error) { + info, err := up.readFromFile() + if err != nil { + return nil, errors.Wrap(err, "failed to read from file") + } + if info != nil { + return info, nil + } + if os.Getenv("PMM_DEV_UPDATE_DOCKER_IMAGE") != "" { + return up.parseDockerTag(os.Getenv("PMM_DEV_UPDATE_DOCKER_IMAGE")) + } + + // File does not exist, ENV variable isn't provided, get the latest tag from DockerHub + return up.latestAvailableFromDockerHub(ctx) +} + +func (up *Updater) readFromFile() (*version.DockerVersionInfo, error) { // Read from file, if it's not exist read from ENV variable, if it's not exist get the latest tag from DockerHub. - fileName := "/etc/pmm-server-update-version.json" content, err := os.ReadFile(fileName) if err != nil && !os.IsNotExist(err) { up.l.WithError(err).Error("Failed to read file") return nil, errors.Wrap(err, "failed to read file") } - if err == nil { - info := version.PackageInfo{} - err = json.Unmarshal(content, &info) - if err != nil { - up.l.WithError(err).Error("Failed to unmarshal file") - return nil, errors.Wrap(err, "failed to unmarshal file") - } - return &info, nil + if os.IsNotExist(err) { + return nil, nil //nolint:nilnil } - if os.Getenv("PMM_SERVER_UPDATE_VERSION") != "" { - return up.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil + info := version.DockerVersionInfo{} + err = json.Unmarshal(content, &info) + if err != nil { + up.l.WithError(err).Error("Failed to unmarshal file") + return nil, errors.Wrap(err, "failed to unmarshal file") } + return &info, nil +} - // File does not exist, ENV variable doesn't provided, get the latest tag from DockerHub - return up.latestAvailableFromDockerHub(ctx, err) +type result struct { + Name string `json:"name"` + TagLastPushed time.Time `json:"tag_last_pushed"` +} + +// TagsResponse is a response from DockerHub. +type TagsResponse struct { + Results []result `json:"results"` } // latestAvailableFromDockerHub returns the latest available version from DockerHub. // It returns the latest minor version for the current major version. // If the current version is the latest minor version, it returns the next major version. // If the current version is the latest version, it returns the current version. -func (up *Updater) latestAvailableFromDockerHub(ctx context.Context, err error) (*version.PackageInfo, error) { - u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" +func (up *Updater) latestAvailableFromDockerHub(ctx context.Context) (*version.DockerVersionInfo, error) { + repo := os.Getenv("PMM_DEV_UPDATE_DOCKER_REPO") + if repo == "" { + repo = "percona/pmm-server" + } + u := "https://registry.hub.docker.com/v2/repositories/" + repo + "/tags/?page_size=100" req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { up.l.WithError(err).Error("Failed to create request") @@ -249,79 +247,88 @@ func (up *Updater) latestAvailableFromDockerHub(ctx context.Context, err error) } if len(tagsResponse.Results) != 0 { - currentVersion, err := version.Parse(up.currentVersion()) - if err != nil { - up.l.WithError(err).Error("Failed to parse current version") - return nil, errors.Wrap(err, "failed to parse current version") - } - - update, err := up.next(*currentVersion, tagsResponse.Results) - if err != nil { - up.l.WithError(err).Error("Failed to get latest minor version") - return nil, errors.Wrap(err, "failed to get latest minor version") + up.l.Infof("Found %d tags", len(tagsResponse.Results)) + next := up.next(*up.currentVersion(), tagsResponse.Results) + if next.DockerImage != "" { + next.DockerImage = repo + ":" + next.DockerImage } - return up.parseDockerTag(update.DockerImage), nil + return next, err } return nil, errors.New("no tags found") } -func (up *Updater) parseDockerTag(tag string) *version.PackageInfo { +func (up *Updater) parseDockerTag(tag string) (*version.DockerVersionInfo, error) { splitTag := strings.Split(tag, ":") if len(splitTag) != 2 { - return nil + return nil, fmt.Errorf("invalid tag: %s", tag) } - return &version.PackageInfo{ - Version: splitTag[1], - FullVersion: tag, - Repo: splitTag[0], + parsed, err := version.Parse(splitTag[1]) + if err != nil { + up.l.Debugf("Failed to parse version: %s", splitTag[1]) + return &version.DockerVersionInfo{ + DockerImage: tag, + }, nil } + return &version.DockerVersionInfo{ + Version: *parsed, + DockerImage: tag, + }, nil } -func (up *Updater) next(currentVersion version.Parsed, results []result) (*versionInfo, error) { - latest := versionInfo{ +func (up *Updater) next(currentVersion version.Parsed, results []result) *version.DockerVersionInfo { + nextMinor := &version.DockerVersionInfo{ Version: currentVersion, } + var nextMajor *version.DockerVersionInfo for _, result := range results { - splitTag := strings.Split(result.Name, ":") - if len(splitTag) != 2 { + v, err := version.Parse(result.Name) + if err != nil { + up.l.Debugf("Failed to parse version: %s", result.Name) continue } - v, err := version.Parse(splitTag[1]) - if err != nil { - up.l.Debugf("Failed to parse version: %s", splitTag[1]) + if !currentVersion.Less(v) { continue } - if v.Major == currentVersion.Major && v.Minor > currentVersion.Minor { - latest = versionInfo{ + if v.Major == currentVersion.Major && nextMinor.Version.Less(v) { // next major + nextMinor = &version.DockerVersionInfo{ Version: *v, DockerImage: result.Name, + BuildTime: result.TagLastPushed, } - } else if v.Major > currentVersion.Major && v.Major < latest.Version.Major { - latest = versionInfo{ + } + if v.Major > currentVersion.Major && + (nextMajor == nil || (nextMajor.Version.Less(v) && nextMajor.Version.Major == v.Major) || v.Major < nextMajor.Version.Major) { + nextMajor = &version.DockerVersionInfo{ Version: *v, DockerImage: result.Name, + BuildTime: result.TagLastPushed, } } } - return &latest, nil + if nextMinor.Version == currentVersion && nextMajor != nil { + return nextMajor + } + return nextMinor } +// InstalledPMMVersion returns the currently installed PMM version. func (up *Updater) InstalledPMMVersion() version.PackageInfo { t, _ := version.Time() return version.PackageInfo{ - Version: up.currentVersion(), + Version: version.Version, FullVersion: version.PMMVersion, BuildTime: &t, - Repo: "local", } } +// IsRunning returns true if the update process is running. func (up *Updater) IsRunning() bool { up.performM.Lock() defer up.performM.Unlock() return up.running } +// UpdateLog returns the log of the update process. func (up *Updater) UpdateLog(offset uint32) ([]string, uint32, error) { up.performM.Lock() defer up.performM.Unlock() @@ -356,9 +363,9 @@ func (up *Updater) UpdateLog(offset uint32) ([]string, uint32, error) { } } -// checkResult returns last `pmm-update -check` result and check time. +// checkResult returns the result of the last update check. // It may force re-check if last result is empty or too old. -func (up *Updater) checkResult(ctx context.Context) (*version.PackageInfo, time.Time) { +func (up *Updater) checkResult(ctx context.Context) (*version.DockerVersionInfo, time.Time) { up.checkRW.RLock() defer up.checkRW.RUnlock() @@ -371,7 +378,7 @@ func (up *Updater) checkResult(ctx context.Context) (*version.PackageInfo, time. return up.lastCheckResult, up.lastCheckTime } -// check calls `pmm-update -check` and fills lastInstalledPackageInfo/lastCheckResult/lastCheckTime on success. +// check performs update check. func (up *Updater) check(ctx context.Context) error { up.checkRW.Lock() defer up.checkRW.Unlock() diff --git a/managed/services/server/updater_test.go b/managed/services/server/updater_test.go index 980a4e0ba4..68bb6e69f4 100644 --- a/managed/services/server/updater_test.go +++ b/managed/services/server/updater_test.go @@ -18,10 +18,13 @@ package server import ( "context" "net/url" + "os" + "path/filepath" "strings" "testing" "time" + "github.com/AlekSi/pointer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,7 +33,6 @@ import ( func TestUpdater(t *testing.T) { gRPCMessageMaxSize := uint32(100 * 1024 * 1024) - gaReleaseDate := time.Date(2019, 9, 18, 0, 0, 0, 0, time.UTC) watchtowerURL, _ := url.Parse("http://watchtower:8080") t.Run("TestNextVersion", func(t *testing.T) { @@ -41,12 +43,12 @@ func TestUpdater(t *testing.T) { type versionInfo struct { Version string DockerImage string + BuildTime *time.Time } tests := []struct { - name string - args args - want *versionInfo - wantErr assert.ErrorAssertionFunc + name string + args args + want *versionInfo }{ { name: "no results", @@ -58,262 +60,215 @@ func TestUpdater(t *testing.T) { Version: "3.0.0", DockerImage: "", }, - wantErr: nil, }, { name: "no new version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.0.0"}, + {Name: "3.0.0"}, }, }, want: &versionInfo{ Version: "3.0.0", DockerImage: "", }, - wantErr: nil, }, { - name: "new minor version", + name: "new minor versions", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.1.0"}, - {Name: "percona/pmm-server:3.0.0"}, + {Name: "3.2.0"}, + {Name: "3.1.0"}, + {Name: "3.0.0"}, }, }, want: &versionInfo{ - Version: "3.1.0", - DockerImage: "percona/pmm-server:3.1.0", + Version: "3.2.0", + DockerImage: "3.2.0", + }, + }, + { + name: "new patch version", + args: args{ + currentVersion: "3.0.0", + results: []result{ + {Name: "3.0.0"}, + {Name: "3.0.1", TagLastPushed: time.Date(2024, 3, 20, 15, 48, 7, 145620000, time.UTC)}, + }, + }, + want: &versionInfo{ + Version: "3.0.1", + DockerImage: "3.0.1", + BuildTime: pointer.To(time.Date(2024, 3, 20, 15, 48, 7, 145620000, time.UTC)), }, - wantErr: nil, }, { name: "new major version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:4.0.0"}, - {Name: "percona/pmm-server:3.0.0"}, + {Name: "4.0.0"}, + {Name: "3.0.0"}, }, }, want: &versionInfo{ Version: "4.0.0", - DockerImage: "percona/pmm-server:4.0.0", + DockerImage: "4.0.0", }, - wantErr: nil, }, { name: "new major version with rc version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:4.0.0"}, - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:4.0.0-rc"}, + {Name: "4.0.0"}, + {Name: "3.0.0"}, + {Name: "4.0.0-rc"}, }, }, want: &versionInfo{ Version: "4.0.0", - DockerImage: "percona/pmm-server:4.0.0", + DockerImage: "4.0.0", }, - wantErr: nil, }, { name: "multiple new major versions", args: args{ currentVersion: "3.3.0", results: []result{ - {Name: "percona/pmm-server:4.0.0"}, - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:4.1.0"}, - {Name: "percona/pmm-server:5.1.0"}, + {Name: "4.1.0"}, + {Name: "4.0.0"}, + {Name: "3.0.0"}, + {Name: "5.1.0"}, }, }, want: &versionInfo{ Version: "4.1.0", - DockerImage: "percona/pmm-server:4.1.0", + DockerImage: "4.1.0", }, - wantErr: nil, }, { name: "new major version with minor version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:4.1.0"}, - {Name: "percona/pmm-server:4.0.0"}, - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:3.1.0"}, + {Name: "4.1.0"}, + {Name: "4.0.0"}, + {Name: "3.0.0"}, + {Name: "3.1.0"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "percona/pmm-server:3.1.0", + DockerImage: "3.1.0", }, - wantErr: nil, }, { name: "invalid version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:3.1.0"}, - {Name: "percona/pmm-server:invalid"}, + {Name: "3.0.0"}, + {Name: "3.1.0"}, + {Name: "invalid"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "percona/pmm-server:3.1.0", + DockerImage: "3.1.0", }, - wantErr: nil, }, { name: "non semver version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:3.1"}, + {Name: "3.0.0"}, + {Name: "3.1"}, }, }, want: &versionInfo{ Version: "3.0.0", DockerImage: "", }, - wantErr: nil, }, { name: "rc version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:3.1.0-rc"}, - {Name: "percona/pmm-server:3.1.0-rc757"}, + {Name: "3.0.0"}, + {Name: "3.1.0-rc"}, + {Name: "3.1.0-rc757"}, }, }, want: &versionInfo{ Version: "3.1.0-rc757", - DockerImage: "percona/pmm-server:3.1.0-rc757", + DockerImage: "3.1.0-rc757", }, - wantErr: nil, }, { name: "rc version and release version", args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "percona/pmm-server:3.0.0"}, - {Name: "percona/pmm-server:3.1.0-rc"}, - {Name: "percona/pmm-server:3.1.0-rc757"}, - {Name: "percona/pmm-server:3.1.0"}, + {Name: "3.0.0"}, + {Name: "3.1.0"}, + {Name: "3.1.0-rc"}, + {Name: "3.1.0-rc757"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "percona/pmm-server:3.1.0", + DockerImage: "3.1.0", }, - wantErr: nil, }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - u := NewUpdater(nil, gRPCMessageMaxSize) + u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) parsed, err := version.Parse(tt.args.currentVersion) require.NoError(t, err) - next, err := u.next(*parsed, tt.args.results) - if tt.wantErr != nil { - tt.wantErr(t, err) - return - } + next := u.next(*parsed, tt.args.results) require.NoError(t, err) assert.Equal(t, tt.want.Version, next.Version.String()) assert.Equal(t, tt.want.DockerImage, next.DockerImage) + if tt.want.BuildTime != nil { + assert.NotNil(t, next.BuildTime) + assert.Equal(t, *tt.want.BuildTime, next.BuildTime) + } }) } }) - t.Run("Installed", func(t *testing.T) { - t.Skip("This test is to be deprecated or completely rewritten") - checker := NewUpdater(watchtowerURL, gRPCMessageMaxSize) - - info := checker.InstalledPMMVersion() - require.NotNil(t, info) - - assert.True(t, strings.HasPrefix(info.Version, "3."), "version should start with `3.`. Actual value is: %s", info.Version) - fullVersion, _ := normalizeFullversion(&info) - assert.True(t, strings.HasPrefix(fullVersion, "3."), "full version should start with `3.`. Actual value is: %s", fullVersion) - require.NotEmpty(t, info.BuildTime) - assert.True(t, info.BuildTime.After(gaReleaseDate), "BuildTime = %s", info.BuildTime) + t.Run("TestLatest", func(t *testing.T) { + // Used PMM 2, because PMM 3 is not released yet. + version.Version = "2.41.0" + u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) + latest, err := u.latest(context.Background()) + require.NoError(t, err) + assert.NotNil(t, latest) + assert.True(t, strings.HasPrefix(latest.Version.String(), "2.41."), "latest version of PMM 2 should have prefix 2.41.") }) - t.Run("Check", func(t *testing.T) { - t.Skip("This test is to be deprecated or completely rewritten") - - ctx := context.TODO() - checker := NewUpdater(watchtowerURL, gRPCMessageMaxSize) - - res, resT := checker.LastCheckUpdatesResult(ctx) - assert.WithinDuration(t, time.Now(), resT, time.Second) - - assert.True(t, strings.HasPrefix(res.Installed.Version, "3."), "installed version should start with `3.`. Actual value is: %s", res.Installed.Version) - installedFullVersion, _ := normalizeFullversion(&res.Installed) - assert.True(t, strings.HasPrefix(installedFullVersion, "3."), "installed full version should start with `3.`. Actual value is: %s", installedFullVersion) - require.NotEmpty(t, res.Installed.BuildTime) - assert.True(t, res.Installed.BuildTime.After(gaReleaseDate), "Installed.BuildTime = %s", res.Installed.BuildTime) - assert.Equal(t, "local", res.Installed.Repo) - - assert.True(t, strings.HasPrefix(res.Latest.Version, "3."), "The latest available version should start with `3.`. Actual value is: %s", res.Latest.Version) - latestFullVersion, isFeatureBranch := normalizeFullversion(&res.Latest) - if isFeatureBranch { - t.Skip("Skipping check latest version.") - } - assert.True(t, strings.HasPrefix(latestFullVersion, "3."), "The latest available versions full value should start with `3.`. Actual value is: %s", latestFullVersion) - require.NotEmpty(t, res.Latest.BuildTime) - assert.True(t, res.Latest.BuildTime.After(gaReleaseDate), "Latest.BuildTime = %s", res.Latest.BuildTime) - assert.NotEmpty(t, res.Latest.Repo) - - // We assume that the latest perconalab/pmm-server:3-dev-latest image - // always contains the latest pmm-update package versions. - // If this test fails, re-pull them and recreate devcontainer. - t.Log("Assuming the latest pmm-update version.") - assert.False(t, res.UpdateAvailable, "update should not be available") - assert.Empty(t, res.LatestNewsURL, "latest_news_url should be empty") - assert.Equal(t, res.Installed, res.Latest, "version should be the same (latest)") - assert.Equal(t, *res.Installed.BuildTime, *res.Latest.BuildTime, "build times should be the same") - assert.Equal(t, "local", res.Latest.Repo) - - // cached result - res2, resT2 := checker.checkResult(ctx) - assert.Equal(t, res, res2) - assert.Equal(t, resT, resT2) + t.Run("TestParseFile", func(t *testing.T) { + fileBody := `{ "version": "2.41.1" , "docker_image": "2.41.1" , "build_time": "2024-03-20T15:48:07.14562Z" }` + oldFileName := fileName + fileName = filepath.Join(os.TempDir(), "pmm-update.json") + defer func() { fileName = oldFileName }() - time.Sleep(100 * time.Millisecond) - ctx, cancel := context.WithTimeout(context.Background(), updateDefaultTimeout) - defer cancel() - go checker.run(ctx) - time.Sleep(100 * time.Millisecond) + err := os.WriteFile(fileName, []byte(fileBody), 0o600) + require.NoError(t, err) - // should block and wait for run to finish one iteration - res3, resT3 := checker.checkResult(ctx) - assert.Equal(t, res2, res3) - assert.NotEqual(t, resT2, resT3, "%s", resT2) - assert.WithinDuration(t, resT2, resT3, 10*time.Second) + u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) + latest, err := u.latest(context.Background()) + require.NoError(t, err) + assert.Equal(t, "2.41.1", latest.Version.String()) + assert.Equal(t, "2.41.1", latest.DockerImage) + assert.Equal(t, time.Date(2024, 3, 20, 15, 48, 7, 145620000, time.UTC), latest.BuildTime) }) } - -func normalizeFullversion(info *version.PackageInfo) (version string, isFeatureBranch bool) { - fullVersion := info.FullVersion - - epochPrefix := "1:" // set by RPM_EPOCH in PMM Server build scripts - isFeatureBranch = strings.HasPrefix(fullVersion, epochPrefix) - if isFeatureBranch { - fullVersion = strings.TrimPrefix(fullVersion, epochPrefix) - } - - return fullVersion, isFeatureBranch -} diff --git a/managed/services/supervisord/devcontainer_test.go b/managed/services/supervisord/devcontainer_test.go index 0d91c7fb4b..d2679a729f 100644 --- a/managed/services/supervisord/devcontainer_test.go +++ b/managed/services/supervisord/devcontainer_test.go @@ -77,76 +77,4 @@ func TestDevContainer(t *testing.T) { err = s.UpdateConfiguration(settings, nil) require.NoError(t, err) }) - - //t.Run("Update", func(t *testing.T) { - // // This test can be run only once as it breaks assumptions of other tests. - // // It also should be the last test in devcontainer. - // if ok, _ := strconv.ParseBool(os.Getenv("PMM_TEST_RUN_UPDATE")); !ok { - // t.Skip("skipping update test") - // } - // - // // logrus.SetLevel(logrus.DebugLevel) - // checker := NewPMMUpdateChecker() - // vmParams := &models.VictoriaMetricsParams{} - // s := New("/etc/supervisord.d", &models.Params{VMParams: vmParams, PGParams: &models.PGParams{}, HAParams: &models.HAParams{}}, gRPCMessageMaxSize) - // require.NotEmpty(t, s.supervisorctlPath) - // - // ctx, cancel := context.WithCancel(context.Background()) - // defer cancel() - // go s.Run(ctx) - // - // require.Equal(t, false, s.UpdateRunning()) - // - // offset, err := s.StartUpdate() - // require.NoError(t, err) - // assert.Zero(t, offset) - // - // assert.True(t, s.UpdateRunning()) - // - // _, err = s.StartUpdate() - // assert.Equal(t, status.Errorf(codes.FailedPrecondition, "Update is already running."), err) - // - // // get logs as often as possible to increase a chance for race detector to spot something - // var lastLine string - // for { - // done := s.UpdateRunning() - // if done { - // // give supervisord a second to flush logs to file - // time.Sleep(time.Second) - // } - // - // lines, newOffset, err := s.UpdateLog(offset) - // require.NoError(t, err) - // if newOffset == offset { - // assert.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) - // if done { - // continue - // } - // break - // } - // - // assert.NotEmpty(t, lines) - // t.Logf("%s", strings.Join(lines, "\n")) - // lastLine = lines[len(lines)-1] - // - // assert.NotZero(t, newOffset) - // assert.True(t, newOffset > offset, "expected newOffset = %d > offset = %d", newOffset, offset) - // offset = newOffset - // } - // - // t.Logf("lastLine = %q", lastLine) - // assert.Contains(t, lastLine, "Waiting for Grafana dashboards update to finish...") - // - // // extra checks that we did not miss `pmp-update -perform` self-update and restart by supervisord - // const wait = 3 * time.Second - // const delay = 200 * time.Millisecond - // for i := 0; i < int(wait/delay); i++ { - // time.Sleep(delay) - // require.False(t, s.UpdateRunning()) - // lines, newOffset, err := s.UpdateLog(offset) - // require.NoError(t, err) - // require.Empty(t, lines, "lines:\n%s", strings.Join(lines, "\n")) - // require.Equal(t, offset, newOffset, "offset = %d, newOffset = %d", offset, newOffset) - // } - //}) } diff --git a/managed/services/supervisord/maintail_test.go b/managed/services/supervisord/maintail_test.go index 2e108a66f6..61d9373e9a 100644 --- a/managed/services/supervisord/maintail_test.go +++ b/managed/services/supervisord/maintail_test.go @@ -29,11 +29,6 @@ func TestParseEvent(t *testing.T) { t.Parallel() log := strings.Split(` - 2019-08-08 17:09:41,806 INFO spawned: 'pmm-update-perform' with pid 12983 - 2019-08-08 17:09:43,509 INFO success: pmm-update-perform entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) - 2019-08-08 17:09:48,494 INFO exited: pmm-update-perform (exit status 1; not expected) - 2019-08-08 17:09:48,506 INFO spawned: 'pmm-update-perform' with pid 13000 - 2019-08-08 17:09:49,506 INFO success: pmm-update-perform entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2019-08-08 17:09:57,284 INFO received SIGUSR2 indicating log reopen request 2019-08-08 17:09:57,284 INFO supervisord logreopen 2019-08-08 17:09:57,854 INFO waiting for pmm-managed to stop @@ -45,7 +40,6 @@ func TestParseEvent(t *testing.T) { 2019-08-08 17:10:27,686 INFO spawned: 'dashboard-upgrade' with pid 13888 2019-08-08 17:10:27,686 INFO success: dashboard-upgrade entered RUNNING state, process has stayed up for > than 0 seconds (startsecs) 2019-08-08 17:10:27,761 INFO exited: dashboard-upgrade (exit status 0; expected) - 2019-08-08 17:10:28,975 INFO exited: pmm-update-perform (exit status 0; expected) `, "\n") var actual []*event @@ -59,11 +53,6 @@ func TestParseEvent(t *testing.T) { } } expected := []*event{ - {Time: time.Date(2019, 8, 8, 17, 9, 41, 806000000, time.UTC), Type: starting, Program: "pmm-update-perform"}, - {Time: time.Date(2019, 8, 8, 17, 9, 43, 509000000, time.UTC), Type: running, Program: "pmm-update-perform"}, - {Time: time.Date(2019, 8, 8, 17, 9, 48, 494000000, time.UTC), Type: exitedUnexpected, Program: "pmm-update-perform"}, - {Time: time.Date(2019, 8, 8, 17, 9, 48, 506000000, time.UTC), Type: starting, Program: "pmm-update-perform"}, - {Time: time.Date(2019, 8, 8, 17, 9, 49, 506000000, time.UTC), Type: running, Program: "pmm-update-perform"}, {Time: time.Date(2019, 8, 8, 17, 9, 57, 284000000, time.UTC), Type: logReopen, Program: "supervisord"}, {Time: time.Date(2019, 8, 8, 17, 9, 57, 854000000, time.UTC), Type: stopping, Program: "pmm-managed"}, {Time: time.Date(2019, 8, 8, 17, 9, 59, 854000000, time.UTC), Type: stopping, Program: "pmm-managed"}, @@ -73,7 +62,6 @@ func TestParseEvent(t *testing.T) { {Time: time.Date(2019, 8, 8, 17, 10, 27, 686000000, time.UTC), Type: starting, Program: "dashboard-upgrade"}, {Time: time.Date(2019, 8, 8, 17, 10, 27, 686000000, time.UTC), Type: running, Program: "dashboard-upgrade"}, {Time: time.Date(2019, 8, 8, 17, 10, 27, 761000000, time.UTC), Type: exitedExpected, Program: "dashboard-upgrade"}, - {Time: time.Date(2019, 8, 8, 17, 10, 28, 975000000, time.UTC), Type: exitedExpected, Program: "pmm-update-perform"}, } assert.Equal(t, expected, actual) }) diff --git a/managed/services/supervisord/pmm_config.go b/managed/services/supervisord/pmm_config.go index 4ef71c0fdd..432e22ea32 100644 --- a/managed/services/supervisord/pmm_config.go +++ b/managed/services/supervisord/pmm_config.go @@ -196,20 +196,4 @@ stdout_logfile = /srv/logs/pmm-agent.log stdout_logfile_maxbytes = 50MB stdout_logfile_backups = 2 redirect_stderr = true - -[program:pmm-update-perform] -command = /usr/sbin/pmm-update -perform -playbook=/opt/ansible/pmm-docker/update.yml -user = pmm -directory = / -autorestart = unexpected -exitcodes = 0 -autostart = false -startretries = 10 -startsecs = 1 -stopsignal = TERM -stopwaitsecs = 300 -stdout_logfile = /srv/logs/pmm-update-perform.log -stdout_logfile_maxbytes = 50MB -stdout_logfile_backups = 3 -redirect_stderr = true `)) diff --git a/managed/services/supervisord/supervisord_test.go b/managed/services/supervisord/supervisord_test.go index c576042826..b6cee7d384 100644 --- a/managed/services/supervisord/supervisord_test.go +++ b/managed/services/supervisord/supervisord_test.go @@ -122,8 +122,8 @@ func TestParseStatus(t *testing.T) { for str, expected := range map[string]*bool{ `pmm-agent STOPPED Sep 20 08:55 AM`: pointer.ToBool(false), `pmm-managed RUNNING pid 826, uptime 0:19:36`: pointer.ToBool(true), - `pmm-update-perform EXITED Sep 20 07:42 AM`: nil, - `pmm-update-perform STARTING`: pointer.ToBool(true), // no last column in that case + `pmm-update-perform-init EXITED Sep 20 07:42 AM`: nil, + `pmm-update-perform-init STARTING`: pointer.ToBool(true), // no last column in that case } { assert.Equal(t, expected, parseStatus(str), "%q", str) } diff --git a/managed/testdata/supervisord.d/pmm-db_disabled.ini b/managed/testdata/supervisord.d/pmm-db_disabled.ini index a9191eb4b5..5e5f482897 100644 --- a/managed/testdata/supervisord.d/pmm-db_disabled.ini +++ b/managed/testdata/supervisord.d/pmm-db_disabled.ini @@ -89,19 +89,3 @@ stdout_logfile = /srv/logs/pmm-agent.log stdout_logfile_maxbytes = 50MB stdout_logfile_backups = 2 redirect_stderr = true - -[program:pmm-update-perform] -command = /usr/sbin/pmm-update -perform -playbook=/opt/ansible/pmm-docker/update.yml -user = pmm -directory = / -autorestart = unexpected -exitcodes = 0 -autostart = false -startretries = 10 -startsecs = 1 -stopsignal = TERM -stopwaitsecs = 300 -stdout_logfile = /srv/logs/pmm-update-perform.log -stdout_logfile_maxbytes = 50MB -stdout_logfile_backups = 3 -redirect_stderr = true diff --git a/managed/testdata/supervisord.d/pmm-db_enabled.ini b/managed/testdata/supervisord.d/pmm-db_enabled.ini index bb28208342..bd0ca87ab8 100644 --- a/managed/testdata/supervisord.d/pmm-db_enabled.ini +++ b/managed/testdata/supervisord.d/pmm-db_enabled.ini @@ -113,19 +113,3 @@ stdout_logfile = /srv/logs/pmm-agent.log stdout_logfile_maxbytes = 50MB stdout_logfile_backups = 2 redirect_stderr = true - -[program:pmm-update-perform] -command = /usr/sbin/pmm-update -perform -playbook=/opt/ansible/pmm-docker/update.yml -user = pmm -directory = / -autorestart = unexpected -exitcodes = 0 -autostart = false -startretries = 10 -startsecs = 1 -stopsignal = TERM -stopwaitsecs = 300 -stdout_logfile = /srv/logs/pmm-update-perform.log -stdout_logfile_maxbytes = 50MB -stdout_logfile_backups = 3 -redirect_stderr = true diff --git a/update/main.go b/update/main.go index 4ecffaf352..68e40ab755 100644 --- a/update/main.go +++ b/update/main.go @@ -17,7 +17,6 @@ package main import ( "context" - "encoding/json" "flag" "log" "os" @@ -27,67 +26,9 @@ import ( "golang.org/x/sys/unix" "github.com/percona/pmm/update/pkg/ansible" - "github.com/percona/pmm/update/pkg/yum" "github.com/percona/pmm/version" ) -const ( - pmmManagedPackageName = "pmm-managed" -) - -func installed(ctx context.Context) { - v, err := yum.Installed(ctx, pmmManagedPackageName) - if err != nil { - logrus.Tracef("%+v", err) - logrus.Fatalf("Installed failed: %s", err) - } - if err = json.NewEncoder(os.Stdout).Encode(v); err != nil { - logrus.Fatal(err) - } -} - -func check(ctx context.Context) { - pmmManagedPackage, err := yum.Check(ctx, pmmManagedPackageName) - if err != nil { - logrus.Tracef("%+v", err) - logrus.Fatalf("Check failed: %s", err) - } - - if err = json.NewEncoder(os.Stdout).Encode(pmmManagedPackage); err != nil { - logrus.Fatal(err) - } -} - -func performStage1SelfUpdate(ctx context.Context) { - const name = "pmm-update" - v, err := yum.Installed(ctx, name) - if err != nil { - logrus.Tracef("%+v", err) - logrus.Fatalf("Installed failed before update: %s", err) - } - before := v.Installed - - if err = yum.Update(ctx, name); err != nil { - logrus.Tracef("%+v", err) - logrus.Fatalf("Update failed: %s", err) - } - - v, err = yum.Installed(ctx, name) - if err != nil { - logrus.Tracef("%+v", err) - logrus.Fatalf("Installed failed after update: %s", err) - } - after := v.Installed - - logrus.Infof("%s:\nbefore update = %+v\n after update = %+v", name, before, after) - if before.FullVersion != after.FullVersion { - // exit with non-zero code to let supervisord restart `pmm-update -perform` from the start - logrus.Info("Version changed, exiting.") - os.Exit(42) - } - logrus.Info("Version did not change.") -} - func performStage2Ansible(ctx context.Context, playbook string, opts *ansible.RunPlaybookOpts) { err := ansible.RunPlaybook(ctx, playbook, opts) if err != nil { @@ -99,22 +40,10 @@ func runAnsible(ctx context.Context, playbook string, opts *ansible.RunPlaybookO performStage2Ansible(ctx, playbook, opts) } -func perform(ctx context.Context, playbook string, opts *ansible.RunPlaybookOpts) { - performStage1SelfUpdate(ctx) - performStage2Ansible(ctx, playbook, opts) - - // pmm-managed will still wait for dashboard-upgrade to finish; - // that string is expected by various automated tests. - logrus.Info("Waiting for Grafana dashboards update to finish...") -} - // Flags have to be global variables for maincover_test.go to work. // //nolint:gochecknoglobals var ( - installedF = flag.Bool("installed", false, "Return installed version") - checkF = flag.Bool("check", false, "Check for updates") - performF = flag.Bool("perform", false, "Perform update") runPlaybookF = flag.Bool("run-playbook", false, "Run playbook without self-update") playbookF = flag.String("playbook", "", "Ansible playbook for -perform") debugF = flag.Bool("debug", false, "Enable debug logging") @@ -137,15 +66,6 @@ func main() { } var modes int - if *installedF { - modes++ - } - if *checkF { - modes++ - } - if *performF { - modes++ - } if *runPlaybookF { modes++ } @@ -165,10 +85,6 @@ func main() { }() switch { - case *installedF: - installed(ctx) - case *checkF: - check(ctx) case *runPlaybookF: if *playbookF == "" { logrus.Fatalf("-playbook flag must be set.") @@ -178,13 +94,5 @@ func main() { Debug: *debugF, Trace: *traceF, }) - case *performF: - if *playbookF == "" { - logrus.Fatalf("-playbook flag must be set.") - } - perform(ctx, *playbookF, &ansible.RunPlaybookOpts{ - Debug: *debugF, - Trace: *traceF, - }) } } diff --git a/update/pkg/yum/info.go b/update/pkg/yum/info.go deleted file mode 100644 index 95728e928d..0000000000 --- a/update/pkg/yum/info.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// Package yum provides functionality for yum dependency manager. -package yum - -import ( - "os/exec" - "regexp" - "strings" - "time" - - "github.com/pkg/errors" -) - -// parseInfo parses `yum info` stdout for a single version of a single package. -// Also used to parse `yum repoinfo`. -func parseInfo(lines []string, firstKey string) (map[string]string, error) { - res := make(map[string]string) - var prevKey string - var keyFound bool - for _, line := range lines { - // separate progress output from data - line = strings.TrimSpace(line) - if line == "" { - continue - } - parts := strings.SplitN(line, ":", 2) - if len(parts) != 2 { - continue - } - key := strings.TrimSpace(parts[0]) - if key == firstKey { - // sanity check that we do not try to parse multiple packages - if keyFound { - return res, errors.New("second `Name` encountered") - } - keyFound = true - } - if !keyFound { - continue - } - - // parse data while handling multiline values - value := strings.TrimSpace(parts[1]) - if key == "" { - if prevKey != "" { - res[prevKey] += " " + value - } - continue - } - res[key] = value - prevKey = key - } - return res, nil -} - -func parseInfoTime(s string) (time.Time, error) { - layout := "Mon 2 Jan 2006 15:04:05 PM UTC" // layout for EL9, default - v, err := getRHELVersion() - if err == nil && v == "7" { - layout = "Mon Jan 2 15:04:05 2006" // change the layout for EL7 - } - return time.Parse(layout, s) -} - -// fullVersion returns full (ugly) package version. -func fullVersion(info map[string]string) string { - var res string - if e := info["Epoch"]; e != "" { - res = e + ":" - } - res += info["Version"] - res += "-" + info["Release"] - return res -} - -// niceVersion returns nice user-visible package version. -func niceVersion(info map[string]string) string { - // cut suffixes from full release - release := info["Release"] - for _, re := range []*regexp.Regexp{ - regexp.MustCompile(`^(.*)\.el\d+$`), // el7 suffix - regexp.MustCompile(`^(.*)\.[0-9a-f]{7}$`), // abbreviated commit suffix - regexp.MustCompile(`^(.*)\.\d{10}$`), // timestamp suffix - } { - release = re.ReplaceAllString(release, "$1") - } - - // if there is more than just release digits (like `9.beta5` or `18.rc4`), return them; - // return only version otherwise. - if !regexp.MustCompile(`^\d+$`).MatchString(release) { - return info["Version"] + "-" + release - } - return info["Version"] -} - -func getRHELVersion() (string, error) { - raw, err := exec.Command("rpm", "--eval", "%{rhel}").Output() - if err != nil { - return "", errors.Wrap(err, "couldn't get RHEL version") - } - - return strings.TrimSpace(string(raw)), nil -} diff --git a/update/pkg/yum/info_test.go b/update/pkg/yum/info_test.go deleted file mode 100644 index 1f06c1e249..0000000000 --- a/update/pkg/yum/info_test.go +++ /dev/null @@ -1,683 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package yum - -import ( - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestParseInfoEL7(t *testing.T) { - v, _ := getRHELVersion() - if v == "9" { - t.Skip("Skip running EL7 tests on EL9") - } - t.Run("Installed", func(t *testing.T) { - stdout := strings.Split(` - Loading "fastestmirror" plugin - Loading "ovl" plugin - Config time: 0.005 - rpmdb time: 0.000 - ovl: Copying up (0) files from OverlayFS lower layer - Yum version: 3.4.3 - Installed Packages - Name : pmm-managed - Arch : x86_64 - Version : 2.0.0 - Release : 9.beta5.1907301101.74f8a67.el7 - Size : 18 M - Repo : installed - From repo : local - Committer : Mykola Marzhan - Committime : Thu Sep 21 12:00:00 2017 - Buildtime : Tue Jul 30 11:02:19 2019 - Install time: Tue Jul 30 18:43:02 2019 - Installed by: 500 - Changed by : System - Summary : Percona Monitoring and Management management daemon - URL : https://github.com/percona/pmm-managed - License : AGPLv3 - Description : pmm-managed manages configuration of PMM server components (Prometheus, - : Grafana, etc.) and exposes API for that. Those APIs are used by pmm-admin tool. - : See the PMM docs for more information. - `, "\n") - expected := map[string]string{ - "Name": "pmm-managed", - "Arch": "x86_64", - "Version": "2.0.0", - "Release": "9.beta5.1907301101.74f8a67.el7", - "Size": "18 M", - "Repo": "installed", - "From repo": "local", - "Committer": "Mykola Marzhan ", - "Committime": "Thu Sep 21 12:00:00 2017", - "Buildtime": "Tue Jul 30 11:02:19 2019", - "Install time": "Tue Jul 30 18:43:02 2019", - "Installed by": "500", - "Changed by": "System ", - "Summary": "Percona Monitoring and Management management daemon", - "URL": "https://github.com/percona/pmm-managed", - "License": "AGPLv3", - "Description": "pmm-managed manages configuration of PMM server components (Prometheus, " + - "Grafana, etc.) and exposes API for that. Those APIs are used by pmm-admin tool. " + - "See the PMM docs for more information.", - } - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2019, 7, 30, 11, 2, 19, 0, time.UTC), buildtime) - assert.Equal(t, "2.0.0-9.beta5.1907301101.74f8a67.el7", fullVersion(actual)) - assert.Equal(t, "2.0.0-9.beta5", niceVersion(actual)) - }) - - t.Run("Updates", func(t *testing.T) { - stdout := strings.Split(` - Loading "fastestmirror" plugin - Loading "ovl" plugin - Config time: 0.017 - rpmdb time: 0.000 - ovl: Copying up (14) files from OverlayFS lower layer - Yum version: 3.4.3 - Building updates object - Setting up Package Sacks - Determining fastest mirrors - * base: mirror.reconn.ru - * epel: mirror.yandex.ru - * extras: mirror.reconn.ru - * updates: mirror.reconn.ru - pkgsack time: 14.667 - up:Obs Init time: 0.235 - up:simple updates time: 0.004 - up:obs time: 0.003 - up:condense time: 0.000 - updates time: 15.139 - Updated Packages - Name : pmm-update - Arch : noarch - Version : 2.0.0 - Release : 9.beta5.1907301223.90149dd.el7 - Size : 1.5 M - Repo : pmm-laboratory - Committer : Mykola Marzhan - Committime : Fri Jun 30 12:00:00 2017 - Buildtime : Tue Jul 30 12:23:10 2019 - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm/update - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - `, "\n") - expected := map[string]string{ - "Name": "pmm-update", - "Arch": "noarch", - "Version": "2.0.0", - "Release": "9.beta5.1907301223.90149dd.el7", - "Size": "1.5 M", - "Repo": "pmm-laboratory", - "Committer": "Mykola Marzhan ", - "Committime": "Fri Jun 30 12:00:00 2017", - "Buildtime": "Tue Jul 30 12:23:10 2019", - "Summary": "Tool for updating packages and OS configuration for PMM Server", - "URL": "https://github.com/percona/pmm/update", - "License": "AGPLv3", - "Description": "Tool for updating packages and OS configuration for PMM Server", - } - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2019, 7, 30, 12, 23, 10, 0, time.UTC), buildtime) - assert.Equal(t, "2.0.0-9.beta5.1907301223.90149dd.el7", fullVersion(actual)) - assert.Equal(t, "2.0.0-9.beta5", niceVersion(actual)) - }) - - t.Run("Available", func(t *testing.T) { - // yum --verbose --showduplicates info available pmm-update, abbreviated - stdout := strings.Split(` - Loading "fastestmirror" plugin - Loading "ovl" plugin - Config time: 0.007 - rpmdb time: 0.000 - ovl: Copying up (0) files from OverlayFS lower layer - Yum version: 3.4.3 - Setting up Package Sacks - Loading mirror speeds from cached hostfile - * base: mirror.logol.ru - * epel: fedora-mirror01.rbc.ru - * extras: mirror.logol.ru - * updates: mirror.logol.ru - pkgsack time: 0.027 - Available Packages - Name : pmm-update - Arch : noarch - Version : PMM - Release : 7.4358.1907161009.7685dba.el7 - Size : 20 k - Repo : pmm-laboratory - Committer : Mykola Marzhan - Committime : Fri Jun 30 12:00:00 2017 - Buildtime : Tue Jul 16 10:09:01 2019 - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm/update - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - - Name : pmm-update - Arch : noarch - Version : 2.0.0 - Release : 1.1903221448.2e245f9.el7 - Size : 20 k - Repo : pmm-laboratory - Committer : Mykola Marzhan - Committime : Fri Jun 30 12:00:00 2017 - Buildtime : Fri Mar 22 14:48:42 2019 - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm/update - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - - … - `, "\n") - expected := map[string]string{ - "Name": "pmm-update", - "Arch": "noarch", - "Version": "PMM", - "Release": "7.4358.1907161009.7685dba.el7", - "Size": "20 k", - "Repo": "pmm-laboratory", - "Committer": "Mykola Marzhan ", - "Committime": "Fri Jun 30 12:00:00 2017", - "Buildtime": "Tue Jul 16 10:09:01 2019", - "Summary": "Tool for updating packages and OS configuration for PMM Server", - "URL": "https://github.com/percona/pmm/update", - "License": "AGPLv3", - "Description": "Tool for updating packages and OS configuration for PMM Server", - } - actual, err := parseInfo(stdout, "Name") - assert.EqualError(t, err, "second `Name` encountered") - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2019, 7, 16, 10, 9, 1, 0, time.UTC), buildtime) - assert.Equal(t, "PMM-7.4358.1907161009.7685dba.el7", fullVersion(actual)) - assert.Equal(t, "PMM-7.4358", niceVersion(actual)) // yes, that one is broken - }) - - t.Run("AvailableGA", func(t *testing.T) { - // yum --verbose --showduplicates info available pmm-update, abbreviated - stdout := strings.Split(` - Available Packages - Name : pmm-update - Arch : noarch - Version : 2.0.0 - Release : 18.1909180550.6de91ea.el7 - Size : 857 k - Repo : pmm-server - Committer : Alexey Palazhchenko - Committime : Wed Sep 18 12:00:00 2019 - Buildtime : Wed Sep 18 05:51:01 2019 - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm/update - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - - … - `, "\n") - expected := map[string]string{ - "Name": "pmm-update", - "Arch": "noarch", - "Version": "2.0.0", - "Release": "18.1909180550.6de91ea.el7", - "Size": "857 k", - "Repo": "pmm-server", - "Committer": "Alexey Palazhchenko ", - "Committime": "Wed Sep 18 12:00:00 2019", - "Buildtime": "Wed Sep 18 05:51:01 2019", - "Summary": "Tool for updating packages and OS configuration for PMM Server", - "URL": "https://github.com/percona/pmm/update", - "License": "AGPLv3", - "Description": "Tool for updating packages and OS configuration for PMM Server", - } - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2019, 9, 18, 5, 51, 1, 0, time.UTC), buildtime) - assert.Equal(t, "2.0.0-18.1909180550.6de91ea.el7", fullVersion(actual)) - assert.Equal(t, "2.0.0", niceVersion(actual)) - }) - - t.Run("Empty", func(t *testing.T) { - // "Error: No matching Packages to list" goes to stderr. - stdout := strings.Split(` - Loading "fastestmirror" plugin - Loading "ovl" plugin - Config time: 0.007 - rpmdb time: 0.000 - ovl: Copying up (0) files from OverlayFS lower layer - Yum version: 3.4.3 - Building updates object - Setting up Package Sacks - Loading mirror speeds from cached hostfile - * base: mirror.logol.ru - * epel: fedora-mirror01.rbc.ru - * extras: mirror.logol.ru - * updates: mirror.logol.ru - pkgsack time: 0.030 - up:Obs Init time: 0.217 - up:simple updates time: 0.008 - up:obs time: 0.004 - up:condense time: 0.000 - updates time: 0.469 - `, "\n") - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Empty(t, actual) - }) - - t.Run("RepoInfo", func(t *testing.T) { - // yum repoinfo pmm-server. - stdout := strings.Split(` - Loaded plugins: changelog, fastestmirror, ovl - Loading mirror speeds from cached hostfile - * base: centos.schlundtech.de - * epel: mirror.netcologne.de - * extras: centos.mirror.iphh.net - * updates: mirror.netcologne.de - Repo-id : pmm-server - Repo-name : PMM Server YUM repository - x86_64 - Repo-status : enabled - Repo-revision: 1622561436 - Repo-updated : Tue Jun 1 15:30:45 2021 - Repo-pkgs : 237 - Repo-size : 2.4 G - Repo-baseurl : https://repo.percona.com/pmm3-components/yum/experimental/7/RPMS/x86_64/ - Repo-expire : 21600 second(s) (last: Thu Jun 10 16:08:12 2021) - Filter : read-only:present - Repo-filename: /etc/yum.repos.d/pmm-server.repo - - repolist: 237 - … - `, "\n") - expected := map[string]string{ - "Repo-id": "pmm-server", - "Repo-name": "PMM Server YUM repository - x86_64", - "Repo-status": "enabled", - "Repo-revision": "1622561436", - "Repo-updated": "Tue Jun 1 15:30:45 2021", - "Repo-pkgs": "237", - "Repo-size": "2.4 G", - "Repo-baseurl": "https://repo.percona.com/pmm3-components/yum/experimental/7/RPMS/x86_64/", - "Repo-expire": "21600 second(s) (last: Thu Jun 10 16:08:12 2021)", - "Filter": "read-only:present", - "Repo-filename": "/etc/yum.repos.d/pmm-server.repo", - "repolist": "237", - } - actual, err := parseInfo(stdout, "Repo-id") - require.NoError(t, err) - assert.Equal(t, expected, actual) - releasetime, err := parseInfoTime(actual["Repo-updated"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2021, 6, 1, 15, 30, 45, 0, time.UTC), releasetime) - }) -} - -func TestParseInfoEL9(t *testing.T) { - v, _ := getRHELVersion() - if v == "7" { - t.Skip("Skip running EL9 tests on EL7") - } - t.Run("Installed EL9", func(t *testing.T) { - stdout := strings.Split(` - Starting "yum --verbose info installed pmm-managed" ... - Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install, download, generate_completion_cache, groups-manager, needs-restarting, playground, repoclosure, repodiff, repograph, repomanage, reposync, system-upgrade - YUM version: 4.14.0 - cachedir: /var/cache/dnf - Unknown configuration option: async = 1 in /etc/yum.repos.d/clickhouse.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/local.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/nginx.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-11.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-14.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/pmm-server.repo - User-Agent: constructed: 'libdnf (Oracle Linux Server 9.2; server; Linux.x86_64)' - Installed Packages - Name : pmm-managed - Version : 2.39.0 - Release : 20.2306271313.b6d58b6.el9 - Architecture : x86_64 - Size : 125 M - Source : pmm-managed-2.39.0-20.2306271313.b6d58b6.el9.src.rpm - Repository : @System - From repo : local - Packager : None - Buildtime : Tue 27 Jun 2023 01:13:03 PM UTC - Install time : Tue 27 Jun 2023 01:31:05 PM UTC - Installed by : System - Summary : Percona Monitoring and Management management daemon - URL : https://github.com/percona/pmm - License : AGPLv3 - Description : pmm-managed manages configuration of PMM server components (VictoriaMetrics, - : Grafana, etc.) and exposes API for that. Those APIs are used by pmm-admin tool. - : See PMM docs for more information. - `, "\n") - expected := map[string]string{ - "Name": "pmm-managed", - "Version": "2.39.0", - "Release": "20.2306271313.b6d58b6.el9", - "Architecture": "x86_64", - "Size": "125 M", - "Source": "pmm-managed-2.39.0-20.2306271313.b6d58b6.el9.src.rpm", - "Repository": "@System", - "From repo": "local", - "Packager": "None", - "Buildtime": "Tue 27 Jun 2023 01:13:03 PM UTC", - "Install time": "Tue 27 Jun 2023 01:31:05 PM UTC", - "Installed by": "System ", - "Summary": "Percona Monitoring and Management management daemon", - "URL": "https://github.com/percona/pmm", - "License": "AGPLv3", - "Description": "pmm-managed manages configuration of PMM server components (VictoriaMetrics, " + - "Grafana, etc.) and exposes API for that. Those APIs are used by pmm-admin tool. " + - "See PMM docs for more information.", - } - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2023, 6, 27, 13, 13, 3, 0, time.UTC), buildtime) - assert.Equal(t, "2.39.0-20.2306271313.b6d58b6.el9", fullVersion(actual)) - assert.Equal(t, "2.39.0", niceVersion(actual)) - }) - - t.Run("Updates EL9", func(t *testing.T) { - // yum --verbose info updates pmm-update - stdout := strings.Split(` - Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install, download, generate_completion_cache, groups-manager, needs-restarting, playground, repoclosure, repodiff, repograph, repomanage, reposync, system-upgrade - YUM version: 4.14.0 - cachedir: /var/cache/dnf - Unknown configuration option: async = 1 in /etc/yum.repos.d/clickhouse.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/local.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/nginx.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-11.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-14.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/pmm-server.repo - User-Agent: constructed: 'libdnf (Oracle Linux Server 9.2; server; Linux.x86_64)' - repo: using cache for: ol9_developer_EPEL - ol9_developer_EPEL: using metadata from Wed 28 Jun 2023 02:28:50 PM UTC. - repo: using cache for: ol9_baseos_latest - ol9_baseos_latest: using metadata from Fri 23 Jun 2023 04:59:24 AM UTC. - repo: using cache for: ol9_appstream - ol9_appstream: using metadata from Fri 23 Jun 2023 05:03:17 AM UTC. - repo: using cache for: percona-release-x86_64 - percona-release-x86_64: using metadata from Mon 26 Jun 2023 01:02:27 PM UTC. - repo: using cache for: percona-release-noarch - percona-release-noarch: using metadata from Wed 06 Jul 2022 08:25:44 PM UTC. - repo: using cache for: percona-testing-x86_64 - percona-testing-x86_64: using metadata from Wed 28 Jun 2023 05:27:06 PM UTC. - repo: using cache for: percona-testing-noarch - percona-testing-noarch: using metadata from Wed 06 Jul 2022 08:20:55 PM UTC. - repo: using cache for: percona-ppg-11 - percona-ppg-11: using metadata from Mon 22 May 2023 08:40:15 AM UTC. - repo: using cache for: percona-ppg-14 - percona-ppg-14: using metadata from Wed 28 Jun 2023 02:57:51 PM UTC. - repo: using cache for: prel-release-noarch - prel-release-noarch: using metadata from Thu 16 Sep 2021 06:35:55 AM UTC. - repo: using cache for: pmm-server - pmm-server: using metadata from Wed 28 Jun 2023 02:46:09 PM UTC. - Last metadata expiration check: 1:42:51 ago on Wed 28 Jun 2023 07:06:43 PM UTC. - Available Upgrades - Name : pmm-update - Version : 2.39.0 - Release : 67.2306281336.d0d7fcb.el9 - Architecture : noarch - Size : 886 k - Source : pmm-update-2.39.0-67.2306281336.d0d7fcb.el9.src.rpm - Repository : pmm-server - Packager : None - Buildtime : Wed 28 Jun 2023 01:36:03 PM UTC - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - `, "\n") - expected := map[string]string{ - "Name": "pmm-update", - "Architecture": "noarch", - "Version": "2.39.0", - "Release": "67.2306281336.d0d7fcb.el9", - "Size": "886 k", - "Source": "pmm-update-2.39.0-67.2306281336.d0d7fcb.el9.src.rpm", - "Repository": "pmm-server", - "Packager": "None", - "Buildtime": "Wed 28 Jun 2023 01:36:03 PM UTC", - "Summary": "Tool for updating packages and OS configuration for PMM Server", - "URL": "https://github.com/percona/pmm", - "License": "AGPLv3", - "Description": "Tool for updating packages and OS configuration for PMM Server", - } - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2023, 6, 28, 13, 36, 3, 0, time.UTC), buildtime) - assert.Equal(t, "2.39.0-67.2306281336.d0d7fcb.el9", fullVersion(actual)) - assert.Equal(t, "2.39.0", niceVersion(actual)) - }) - - t.Run("AvailableGA EL9", func(t *testing.T) { - // yum --verbose --showduplicates info available pmm-update (just two versions) - stdout := strings.Split(` - Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install, download, generate_completion_cache, groups-manager, needs-restarting, playground, repoclosure, repodiff, repograph, repomanage, reposync, system-upgrade - YUM version: 4.14.0 - cachedir: /var/cache/dnf - Unknown configuration option: async = 1 in /etc/yum.repos.d/clickhouse.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/local.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/nginx.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-11.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-14.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/pmm-server.repo - User-Agent: constructed: 'libdnf (Oracle Linux Server 9.2; server; Linux.x86_64)' - repo: using cache for: ol9_developer_EPEL - ol9_developer_EPEL: using metadata from Wed 28 Jun 2023 02:28:50 PM UTC. - repo: using cache for: ol9_baseos_latest - ol9_baseos_latest: using metadata from Fri 23 Jun 2023 04:59:24 AM UTC. - repo: using cache for: ol9_appstream - ol9_appstream: using metadata from Fri 23 Jun 2023 05:03:17 AM UTC. - repo: using cache for: percona-release-x86_64 - percona-release-x86_64: using metadata from Mon 26 Jun 2023 01:02:27 PM UTC. - repo: using cache for: percona-release-noarch - percona-release-noarch: using metadata from Wed 06 Jul 2022 08:25:44 PM UTC. - repo: using cache for: percona-testing-x86_64 - percona-testing-x86_64: using metadata from Wed 28 Jun 2023 05:27:06 PM UTC. - repo: using cache for: percona-testing-noarch - percona-testing-noarch: using metadata from Wed 06 Jul 2022 08:20:55 PM UTC. - repo: using cache for: percona-ppg-11 - percona-ppg-11: using metadata from Mon 22 May 2023 08:40:15 AM UTC. - repo: using cache for: percona-ppg-14 - percona-ppg-14: using metadata from Wed 28 Jun 2023 02:57:51 PM UTC. - repo: using cache for: prel-release-noarch - prel-release-noarch: using metadata from Thu 16 Sep 2021 06:35:55 AM UTC. - repo: using cache for: pmm-server - pmm-server: using metadata from Wed 28 Jun 2023 02:46:09 PM UTC. - Last metadata expiration check: 1:18:00 ago on Wed 28 Jun 2023 07:06:43 PM UTC. - Available Packages - Name : pmm-update - Version : 2.39.0 - Release : 67.2306280932.70f3748.el9 - Architecture : noarch - Size : 887 k - Source : pmm-update-2.39.0-67.2306280932.70f3748.el9.src.rpm - Repository : pmm-server - Packager : None - Buildtime : Wed 28 Jun 2023 09:32:21 AM UTC - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - - Name : pmm-update - Version : 2.39.0 - Release : 67.2306281012.fe8e947.el9 - Architecture : noarch - Size : 887 k - Source : pmm-update-2.39.0-67.2306281012.fe8e947.el9.src.rpm - Repository : pmm-server - Packager : None - Buildtime : Wed 28 Jun 2023 10:12:02 AM UTC - Summary : Tool for updating packages and OS configuration for PMM Server - URL : https://github.com/percona/pmm - License : AGPLv3 - Description : Tool for updating packages and OS configuration for PMM Server - `, "\n") - expected := map[string]string{ - "Name": "pmm-update", - "Architecture": "noarch", - "Version": "2.39.0", - "Release": "67.2306280932.70f3748.el9", - "Size": "887 k", - "Source": "pmm-update-2.39.0-67.2306280932.70f3748.el9.src.rpm", - "Repository": "pmm-server", - "Packager": "None", - "Buildtime": "Wed 28 Jun 2023 09:32:21 AM UTC", - "Summary": "Tool for updating packages and OS configuration for PMM Server", - "URL": "https://github.com/percona/pmm", - "License": "AGPLv3", - "Description": "Tool for updating packages and OS configuration for PMM Server", - } - actual, err := parseInfo(stdout, "Name") - assert.EqualError(t, err, "second `Name` encountered") - assert.Equal(t, expected, actual) - buildtime, err := parseInfoTime(actual["Buildtime"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2023, 6, 28, 9, 32, 21, 0, time.UTC), buildtime) - assert.Equal(t, "2.39.0-67.2306280932.70f3748.el9", fullVersion(actual)) - assert.Equal(t, "2.39.0", niceVersion(actual)) - }) - - t.Run("Empty EL9", func(t *testing.T) { - // yum --verbose info updates pmm-managed - // "Error: No matching Packages to list" goes to stderr. - // The output below is generated when there are no updates available. - stdout := strings.Split(` - Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install, download, generate_completion_cache, groups-manager, needs-restarting, playground, repoclosure, repodiff, repograph, repomanage, reposync, system-upgrade - YUM version: 4.14.0 - cachedir: /var/cache/dnf - Unknown configuration option: async = 1 in /etc/yum.repos.d/clickhouse.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/local.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/nginx.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-11.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/percona-ppg-14.repo - Unknown configuration option: async = 1 in /etc/yum.repos.d/pmm-server.repo - User-Agent: constructed: 'libdnf (Oracle Linux Server 9.2; server; Linux.x86_64)' - repo: using cache for: ol9_developer_EPEL - ol9_developer_EPEL: using metadata from Wed 28 Jun 2023 02:28:50 PM UTC. - repo: using cache for: ol9_baseos_latest - ol9_baseos_latest: using metadata from Fri 23 Jun 2023 04:59:24 AM UTC. - repo: using cache for: ol9_appstream - ol9_appstream: using metadata from Fri 23 Jun 2023 05:03:17 AM UTC. - repo: using cache for: percona-release-x86_64 - percona-release-x86_64: using metadata from Mon 26 Jun 2023 01:02:27 PM UTC. - repo: using cache for: percona-release-noarch - percona-release-noarch: using metadata from Wed 06 Jul 2022 08:25:44 PM UTC. - repo: using cache for: percona-testing-x86_64 - percona-testing-x86_64: using metadata from Wed 28 Jun 2023 05:27:06 PM UTC. - repo: using cache for: percona-testing-noarch - percona-testing-noarch: using metadata from Wed 06 Jul 2022 08:20:55 PM UTC. - repo: using cache for: percona-ppg-11 - percona-ppg-11: using metadata from Mon 22 May 2023 08:40:15 AM UTC. - repo: using cache for: percona-ppg-14 - percona-ppg-14: using metadata from Wed 28 Jun 2023 02:57:51 PM UTC. - repo: using cache for: prel-release-noarch - prel-release-noarch: using metadata from Thu 16 Sep 2021 06:35:55 AM UTC. - repo: using cache for: pmm-server - pmm-server: using metadata from Wed 28 Jun 2023 02:46:09 PM UTC. - Last metadata expiration check: 0:59:54 ago on Wed 28 Jun 2023 07:06:43 PM UTC. - `, "\n") - actual, err := parseInfo(stdout, "Name") - require.NoError(t, err) - assert.Empty(t, actual) - }) - - t.Run("RepoInfo EL9", func(t *testing.T) { - // yum repoinfo pmm-server. - stdout := strings.Split(` - Last metadata expiration check: 9:26:06 ago on Wed 28 Jun 2023 09:26:18 AM UTC. - Repo-id : pmm-server - Repo-name : PMM Server YUM repository - x86_64 - Repo-status : enabled - Repo-revision : 1687873070 - Repo-updated : Tue 27 Jun 2023 01:25:23 PM UTC - Repo-pkgs : 478 - Repo-available-pkgs: 478 - Repo-size : 3.7 G - Repo-baseurl : https://repo.percona.com/pmm3-components/yum/experimental/9/RPMS/x86_64/ - Repo-expire : 172,800 second(s) (last: Wed 28 Jun 2023 09:26:18 AM UTC) - Repo-filename : /etc/yum.repos.d/pmm-server.repo - Total packages: 478 - `, "\n") - expected := map[string]string{ - "Repo-id": "pmm-server", - "Repo-name": "PMM Server YUM repository - x86_64", - "Repo-status": "enabled", - "Repo-revision": "1687873070", - "Repo-updated": "Tue 27 Jun 2023 01:25:23 PM UTC", - "Repo-pkgs": "478", - "Repo-available-pkgs": "478", - "Repo-size": "3.7 G", - "Repo-baseurl": "https://repo.percona.com/pmm3-components/yum/experimental/9/RPMS/x86_64/", - "Repo-expire": "172,800 second(s) (last: Wed 28 Jun 2023 09:26:18 AM UTC)", - "Repo-filename": "/etc/yum.repos.d/pmm-server.repo", - "Total packages": "478", - } - actual, err := parseInfo(stdout, "Repo-id") - require.NoError(t, err) - assert.Equal(t, expected, actual) - releasetime, err := parseInfoTime(actual["Repo-updated"]) - require.NoError(t, err) - assert.Equal(t, time.Date(2023, time.June, 27, 13, 25, 23, 0, time.UTC), releasetime) - }) -} - -func TestGetRHELVersion(t *testing.T) { - t.Run("getRHELVersion EL9", func(t *testing.T) { - actual, err := getRHELVersion() - if actual == "7" { - t.Skip("Skip running EL9 tests on EL7") - } - expected := "9" - require.NoError(t, err) - assert.Equal(t, expected, actual) - }) - - t.Run("getRHELVersion EL7", func(t *testing.T) { - actual, err := getRHELVersion() - if actual == "9" { - t.Skip("Skip running EL7 test on EL9") - } - expected := "7" - require.NoError(t, err) - assert.Equal(t, expected, actual) - }) -} diff --git a/update/pkg/yum/yum.go b/update/pkg/yum/yum.go deleted file mode 100644 index 008ad208b1..0000000000 --- a/update/pkg/yum/yum.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package yum - -import ( - "context" - "strings" - "time" - - "github.com/pkg/errors" - - "github.com/percona/pmm/update/pkg/run" - "github.com/percona/pmm/version" -) - -const ( - yumInfoCancelTimeout = 30 * time.Second // must be _much_ less than stopwaitsecs in supervisord config - yumUpdateCancelTimeout = 120 * time.Second // must be less than stopwaitsecs in supervisord config - changeLogURLPath = "https://per.co.na/pmm/" -) - -// http://man7.org/linux/man-pages/man8/yum.8.html#LIST_OPTIONS - -// Installed returns current version information for a package with given name. -// It runs quickly. -func Installed(ctx context.Context, name string) (*version.UpdateInstalledResult, error) { - cmdLine := "yum --verbose info installed " + name - stdout, _, err := run.Run(ctx, yumInfoCancelTimeout, cmdLine, nil) - if err != nil { - return nil, errors.Wrapf(err, "%#q failed", cmdLine) - } - - info, err := parseInfo(stdout, "Name") - if err != nil { - return nil, err - } - res := version.PackageInfo{ - Version: niceVersion(info), - FullVersion: fullVersion(info), - Repo: info["From repo"], - } - buildTime, err := parseInfoTime(info["Buildtime"]) - if err == nil { - res.BuildTime = &buildTime - } - return &version.UpdateInstalledResult{ - Installed: res, - }, nil -} - -// getReleaseTime returns date and time when repo was updated (packages published or repo got rebuilt). -func getReleaseTime(ctx context.Context, repo string) (string, error) { - cmdLine := "yum repoinfo " + repo - stdout, _, err := run.Run(ctx, yumInfoCancelTimeout, cmdLine, nil) - if err != nil { - return "", errors.Wrapf(err, "%#q failed", cmdLine) - } - - info, err := parseInfo(stdout, "Repo-id") - if err != nil { - return "", err - } - - if time, ok := info["Repo-updated"]; ok { - return time, nil - } - - return "", errors.New("Repo-updated field is not found in repoinfo") -} - -// Check returns up-to-date versions information for a package with given name. -// It runs slowly. -func Check(ctx context.Context, name string) (*version.UpdateCheckResult, error) { - repoPropName := "Repository" // default value for RHEL9 - - installed, err := Installed(ctx, name) - if err != nil { - return nil, err - } - res := &version.UpdateCheckResult{ - Installed: installed.Installed, - } - - cmdLine := "yum --verbose info updates " + name - stdout, stderr, err := run.Run(ctx, yumInfoCancelTimeout, cmdLine, nil) - if err != nil { - if strings.Contains(strings.Join(stderr, "\n"), "Error: No matching Packages to list") { - // no update available, return the same values - res.Latest = res.Installed - return res, nil - } - - return nil, errors.Wrapf(err, "%#q failed", cmdLine) - } - - info, err := parseInfo(stdout, "Name") - if err != nil { - return nil, err - } - - v, err := getRHELVersion() - if err == nil && v == "7" { - // change the prop name for EL7 - repoPropName = "Repo" - } - repo, ok := info[repoPropName] - if !ok { - return nil, errors.New("Repository field is not found in yum info") - } - - res.Latest = version.PackageInfo{ - Version: niceVersion(info), - FullVersion: fullVersion(info), - Repo: repo, - } - - // replace Buildtime with repo release time to show time of release. - repoUpdated, err := getReleaseTime(ctx, repo) - if err != nil { - return nil, err - } - releaseTime, err := parseInfoTime(repoUpdated) - if err == nil { - res.Latest.BuildTime = &releaseTime - } - - res.LatestNewsURL = changeLogURLPath + res.Latest.Version - - res.UpdateAvailable = true - return res, nil -} - -// Update updates package with given name. -func Update(ctx context.Context, name string) error { - cmdLine := "yum update --assumeyes " + name - _, _, err := run.Run(ctx, yumUpdateCancelTimeout, cmdLine, nil) - if err != nil { - return errors.Wrapf(err, "%#q failed", cmdLine) - } - return nil -} diff --git a/update/pkg/yum/yum_test.go b/update/pkg/yum/yum_test.go deleted file mode 100644 index a508b47749..0000000000 --- a/update/pkg/yum/yum_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package yum - -import ( - "context" - "os" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var gaReleaseDate = time.Date(2019, 9, 18, 0, 0, 0, 0, time.UTC) - -const ( - pmmManagedPackageName = "pmm-managed" -) - -func TestInstalled(t *testing.T) { - res, err := Installed(context.Background(), pmmManagedPackageName) - require.NoError(t, err) - - assert.True(t, strings.HasPrefix(res.Installed.Version, "3."), "installed version should start with `3.`. Actual value is: %s", res.Installed.Version) - assert.True(t, strings.HasPrefix(res.Installed.FullVersion, "3."), "installed full version should start with `3.`. Actual value is: %s", res.Installed.FullVersion) - require.NotEmpty(t, res.Installed.BuildTime) - assert.True(t, res.Installed.BuildTime.After(gaReleaseDate), "Installed.BuildTime = %s", res.Installed.BuildTime) - assert.Equal(t, "local", res.Installed.Repo) -} - -func TestCheck(t *testing.T) { - res, err := Check(context.Background(), pmmManagedPackageName) - - require.NoError(t, err) - - assert.True(t, strings.HasPrefix(res.Installed.Version, "3."), "installed version should start with `3.`. Actual value is: %s", res.Installed.Version) - assert.True(t, strings.HasPrefix(res.Installed.FullVersion, "3."), "installed full version should start with `3.`. Actual value is: %s", res.Installed.FullVersion) - require.NotEmpty(t, res.Installed.BuildTime) - assert.True(t, res.Installed.BuildTime.After(gaReleaseDate), "Installed.BuildTime = %s", res.Installed.BuildTime) - assert.Equal(t, "local", res.Installed.Repo) - - assert.True(t, strings.HasPrefix(res.Latest.Version, "3."), "The latest available version should start with `3.`. Actual value is: %s", res.Latest.Version) - assert.True(t, strings.HasPrefix(res.Latest.FullVersion, "3."), "The latest available versions full value should start with `3.`. Actual value is: %s", res.Latest.FullVersion) - require.NotEmpty(t, res.Latest.BuildTime) - assert.True(t, res.Latest.BuildTime.After(gaReleaseDate), "Latest.BuildTime = %s", res.Latest.BuildTime) - assert.NotEmpty(t, res.Latest.Repo) - - // We assume that the latest perconalab/pmm-server:3-dev-latest image - // always contains the latest pmm-update package versions. - // If this test fails, re-pull them and recreate devcontainer. - var updateAvailable bool - image := os.Getenv("PMM_SERVER_IMAGE") - require.NotEmpty(t, image) - if image != "perconalab/pmm-server:3-dev-latest" { - updateAvailable = true - } - - if updateAvailable { - t.Log("Assuming pmm-update update is available.") - assert.True(t, res.UpdateAvailable, "update should be available") - - // latest_news_url may not be present yet for this version if VERSION file was bumped already, - // but pmm-update.spec's changelog wasn't updated yet - if res.LatestNewsURL != "" { - assert.True(t, strings.HasPrefix(res.LatestNewsURL, "https://per.co.na/pmm/3."), "latest_news_url = %q", res.LatestNewsURL) - } - - assert.NotEqual(t, res.Installed.Version, res.Latest.Version, "versions should not be the same") - assert.NotEqual(t, res.Installed.FullVersion, res.Latest.FullVersion, "versions should not be the same") - assert.NotEqual(t, *res.Installed.BuildTime, *res.Latest.BuildTime, "build times should not be the same (%s)", *res.Installed.BuildTime) - assert.Equal(t, "pmm-server", res.Latest.Repo) - } else { - t.Log("Assuming the latest pmm-update version.") - assert.False(t, res.UpdateAvailable, "update should not be available") - assert.Empty(t, res.LatestNewsURL, "latest_news_url should be empty") - assert.Equal(t, res.Installed, res.Latest, "version should be the same (latest)") - assert.Equal(t, *res.Installed.BuildTime, *res.Latest.BuildTime, "build times should be the same") - assert.Equal(t, "local", res.Latest.Repo) - } -} - -func TestUpdate(t *testing.T) { - err := Update(context.Background(), "make") - require.NoError(t, err) -} diff --git a/version/parsed.go b/version/parsed.go index dce3d6887d..0d319047cd 100644 --- a/version/parsed.go +++ b/version/parsed.go @@ -19,6 +19,7 @@ import ( "fmt" "regexp" "strconv" + "strings" "github.com/pkg/errors" ) @@ -100,3 +101,14 @@ func (p *Parsed) Less(right *Parsed) bool { return p.Rest < right.Rest } + +func (p *Parsed) UnmarshalJSON(b []byte) error { + s := string(b) + s = strings.Trim(s, `"`) + parsed, err := Parse(s) + if err != nil { + return err + } + *p = *parsed + return nil +} diff --git a/version/update.go b/version/update.go index 5441043343..235004df4d 100644 --- a/version/update.go +++ b/version/update.go @@ -32,8 +32,15 @@ type UpdateInstalledResult struct { // UpdateCheckResult represents `pmm-update -check` result. type UpdateCheckResult struct { - Installed PackageInfo `json:"installed"` - Latest PackageInfo `json:"latest,omitempty"` - UpdateAvailable bool `json:"update_available"` - LatestNewsURL string `json:"latest_news_url"` + Installed PackageInfo `json:"installed"` + Latest DockerVersionInfo `json:"latest,omitempty"` + UpdateAvailable bool `json:"update_available"` + LatestNewsURL string `json:"latest_news_url"` +} + +// DockerVersionInfo describes the version of the Docker image. +type DockerVersionInfo struct { + Version Parsed `json:"version"` + DockerImage string `json:"docker_image"` + BuildTime time.Time `json:"build_time"` } From 32e669de34fb432ef153e4f0d0b7c16a6b7b9c73 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 15 Apr 2024 14:46:21 +0300 Subject: [PATCH 19/33] PMM-12762 Fix deadlock --- managed/services/supervisord/supervisord.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/managed/services/supervisord/supervisord.go b/managed/services/supervisord/supervisord.go index f91d6bc76e..f850194900 100644 --- a/managed/services/supervisord/supervisord.go +++ b/managed/services/supervisord/supervisord.go @@ -101,10 +101,6 @@ func New(configDir string, params *models.Params) *Service { // Run reads supervisord's log (maintail) and sends events to subscribers. func (s *Service) Run(ctx context.Context) { - var wg sync.WaitGroup - wg.Add(1) - defer wg.Wait() - if s.supervisorctlPath == "" { s.l.Errorf("supervisorctl not found, updates are disabled.") return From 302441b62a657537926ae7223c3baac83dd06346 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 15 Apr 2024 14:50:03 +0300 Subject: [PATCH 20/33] PMM-12762 Fix linters. --- managed/services/server/updater.go | 4 +--- version/parsed.go | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index d4093d7d81..66cdef1cff 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -265,9 +265,7 @@ func (up *Updater) parseDockerTag(tag string) (*version.DockerVersionInfo, error parsed, err := version.Parse(splitTag[1]) if err != nil { up.l.Debugf("Failed to parse version: %s", splitTag[1]) - return &version.DockerVersionInfo{ - DockerImage: tag, - }, nil + return &version.DockerVersionInfo{DockerImage: tag}, nil //nolint:nilerr } return &version.DockerVersionInfo{ Version: *parsed, diff --git a/version/parsed.go b/version/parsed.go index 0d319047cd..a256beeef6 100644 --- a/version/parsed.go +++ b/version/parsed.go @@ -102,6 +102,7 @@ func (p *Parsed) Less(right *Parsed) bool { return p.Rest < right.Rest } +// UnmarshalJSON implements json.Unmarshaler interface and allows to unmarshal version information from JSON. func (p *Parsed) UnmarshalJSON(b []byte) error { s := string(b) s = strings.Trim(s, `"`) From d49ce3ff8cf3d6a265aceab217453a0b57108479 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 12:42:53 +0300 Subject: [PATCH 21/33] PMM-12762 add more log info. --- .github/workflows/clean.yml | 2 -- .github/workflows/managed.yml | 5 +++++ docker-compose.yml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/clean.yml b/.github/workflows/clean.yml index 90dfcbc3e8..73c6ab1abd 100644 --- a/.github/workflows/clean.yml +++ b/.github/workflows/clean.yml @@ -15,8 +15,6 @@ jobs: go: - version: 1.21.x may-fail: false - - version: tip - may-fail: true continue-on-error: ${{ matrix.go.may-fail }} runs-on: ubuntu-22.04 diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 120d538409..4bf6306263 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -120,3 +120,8 @@ jobs: env | sort go env | sort git status + docker exec pmm-server supervisorctl status + docker exec pmm-server supervisorctl tail -f all + docker exec pmm-server env + docker exec pmm-server go version + docker exec pmm-server tail /srv/logs/*.log diff --git a/docker-compose.yml b/docker-compose.yml index 0195e96f9f..d2361164fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -247,7 +247,7 @@ services: - GF_DATABASE_URL=postgres://grafana:grafana@pg:5432/grafana # - GF_DATABASE_SSL_MODE=require # - PMM_DEBUG=1 - - GO_VERSION=1.20 + - GO_VERSION=1.22 - PMM_VM_URL=${PMM_VM_URL:-http://victoriametrics:8428/} - PMM_TEST_HA_ENABLE=1 - PMM_TEST_HA_BOOTSTRAP=1 From d9357f6b580aeba16e477455f9f0588ce7df5afd Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 12:49:48 +0300 Subject: [PATCH 22/33] PMM-12762 add more log info. --- .github/workflows/managed.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 4bf6306263..3905d898a3 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -121,7 +121,7 @@ jobs: go env | sort git status docker exec pmm-server supervisorctl status - docker exec pmm-server supervisorctl tail -f all docker exec pmm-server env - docker exec pmm-server go version + docker exec pmm-server go env docker exec pmm-server tail /srv/logs/*.log + docker exec pmm-server supervisorctl tail all From b1f4d648c51c5985ead4722e6f6f8ce3f15c6b61 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 12:56:45 +0300 Subject: [PATCH 23/33] PMM-12762 add more log info. --- .github/workflows/managed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 3905d898a3..f27c8b0f68 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -120,8 +120,8 @@ jobs: env | sort go env | sort git status - docker exec pmm-server supervisorctl status docker exec pmm-server env docker exec pmm-server go env docker exec pmm-server tail /srv/logs/*.log + docker exec pmm-server supervisorctl status docker exec pmm-server supervisorctl tail all From fe9a6b9ba5e84fde0bcdd7c8bc51e8e6ae95fea6 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 13:04:07 +0300 Subject: [PATCH 24/33] PMM-12762 add more log info. --- .github/workflows/managed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index f27c8b0f68..7b5a3f7ce0 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -122,6 +122,6 @@ jobs: git status docker exec pmm-server env docker exec pmm-server go env - docker exec pmm-server tail /srv/logs/*.log + docker exec pmm-server tail /srv/logs/* docker exec pmm-server supervisorctl status docker exec pmm-server supervisorctl tail all From 1adc8f5c40b7c4d968d676820b0ff98d4263c10a Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 13:22:33 +0300 Subject: [PATCH 25/33] PMM-12762 add more log info. --- .github/workflows/managed.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 7b5a3f7ce0..705bcdcc50 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -122,6 +122,10 @@ jobs: git status docker exec pmm-server env docker exec pmm-server go env - docker exec pmm-server tail /srv/logs/* docker exec pmm-server supervisorctl status - docker exec pmm-server supervisorctl tail all + services=$(docker exec pmm-server supervisorctl status | awk '{print $1}') + lines=() + while IFS= read -r service; do + echo "Logs for $service:" + docker exec pmm-server supervisorctl tail $service + done <<< "$services" \ No newline at end of file From 2255735386a098ef88325b9d5ae17e93cdf1d7e9 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 13:32:35 +0300 Subject: [PATCH 26/33] PMM-12762 add more log info. --- .github/workflows/managed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 705bcdcc50..b2e79118ba 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -122,7 +122,7 @@ jobs: git status docker exec pmm-server env docker exec pmm-server go env - docker exec pmm-server supervisorctl status + docker exec pmm-server supervisorctl status || true services=$(docker exec pmm-server supervisorctl status | awk '{print $1}') lines=() while IFS= read -r service; do From 0479c9f4d499287c79b52cd9f8f9ebd18887723f Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 13:48:11 +0300 Subject: [PATCH 27/33] PMM-12762 set PMM version. --- docker-compose.yml | 1 + managed/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index d2361164fc..4db9caabd1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: - PERCONA_TEST_VERSION_SERVICE_URL=${PERCONA_TEST_VERSION_SERVICE_URL} - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://watchtower:8080} - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-INSECURE_TOKEN} + # - PMM_RELEASE_VERSION=3.0.0-alpha # - PERCONA_TEST_PLATFORM_ADDRESS=https://check.localhost # - PERCONA_TEST_PLATFORM_INSECURE=1 # - PERCONA_TEST_PLATFORM_PUBLIC_KEY= diff --git a/managed/Makefile b/managed/Makefile index 48005e7d3c..e71b80b79c 100644 --- a/managed/Makefile +++ b/managed/Makefile @@ -8,7 +8,7 @@ help: ## Display this help message # `cut` is used to remove first `v` from `git describe` output PMM_RELEASE_PATH ?= ../bin -PMM_RELEASE_VERSION ?= $(shell git describe --always --dirty | cut -b2-) +PMM_RELEASE_VERSION ?= $(shell git describe --always | cut -b2-) PMM_RELEASE_TIMESTAMP ?= $(shell date '+%s') PMM_RELEASE_FULLCOMMIT ?= $(shell git rev-parse HEAD) PMM_RELEASE_BRANCH ?= $(shell git describe --always --contains --all) From 7045e328efef6c7436ecf5057364663be7eab682 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 15:03:20 +0300 Subject: [PATCH 28/33] PMM-12762 set PMM version. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4db9caabd1..7318b9dd0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: - PERCONA_TEST_VERSION_SERVICE_URL=${PERCONA_TEST_VERSION_SERVICE_URL} - PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://watchtower:8080} - PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-INSECURE_TOKEN} - # - PMM_RELEASE_VERSION=3.0.0-alpha + - PMM_RELEASE_VERSION=3.0.0-alpha # - PERCONA_TEST_PLATFORM_ADDRESS=https://check.localhost # - PERCONA_TEST_PLATFORM_INSECURE=1 # - PERCONA_TEST_PLATFORM_PUBLIC_KEY= From 9d89d227ed26079624faaae1be18700eba0685dc Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Tue, 16 Apr 2024 15:06:55 +0300 Subject: [PATCH 29/33] Update managed/services/server/updater.go Co-authored-by: Alex Demidoff --- managed/services/server/updater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 6b2f9c24d4..9fc66da088 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -185,7 +185,7 @@ func (s *Updater) latest(ctx context.Context) (*version.PackageInfo, error) { return s.parseDockerTag(os.Getenv("PMM_SERVER_UPDATE_VERSION")), nil } - // File does not exist, ENV variable doesn't provided, get the latest tag from DockerHub + // If file does not exist, and ENV variable is not set, go get the latest tag from DockerHub u := "https://registry.hub.docker.com/v2/repositories/percona/pmm-server/tags/" req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { From e07cc83b581ac26438a4f859c66682ad099c6352 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Sat, 20 Apr 2024 00:27:03 +0300 Subject: [PATCH 30/33] PMM-12762 fix merge conflicts. --- descriptor.bin | Bin 705527 -> 706002 bytes managed/cmd/pmm-managed/main.go | 2 -- 2 files changed, 2 deletions(-) diff --git a/descriptor.bin b/descriptor.bin index 212cdbd67aee2c18f29c9556d7bffc155d8660bb..052c2284800704ed65022b356ca2d98b62cc4382 100644 GIT binary patch delta 6163 zcmZ8ldvH|M8Q<^h&E4ITWV5+<17Q=$@<@0E3=a_mTcoH6G6)oDrK5ms)6|&I1SzG| zMJDwD3gICq28!}Z5sJn!5)?#+QU^;JN|B+X9VZ=U9NHP3($3UUTc^M8+;i{6{&#=p ze82DeoyYxtclV2@NB?2d==E*XCfcHHR$D=v-4<($wW8hxK zy(e4c6i2?gK*pScNaQy{y?!m0?scD%&&Kj|NJ<&C;^ahU#s|m>X<2a*aiVvNvP?32 z|J=FR2XZZ~4b4qsr7V&KJXyfAaUX$rcOvDZD3F_$S)B$`vqWje&3gK?T3r^a4suZ* z$z}z~h#83@lZ=pTR!K@$>SV%+&K9FGCD{eJ#@w>jT$Yy~Boa1HR~V*1p4pYvK0=<^ zBSvDK!b&*S+{kylH75|2oExu{lTaYRi=L<6d|r+pk7uNtCyI3fAOy}!_V*Fe&C68C z37Une`Jze<*eu7?B?N&tU$`ccmoq<|@ez3Q2M&_o&^#<>p<2CJ-VT<)CM*=TiDU5# zV}3OO)l8`JT5?5>XGvGqMobB=6G_;mHGlh$Th@5CWGZ9Gwmb z>6VoB)9DHw>!HXam0rF=ggq3mkkgT`kn=4S<(Ua;Z@Vm0pKOss>oADCOHE!N5SAvq zZ3RN!rTzNLp_-1Vfq#{zZ9F ze$g(ob$CYgdXo(ZarGt}5VF;q>P3834P3n{k7uwN0v2m%2w1G4!DuLUtj0*Ir=b{8 zjktnCprM#GG>L4cEPH=TbA3y$wKdz=T%T=hXv(#kn~oTqW|Qzng7S5$ce|W9 zJ}J08tP5DId|kj|#ld-UrV{fF$5%tUq@|J$Qt`vedQamLGGC*70 zq<;5;%;ZxEEO8SR7HJJYh`Sj=goZ_sltKpu!m0D(f&LHbSj>8{8kM>xmc?$O5SrQB zOfa->qO$%b7|rc#PzPg{cQwUlvRUokDMwDga{&P1j%r1Gs{qkV4Mf__gl_5)G1;#E z1!6wMZ-mtz5_u`@6e~AGK8bchL)A+WsK1rO7&FPo0GRe6s9UMbJH(XWW7x`v=uv^T zkr-=Yqo4xjz3Y?WE)HBV(x2ARwPOs|a;)tn%FLt%#ei`ig1VjH#NJZT%K>4~53y=v=`mjzZX3j%;jY;r?xdJw zh&G5j2@dd(KBt&tb*N(<@<9+|Aa;b}V<2`=!at`Nh#i!vl(m`|cdSnJtrz785aS?r zh86MM0vH@{9K=p0j?zS2>)mS4i?Rm91cC=^fv;vp7rhZc}>ti$Tz-Esn(_n?Q$y>{d#@Ok((s1sw>i^Y-kP~{+#n48AUP{(4{i^YET zPiHWe4b`nAtb}DgqqfT_=|v;JD^$Dn5)D`cyuT<9<^@ zEU3rXb-c1bZ;=>i6yq!2Y5?}Rd_Hga#^VZn$O9VVadF43w|(OQ!ma{(#sdiI+rIGt zg8DWa&j#ZA#TrklFJF>R06p6Q1oa)? zb^t+r$G06<;3QA^wgUwDfK$BJ4j8FU`E3ResZRN}1Bg_o*mi2Qe3-y#HEu6Vz||&j zI@~ihfzuT8>F2EZ__IL@35?~HM?BZ?w6HNpTs4=tk)m`k?Fi|f`G_$o=vbu zXM!VKP(R%-hk(eAa3Peyj&Olu{`<;~aDmki*F-qNMfLmrawv%G2p2;lJHkcZN-zuJ zMS_)#)I@l~B~^1kR)bgy;-!$t7IBGURc1>{LA*pmhUqT^S2&J!Sv_$8UkG>x@p4FH z1GyaTmILBt-mPj~(RHjV>goYG7(^GuDZsv?seBRH^Gm5a|6Oz0eWv4AYwoAy$ujq zKVomI=Coyw{V_%UY|@q?^ka%w$=k8UGEUp4t{;?>@_2^SKK~X1BC?MXUh4rw(mv|% z*()Gk);=2W4OuD^oG1QTJc*9kN0~dch4*u;Pbe}}`*c5K`h?XROBQoftNPPYCT#Pbkwol^Qkk0C@{r_s}l2!e>elQqGJAR|H#c_I*D|AVZ51|rB} z5oYKCtwA{U4H6qfG;??MzTC1Es_&4zFMoq<{Rxe#>`*tTyv|f*54u59zb(BIFcSOU zWc?Qk>AXBhRZHM#m;cqY^R;!vhm}~-X*L(LB#^IY%}OBo1aaRV;gaR()_pPMdl#TsD7G9SoPv#(XebwvF^%!g?hTVJkX{W%Kx9 zVI2+1+PbV6!go8C9dqn%A>L9Oev&Ktco$9xaTd!Sn^kumm6P))gss2RcoHH`i2nKq zHbaOwA*ReXBH~DYQdsW>BH~7b8T3SO)M;V;IuH@pBD|sH_R5y#Rm~IRhvl;W;|;mh Nxu)L#9F<>|{SPek?yLX+ delta 5847 zcmZu#eQcH09lqz>)A!zc`hD8c_O_+3rF@o;@}UTVQG$RdZkTBe? zZWn|wR5$O ze$Veb=j->p?QeEA-F&g>`5epfTs$Xoc{wka$R%^BcjeA@{^#e0f7~w1;w-1@y5z&D zCh4tf>CSX@>p2~=PVeoKeHG|XxN8iXFrbZkU?_*>m_mXcpSA`>bv7JHBD z6JI3Chfi*kI}+88FeznRB$9z~G1pr|rH zaiDaKoNibME#lSsNROPUcAML^Fdw0wFY?8-8U(Az^9tVAKswzOlsHv6phAvcm z32#a(e{oA!x8M3yruAvRd+qwnWa-ic^e^Ex0Ya%IwPON=QcK29kSWPUO2wDP>Sz<2 zL<(6;lW71hq!P|zYF}^HWBk#l1l6H5w-n&Q6X~u5|UhV_~A#ZuA%*+CWS(cBe zl%os_p%wdHlJ$!uXCSQzNwl>qLK1E53Xn)bz7kKwzHKGsBkKuBXhgAmlCV;@y(Il+ z{6@8vt{M>XR=R3HsJ7Bc$fwg-1qq|)tqRj=@>O9vO}@%aUZ6xv>?u2W0kT?fyBaWg z0ZrbjNA}8*_u@Csp_SV`2ZEH={8F=iAh24MJpmxpZXH=K?>03M%INR*${EcCW;-%Y z5fFu(A|S9bP&Cf4aMRlK=e@EKEV^lJ?xq2O)t1P2Gt*6LD=L=Dv5AFBJRR%Q)Aq`x zst{RE<9r`PwL)6Qdfm5IKG2NcxGn2>+VFvpx4xz>K&ZCfze7H3SO~Ri*(Vo*MQ@}% zWRddrkVVSd!CGWkP~M?m=#%ro;$U@zEK=SPvPgM{VR2EU#Kzcj`evWJZv?&ZB4ln% zR?D%dSVZbK=|}d-`Wf`Hfl+mns|tkNO*IqE3V={`)0Ad8(J&F(tPkyzjgCpH*c>ux z6`O0uIVP=QbJIlGY?xTZ7R|LB=a{sTEg_RuvL&38Rv z2XAw+6i_2bxmm(C*-%T%Tr$)nIf6md=Ef;lQR#Bgn7#&0E~1l2FiuANkn!4dz5iI} z#*DxANq?hh=UskFXGZUSS(Z#kQl823Y(+XRkkBfPayl?T^h#S1!L9n^m*x0uF})VC zmEq#sOj_esmZ%CKh+7%Dq>;@bY#ZZ~ToA`ausndEZetbW0to6hhO@R*pcfgR?1FJn z0ki1`vf?W~Nfg*FelI~X7Bf_bO} zCG(VP3_7!Xq+?ullECjq8voYWMEd)P={PBlchRImQ(O*sifi3RsE z?k+TkX#tjxbwmkbFPkt?-f4*NmOef0RXG*Je9YJvNrlw_CW2kf2eFTh8ZD<8B78yX zeXq*NAQphABO+`9Fj4DfEC5ln`a9(PhKNS|ioW@(oC{(hh_6IM^ku-1SP0@PM4VxW z=!5;b?SO2aSImoWA^M{WQG`1EEW8iskbo+R~&&Ew~%8QjapnrG3C@%)_KqLSS z2{05;4B`P2FxLnuQR1MU{hFMG=T`#a!RT~KKs?Csjbblk35W+7x;fc5XsD8$sq)@ru|tfRP$@!hGFUr3fKuun189e)AP~+J&_00Dxu#DHuzY*Q2xGnh z27jcoN_mG_>{qU=LfOMCStn~Ty}|_>)Kd=1>a3!MIv6xmAmrT+(J~AqHHt3ZV9-H< z{s)>|*H2Z-pi=v$fJ|-#T{LT!spuLHvhopTnLs8vf+iWziolrOQB4w2echK3k>cNmay#+5Lq0WPN6BLBv_QuguXEGlJDgy^rQ*nOkJI}vycqF|n2 z&SMmH_mhFg0HF?`^%y`JnM**6A^Qm2BR0*F$l0*?Vi zsZ-=J6ODXy{L{MN4Rm~EI{xWs)2QR0W(n(6h=O>UZai7K;&_n5y6p{EI(}ou;fP3& zZa6R}L_r*;Zx7!P(ecmF*M;&Q*wC_iUBfXhnd0ORX9Fu!9R6_5SQ!>Z{%|fj z74nC3ft4W&;yJQ1djsJQ?=wEeErJ{ZFqo4Z;{Cvr6eovxpFD|NP;ofK2e^UhQT~G) zx-*^6wyf*&SL?)pti`bu;ie#JTP7eXeGu3pAS!)8wm8OAf=8U!j}OQO5XmFXM-s>* z&a*`Ds>vhHlY06bR~*g$f<7`JM}bHlaUmj7@4pb33!)%iU@({QhFGe^Ma>S$(IA$B zcrhZ9GhAeedbcH|AYNn*jpmy{aizp1{mnyi%su!G;-!eFK)e*~mICn-?bc{BW0?|{ z8E;5e;s)vBw`4VDE<*tf2HRbR0+%Dn^k^@WWV=b_N?g(2Te1O1Tn^%uh*%Ed6_yD4 zNI8gCsKb&!l_~E-7W=jHCz|3zmKVuM}h4D;miQ-jRr*SM}g}BqUuNFdZVdq zx$-_{u}@rC67Vrg*2~#gYdMv@s;|5y?`p?yNWB`|MnGg0siGZuSKcN~@r)MqSN zME{fVVo>5;WBgD0mxtw@*=x)zq={%8Rj;uk)9?vG#x*wft{{r$^f?nVNCrj4@ykDN za6`qGFO>HOCjQ7gSCkrN1{Qf04b;JoA?l#UbK4 zD>0vZ1R>%&YntOkFo^gI6Vsgt=0unwD*_qb7fk#$6u|_Ea6^w94P1FQ7{3V(3;e~I zmNok9+j4RC2J?&~VOH|58?36?%}NG!gWdC(v{S%lyuUN?C8j7dd%>-YU@*%12NPd~ zLbws)h87wjapm1&{0BUqp6TmtN96t4Tlf>$%^HV@Tdd5qA!s72yTztH;6&g{%KIl1 z{|-gOod`E*MNrm%n0Nut$sS4Eh;TzQjR>UVINt>kV|~5g9XU0d^qyA#5RaD!F^W$obNN1+H|M7SaRCkylBDX)j~mm#9r*I&IO zXJ>oht8Ugji0I+rPLTcf@Ng&aVdL%QqBj(g=R~+cD}u82a-l;Jc}9dAnrB3K%G=NR z8xS$g*F#6;ob3K+Cp?JQAMFGg`Tl4pJe2R};YA5F(EASxcRW zB+8%Q;@wb0(ur_`Rs?08=Hh3eh@=r=hgN&fbhdZ5PnW;1l9e0RW}eM#82;^${8z<) E0n;+I!vFvP diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index a486cc4369..ccde3d9425 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -969,8 +969,6 @@ func main() { //nolint:cyclop,maintidx dumpService := dump.New(db) - updater := server.NewUpdater(supervisord, *watchtowerHostF) - serverParams := &server.Params{ DB: db, VMDB: vmdb, From 62917376aa093811f737ca33f8c82d98455efb89 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Sat, 20 Apr 2024 11:44:06 +0300 Subject: [PATCH 31/33] Update .github/workflows/managed.yml Co-authored-by: Alex Demidoff --- .github/workflows/managed.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index b2e79118ba..60bea35d6e 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -124,7 +124,6 @@ jobs: docker exec pmm-server go env docker exec pmm-server supervisorctl status || true services=$(docker exec pmm-server supervisorctl status | awk '{print $1}') - lines=() while IFS= read -r service; do echo "Logs for $service:" docker exec pmm-server supervisorctl tail $service From 26b57d597ee289f26738ec05794d7596658e36a2 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 22 Apr 2024 11:16:39 +0300 Subject: [PATCH 32/33] PMM-12762 sort env variables. --- .github/workflows/managed.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 60bea35d6e..6c8489be46 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -120,8 +120,8 @@ jobs: env | sort go env | sort git status - docker exec pmm-server env - docker exec pmm-server go env + docker exec pmm-server env | sort + docker exec pmm-server go env | sort docker exec pmm-server supervisorctl status || true services=$(docker exec pmm-server supervisorctl status | awk '{print $1}') while IFS= read -r service; do From dac9a3ff59aa95647e32dd09e9d2802d37b6ef13 Mon Sep 17 00:00:00 2001 From: Nurlan Moldomurov Date: Mon, 24 Jun 2024 11:37:24 +0300 Subject: [PATCH 33/33] PMM-13028 Non blocking StartUpgrade operation (#2972) * PMM-13028 Non blocking StartUpgrade operation * PMM-13028 Fix imports * PMM-13028 Fix linters --- managed/services/server/updater.go | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index fe18fd8619..0240536e19 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "io" + "net" "net/http" "net/url" "os" @@ -30,6 +31,8 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" "github.com/percona/pmm/version" ) @@ -149,6 +152,12 @@ func (up *Updater) StartUpdate(ctx context.Context, newImageName string) error { return errors.New("newImageName is empty") } + err := up.checkWatchtowerHost() + if err != nil { + up.l.WithError(err).Error("Failed to check watchtower host") + return grpcstatus.Errorf(codes.FailedPrecondition, "failed to check watchtower host") + } + if err := up.sendRequestToWatchtower(ctx, newImageName); err != nil { up.l.WithError(err).Error("Failed to trigger update") return errors.Wrap(err, "failed to trigger update") @@ -389,3 +398,26 @@ func (up *Updater) check(ctx context.Context) error { up.lastCheckTime = time.Now() return nil } + +func (up *Updater) checkWatchtowerHost() error { + // Check if watchtower host is available + if up.watchtowerHost == nil { + return errors.New("watchtower host is not set") + } + if !isHostAvailable(up.watchtowerHost.Hostname(), up.watchtowerHost.Port(), updateDefaultTimeout) { + return errors.New("watchtower host is not available") + } + return nil +} + +func isHostAvailable(host string, port string, timeout time.Duration) bool { + conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout) + if err != nil { + return false + } + if conn != nil { + defer conn.Close() //nolint:errcheck + return true + } + return false +}