diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 75983458d2..e7c38a3d46 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -71,7 +71,7 @@ jobs: - name: Update API compatibility descriptors run: | # log if descriptors changed, useful for "update descriptors" PRs - make descriptors + make -C api descriptors git diff --text - name: Run check-license diff --git a/Makefile.include b/Makefile.include index f329c5aa5d..615f32251b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,5 +1,4 @@ -# vim: ts=8:sw=8:ft=make:noai:noet -SWAGGER_UI_VERSION?=latest + .PHONY: default init release gen test clean all default: help @@ -25,8 +24,8 @@ release: ## Build release versions of all components make -C qan-api2 release gen: clean ## Generate files - make gen-api - make clean_swagger + make -C api gen + make -C api clean-swagger make -C agent gen make -C admin gen @@ -38,129 +37,13 @@ gen: clean ## Generate files make format ## TODO: One formatting run is not enough, figure out why. go install -v ./... +clean: ## Remove generated files + make -C api clean + gen-mocks: find . -name mock_*.go -delete ./bin/mockery --config .mockery.yaml -gen-api: ## Generate PMM API - # generated by descriptors target - bin/buf breaking --against descriptor.bin api - - bin/buf generate -v api - - SPECS="\ - api/agentlocal/v1 \ - api/server/v1 \ - api/user/v1 \ - api/inventory/v1 \ - api/management/v1 \ - api/management/v1/service \ - api/actions/v1 \ - api/advisors/v1 \ - api/alerting/v1 \ - api/backup/v1 \ - api/dump/v1beta1 \ - api/accesscontrol/v1beta1 \ - api/qan/v1 \ - api/platform/v1"; \ - for API in $$SPECS; do \ - set -x ; \ - bin/swagger mixin $$API/json/header.json $$API/*.swagger.json --output=$$API/json/$$(basename $$API).json --keep-spec-order; \ - bin/swagger flatten --with-flatten=expand --with-flatten=remove-unused $$API/json/$$(basename $$API).json --output=$$API/json/$$(basename $$API).json ; \ - bin/swagger validate $$API/json/$$(basename $$API).json ; \ - bin/swagger generate client --with-flatten=expand --with-flatten=remove-unused --spec=$$API/json/$$(basename $$API).json --target=$$API/json \ - --additional-initialism=aws \ - --additional-initialism=db \ - --additional-initialism=ok \ - --additional-initialism=pmm \ - --additional-initialism=psmdb \ - --additional-initialism=pxc \ - --additional-initialism=pt \ - --additional-initialism=qan \ - --additional-initialism=rds \ - --additional-initialism=sql \ - --additional-initialism=ha ; \ - done - - # generate public API spec, omit agentlocal and inventory (always private), - # as well as a number of protos that are in beta (not v1 yet, they all go to a similar call below) - bin/swagger mixin --output=api/swagger/swagger.json \ - api/swagger/header.json \ - api/server/v1/json/v1.json \ - api/user/v1/json/v1.json \ - api/inventory/v1/json/v1.json \ - api/management/v1/json/v1.json \ - api/actions/v1/json/v1.json \ - api/alerting/v1/json/v1.json \ - api/advisors/v1/json/v1.json \ - api/backup/v1/json/v1.json \ - api/qan/v1/json/v1.json \ - api/platform/v1/json/v1.json - bin/swagger validate api/swagger/swagger.json - - bin/swagger-order --output=api/swagger/swagger.json api/swagger/swagger.json - - # generate API spec with all PMM Server APIs (omit agentlocal) - bin/swagger mixin --output=api/swagger/swagger-dev.json \ - api/swagger/header-dev.json \ - api/server/v1/json/v1.json \ - api/user/v1/json/v1.json \ - api/inventory/v1/json/v1.json \ - api/management/v1/json/v1.json \ - api/actions/v1/json/v1.json \ - api/alerting/v1/json/v1.json \ - api/advisors/v1/json/v1.json \ - api/backup/v1/json/v1.json \ - api/dump/v1beta1/json/v1beta1.json \ - api/accesscontrol/v1beta1/json/v1beta1.json \ - api/qan/v1/json/v1.json \ - api/platform/v1/json/v1.json - - bin/swagger validate api/swagger/swagger-dev.json - - bin/swagger-order --output=api/swagger/swagger-dev.json api/swagger/swagger-dev.json - -clean_swagger: - find api -name '*.swagger.json' -print -delete - - -ifeq ($(shell test "${SWAGGER_UI_VERSION}" = "latest" && echo 1 || echo 0), 1) -get_swagger_version: -override SWAGGER_UI_VERSION = $(shell curl --silent --head https://github.com/swagger-api/swagger-ui/releases/latest | grep -E '^[lL]ocation' | sed 's;^.*/;;') -else -get_swagger_version: -endif - -update-swagger: get_swagger_version ## Update Swagger UI in api/swagger, use `SWAGGER_UI_VERSION=xxx make update-swagger` to choose a version other than latest - curl --output /tmp/swagger.tar.gz -sSfL "https://github.com/swagger-api/swagger-ui/archive/refs/tags/${SWAGGER_UI_VERSION}.tar.gz" - tar xf /tmp/swagger.tar.gz --transform 's;swagger-ui-.*/dist/;api/swagger/;g' - rm -f api/swagger/.npmrc - sed -i 's/url: ".*"/url: "\/swagger.json",\n validatorUrl: "none"/' api/swagger/swagger-initializer.js - -clean: clean_swagger ## Remove generated files - find api -name '*.pb.go' -print -delete - find api -name '*.pb.gw.go' -print -delete - find api -name '*.validate.go' -print -delete - - SPECS="\ - api/agentlocal/v1 \ - api/server/v1 \ - api/user/v1 \ - api/inventory/v1 \ - api/management/v1 \ - api/actions/v1 \ - api/alerting/v1 \ - api/advisors/v1 \ - api/backup/v1 \ - api/dump/v1beta1 \ - api/accesscontrol/v1beta1 \ - api/qan/v1 \ - api/platform/v1"; \ - for API in $$SPECS; do \ - rm -fr $$API/json/client $$API/json/models $$API/json/$$(basename $$API).json ; \ - done - rm -f api/swagger/swagger.json api/swagger/swagger-dev.json - test-common: ## Run tests from API (and other shared) packages only (i.e it ignores directories that are explicitly listed) go test $(shell go list ./... | grep -v -e admin -e agent -e managed -e api-tests -e qan-api2 -e update) @@ -182,14 +65,10 @@ check-all: check-license check ## Run golangci linter to check for changes ag FILES = $(shell find . -type f -name '*.go') format: ## Format source code + make -C api format bin/gofumpt -l -w $(FILES) bin/goimports -local github.com/percona/pmm -l -w $(FILES) bin/gci write --section Standard --section Default --section "Prefix(github.com/percona/pmm)" $(FILES) - bin/buf format api -w serve: ## Serve API documentation with nginx nginx -p . -c api/nginx/nginx.conf - -descriptors: ## Update API compatibility descriptors - #./prototool break descriptor-set . -o api/api.descriptor - bin/buf build -o descriptor.bin --as-file-descriptor-set api diff --git a/api-tests/server/updates_test.go b/api-tests/server/updates_test.go index 97ad81d822..e8ecd0c01b 100644 --- a/api-tests/server/updates_test.go +++ b/api-tests/server/updates_test.go @@ -71,6 +71,15 @@ func TestCheckUpdates(t *testing.T) { assert.NotEmpty(t, res.Payload.Installed.FullVersion) if res.Payload.UpdateAvailable { + require.NotEmpty(t, res.Payload.Latest) + assert.True(t, strings.HasPrefix(res.Payload.Latest.Version, "2.") || strings.HasPrefix(res.Payload.Installed.Version, "3."), + "latest.version = %q should have '2.' or '3.' prefix", res.Payload.Latest.Version) + require.NotEmpty(t, res.Payload.Latest.Timestamp) + ts = time.Time(res.Payload.Latest.Timestamp) + hour, min, _ = ts.Clock() + assert.Zero(t, hour, "latest.timestamp should contain only date") + assert.Zero(t, min, "latest.timestamp should contain only date") + assert.NotEmpty(t, res.Payload.Latest.Tag) require.NotEmpty(t, res.Payload.Latest.Timestamp) ts = time.Time(res.Payload.Latest.Timestamp) @@ -81,6 +90,7 @@ func TestCheckUpdates(t *testing.T) { 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) + assert.True(t, strings.HasPrefix(res.Payload.Latest.ReleaseNotesURL, "https://per.co.na/pmm/2."), "latest_news_url = %q", res.Payload.Latest.ReleaseNotesURL) } assert.NotEmpty(t, res.Payload.LastCheck) @@ -110,6 +120,32 @@ func TestCheckUpdates(t *testing.T) { }) } +func TestListUpdates(t *testing.T) { + const fast, slow = 5 * time.Second, 60 * time.Second + + if !pmmapitests.RunUpdateTest { + t.Skip("skipping PMM Server check update test") + } + + version, err := serverClient.Default.ServerService.Version(server.NewVersionParamsWithTimeout(fast)) + require.NoError(t, err) + if version.Payload.Server == nil || version.Payload.Server.Version == "" { + t.Skip("skipping test in developer's environment") + } + + params := &server.ListChangeLogsParams{ + Context: pmmapitests.Context, + } + params.SetTimeout(slow) + res, err := serverClient.Default.ServerService.ListChangeLogs(params) + require.NoError(t, err) + + if len(res.Payload.Updates) > 0 { + assert.True(t, strings.HasPrefix(res.Payload.Updates[0].Version, "3."), + "installed.version = %q should have '3.' prefix", res.Payload.Updates[0].Version) + } +} + func TestUpdate(t *testing.T) { // do not run this test in parallel with other tests diff --git a/api/Makefile b/api/Makefile new file mode 100644 index 0000000000..922866a671 --- /dev/null +++ b/api/Makefile @@ -0,0 +1,127 @@ +# vim: ts=8:sw=8:ft=make:noai:noet +SWAGGER_UI_VERSION?=latest + +gen: ## Generate PMM API + # generated by descriptors target + ../bin/buf breaking --against descriptor.bin . + + ../bin/buf generate -v . + + SPECS="\ + agentlocal/v1 \ + server/v1 \ + user/v1 \ + inventory/v1 \ + management/v1 \ + management/v1/service \ + actions/v1 \ + advisors/v1 \ + alerting/v1 \ + backup/v1 \ + dump/v1beta1 \ + accesscontrol/v1beta1 \ + qan/v1 \ + platform/v1"; \ + for API in $$SPECS; do \ + set -x ; \ + ../bin/swagger mixin $$API/json/header.json $$API/*.swagger.json --output=$$API/json/$$(basename $$API).json --keep-spec-order; \ + ../bin/swagger flatten --with-flatten=expand --with-flatten=remove-unused $$API/json/$$(basename $$API).json --output=$$API/json/$$(basename $$API).json ; \ + ../bin/swagger validate $$API/json/$$(basename $$API).json ; \ + ../bin/swagger generate client --with-flatten=expand --with-flatten=remove-unused --spec=$$API/json/$$(basename $$API).json --target=$$API/json \ + --additional-initialism=aws \ + --additional-initialism=db \ + --additional-initialism=ok \ + --additional-initialism=pmm \ + --additional-initialism=psmdb \ + --additional-initialism=pxc \ + --additional-initialism=pt \ + --additional-initialism=qan \ + --additional-initialism=rds \ + --additional-initialism=sql \ + --additional-initialism=ha ; \ + done + + # generate public API spec, omit agentlocal and inventory (always private), + # as well as a number of protos that are in beta (not v1 yet, they all go to a similar call below) + ../bin/swagger mixin --output=swagger/swagger.json \ + swagger/header.json \ + server/v1/json/v1.json \ + user/v1/json/v1.json \ + inventory/v1/json/v1.json \ + management/v1/json/v1.json \ + actions/v1/json/v1.json \ + alerting/v1/json/v1.json \ + advisors/v1/json/v1.json \ + backup/v1/json/v1.json \ + qan/v1/json/v1.json \ + platform/v1/json/v1.json + ../bin/swagger validate swagger/swagger.json + + ../bin/swagger-order --output=swagger/swagger.json swagger/swagger.json + + # generate API spec with all PMM Server APIs (omit agentlocal) + ../bin/swagger mixin --output=swagger/swagger-dev.json \ + swagger/header-dev.json \ + server/v1/json/v1.json \ + user/v1/json/v1.json \ + inventory/v1/json/v1.json \ + management/v1/json/v1.json \ + actions/v1/json/v1.json \ + alerting/v1/json/v1.json \ + advisors/v1/json/v1.json \ + backup/v1/json/v1.json \ + dump/v1beta1/json/v1beta1.json \ + accesscontrol/v1beta1/json/v1beta1.json \ + qan/v1/json/v1.json \ + platform/v1/json/v1.json + + ../bin/swagger validate swagger/swagger-dev.json + + ../bin/swagger-order --output=swagger/swagger-dev.json swagger/swagger-dev.json + +format: ## Format API definitions + ../bin/buf format . -w + +clean-swagger: + find . -name '*.swagger.json' -print -delete + + +ifeq ($(shell test "${SWAGGER_UI_VERSION}" = "latest" && echo 1 || echo 0), 1) +get_swagger_version: +override SWAGGER_UI_VERSION = $(shell curl --silent --head https://github.com/swagger-api/swagger-ui/releases/latest | grep -E '^[lL]ocation' | sed 's;^.*/;;') +else +get_swagger_version: +endif + +update-swagger: get_swagger_version ## Update Swagger UI in swagger, use `SWAGGER_UI_VERSION=xxx make update-swagger` to choose a version other than latest + curl --output /tmp/swagger.tar.gz -sSfL "https://github.com/swagger-api/swagger-ui/archive/refs/tags/${SWAGGER_UI_VERSION}.tar.gz" + tar xf /tmp/swagger.tar.gz --transform 's;swagger-ui-.*/dist/;swagger/;g' + rm -f swagger/.npmrc + sed -i 's/url: ".*"/url: "\/swagger.json",\n validatorUrl: "none"/' swagger/swagger-initializer.js + +clean: clean-swagger ## Remove generated files + find . -name '*.pb.go' -print -delete + find . -name '*.pb.gw.go' -print -delete + find . -name '*.validate.go' -print -delete + + SPECS="\ + agentlocal/v1 \ + server/v1 \ + user/v1 \ + inventory/v1 \ + management/v1 \ + actions/v1 \ + alerting/v1 \ + advisors/v1 \ + backup/v1 \ + dump/v1beta1 \ + accesscontrol/v1beta1 \ + qan/v1 \ + platform/v1"; \ + for API in $$SPECS; do \ + rm -fr $$API/json/client $$API/json/models $$API/json/$$(basename $$API).json ; \ + done + rm -f swagger/swagger.json swagger/swagger-dev.json + +descriptors: ## Update API compatibility descriptors + ../bin/buf build -o descriptor.bin --as-file-descriptor-set . \ No newline at end of file diff --git a/api/buf.gen.yaml b/api/buf.gen.yaml new file mode 100644 index 0000000000..b412cc9f32 --- /dev/null +++ b/api/buf.gen.yaml @@ -0,0 +1,34 @@ +version: v2 +managed: + enabled: true + disable: + - file_option: go_package + module: buf.build/googleapis/googleapis + - file_option: go_package + module: buf.build/grpc-ecosystem/grpc-gateway + - file_option: go_package + module: buf.build/envoyproxy/protoc-gen-validate + override: + - file_option: go_package_prefix + value: github.com/percona/pmm/api +plugins: + - local: ../bin/protoc-gen-go + out: . + opt: paths=source_relative + - local: ../bin/protoc-gen-go-grpc + out: . + opt: paths=source_relative + - local: ../bin/protoc-gen-grpc-gateway + out: . + opt: paths=source_relative + - local: ../bin/protoc-gen-validate + out: . + opt: + - paths=source_relative + - lang=go + - local: ../bin/protoc-gen-openapiv2 + out: . + opt: + - simple_operation_ids=true + - json_names_for_fields=false + - proto3_optional_nullable=true diff --git a/api/buf.lock b/api/buf.lock index 66753d27f3..0e9cebedcf 100644 --- a/api/buf.lock +++ b/api/buf.lock @@ -1,18 +1,12 @@ # Generated by buf. DO NOT EDIT. -version: v1 +version: v2 deps: - - remote: buf.build - owner: envoyproxy - repository: protoc-gen-validate + - name: buf.build/envoyproxy/protoc-gen-validate commit: eac44469a7af47e7839a7f1f3d7ac004 - digest: shake256:0feabcde01b6b11e3c75a5e3f807968d5995626546f39c37e5d4205892b3a59cced0ed83b35a2eb9e6dddd3309660ad46b737c9dcd224b425de0a6654ce04417 - - remote: buf.build - owner: googleapis - repository: googleapis + digest: b5:2ef7b25d9671fde82d58278e94d209788fb6a42936cc2d60e42303b67dcdb72b2d0e121238ba44caf1870a34edab55518df5d3f1ee1e62b8d9b6cf98817eae6e + - name: buf.build/googleapis/googleapis commit: 28151c0d0a1641bf938a7672c500e01d - digest: shake256:49215edf8ef57f7863004539deff8834cfb2195113f0b890dd1f67815d9353e28e668019165b9d872395871eeafcbab3ccfdb2b5f11734d3cca95be9e8d139de - - remote: buf.build - owner: grpc-ecosystem - repository: grpc-gateway + digest: b5:93b70089baa4fc05a92d3e52db91a4b7812db3b57b9664f6cb301733938cb630e377a938e8a56779388171c749c1d42a2e9a6c6230f2ff45f127a8102a6a27d0 + - name: buf.build/grpc-ecosystem/grpc-gateway commit: 3f42134f4c564983838425bc43c7a65f - digest: shake256:3d11d4c0fe5e05fda0131afefbce233940e27f0c31c5d4e385686aea58ccd30f72053f61af432fa83f1fc11cda57f5f18ca3da26a29064f73c5a0d076bba8d92 + digest: b5:291b947d8ac09492517557e4e72e294788cb8201afc7d0df7bda80fa10931adb60d4d669208a7696bf24f1ecb2a33a16d4c1e766e6f31809248b00343119569b diff --git a/api/buf.yaml b/api/buf.yaml index 84e841ca3e..b130c4ee02 100644 --- a/api/buf.yaml +++ b/api/buf.yaml @@ -1,21 +1,28 @@ -version: v1 -breaking: - use: - - FILE +version: v2 +modules: + - path: . +deps: + - buf.build/envoyproxy/protoc-gen-validate + - buf.build/googleapis/googleapis + - buf.build/grpc-ecosystem/grpc-gateway lint: use: - DEFAULT + except: + - FIELD_NOT_REQUIRED + - PACKAGE_NO_IMPORT_CYCLE ignore_only: + PACKAGE_VERSION_SUFFIX: + - api/common/common.proto + - api/common/metrics_resolutions.proto RPC_REQUEST_STANDARD_NAME: - - agent/v1/agent.proto # We want our naming in this file to be different + - api/agent/v1/agent.proto RPC_RESPONSE_STANDARD_NAME: - - agent/v1/agent.proto # We want our naming in this file to be different - PACKAGE_VERSION_SUFFIX: - - common/common.proto # We don't want to version this file - - common/metrics_resolutions.proto # We don't want to version this file - - -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc-ecosystem/grpc-gateway - - buf.build/envoyproxy/protoc-gen-validate + - api/agent/v1/agent.proto + disallow_comment_ignores: true +breaking: + use: + - FILE + except: + - EXTENSION_NO_DELETE + - FIELD_SAME_DEFAULT diff --git a/descriptor.bin b/api/descriptor.bin similarity index 98% rename from descriptor.bin rename to api/descriptor.bin index b6d4384871..140f0af272 100644 Binary files a/descriptor.bin and b/api/descriptor.bin differ diff --git a/api/server/v1/json/client/server_service/check_updates_responses.go b/api/server/v1/json/client/server_service/check_updates_responses.go index 7f81080833..5dec415b5e 100644 --- a/api/server/v1/json/client/server_service/check_updates_responses.go +++ b/api/server/v1/json/client/server_service/check_updates_responses.go @@ -610,6 +610,12 @@ type CheckUpdatesOKBodyLatest struct { // Release date. // Format: date-time Timestamp strfmt.DateTime `json:"timestamp,omitempty"` + + // Release notes URL for the version (if available). + ReleaseNotesURL string `json:"release_notes_url,omitempty"` + + // Release notes text for the version (if available). + ReleaseNotesText string `json:"release_notes_text,omitempty"` } // Validate validates this check updates OK body latest diff --git a/api/server/v1/json/client/server_service/list_change_logs_parameters.go b/api/server/v1/json/client/server_service/list_change_logs_parameters.go new file mode 100644 index 0000000000..4160eaf6fa --- /dev/null +++ b/api/server/v1/json/client/server_service/list_change_logs_parameters.go @@ -0,0 +1,127 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package server_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListChangeLogsParams creates a new ListChangeLogsParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListChangeLogsParams() *ListChangeLogsParams { + return &ListChangeLogsParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListChangeLogsParamsWithTimeout creates a new ListChangeLogsParams object +// with the ability to set a timeout on a request. +func NewListChangeLogsParamsWithTimeout(timeout time.Duration) *ListChangeLogsParams { + return &ListChangeLogsParams{ + timeout: timeout, + } +} + +// NewListChangeLogsParamsWithContext creates a new ListChangeLogsParams object +// with the ability to set a context for a request. +func NewListChangeLogsParamsWithContext(ctx context.Context) *ListChangeLogsParams { + return &ListChangeLogsParams{ + Context: ctx, + } +} + +// NewListChangeLogsParamsWithHTTPClient creates a new ListChangeLogsParams object +// with the ability to set a custom HTTPClient for a request. +func NewListChangeLogsParamsWithHTTPClient(client *http.Client) *ListChangeLogsParams { + return &ListChangeLogsParams{ + HTTPClient: client, + } +} + +/* +ListChangeLogsParams contains all the parameters to send to the API endpoint + + for the list change logs operation. + + Typically these are written to a http.Request. +*/ +type ListChangeLogsParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list change logs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListChangeLogsParams) WithDefaults() *ListChangeLogsParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list change logs params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListChangeLogsParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list change logs params +func (o *ListChangeLogsParams) WithTimeout(timeout time.Duration) *ListChangeLogsParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list change logs params +func (o *ListChangeLogsParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list change logs params +func (o *ListChangeLogsParams) WithContext(ctx context.Context) *ListChangeLogsParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list change logs params +func (o *ListChangeLogsParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list change logs params +func (o *ListChangeLogsParams) WithHTTPClient(client *http.Client) *ListChangeLogsParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list change logs params +func (o *ListChangeLogsParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *ListChangeLogsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/server/v1/json/client/server_service/list_change_logs_responses.go b/api/server/v1/json/client/server_service/list_change_logs_responses.go new file mode 100644 index 0000000000..72af20d2a8 --- /dev/null +++ b/api/server/v1/json/client/server_service/list_change_logs_responses.go @@ -0,0 +1,561 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package server_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListChangeLogsReader is a Reader for the ListChangeLogs structure. +type ListChangeLogsReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListChangeLogsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewListChangeLogsOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListChangeLogsDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListChangeLogsOK creates a ListChangeLogsOK with default headers values +func NewListChangeLogsOK() *ListChangeLogsOK { + return &ListChangeLogsOK{} +} + +/* +ListChangeLogsOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListChangeLogsOK struct { + Payload *ListChangeLogsOKBody +} + +func (o *ListChangeLogsOK) Error() string { + return fmt.Sprintf("[GET /v1/server/updates/changelogs][%d] listChangeLogsOk %+v", 200, o.Payload) +} + +func (o *ListChangeLogsOK) GetPayload() *ListChangeLogsOKBody { + return o.Payload +} + +func (o *ListChangeLogsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListChangeLogsOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewListChangeLogsDefault creates a ListChangeLogsDefault with default headers values +func NewListChangeLogsDefault(code int) *ListChangeLogsDefault { + return &ListChangeLogsDefault{ + _statusCode: code, + } +} + +/* +ListChangeLogsDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListChangeLogsDefault struct { + _statusCode int + + Payload *ListChangeLogsDefaultBody +} + +// Code gets the status code for the list change logs default response +func (o *ListChangeLogsDefault) Code() int { + return o._statusCode +} + +func (o *ListChangeLogsDefault) Error() string { + return fmt.Sprintf("[GET /v1/server/updates/changelogs][%d] ListChangeLogs default %+v", o._statusCode, o.Payload) +} + +func (o *ListChangeLogsDefault) GetPayload() *ListChangeLogsDefaultBody { + return o.Payload +} + +func (o *ListChangeLogsDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListChangeLogsDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +/* +ListChangeLogsDefaultBody list change logs default body +swagger:model ListChangeLogsDefaultBody +*/ +type ListChangeLogsDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListChangeLogsDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list change logs default body +func (o *ListChangeLogsDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListChangeLogsDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ListChangeLogs default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ListChangeLogs default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list change logs default body based on the context it is used +func (o *ListChangeLogsDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListChangeLogsDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ListChangeLogs default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ListChangeLogs default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListChangeLogsDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListChangeLogsDefaultBody) UnmarshalBinary(b []byte) error { + var res ListChangeLogsDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListChangeLogsDefaultBodyDetailsItems0 `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +swagger:model ListChangeLogsDefaultBodyDetailsItems0 +*/ +type ListChangeLogsDefaultBodyDetailsItems0 struct { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + AtType string `json:"@type,omitempty"` +} + +// Validate validates this list change logs default body details items0 +func (o *ListChangeLogsDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list change logs default body details items0 based on context it is used +func (o *ListChangeLogsDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListChangeLogsDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListChangeLogsDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListChangeLogsDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListChangeLogsOKBody list change logs OK body +swagger:model ListChangeLogsOKBody +*/ +type ListChangeLogsOKBody struct { + // List of available updates. + Updates []*ListChangeLogsOKBodyUpdatesItems0 `json:"updates"` + + // Last check time. + // Format: date-time + LastCheck strfmt.DateTime `json:"last_check,omitempty"` +} + +// Validate validates this list change logs OK body +func (o *ListChangeLogsOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateUpdates(formats); err != nil { + res = append(res, err) + } + + if err := o.validateLastCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListChangeLogsOKBody) validateUpdates(formats strfmt.Registry) error { + if swag.IsZero(o.Updates) { // not required + return nil + } + + for i := 0; i < len(o.Updates); i++ { + if swag.IsZero(o.Updates[i]) { // not required + continue + } + + if o.Updates[i] != nil { + if err := o.Updates[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("listChangeLogsOk" + "." + "updates" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("listChangeLogsOk" + "." + "updates" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (o *ListChangeLogsOKBody) validateLastCheck(formats strfmt.Registry) error { + if swag.IsZero(o.LastCheck) { // not required + return nil + } + + if err := validate.FormatOf("listChangeLogsOk"+"."+"last_check", "body", "date-time", o.LastCheck.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this list change logs OK body based on the context it is used +func (o *ListChangeLogsOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateUpdates(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListChangeLogsOKBody) contextValidateUpdates(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Updates); i++ { + if o.Updates[i] != nil { + if err := o.Updates[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("listChangeLogsOk" + "." + "updates" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("listChangeLogsOk" + "." + "updates" + "." + strconv.Itoa(i)) + } + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListChangeLogsOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListChangeLogsOKBody) UnmarshalBinary(b []byte) error { + var res ListChangeLogsOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListChangeLogsOKBodyUpdatesItems0 list change logs OK body updates items0 +swagger:model ListChangeLogsOKBodyUpdatesItems0 +*/ +type ListChangeLogsOKBodyUpdatesItems0 struct { + // PMM Version. + Version string `json:"version,omitempty"` + + // Docker image tag. + Tag string `json:"tag,omitempty"` + + // Release date. + // Format: date-time + Timestamp strfmt.DateTime `json:"timestamp,omitempty"` + + // Release notes URL for the version (if available). + ReleaseNotesURL string `json:"release_notes_url,omitempty"` + + // Release notes text for the version (if available). + ReleaseNotesText string `json:"release_notes_text,omitempty"` +} + +// Validate validates this list change logs OK body updates items0 +func (o *ListChangeLogsOKBodyUpdatesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateTimestamp(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListChangeLogsOKBodyUpdatesItems0) validateTimestamp(formats strfmt.Registry) error { + if swag.IsZero(o.Timestamp) { // not required + return nil + } + + if err := validate.FormatOf("timestamp", "body", "date-time", o.Timestamp.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list change logs OK body updates items0 based on context it is used +func (o *ListChangeLogsOKBodyUpdatesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListChangeLogsOKBodyUpdatesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListChangeLogsOKBodyUpdatesItems0) UnmarshalBinary(b []byte) error { + var res ListChangeLogsOKBodyUpdatesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/server/v1/json/client/server_service/server_service_client.go b/api/server/v1/json/client/server_service/server_service_client.go index 4d1cd044ff..15bd3eb6e5 100644 --- a/api/server/v1/json/client/server_service/server_service_client.go +++ b/api/server/v1/json/client/server_service/server_service_client.go @@ -38,6 +38,8 @@ type ClientService interface { LeaderHealthCheck(params *LeaderHealthCheckParams, opts ...ClientOption) (*LeaderHealthCheckOK, error) + ListChangeLogs(params *ListChangeLogsParams, opts ...ClientOption) (*ListChangeLogsOK, error) + Logs(params *LogsParams, writer io.Writer, opts ...ClientOption) (*LogsOK, error) Readiness(params *ReadinessParams, opts ...ClientOption) (*ReadinessOK, error) @@ -207,6 +209,45 @@ func (a *Client) LeaderHealthCheck(params *LeaderHealthCheckParams, opts ...Clie return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ListChangeLogs lists all the changes between the installed version and the latest available version + +List all the changes between the installed version and the latest available version +*/ +func (a *Client) ListChangeLogs(params *ListChangeLogsParams, opts ...ClientOption) (*ListChangeLogsOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewListChangeLogsParams() + } + op := &runtime.ClientOperation{ + ID: "ListChangeLogs", + Method: "GET", + PathPattern: "/v1/server/updates/changelogs", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListChangeLogsReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ListChangeLogsOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ListChangeLogsDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* Logs logs diff --git a/api/server/v1/json/v1.json b/api/server/v1/json/v1.json index a47880959b..1a43beb50b 100644 --- a/api/server/v1/json/v1.json +++ b/api/server/v1/json/v1.json @@ -718,6 +718,16 @@ "latest": { "type": "object", "properties": { + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, "tag": { "description": "Docker image tag.", "type": "string", @@ -786,6 +796,101 @@ } } }, + "/v1/server/updates/changelogs": { + "get": { + "description": "List all the changes between the installed version and the latest available version", + "tags": [ + "ServerService" + ], + "summary": "List all the changes between the installed version and the latest available version", + "operationId": "ListChangeLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "last_check": { + "description": "Last check time.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "updates": { + "description": "List of available updates.", + "type": "array", + "items": { + "type": "object", + "properties": { + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, + "tag": { + "description": "Docker image tag.", + "type": "string", + "x-order": 1 + }, + "timestamp": { + "description": "Release date.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "version": { + "description": "PMM Version.", + "type": "string", + "x-order": 0 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "details": { + "type": "array", + "items": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + }, + "message": { + "type": "string", + "x-order": 1 + } + } + } + } + } + } + }, "/v1/server/updates:getStatus": { "post": { "description": "Returns PMM Server update status.", diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index 8315a4824b..076e4063a7 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -496,6 +496,10 @@ type DockerVersionInfo struct { 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"` + // Release notes URL for the version (if available). + ReleaseNotesUrl string `protobuf:"bytes,4,opt,name=release_notes_url,json=releaseNotesUrl,proto3" json:"release_notes_url,omitempty"` + // Release notes text for the version (if available). + ReleaseNotesText string `protobuf:"bytes,5,opt,name=release_notes_text,json=releaseNotesText,proto3" json:"release_notes_text,omitempty"` } func (x *DockerVersionInfo) Reset() { @@ -551,6 +555,20 @@ func (x *DockerVersionInfo) GetTimestamp() *timestamppb.Timestamp { return nil } +func (x *DockerVersionInfo) GetReleaseNotesUrl() string { + if x != nil { + return x.ReleaseNotesUrl + } + return "" +} + +func (x *DockerVersionInfo) GetReleaseNotesText() string { + if x != nil { + return x.ReleaseNotesText + } + return "" +} + type CheckUpdatesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -635,6 +653,101 @@ func (x *CheckUpdatesResponse) GetLastCheck() *timestamppb.Timestamp { return nil } +type ListChangeLogsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListChangeLogsRequest) Reset() { + *x = ListChangeLogsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_server_v1_server_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListChangeLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListChangeLogsRequest) ProtoMessage() {} + +func (x *ListChangeLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_v1_server_proto_msgTypes[10] + 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 ListChangeLogsRequest.ProtoReflect.Descriptor instead. +func (*ListChangeLogsRequest) Descriptor() ([]byte, []int) { + return file_server_v1_server_proto_rawDescGZIP(), []int{10} +} + +type ListChangeLogsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // List of available updates. + Updates []*DockerVersionInfo `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty"` + // Last check time. + LastCheck *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=last_check,json=lastCheck,proto3" json:"last_check,omitempty"` +} + +func (x *ListChangeLogsResponse) Reset() { + *x = ListChangeLogsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_server_v1_server_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListChangeLogsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListChangeLogsResponse) ProtoMessage() {} + +func (x *ListChangeLogsResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_v1_server_proto_msgTypes[11] + 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 ListChangeLogsResponse.ProtoReflect.Descriptor instead. +func (*ListChangeLogsResponse) Descriptor() ([]byte, []int) { + return file_server_v1_server_proto_rawDescGZIP(), []int{11} +} + +func (x *ListChangeLogsResponse) GetUpdates() []*DockerVersionInfo { + if x != nil { + return x.Updates + } + return nil +} + +func (x *ListChangeLogsResponse) GetLastCheck() *timestamppb.Timestamp { + if x != nil { + return x.LastCheck + } + return nil +} + type StartUpdateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -646,7 +759,7 @@ type StartUpdateRequest struct { func (x *StartUpdateRequest) Reset() { *x = StartUpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[10] + mi := &file_server_v1_server_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -659,7 +772,7 @@ func (x *StartUpdateRequest) String() string { func (*StartUpdateRequest) ProtoMessage() {} func (x *StartUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[10] + mi := &file_server_v1_server_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -672,7 +785,7 @@ func (x *StartUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartUpdateRequest.ProtoReflect.Descriptor instead. func (*StartUpdateRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{10} + return file_server_v1_server_proto_rawDescGZIP(), []int{12} } func (x *StartUpdateRequest) GetNewImage() string { @@ -696,7 +809,7 @@ type StartUpdateResponse struct { func (x *StartUpdateResponse) Reset() { *x = StartUpdateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[11] + mi := &file_server_v1_server_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -709,7 +822,7 @@ func (x *StartUpdateResponse) String() string { func (*StartUpdateResponse) ProtoMessage() {} func (x *StartUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[11] + mi := &file_server_v1_server_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -722,7 +835,7 @@ func (x *StartUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartUpdateResponse.ProtoReflect.Descriptor instead. func (*StartUpdateResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{11} + return file_server_v1_server_proto_rawDescGZIP(), []int{13} } func (x *StartUpdateResponse) GetAuthToken() string { @@ -753,7 +866,7 @@ type UpdateStatusRequest struct { func (x *UpdateStatusRequest) Reset() { *x = UpdateStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[12] + mi := &file_server_v1_server_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -766,7 +879,7 @@ func (x *UpdateStatusRequest) String() string { func (*UpdateStatusRequest) ProtoMessage() {} func (x *UpdateStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[12] + mi := &file_server_v1_server_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -779,7 +892,7 @@ func (x *UpdateStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateStatusRequest.ProtoReflect.Descriptor instead. func (*UpdateStatusRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{12} + return file_server_v1_server_proto_rawDescGZIP(), []int{14} } func (x *UpdateStatusRequest) GetAuthToken() string { @@ -812,7 +925,7 @@ type UpdateStatusResponse struct { func (x *UpdateStatusResponse) Reset() { *x = UpdateStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[13] + mi := &file_server_v1_server_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -825,7 +938,7 @@ func (x *UpdateStatusResponse) String() string { func (*UpdateStatusResponse) ProtoMessage() {} func (x *UpdateStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[13] + mi := &file_server_v1_server_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -838,7 +951,7 @@ func (x *UpdateStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateStatusResponse.ProtoReflect.Descriptor instead. func (*UpdateStatusResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{13} + return file_server_v1_server_proto_rawDescGZIP(), []int{15} } func (x *UpdateStatusResponse) GetLogLines() []string { @@ -879,7 +992,7 @@ type MetricsResolutions struct { func (x *MetricsResolutions) Reset() { *x = MetricsResolutions{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[14] + mi := &file_server_v1_server_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -892,7 +1005,7 @@ func (x *MetricsResolutions) String() string { func (*MetricsResolutions) ProtoMessage() {} func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[14] + mi := &file_server_v1_server_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -905,7 +1018,7 @@ func (x *MetricsResolutions) ProtoReflect() protoreflect.Message { // Deprecated: Use MetricsResolutions.ProtoReflect.Descriptor instead. func (*MetricsResolutions) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{14} + return file_server_v1_server_proto_rawDescGZIP(), []int{16} } func (x *MetricsResolutions) GetHr() *durationpb.Duration { @@ -946,7 +1059,7 @@ type AdvisorRunIntervals struct { func (x *AdvisorRunIntervals) Reset() { *x = AdvisorRunIntervals{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[15] + mi := &file_server_v1_server_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -959,7 +1072,7 @@ func (x *AdvisorRunIntervals) String() string { func (*AdvisorRunIntervals) ProtoMessage() {} func (x *AdvisorRunIntervals) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[15] + mi := &file_server_v1_server_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -972,7 +1085,7 @@ func (x *AdvisorRunIntervals) ProtoReflect() protoreflect.Message { // Deprecated: Use AdvisorRunIntervals.ProtoReflect.Descriptor instead. func (*AdvisorRunIntervals) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{15} + return file_server_v1_server_proto_rawDescGZIP(), []int{17} } func (x *AdvisorRunIntervals) GetStandardInterval() *durationpb.Duration { @@ -1037,7 +1150,7 @@ type Settings struct { func (x *Settings) Reset() { *x = Settings{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[16] + mi := &file_server_v1_server_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1050,7 +1163,7 @@ func (x *Settings) String() string { func (*Settings) ProtoMessage() {} func (x *Settings) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[16] + mi := &file_server_v1_server_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1063,7 +1176,7 @@ func (x *Settings) ProtoReflect() protoreflect.Message { // Deprecated: Use Settings.ProtoReflect.Descriptor instead. func (*Settings) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{16} + return file_server_v1_server_proto_rawDescGZIP(), []int{18} } func (x *Settings) GetUpdatesEnabled() bool { @@ -1194,7 +1307,7 @@ type GetSettingsRequest struct { func (x *GetSettingsRequest) Reset() { *x = GetSettingsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[17] + mi := &file_server_v1_server_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1207,7 +1320,7 @@ func (x *GetSettingsRequest) String() string { func (*GetSettingsRequest) ProtoMessage() {} func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[17] + mi := &file_server_v1_server_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1220,7 +1333,7 @@ func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsRequest.ProtoReflect.Descriptor instead. func (*GetSettingsRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{17} + return file_server_v1_server_proto_rawDescGZIP(), []int{19} } type GetSettingsResponse struct { @@ -1234,7 +1347,7 @@ type GetSettingsResponse struct { func (x *GetSettingsResponse) Reset() { *x = GetSettingsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[18] + mi := &file_server_v1_server_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1247,7 +1360,7 @@ func (x *GetSettingsResponse) String() string { func (*GetSettingsResponse) ProtoMessage() {} func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[18] + mi := &file_server_v1_server_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1260,7 +1373,7 @@ func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSettingsResponse.ProtoReflect.Descriptor instead. func (*GetSettingsResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{18} + return file_server_v1_server_proto_rawDescGZIP(), []int{20} } func (x *GetSettingsResponse) GetSettings() *Settings { @@ -1301,7 +1414,7 @@ type ChangeSettingsRequest struct { func (x *ChangeSettingsRequest) Reset() { *x = ChangeSettingsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[19] + mi := &file_server_v1_server_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1314,7 +1427,7 @@ func (x *ChangeSettingsRequest) String() string { func (*ChangeSettingsRequest) ProtoMessage() {} func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[19] + mi := &file_server_v1_server_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1327,7 +1440,7 @@ func (x *ChangeSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsRequest.ProtoReflect.Descriptor instead. func (*ChangeSettingsRequest) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{19} + return file_server_v1_server_proto_rawDescGZIP(), []int{21} } func (x *ChangeSettingsRequest) GetEnableUpdates() bool { @@ -1432,7 +1545,7 @@ type ChangeSettingsResponse struct { func (x *ChangeSettingsResponse) Reset() { *x = ChangeSettingsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_v1_server_proto_msgTypes[20] + mi := &file_server_v1_server_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1445,7 +1558,7 @@ func (x *ChangeSettingsResponse) String() string { func (*ChangeSettingsResponse) ProtoMessage() {} func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_v1_server_proto_msgTypes[20] + mi := &file_server_v1_server_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1458,7 +1571,7 @@ func (x *ChangeSettingsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSettingsResponse.ProtoReflect.Descriptor instead. func (*ChangeSettingsResponse) Descriptor() ([]byte, []int) { - return file_server_v1_server_proto_rawDescGZIP(), []int{20} + return file_server_v1_server_proto_rawDescGZIP(), []int{22} } func (x *ChangeSettingsResponse) GetSettings() *Settings { @@ -1520,270 +1633,305 @@ var file_server_v1_server_proto_rawDesc = []byte{ 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x16, 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, 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, 0x90, 0x02, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x34, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, - 0x31, 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, 0xe5, 0x01, 0x0a, 0x13, 0x41, 0x64, 0x76, 0x69, 0x73, - 0x6f, 0x72, 0x52, 0x75, 0x6e, 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, + 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd3, 0x01, 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, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x73, + 0x55, 0x72, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6e, + 0x6f, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x54, 0x65, 0x78, + 0x74, 0x22, 0x90, 0x02, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, + 0x12, 0x34, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, - 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, 0xe1, - 0x06, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 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, 0x4e, 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, 0x1d, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x22, 0x17, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8b, 0x01, + 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x02, + 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, 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, 0x27, 0x0a, 0x0f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x61, 0x64, - 0x76, 0x69, 0x73, 0x6f, 0x72, 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, 0x08, - 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, 0x0a, 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, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x52, 0x0a, 0x15, - 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, - 0x75, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x13, 0x61, 0x64, 0x76, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6c, 0x72, 0x22, 0xe5, 0x01, 0x0a, 0x13, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, 0x6e, 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, 0x0d, 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, 0x0e, 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, 0x0f, 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, 0x10, 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, - 0x11, 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, 0x12, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x6c, 0x65, - 0x49, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x46, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2f, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x22, 0xca, 0x07, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x0e, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x48, 0x01, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4e, 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, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, 0x1c, 0x0a, 0x07, 0x73, 0x73, 0x68, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x73, 0x73, 0x68, - 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x0e, 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x72, - 0x72, 0x61, 0x79, 0x48, 0x03, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, - 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, - 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, - 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x48, 0x05, 0x52, 0x0e, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x88, 0x01, - 0x01, 0x12, 0x31, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, 0x52, - 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x88, 0x01, 0x01, 0x12, 0x52, 0x0a, 0x15, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, - 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x73, 0x52, 0x13, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, 0x6e, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x14, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x07, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x88, 0x01, 0x01, - 0x12, 0x3d, 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, 0x0c, 0x20, 0x01, - 0x28, 0x08, 0x48, 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, 0x88, 0x01, 0x01, 0x12, - 0x37, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x48, 0x09, - 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x11, 0x0a, 0x0f, - 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, - 0x11, 0x0a, 0x0f, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, - 0x6f, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, - 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x70, 0x6d, 0x6d, 0x5f, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x17, 0x0a, - 0x15, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x49, 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, 0x2f, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2a, 0xce, 0x01, 0x0a, 0x12, 0x44, 0x69, 0x73, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, - 0x23, 0x0a, 0x1f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x4f, 0x43, 0x4b, - 0x45, 0x52, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x56, 0x46, 0x10, - 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x4d, 0x49, 0x10, 0x03, 0x12, 0x1d, - 0x0a, 0x19, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, - 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, 0x1a, 0x0a, - 0x16, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, - 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x4f, 0x10, 0x05, 0x32, 0x91, 0x0c, 0x0a, 0x0d, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x07, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, - 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, 0x14, - 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0xab, 0x02, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, - 0x73, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, - 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 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, 0x13, 0x12, - 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x61, 0x64, - 0x79, 0x7a, 0x12, 0x81, 0x02, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x76, 0x31, 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, 0x24, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, 0xa0, 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, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa7, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 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, 0x14, 0x12, 0x12, 0x2f, 0x76, - 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 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, 0xe1, 0x06, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x27, 0x0a, + 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x45, + 0x6e, 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, 0x4e, 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, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, 0x27, 0x0a, 0x0f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, + 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 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, 0x08, 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, 0x0a, 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, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6d, + 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x52, + 0x0a, 0x15, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x13, 0x61, + 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, 0x6e, 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, + 0x0d, 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, 0x0e, 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, 0x0f, 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, 0x10, + 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, 0x11, 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, + 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, + 0x6c, 0x65, 0x49, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x46, 0x0a, 0x13, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x22, 0xca, 0x07, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x0e, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x48, 0x01, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4e, 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, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, + 0x31, 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, 0x1c, 0x0a, 0x07, 0x73, 0x73, + 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x73, + 0x73, 0x68, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x0e, 0x61, 0x77, 0x73, 0x5f, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x41, 0x72, 0x72, 0x61, 0x79, 0x48, 0x03, 0x52, 0x0d, 0x61, 0x77, 0x73, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x48, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x64, 0x76, 0x69, 0x73, + 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x48, 0x05, + 0x52, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x70, 0x6d, 0x6d, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x06, 0x52, 0x10, 0x70, 0x6d, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x52, 0x0a, 0x15, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x13, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x52, 0x75, + 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x14, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x07, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x88, + 0x01, 0x01, 0x12, 0x3d, 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, 0x0c, + 0x20, 0x01, 0x28, 0x08, 0x48, 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, 0x88, 0x01, + 0x01, 0x12, 0x37, 0x0a, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, + 0x48, 0x09, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x42, 0x13, 0x0a, + 0x11, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x11, + 0x0a, 0x0f, 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x64, 0x76, + 0x69, 0x73, 0x6f, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x70, 0x6d, 0x6d, + 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, + 0x17, 0x0a, 0x15, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x7a, 0x75, 0x72, 0x65, + 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x22, + 0x49, 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, 0x2f, 0x0a, 0x08, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2a, 0xce, 0x01, 0x0a, 0x12, 0x44, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, + 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x4f, + 0x43, 0x4b, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, + 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x56, + 0x46, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x4d, 0x49, 0x10, 0x03, + 0x12, 0x1d, 0x0a, 0x19, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x04, 0x12, + 0x1a, 0x0a, 0x16, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x4f, 0x10, 0x05, 0x32, 0xbf, 0x0e, 0x0a, 0x0d, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x86, 0x01, + 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x44, 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, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0xab, 0x02, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x64, 0x69, + 0x6e, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0xe2, 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, + 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x79, 0x7a, 0x12, 0x81, 0x02, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x23, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, + 0x24, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 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, 0xa0, 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, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0xa7, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 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, 0x14, 0x12, 0x12, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x12, 0xab, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, + 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd3, 0x01, 0x92, 0x41, 0xaa, + 0x01, 0x12, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x61, 0x6c, 0x6c, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x62, 0x65, 0x74, + 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x65, 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, @@ -1852,7 +2000,7 @@ func file_server_v1_server_proto_rawDescGZIP() []byte { var ( file_server_v1_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) - file_server_v1_server_proto_msgTypes = make([]protoimpl.MessageInfo, 21) + file_server_v1_server_proto_msgTypes = make([]protoimpl.MessageInfo, 23) file_server_v1_server_proto_goTypes = []any{ (DistributionMethod)(0), // 0: server.v1.DistributionMethod (*VersionInfo)(nil), // 1: server.v1.VersionInfo @@ -1865,68 +2013,74 @@ var ( (*CheckUpdatesRequest)(nil), // 8: server.v1.CheckUpdatesRequest (*DockerVersionInfo)(nil), // 9: server.v1.DockerVersionInfo (*CheckUpdatesResponse)(nil), // 10: server.v1.CheckUpdatesResponse - (*StartUpdateRequest)(nil), // 11: server.v1.StartUpdateRequest - (*StartUpdateResponse)(nil), // 12: server.v1.StartUpdateResponse - (*UpdateStatusRequest)(nil), // 13: server.v1.UpdateStatusRequest - (*UpdateStatusResponse)(nil), // 14: server.v1.UpdateStatusResponse - (*MetricsResolutions)(nil), // 15: server.v1.MetricsResolutions - (*AdvisorRunIntervals)(nil), // 16: server.v1.AdvisorRunIntervals - (*Settings)(nil), // 17: server.v1.Settings - (*GetSettingsRequest)(nil), // 18: server.v1.GetSettingsRequest - (*GetSettingsResponse)(nil), // 19: server.v1.GetSettingsResponse - (*ChangeSettingsRequest)(nil), // 20: server.v1.ChangeSettingsRequest - (*ChangeSettingsResponse)(nil), // 21: server.v1.ChangeSettingsResponse - (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 23: google.protobuf.Duration - (*common.StringArray)(nil), // 24: common.StringArray + (*ListChangeLogsRequest)(nil), // 11: server.v1.ListChangeLogsRequest + (*ListChangeLogsResponse)(nil), // 12: server.v1.ListChangeLogsResponse + (*StartUpdateRequest)(nil), // 13: server.v1.StartUpdateRequest + (*StartUpdateResponse)(nil), // 14: server.v1.StartUpdateResponse + (*UpdateStatusRequest)(nil), // 15: server.v1.UpdateStatusRequest + (*UpdateStatusResponse)(nil), // 16: server.v1.UpdateStatusResponse + (*MetricsResolutions)(nil), // 17: server.v1.MetricsResolutions + (*AdvisorRunIntervals)(nil), // 18: server.v1.AdvisorRunIntervals + (*Settings)(nil), // 19: server.v1.Settings + (*GetSettingsRequest)(nil), // 20: server.v1.GetSettingsRequest + (*GetSettingsResponse)(nil), // 21: server.v1.GetSettingsResponse + (*ChangeSettingsRequest)(nil), // 22: server.v1.ChangeSettingsRequest + (*ChangeSettingsResponse)(nil), // 23: server.v1.ChangeSettingsResponse + (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 25: google.protobuf.Duration + (*common.StringArray)(nil), // 26: common.StringArray } ) var file_server_v1_server_proto_depIdxs = []int32{ - 22, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 24, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo 1, // 2: server.v1.VersionResponse.managed:type_name -> server.v1.VersionInfo 0, // 3: server.v1.VersionResponse.distribution_method:type_name -> server.v1.DistributionMethod - 22, // 4: server.v1.DockerVersionInfo.timestamp:type_name -> google.protobuf.Timestamp + 24, // 4: server.v1.DockerVersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 5: server.v1.CheckUpdatesResponse.installed:type_name -> server.v1.VersionInfo 9, // 6: server.v1.CheckUpdatesResponse.latest:type_name -> server.v1.DockerVersionInfo - 22, // 7: server.v1.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp - 23, // 8: server.v1.MetricsResolutions.hr:type_name -> google.protobuf.Duration - 23, // 9: server.v1.MetricsResolutions.mr:type_name -> google.protobuf.Duration - 23, // 10: server.v1.MetricsResolutions.lr:type_name -> google.protobuf.Duration - 23, // 11: server.v1.AdvisorRunIntervals.standard_interval:type_name -> google.protobuf.Duration - 23, // 12: server.v1.AdvisorRunIntervals.rare_interval:type_name -> google.protobuf.Duration - 23, // 13: server.v1.AdvisorRunIntervals.frequent_interval:type_name -> google.protobuf.Duration - 15, // 14: server.v1.Settings.metrics_resolutions:type_name -> server.v1.MetricsResolutions - 23, // 15: server.v1.Settings.data_retention:type_name -> google.protobuf.Duration - 16, // 16: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 17, // 17: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings - 15, // 18: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions - 23, // 19: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration - 24, // 20: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray - 16, // 21: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 17, // 22: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings - 2, // 23: server.v1.ServerService.Version:input_type -> server.v1.VersionRequest - 4, // 24: server.v1.ServerService.Readiness:input_type -> server.v1.ReadinessRequest - 6, // 25: server.v1.ServerService.LeaderHealthCheck:input_type -> server.v1.LeaderHealthCheckRequest - 8, // 26: server.v1.ServerService.CheckUpdates:input_type -> server.v1.CheckUpdatesRequest - 11, // 27: server.v1.ServerService.StartUpdate:input_type -> server.v1.StartUpdateRequest - 13, // 28: server.v1.ServerService.UpdateStatus:input_type -> server.v1.UpdateStatusRequest - 18, // 29: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest - 20, // 30: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest - 3, // 31: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse - 5, // 32: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse - 7, // 33: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse - 10, // 34: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse - 12, // 35: server.v1.ServerService.StartUpdate:output_type -> server.v1.StartUpdateResponse - 14, // 36: server.v1.ServerService.UpdateStatus:output_type -> server.v1.UpdateStatusResponse - 19, // 37: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse - 21, // 38: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse - 31, // [31:39] is the sub-list for method output_type - 23, // [23:31] is the sub-list for method input_type - 23, // [23:23] is the sub-list for extension type_name - 23, // [23:23] is the sub-list for extension extendee - 0, // [0:23] is the sub-list for field type_name + 24, // 7: server.v1.CheckUpdatesResponse.last_check:type_name -> google.protobuf.Timestamp + 9, // 8: server.v1.ListChangeLogsResponse.updates:type_name -> server.v1.DockerVersionInfo + 24, // 9: server.v1.ListChangeLogsResponse.last_check:type_name -> google.protobuf.Timestamp + 25, // 10: server.v1.MetricsResolutions.hr:type_name -> google.protobuf.Duration + 25, // 11: server.v1.MetricsResolutions.mr:type_name -> google.protobuf.Duration + 25, // 12: server.v1.MetricsResolutions.lr:type_name -> google.protobuf.Duration + 25, // 13: server.v1.AdvisorRunIntervals.standard_interval:type_name -> google.protobuf.Duration + 25, // 14: server.v1.AdvisorRunIntervals.rare_interval:type_name -> google.protobuf.Duration + 25, // 15: server.v1.AdvisorRunIntervals.frequent_interval:type_name -> google.protobuf.Duration + 17, // 16: server.v1.Settings.metrics_resolutions:type_name -> server.v1.MetricsResolutions + 25, // 17: server.v1.Settings.data_retention:type_name -> google.protobuf.Duration + 18, // 18: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 19, // 19: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings + 17, // 20: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions + 25, // 21: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration + 26, // 22: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray + 18, // 23: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 19, // 24: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings + 2, // 25: server.v1.ServerService.Version:input_type -> server.v1.VersionRequest + 4, // 26: server.v1.ServerService.Readiness:input_type -> server.v1.ReadinessRequest + 6, // 27: server.v1.ServerService.LeaderHealthCheck:input_type -> server.v1.LeaderHealthCheckRequest + 8, // 28: server.v1.ServerService.CheckUpdates:input_type -> server.v1.CheckUpdatesRequest + 11, // 29: server.v1.ServerService.ListChangeLogs:input_type -> server.v1.ListChangeLogsRequest + 13, // 30: server.v1.ServerService.StartUpdate:input_type -> server.v1.StartUpdateRequest + 15, // 31: server.v1.ServerService.UpdateStatus:input_type -> server.v1.UpdateStatusRequest + 20, // 32: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest + 22, // 33: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest + 3, // 34: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse + 5, // 35: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse + 7, // 36: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse + 10, // 37: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse + 12, // 38: server.v1.ServerService.ListChangeLogs:output_type -> server.v1.ListChangeLogsResponse + 14, // 39: server.v1.ServerService.StartUpdate:output_type -> server.v1.StartUpdateResponse + 16, // 40: server.v1.ServerService.UpdateStatus:output_type -> server.v1.UpdateStatusResponse + 21, // 41: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse + 23, // 42: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse + 34, // [34:43] is the sub-list for method output_type + 25, // [25:34] is the sub-list for method input_type + 25, // [25:25] is the sub-list for extension type_name + 25, // [25:25] is the sub-list for extension extendee + 0, // [0:25] is the sub-list for field type_name } func init() { file_server_v1_server_proto_init() } @@ -2056,7 +2210,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*StartUpdateRequest); i { + switch v := v.(*ListChangeLogsRequest); i { case 0: return &v.state case 1: @@ -2068,7 +2222,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*StartUpdateResponse); i { + switch v := v.(*ListChangeLogsResponse); i { case 0: return &v.state case 1: @@ -2080,7 +2234,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*UpdateStatusRequest); i { + switch v := v.(*StartUpdateRequest); i { case 0: return &v.state case 1: @@ -2092,7 +2246,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*UpdateStatusResponse); i { + switch v := v.(*StartUpdateResponse); i { case 0: return &v.state case 1: @@ -2104,7 +2258,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*MetricsResolutions); i { + switch v := v.(*UpdateStatusRequest); i { case 0: return &v.state case 1: @@ -2116,7 +2270,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*AdvisorRunIntervals); i { + switch v := v.(*UpdateStatusResponse); i { case 0: return &v.state case 1: @@ -2128,7 +2282,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*Settings); i { + switch v := v.(*MetricsResolutions); i { case 0: return &v.state case 1: @@ -2140,7 +2294,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*GetSettingsRequest); i { + switch v := v.(*AdvisorRunIntervals); i { case 0: return &v.state case 1: @@ -2152,7 +2306,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*GetSettingsResponse); i { + switch v := v.(*Settings); i { case 0: return &v.state case 1: @@ -2164,7 +2318,7 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*ChangeSettingsRequest); i { + switch v := v.(*GetSettingsRequest); i { case 0: return &v.state case 1: @@ -2176,6 +2330,30 @@ func file_server_v1_server_proto_init() { } } file_server_v1_server_proto_msgTypes[20].Exporter = func(v any, i int) any { + switch v := v.(*GetSettingsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_v1_server_proto_msgTypes[21].Exporter = func(v any, i int) any { + switch v := v.(*ChangeSettingsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_v1_server_proto_msgTypes[22].Exporter = func(v any, i int) any { switch v := v.(*ChangeSettingsResponse); i { case 0: return &v.state @@ -2188,14 +2366,14 @@ func file_server_v1_server_proto_init() { } } } - file_server_v1_server_proto_msgTypes[19].OneofWrappers = []any{} + file_server_v1_server_proto_msgTypes[21].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_server_v1_server_proto_rawDesc, NumEnums: 1, - NumMessages: 21, + NumMessages: 23, NumExtensions: 0, NumServices: 1, }, diff --git a/api/server/v1/server.pb.gw.go b/api/server/v1/server.pb.gw.go index 07e35fb1ec..26253aedbb 100644 --- a/api/server/v1/server.pb.gw.go +++ b/api/server/v1/server.pb.gw.go @@ -129,6 +129,22 @@ func local_request_ServerService_CheckUpdates_0(ctx context.Context, marshaler r return msg, metadata, err } +func request_ServerService_ListChangeLogs_0(ctx context.Context, marshaler runtime.Marshaler, client ServerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListChangeLogsRequest + var metadata runtime.ServerMetadata + + msg, err := client.ListChangeLogs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_ServerService_ListChangeLogs_0(ctx context.Context, marshaler runtime.Marshaler, server ServerServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListChangeLogsRequest + var metadata runtime.ServerMetadata + + msg, err := server.ListChangeLogs(ctx, &protoReq) + return msg, metadata, err +} + func request_ServerService_StartUpdate_0(ctx context.Context, marshaler runtime.Marshaler, client ServerServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq StartUpdateRequest var metadata runtime.ServerMetadata @@ -319,6 +335,30 @@ func RegisterServerServiceHandlerServer(ctx context.Context, mux *runtime.ServeM forward_ServerService_CheckUpdates_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("GET", pattern_ServerService_ListChangeLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/server.v1.ServerService/ListChangeLogs", runtime.WithHTTPPathPattern("/v1/server/updates/changelogs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ServerService_ListChangeLogs_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ServerService_ListChangeLogs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ServerService_StartUpdate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -539,6 +579,27 @@ func RegisterServerServiceHandlerClient(ctx context.Context, mux *runtime.ServeM forward_ServerService_CheckUpdates_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("GET", pattern_ServerService_ListChangeLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/server.v1.ServerService/ListChangeLogs", runtime.WithHTTPPathPattern("/v1/server/updates/changelogs")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ServerService_ListChangeLogs_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ServerService_ListChangeLogs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ServerService_StartUpdate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -635,6 +696,8 @@ var ( pattern_ServerService_CheckUpdates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "updates"}, "")) + pattern_ServerService_ListChangeLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "server", "updates", "changelogs"}, "")) + pattern_ServerService_StartUpdate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "updates"}, "start")) pattern_ServerService_UpdateStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "server", "updates"}, "getStatus")) @@ -653,6 +716,8 @@ var ( forward_ServerService_CheckUpdates_0 = runtime.ForwardResponseMessage + forward_ServerService_ListChangeLogs_0 = runtime.ForwardResponseMessage + forward_ServerService_StartUpdate_0 = runtime.ForwardResponseMessage forward_ServerService_UpdateStatus_0 = runtime.ForwardResponseMessage diff --git a/api/server/v1/server.pb.validate.go b/api/server/v1/server.pb.validate.go index 39897b8317..48dad7e546 100644 --- a/api/server/v1/server.pb.validate.go +++ b/api/server/v1/server.pb.validate.go @@ -998,6 +998,10 @@ func (m *DockerVersionInfo) validate(all bool) error { } } + // no validation rules for ReleaseNotesUrl + + // no validation rules for ReleaseNotesText + if len(errors) > 0 { return DockerVersionInfoMultiError(errors) } @@ -1271,6 +1275,273 @@ var _ interface { ErrorName() string } = CheckUpdatesResponseValidationError{} +// Validate checks the field values on ListChangeLogsRequest 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 *ListChangeLogsRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListChangeLogsRequest 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 +// ListChangeLogsRequestMultiError, or nil if none found. +func (m *ListChangeLogsRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListChangeLogsRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return ListChangeLogsRequestMultiError(errors) + } + + return nil +} + +// ListChangeLogsRequestMultiError is an error wrapping multiple validation +// errors returned by ListChangeLogsRequest.ValidateAll() if the designated +// constraints aren't met. +type ListChangeLogsRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListChangeLogsRequestMultiError) 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 ListChangeLogsRequestMultiError) AllErrors() []error { return m } + +// ListChangeLogsRequestValidationError is the validation error returned by +// ListChangeLogsRequest.Validate if the designated constraints aren't met. +type ListChangeLogsRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListChangeLogsRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListChangeLogsRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListChangeLogsRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListChangeLogsRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListChangeLogsRequestValidationError) ErrorName() string { + return "ListChangeLogsRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListChangeLogsRequestValidationError) 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 %sListChangeLogsRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ListChangeLogsRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListChangeLogsRequestValidationError{} + +// Validate checks the field values on ListChangeLogsResponse 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 *ListChangeLogsResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListChangeLogsResponse 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 +// ListChangeLogsResponseMultiError, or nil if none found. +func (m *ListChangeLogsResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListChangeLogsResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetUpdates() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListChangeLogsResponseValidationError{ + field: fmt.Sprintf("Updates[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListChangeLogsResponseValidationError{ + field: fmt.Sprintf("Updates[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListChangeLogsResponseValidationError{ + field: fmt.Sprintf("Updates[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if all { + switch v := interface{}(m.GetLastCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListChangeLogsResponseValidationError{ + field: "LastCheck", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListChangeLogsResponseValidationError{ + field: "LastCheck", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetLastCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListChangeLogsResponseValidationError{ + field: "LastCheck", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return ListChangeLogsResponseMultiError(errors) + } + + return nil +} + +// ListChangeLogsResponseMultiError is an error wrapping multiple validation +// errors returned by ListChangeLogsResponse.ValidateAll() if the designated +// constraints aren't met. +type ListChangeLogsResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListChangeLogsResponseMultiError) 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 ListChangeLogsResponseMultiError) AllErrors() []error { return m } + +// ListChangeLogsResponseValidationError is the validation error returned by +// ListChangeLogsResponse.Validate if the designated constraints aren't met. +type ListChangeLogsResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListChangeLogsResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListChangeLogsResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListChangeLogsResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListChangeLogsResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListChangeLogsResponseValidationError) ErrorName() string { + return "ListChangeLogsResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListChangeLogsResponseValidationError) 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 %sListChangeLogsResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ListChangeLogsResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListChangeLogsResponseValidationError{} + // Validate checks the field values on StartUpdateRequest with the rules // defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. diff --git a/api/server/v1/server.proto b/api/server/v1/server.proto index a7785f2058..79841df710 100644 --- a/api/server/v1/server.proto +++ b/api/server/v1/server.proto @@ -71,6 +71,10 @@ message DockerVersionInfo { string tag = 2; // Release date. google.protobuf.Timestamp timestamp = 3; + // Release notes URL for the version (if available). + string release_notes_url = 4; + // Release notes text for the version (if available). + string release_notes_text = 5; } message CheckUpdatesResponse { @@ -86,6 +90,16 @@ message CheckUpdatesResponse { google.protobuf.Timestamp last_check = 5; } +message ListChangeLogsRequest {} + +message ListChangeLogsResponse { + // List of available updates. + repeated DockerVersionInfo updates = 1; + + // Last check time. + google.protobuf.Timestamp last_check = 2; +} + message StartUpdateRequest { string new_image = 1; } @@ -236,6 +250,14 @@ service ServerService { description: "Checks for available PMM Server updates." }; } + + rpc ListChangeLogs(ListChangeLogsRequest) returns (ListChangeLogsResponse) { + option (google.api.http) = {get: "/v1/server/updates/changelogs"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List all the changes between the installed version and the latest available version" + description: "List all the changes between the installed version and the latest available version" + }; + } // StartUpdate starts PMM Server update. rpc StartUpdate(StartUpdateRequest) returns (StartUpdateResponse) { option (google.api.http) = { diff --git a/api/server/v1/server_grpc.pb.go b/api/server/v1/server_grpc.pb.go index 708f24cadf..0a33954455 100644 --- a/api/server/v1/server_grpc.pb.go +++ b/api/server/v1/server_grpc.pb.go @@ -24,6 +24,7 @@ const ( ServerService_Readiness_FullMethodName = "/server.v1.ServerService/Readiness" ServerService_LeaderHealthCheck_FullMethodName = "/server.v1.ServerService/LeaderHealthCheck" ServerService_CheckUpdates_FullMethodName = "/server.v1.ServerService/CheckUpdates" + ServerService_ListChangeLogs_FullMethodName = "/server.v1.ServerService/ListChangeLogs" ServerService_StartUpdate_FullMethodName = "/server.v1.ServerService/StartUpdate" ServerService_UpdateStatus_FullMethodName = "/server.v1.ServerService/UpdateStatus" ServerService_GetSettings_FullMethodName = "/server.v1.ServerService/GetSettings" @@ -45,6 +46,7 @@ type ServerServiceClient interface { LeaderHealthCheck(ctx context.Context, in *LeaderHealthCheckRequest, opts ...grpc.CallOption) (*LeaderHealthCheckResponse, error) // CheckUpdates checks for available PMM Server updates. CheckUpdates(ctx context.Context, in *CheckUpdatesRequest, opts ...grpc.CallOption) (*CheckUpdatesResponse, error) + ListChangeLogs(ctx context.Context, in *ListChangeLogsRequest, opts ...grpc.CallOption) (*ListChangeLogsResponse, error) // StartUpdate starts PMM Server update. StartUpdate(ctx context.Context, in *StartUpdateRequest, opts ...grpc.CallOption) (*StartUpdateResponse, error) // UpdateStatus returns PMM Server update status. @@ -103,6 +105,16 @@ func (c *serverServiceClient) CheckUpdates(ctx context.Context, in *CheckUpdates return out, nil } +func (c *serverServiceClient) ListChangeLogs(ctx context.Context, in *ListChangeLogsRequest, opts ...grpc.CallOption) (*ListChangeLogsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListChangeLogsResponse) + err := c.cc.Invoke(ctx, ServerService_ListChangeLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *serverServiceClient) StartUpdate(ctx context.Context, in *StartUpdateRequest, opts ...grpc.CallOption) (*StartUpdateResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StartUpdateResponse) @@ -158,6 +170,7 @@ type ServerServiceServer interface { LeaderHealthCheck(context.Context, *LeaderHealthCheckRequest) (*LeaderHealthCheckResponse, error) // CheckUpdates checks for available PMM Server updates. CheckUpdates(context.Context, *CheckUpdatesRequest) (*CheckUpdatesResponse, error) + ListChangeLogs(context.Context, *ListChangeLogsRequest) (*ListChangeLogsResponse, error) // StartUpdate starts PMM Server update. StartUpdate(context.Context, *StartUpdateRequest) (*StartUpdateResponse, error) // UpdateStatus returns PMM Server update status. @@ -192,6 +205,10 @@ func (UnimplementedServerServiceServer) CheckUpdates(context.Context, *CheckUpda return nil, status.Errorf(codes.Unimplemented, "method CheckUpdates not implemented") } +func (UnimplementedServerServiceServer) ListChangeLogs(context.Context, *ListChangeLogsRequest) (*ListChangeLogsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListChangeLogs not implemented") +} + func (UnimplementedServerServiceServer) StartUpdate(context.Context, *StartUpdateRequest) (*StartUpdateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method StartUpdate not implemented") } @@ -300,6 +317,24 @@ func _ServerService_CheckUpdates_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _ServerService_ListChangeLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListChangeLogsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServerServiceServer).ListChangeLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ServerService_ListChangeLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServerServiceServer).ListChangeLogs(ctx, req.(*ListChangeLogsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ServerService_StartUpdate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StartUpdateRequest) if err := dec(in); err != nil { @@ -395,6 +430,10 @@ var ServerService_ServiceDesc = grpc.ServiceDesc{ MethodName: "CheckUpdates", Handler: _ServerService_CheckUpdates_Handler, }, + { + MethodName: "ListChangeLogs", + Handler: _ServerService_ListChangeLogs_Handler, + }, { MethodName: "StartUpdate", Handler: _ServerService_StartUpdate_Handler, diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index fa2acd03a6..c04bb18816 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -27418,6 +27418,16 @@ "type": "string", "format": "date-time", "x-order": 2 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 } }, "x-order": 1 @@ -27477,6 +27487,101 @@ } } }, + "/v1/server/updates/changelogs": { + "get": { + "description": "List all the changes between the installed version and the latest available version", + "tags": [ + "ServerService" + ], + "summary": "List all the changes between the installed version and the latest available version", + "operationId": "ListChangeLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "updates": { + "description": "List of available updates.", + "type": "array", + "items": { + "type": "object", + "properties": { + "version": { + "description": "PMM Version.", + "type": "string", + "x-order": 0 + }, + "tag": { + "description": "Docker image tag.", + "type": "string", + "x-order": 1 + }, + "timestamp": { + "description": "Release date.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 + } + } + }, + "x-order": 0 + }, + "last_check": { + "description": "Last check time.", + "type": "string", + "format": "date-time", + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/server/updates:getStatus": { "post": { "description": "Returns PMM Server update status.", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 1a8543e12f..d4f0128cbb 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -26460,6 +26460,16 @@ "type": "string", "format": "date-time", "x-order": 2 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 } }, "x-order": 1 @@ -26519,6 +26529,101 @@ } } }, + "/v1/server/updates/changelogs": { + "get": { + "description": "List all the changes between the installed version and the latest available version", + "tags": [ + "ServerService" + ], + "summary": "List all the changes between the installed version and the latest available version", + "operationId": "ListChangeLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "updates": { + "description": "List of available updates.", + "type": "array", + "items": { + "type": "object", + "properties": { + "version": { + "description": "PMM Version.", + "type": "string", + "x-order": 0 + }, + "tag": { + "description": "Docker image tag.", + "type": "string", + "x-order": 1 + }, + "timestamp": { + "description": "Release date.", + "type": "string", + "format": "date-time", + "x-order": 2 + }, + "release_notes_url": { + "description": "Release notes URL for the version (if available).", + "type": "string", + "x-order": 3 + }, + "release_notes_text": { + "description": "Release notes text for the version (if available).", + "type": "string", + "x-order": 4 + } + } + }, + "x-order": 0 + }, + "last_check": { + "description": "Last check time.", + "type": "string", + "format": "date-time", + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }", + "type": "object", + "properties": { + "@type": { + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics.", + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/server/updates:getStatus": { "post": { "description": "Returns PMM Server update status.", diff --git a/buf.gen.yaml b/buf.gen.yaml deleted file mode 100644 index 53d088dcf4..0000000000 --- a/buf.gen.yaml +++ /dev/null @@ -1,44 +0,0 @@ -version: v1 -managed: - enabled: true - go_package_prefix: - default: github.com/percona/pmm/api - except: - - buf.build/googleapis/googleapis - - buf.build/grpc-ecosystem/grpc-gateway - - buf.build/envoyproxy/protoc-gen-validate - -plugins: - - name: go - path: bin/protoc-gen-go - out: api - opt: - - paths=source_relative - - - name: go-grpc - path: bin/protoc-gen-go-grpc - out: api - opt: - - paths=source_relative - - - name: grpc-gateway - path: bin/protoc-gen-grpc-gateway - out: api - opt: - - paths=source_relative - - - name: validate - path: bin/protoc-gen-validate - out: api - opt: - - paths=source_relative - - lang=go - - - name: openapiv2 - out: api - path: bin/protoc-gen-openapiv2 - opt: - - simple_operation_ids=true - - json_names_for_fields=false - - proto3_optional_nullable=true - # - visibility_restriction_selectors=INTERNAL # Uncomment to show elements marked up with `INTERNAL` diff --git a/buf.work.yaml b/buf.work.yaml deleted file mode 100644 index a2fa5f5176..0000000000 --- a/buf.work.yaml +++ /dev/null @@ -1,3 +0,0 @@ -version: v1 -directories: - - api diff --git a/docker-compose.yml b/docker-compose.yml index be66d5f014..06341c92cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,8 +25,7 @@ services: - 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_DEV_PERCONA_PLATFORM_ADDRESS=https://check.localhost - # - PMM_DEV_PERCONA_PLATFORM_INSECURE=1 + # - PMM_DEV_VERSION_SERVICE_URL=http://localhost:11000 # - PMM_DEV_PERCONA_PLATFORM_PUBLIC_KEY= # - PMM_DEV_TELEMETRY_INTERVAL=10s # - PMM_DEV_TELEMETRY_DISABLE_START_DELAY=1 diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 051214bf8c..2a2a358308 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -269,8 +269,10 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverv1.CheckUpdatesReq Timestamp: timestamppb.New(*v.Installed.BuildTime), }, Latest: &serverv1.DockerVersionInfo{ - Version: v.Latest.Version.String(), - Tag: v.Latest.DockerImage, + Version: v.Latest.Version.String(), + Tag: v.Latest.DockerImage, + ReleaseNotesUrl: v.Latest.ReleaseNotesURL, + ReleaseNotesText: v.Latest.ReleaseNotesText, }, UpdateAvailable: v.Latest.DockerImage != "", LatestNewsUrl: v.LatestNewsURL, @@ -295,6 +297,30 @@ func (s *Server) CheckUpdates(ctx context.Context, req *serverv1.CheckUpdatesReq return res, nil } +// ListChangeLogs lists PMM versions between currently installed version and the latest one. +func (s *Server) ListChangeLogs(ctx context.Context, req *serverv1.ListChangeLogsRequest) (*serverv1.ListChangeLogsResponse, error) { + versions, err := s.updater.ListUpdates(ctx) + if err != nil { + return nil, status.Error(codes.Unavailable, "failed to list available updates") + } + + updates := make([]*serverv1.DockerVersionInfo, 0, len(versions)) + for _, v := range versions { + updates = append(updates, &serverv1.DockerVersionInfo{ + Version: v.Version.String(), + Tag: v.DockerImage, + ReleaseNotesText: v.ReleaseNotesText, + ReleaseNotesUrl: v.ReleaseNotesURL, + }) + } + res := &serverv1.ListChangeLogsResponse{ + Updates: updates, + LastCheck: timestamppb.Now(), + } + + return res, nil +} + // StartUpdate starts PMM Server update. func (s *Server) StartUpdate(ctx context.Context, req *serverv1.StartUpdateRequest) (*serverv1.StartUpdateResponse, error) { s.envRW.RLock() @@ -307,7 +333,7 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverv1.StartUpdateReque newImage := req.GetNewImage() if newImage == "" { - latest, err := s.updater.latest(ctx) + _, latest, err := s.updater.latest(ctx) if err != nil { s.l.WithError(err).Error("Failed to get latest version") newImage = defaultLatestPMMImage diff --git a/managed/services/server/updater.go b/managed/services/server/updater.go index 62683a7643..5f1a30fdc6 100644 --- a/managed/services/server/updater.go +++ b/managed/services/server/updater.go @@ -25,6 +25,7 @@ import ( "net/http" "net/url" "os" + "sort" "strings" "sync" "time" @@ -39,11 +40,12 @@ import ( // 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" - updateCheckInterval = 24 * time.Hour - updateCheckResultFresh = updateCheckInterval + 10*time.Minute - updateDefaultTimeout = 30 * time.Second + defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest" + pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log" + defaultVersionServiceAddress = "https://check-dev.percona.com" + updateCheckInterval = 24 * time.Hour + updateCheckResultFresh = updateCheckInterval + 10*time.Minute + updateDefaultTimeout = 30 * time.Second ) var fileName = "/etc/pmm-server-update-version.json" @@ -60,6 +62,10 @@ type Updater struct { checkRW sync.RWMutex lastCheckResult *version.DockerVersionInfo lastCheckTime time.Time + + // releaseNotes holds a map of PMM server versions to their release notes. + releaseNotes map[string]string + releaseNotesRW sync.RWMutex } // NewUpdater creates a new Updater service. @@ -68,6 +74,7 @@ func NewUpdater(watchtowerHost *url.URL, gRPCMessageMaxSize uint32) *Updater { l: logrus.WithField("service", "updater"), watchtowerHost: watchtowerHost, gRPCMessageMaxSize: gRPCMessageMaxSize, + releaseNotes: make(map[string]string), } return u } @@ -181,20 +188,29 @@ func (up *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateC }, lastCheckTime } -func (up *Updater) latest(ctx context.Context) (*version.DockerVersionInfo, error) { +// ListUpdates returns the list of available versions between installed and latest. +func (up *Updater) ListUpdates(ctx context.Context) ([]*version.DockerVersionInfo, error) { + all, _, err := up.latest(ctx) + if err != nil { + return nil, err + } + return all, nil +} + +func (up *Updater) latest(ctx context.Context) ([]*version.DockerVersionInfo, *version.DockerVersionInfo, error) { info, err := up.readFromFile() if err != nil { - return nil, errors.Wrap(err, "failed to read from file") + return nil, nil, errors.Wrap(err, "failed to read from file") } if info != nil { - return info, nil + return nil, info, nil } if os.Getenv("PMM_DEV_UPDATE_DOCKER_IMAGE") != "" { return up.parseDockerTag(os.Getenv("PMM_DEV_UPDATE_DOCKER_IMAGE")) } - // If file does not exist, and ENV variable is not set, go get the latest tag from DockerHub - return up.latestAvailableFromDockerHub(ctx) + // If file does not exist, and ENV variable is not set, go get the latest versions from Percona version service. + return up.latestAvailableFromVersionService(ctx) } func (up *Updater) readFromFile() (*version.DockerVersionInfo, error) { @@ -217,104 +233,144 @@ func (up *Updater) readFromFile() (*version.DockerVersionInfo, error) { } type result struct { - Name string `json:"name"` - TagLastPushed time.Time `json:"tag_last_pushed"` + Version string `json:"version"` + ImageInfo imageInfo `json:"imageInfo"` } -// TagsResponse is a response from DockerHub. -type TagsResponse struct { - Results []result `json:"results"` +type imageInfo struct { + ImagePath string `json:"imagePath"` + ImageReleaseTimestamp time.Time `json:"imageReleaseTimestamp"` } -// 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) (*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" +// MetadataResponse is a response from the metadata endpoint on Percona version service. +type MetadataResponse struct { + Versions []result `json:"versions"` +} + +// ReleaseNotesResponse is a response from the release-notes endpoint on Percona version service. +type ReleaseNotesResponse struct { + ReleaseNote string `json:"releaseNote"` +} + +// latestAvailableFromVersionService queries Percona version service and returns: +// - list of versions between the installed version and the latest version (inclusive) +// - the latest available version (i.e., the latest minor version for the current major version). +// If the current version is the latest minor version, it returns the next major version as the latest. +// If the current version is the latest version, it returns the current version as the latest. +func (up *Updater) latestAvailableFromVersionService(ctx context.Context) ([]*version.DockerVersionInfo, *version.DockerVersionInfo, error) { + versionServiceUrl := os.Getenv("PMM_DEV_VERSION_SERVICE_URL") + if versionServiceUrl == "" { + versionServiceUrl = defaultVersionServiceAddress + } + u := versionServiceUrl + "/metadata/v1/pmm-server" req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { up.l.WithError(err).Error("Failed to create request") - return nil, errors.Wrap(err, "failed to create request") + return nil, nil, errors.Wrap(err, "failed to create request") } resp, err := http.DefaultClient.Do(req) if err != nil { - up.l.WithError(err).Error("Failed to get tags from DockerHub") - return nil, errors.Wrap(err, "failed to get tags from DockerHub") + up.l.WithError(err).Error("Failed to get PMM server versions") + return nil, nil, errors.Wrap(err, "failed to get PMM server versions") } defer resp.Body.Close() //nolint:errcheck - var tagsResponse TagsResponse - if err := json.NewDecoder(resp.Body).Decode(&tagsResponse); err != nil { + var metadataResponse MetadataResponse + if err := json.NewDecoder(resp.Body).Decode(&metadataResponse); err != nil { up.l.WithError(err).Error("Failed to decode response") - return nil, errors.Wrap(err, "failed to decode response") + return nil, nil, errors.Wrap(err, "failed to decode response") } - if len(tagsResponse.Results) != 0 { - 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 next, err + if len(metadataResponse.Versions) != 0 { + up.l.Infof("Found %d versions", len(metadataResponse.Versions)) + updates, next := up.next(*up.currentVersion(), metadataResponse.Versions) + return updates, next, err } - return nil, errors.New("no tags found") + return nil, nil, errors.New("no tags found") } -func (up *Updater) parseDockerTag(tag string) (*version.DockerVersionInfo, error) { +func (up *Updater) parseDockerTag(tag string) ([]*version.DockerVersionInfo, *version.DockerVersionInfo, error) { splitTag := strings.Split(tag, ":") if len(splitTag) != 2 { - return nil, fmt.Errorf("invalid tag: %s", tag) + return nil, nil, fmt.Errorf("invalid tag: %s", tag) } 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 //nolint:nilerr + return nil, &version.DockerVersionInfo{DockerImage: tag}, nil //nolint:nilerr } - return &version.DockerVersionInfo{ + return nil, &version.DockerVersionInfo{ Version: *parsed, DockerImage: tag, }, nil } -func (up *Updater) next(currentVersion version.Parsed, results []result) *version.DockerVersionInfo { +func (up *Updater) next(currentVersion version.Parsed, results []result) ([]*version.DockerVersionInfo, *version.DockerVersionInfo) { + repo := os.Getenv("PMM_DEV_UPDATE_DOCKER_REPO") + if repo == "" { + repo = "percona/pmm-server" + } nextMinor := &version.DockerVersionInfo{ Version: currentVersion, } + updates := version.DockerVersionsInfo{} var nextMajor *version.DockerVersionInfo for _, result := range results { - v, err := version.Parse(result.Name) + v, err := version.Parse(result.Version) if err != nil { - up.l.Debugf("Failed to parse version: %s", result.Name) + up.l.Debugf("Failed to parse version: %s", result.Version) continue } if !currentVersion.Less(v) { continue } - if v.Major == currentVersion.Major && nextMinor.Version.Less(v) { // next major + releaseNotesURL := "https://per.co.na/pmm/" + v.String() + releaseNote, err := up.getReleaseNotesText(context.Background(), *v) + if err != nil { + up.l.Errorf("Failed to get release notes for version: %s, %s", v.String(), err.Error()) + } + + dockerImage := result.ImageInfo.ImagePath + if dockerImage == "" { + dockerImage = repo + ":" + result.Version + } + // versions with pre-lease labels (e.g 2.40.1-rc) are not considered for the update diffs + if v.Rest == "" && currentVersion.Less(v) { + updates = append(updates, &version.DockerVersionInfo{ + Version: *v, + DockerImage: dockerImage, + BuildTime: result.ImageInfo.ImageReleaseTimestamp, + ReleaseNotesURL: releaseNotesURL, + ReleaseNotesText: releaseNote, + }) + } + + if v.Major == currentVersion.Major && nextMinor.Version.Less(v) { nextMinor = &version.DockerVersionInfo{ - Version: *v, - DockerImage: result.Name, - BuildTime: result.TagLastPushed, + Version: *v, + DockerImage: dockerImage, + BuildTime: result.ImageInfo.ImageReleaseTimestamp, + ReleaseNotesURL: releaseNotesURL, + ReleaseNotesText: releaseNote, } } 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, + Version: *v, + DockerImage: dockerImage, + BuildTime: result.ImageInfo.ImageReleaseTimestamp, + ReleaseNotesURL: releaseNotesURL, + ReleaseNotesText: releaseNote, } } } + + sort.Sort(updates) if nextMinor.Version == currentVersion && nextMajor != nil { - return nextMajor + return updates, nextMajor } - return nextMinor + return updates, nextMinor } // InstalledPMMVersion returns the currently installed PMM version. @@ -389,7 +445,7 @@ func (up *Updater) check(ctx context.Context) error { up.checkRW.Lock() defer up.checkRW.Unlock() - latest, err := up.latest(ctx) + _, latest, err := up.latest(ctx) if err != nil { return errors.Wrap(err, "failed to get latest version") } @@ -420,3 +476,48 @@ func isHostAvailable(host string, port string, timeout time.Duration) bool { } return false } + +// getReleaseNotesText is a placeholder for getting release notes in MarkDown format +// until we finalize the implementation on version service. +func (up *Updater) getReleaseNotesText(ctx context.Context, version version.Parsed) (string, error) { + if version.Rest != "" { + version.Rest = "" + } + + up.releaseNotesRW.Lock() + defer up.releaseNotesRW.Unlock() + versionString := version.String() + if releaseNotes, ok := up.releaseNotes[versionString]; ok { + return releaseNotes, nil + } + + versionServiceUrl := os.Getenv("PMM_DEV_VERSION_SERVICE_URL") + if versionServiceUrl == "" { + versionServiceUrl = defaultVersionServiceAddress + } + u := versionServiceUrl + "/release-notes/v1/pmm/" + versionString + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + up.l.WithError(err).Error("Failed to create request") + return "", errors.Wrap(err, "failed to create request") + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + up.l.WithError(err).Errorf("Failed to get release note for version: %s", versionString) + return "", errors.Wrapf(err, "failed to get release notes for version: %s", versionString) + } + + if resp.StatusCode != http.StatusOK { + up.l.Errorf("Failed to get release notes for PMM %s, got HTTP %d", version.String(), resp.StatusCode) + return "", nil + } + defer resp.Body.Close() //nolint:errcheck + var rnResponse ReleaseNotesResponse + if err := json.NewDecoder(resp.Body).Decode(&rnResponse); err != nil { + up.l.WithError(err).Error("Failed to decode response") + return "", errors.Wrap(err, "failed to decode response") + } + + up.releaseNotes[versionString] = rnResponse.ReleaseNote + return rnResponse.ReleaseNote, nil +} diff --git a/managed/services/server/updater_test.go b/managed/services/server/updater_test.go index 3f033bfbb9..8d5ff848c7 100644 --- a/managed/services/server/updater_test.go +++ b/managed/services/server/updater_test.go @@ -20,6 +20,7 @@ import ( "net/url" "os" "path/filepath" + "sort" "strings" "testing" "time" @@ -66,7 +67,7 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.0.0"}, + {Version: "3.0.0"}, }, }, want: &versionInfo{ @@ -79,14 +80,14 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.2.0"}, - {Name: "3.1.0"}, - {Name: "3.0.0"}, + {Version: "3.2.0"}, + {Version: "3.1.0"}, + {Version: "3.0.0"}, }, }, want: &versionInfo{ Version: "3.2.0", - DockerImage: "3.2.0", + DockerImage: "percona/pmm-server:3.2.0", }, }, { @@ -94,13 +95,18 @@ func TestUpdater(t *testing.T) { 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)}, + {Version: "3.0.0"}, + { + Version: "3.0.1", + ImageInfo: imageInfo{ + ImageReleaseTimestamp: time.Date(2024, 3, 20, 15, 48, 7, 145620000, time.UTC), + }, + }, }, }, want: &versionInfo{ Version: "3.0.1", - DockerImage: "3.0.1", + DockerImage: "percona/pmm-server:3.0.1", BuildTime: pointer.To(time.Date(2024, 3, 20, 15, 48, 7, 145620000, time.UTC)), }, }, @@ -109,13 +115,13 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "4.0.0"}, - {Name: "3.0.0"}, + {Version: "4.0.0"}, + {Version: "3.0.0"}, }, }, want: &versionInfo{ Version: "4.0.0", - DockerImage: "4.0.0", + DockerImage: "percona/pmm-server:4.0.0", }, }, { @@ -123,14 +129,14 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "4.0.0"}, - {Name: "3.0.0"}, - {Name: "4.0.0-rc"}, + {Version: "4.0.0"}, + {Version: "3.0.0"}, + {Version: "4.0.0-rc"}, }, }, want: &versionInfo{ Version: "4.0.0", - DockerImage: "4.0.0", + DockerImage: "percona/pmm-server:4.0.0", }, }, { @@ -138,15 +144,15 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.3.0", results: []result{ - {Name: "4.1.0"}, - {Name: "4.0.0"}, - {Name: "3.0.0"}, - {Name: "5.1.0"}, + {Version: "4.1.0"}, + {Version: "4.0.0"}, + {Version: "3.0.0"}, + {Version: "5.1.0"}, }, }, want: &versionInfo{ Version: "4.1.0", - DockerImage: "4.1.0", + DockerImage: "percona/pmm-server:4.1.0", }, }, { @@ -154,15 +160,15 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "4.1.0"}, - {Name: "4.0.0"}, - {Name: "3.0.0"}, - {Name: "3.1.0"}, + {Version: "4.1.0"}, + {Version: "4.0.0"}, + {Version: "3.0.0"}, + {Version: "3.1.0"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", }, }, { @@ -170,14 +176,14 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.0.0"}, - {Name: "3.1.0"}, - {Name: "invalid"}, + {Version: "3.0.0"}, + {Version: "3.1.0"}, + {Version: "invalid"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", }, }, { @@ -185,8 +191,8 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.0.0"}, - {Name: "3.1"}, + {Version: "3.0.0"}, + {Version: "3.1"}, }, }, want: &versionInfo{ @@ -199,14 +205,14 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.0.0"}, - {Name: "3.1.0-rc"}, - {Name: "3.1.0-rc757"}, + {Version: "3.0.0"}, + {Version: "3.1.0-rc"}, + {Version: "3.1.0-rc757"}, }, }, want: &versionInfo{ Version: "3.1.0-rc757", - DockerImage: "3.1.0-rc757", + DockerImage: "percona/pmm-server:3.1.0-rc757", }, }, { @@ -214,15 +220,15 @@ func TestUpdater(t *testing.T) { args: args{ currentVersion: "3.0.0", results: []result{ - {Name: "3.0.0"}, - {Name: "3.1.0"}, - {Name: "3.1.0-rc"}, - {Name: "3.1.0-rc757"}, + {Version: "3.0.0"}, + {Version: "3.1.0"}, + {Version: "3.1.0-rc"}, + {Version: "3.1.0-rc757"}, }, }, want: &versionInfo{ Version: "3.1.0", - DockerImage: "3.1.0", + DockerImage: "percona/pmm-server:3.1.0", }, }, } @@ -233,7 +239,7 @@ func TestUpdater(t *testing.T) { u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) parsed, err := version.Parse(tt.args.currentVersion) require.NoError(t, err) - next := u.next(*parsed, tt.args.results) + _, 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) @@ -245,14 +251,29 @@ func TestUpdater(t *testing.T) { } }) + t.Run("TestSortedVersionList", func(t *testing.T) { + versions := version.DockerVersionsInfo{ + {Version: *version.MustParse("3.0.0")}, + {Version: *version.MustParse("3.1.0")}, + {Version: *version.MustParse("3.0.1")}, + {Version: *version.MustParse("3.0.0-rc")}, + } + + sort.Sort(versions) + assert.Equal(t, "3.0.0-rc", versions[0].Version.String()) + assert.Equal(t, "3.0.0", versions[1].Version.String()) + assert.Equal(t, "3.0.1", versions[2].Version.String()) + assert.Equal(t, "3.1.0", versions[3].Version.String()) + }) + t.Run("TestLatest", func(t *testing.T) { version.Version = "2.41.0" u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) - latest, err := u.latest(context.Background()) + _, latest, err := u.latest(context.Background()) require.NoError(t, err) assert.NotNil(t, latest) assert.True(t, strings.HasPrefix(latest.Version.String(), "2.") || strings.HasPrefix(latest.Version.String(), "3."), - "latest version of PMM 2 should have prefix 2.") + "latest version of PMM should have either a '2.' or '3.' prefix") }) t.Run("TestParseFile", func(t *testing.T) { @@ -265,7 +286,7 @@ func TestUpdater(t *testing.T) { require.NoError(t, err) u := NewUpdater(watchtowerURL, gRPCMessageMaxSize) - latest, err := u.latest(context.Background()) + _, 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) diff --git a/version/update.go b/version/update.go index 235004df4d..8c1e4967f3 100644 --- a/version/update.go +++ b/version/update.go @@ -40,7 +40,22 @@ type UpdateCheckResult struct { // 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"` + Version Parsed `json:"version"` + DockerImage string `json:"docker_image"` + BuildTime time.Time `json:"build_time"` + ReleaseNotesURL string `json:"release_notes_url"` + ReleaseNotesText string `json:"release_notes_text"` +} + +// DockerVersionsInfo is a wrapper around a DockerVersionInfo array to implement sorting. +type DockerVersionsInfo []*DockerVersionInfo + +func (d DockerVersionsInfo) Len() int { return len(d) } + +func (d DockerVersionsInfo) Less(i, j int) bool { + return d[i].Version.Less(&d[j].Version) +} + +func (d DockerVersionsInfo) Swap(i, j int) { + d[i], d[j] = d[j], d[i] }