diff --git a/Makefile.include b/Makefile.include index 65b4e17a6f4..cf8b0f72817 100644 --- a/Makefile.include +++ b/Makefile.include @@ -106,7 +106,6 @@ gen-api: ## Generate PMM API api/user/v1/json/v1.json \ api/inventory/v1/json/v1.json \ api/management/v1/json/v1.json \ - api/management/v1/service/json/service.json \ api/actions/v1/json/v1.json \ api/alerting/v1/json/v1.json \ api/advisors/v1/json/v1.json \ @@ -148,7 +147,6 @@ clean: clean_swagger ## Remove generated files api/user/v1 \ api/inventory/v1 \ api/management/v1 \ - api/management/v1/service \ api/actions/v1 \ api/alerting/v1 \ api/advisors/v1 \ diff --git a/api/MIGRATION_TO_V3.md b/api/MIGRATION_TO_V3.md index 41e713f3594..605b851750b 100644 --- a/api/MIGRATION_TO_V3.md +++ b/api/MIGRATION_TO_V3.md @@ -47,6 +47,7 @@ POST /v1/inventory/Services/CustomLabels/Remove PUT /v1/inventory/services/{ **ManagementService** **ManagementService** POST /v1/management/Annotations/Add POST /v1/management/annotations ✅ +POST /v1/management/Agent/List GET /v1/management/agents ✅ Moved from MgmtService POST /v1/management/Node/Register POST /v1/management/nodes ✅ POST /v1/management/Node/Unregister DELETE /v1/management/nodes/{node_id} ✅ ?force=true POST /v1/management/Node/Get GET /v1/management/nodes/{node_id} ✅ Moved from MgmtService @@ -64,13 +65,13 @@ POST /v1/management/AzureDatabase/Discover POST /v1/management/services POST /v1/management/RDS/Discover POST /v1/management/services:discoverRDS ✅ POST /v1/management/Service/Remove DELETE /v1/management/services/{service_id} ✅ NOTE: in addition, it accepts ?service_type= -**MgmtService** **ManagementV1Beta1Service** NOTE: promote to v1 from v1beta1 -POST /v1/management/Agent/List GET /v1/management/agents -POST /v1/management/Node/Get GET /v1/management/nodes/{node_id} ✅ -POST /v1/management/Node/List GET /v1/management/nodes ✅ -POST /v1/management/AzureDatabase/Add POST /v1/management/services ✅ -POST /v1/management/AzureDatabase/Discover POST /v1/management/services:discoverAzure ✅ -POST /v1/management/Service/List GET /v1/management/services ✅ +**MgmtService** **MgmtService** NOTE: promoted to v1 from v1beta1 +POST /v1/management/Agent/List GET /v1/management/agents ✅ Moved to ManagementService +POST /v1/management/Node/Get GET /v1/management/nodes/{node_id} ✅ Moved to ManagementService +POST /v1/management/Node/List GET /v1/management/nodes ✅ Moved to ManagementService +POST /v1/management/AzureDatabase/Add POST /v1/management/services ✅ Moved to ManagementService +POST /v1/management/AzureDatabase/Discover POST /v1/management/services:discoverAzure ✅ Moved to ManagementService +POST /v1/management/Service/List GET /v1/management/services ✅ Moved to ManagementService **ActionsService** **ActionService** POST /v1/actions/Cancel POST /v1/actions:cancelAction ✅ diff --git a/api/buf.yaml b/api/buf.yaml index 431a7763025..1aab5ba8b68 100644 --- a/api/buf.yaml +++ b/api/buf.yaml @@ -10,8 +10,6 @@ lint: - agent/v1/agent.proto # We want our naming in this file to be different RPC_RESPONSE_STANDARD_NAME: - agent/v1/agent.proto # We want our naming in this file to be different - PACKAGE_DIRECTORY_MATCH: # Address these warnings during API restructuring - - management/v1/service/service.proto PACKAGE_VERSION_SUFFIX: - common/common.proto # We don't want to version this file diff --git a/api/management/v1/service/json/client/management_v1_beta1_service/list_agents_parameters.go b/api/management/v1/json/client/management_service/list_agents_parameters.go similarity index 72% rename from api/management/v1/service/json/client/management_v1_beta1_service/list_agents_parameters.go rename to api/management/v1/json/client/management_service/list_agents_parameters.go index a7025feb8d9..5dd7b7b6a4f 100644 --- a/api/management/v1/service/json/client/management_v1_beta1_service/list_agents_parameters.go +++ b/api/management/v1/json/client/management_service/list_agents_parameters.go @@ -1,6 +1,6 @@ // Code generated by go-swagger; DO NOT EDIT. -package management_v1_beta1_service +package management_service // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command @@ -60,11 +60,17 @@ ListAgentsParams contains all the parameters to send to the API endpoint Typically these are written to a http.Request. */ type ListAgentsParams struct { - /* Body. + /* NodeID. - Only one of the parameters below must be set. + Return only Agents that relate to a specific NodeID. */ - Body ListAgentsBody + NodeID *string + + /* ServiceID. + + Return only Agents that relate to a specific ServiceID. + */ + ServiceID *string timeout time.Duration Context context.Context @@ -119,15 +125,26 @@ func (o *ListAgentsParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } -// WithBody adds the body to the list agents params -func (o *ListAgentsParams) WithBody(body ListAgentsBody) *ListAgentsParams { - o.SetBody(body) +// WithNodeID adds the nodeID to the list agents params +func (o *ListAgentsParams) WithNodeID(nodeID *string) *ListAgentsParams { + o.SetNodeID(nodeID) + return o +} + +// SetNodeID adds the nodeId to the list agents params +func (o *ListAgentsParams) SetNodeID(nodeID *string) { + o.NodeID = nodeID +} + +// WithServiceID adds the serviceID to the list agents params +func (o *ListAgentsParams) WithServiceID(serviceID *string) *ListAgentsParams { + o.SetServiceID(serviceID) return o } -// SetBody adds the body to the list agents params -func (o *ListAgentsParams) SetBody(body ListAgentsBody) { - o.Body = body +// SetServiceID adds the serviceId to the list agents params +func (o *ListAgentsParams) SetServiceID(serviceID *string) { + o.ServiceID = serviceID } // WriteToRequest writes these params to a swagger request @@ -136,8 +153,37 @@ func (o *ListAgentsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Re return err } var res []error - if err := r.SetBodyParam(o.Body); err != nil { - return err + + if o.NodeID != nil { + + // query param node_id + var qrNodeID string + + if o.NodeID != nil { + qrNodeID = *o.NodeID + } + qNodeID := qrNodeID + if qNodeID != "" { + if err := r.SetQueryParam("node_id", qNodeID); err != nil { + return err + } + } + } + + if o.ServiceID != nil { + + // query param service_id + var qrServiceID string + + if o.ServiceID != nil { + qrServiceID = *o.ServiceID + } + qServiceID := qrServiceID + if qServiceID != "" { + if err := r.SetQueryParam("service_id", qServiceID); err != nil { + return err + } + } } if len(res) > 0 { diff --git a/api/management/v1/service/json/client/management_v1_beta1_service/list_agents_responses.go b/api/management/v1/json/client/management_service/list_agents_responses.go similarity index 95% rename from api/management/v1/service/json/client/management_v1_beta1_service/list_agents_responses.go rename to api/management/v1/json/client/management_service/list_agents_responses.go index 13e70d6141a..9427bbe3dae 100644 --- a/api/management/v1/service/json/client/management_v1_beta1_service/list_agents_responses.go +++ b/api/management/v1/json/client/management_service/list_agents_responses.go @@ -1,6 +1,6 @@ // Code generated by go-swagger; DO NOT EDIT. -package management_v1_beta1_service +package management_service // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command @@ -59,7 +59,7 @@ type ListAgentsOK struct { } func (o *ListAgentsOK) Error() string { - return fmt.Sprintf("[POST /v1/management/Agent/List][%d] listAgentsOk %+v", 200, o.Payload) + return fmt.Sprintf("[GET /v1/management/agents][%d] listAgentsOk %+v", 200, o.Payload) } func (o *ListAgentsOK) GetPayload() *ListAgentsOKBody { @@ -101,7 +101,7 @@ func (o *ListAgentsDefault) Code() int { } func (o *ListAgentsDefault) Error() string { - return fmt.Sprintf("[POST /v1/management/Agent/List][%d] ListAgents default %+v", o._statusCode, o.Payload) + return fmt.Sprintf("[GET /v1/management/agents][%d] ListAgents default %+v", o._statusCode, o.Payload) } func (o *ListAgentsDefault) GetPayload() *ListAgentsDefaultBody { @@ -119,46 +119,6 @@ func (o *ListAgentsDefault) readResponse(response runtime.ClientResponse, consum return nil } -/* -ListAgentsBody Only one of the parameters below must be set. -swagger:model ListAgentsBody -*/ -type ListAgentsBody struct { - // Return only Agents that relate to a specific ServiceID. - ServiceID string `json:"service_id,omitempty"` - - // Return only Agents that relate to a specific NodeID. - NodeID string `json:"node_id,omitempty"` -} - -// Validate validates this list agents body -func (o *ListAgentsBody) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validates this list agents body based on context it is used -func (o *ListAgentsBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (o *ListAgentsBody) MarshalBinary() ([]byte, error) { - if o == nil { - return nil, nil - } - return swag.WriteJSON(o) -} - -// UnmarshalBinary interface implementation -func (o *ListAgentsBody) UnmarshalBinary(b []byte) error { - var res ListAgentsBody - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *o = res - return nil -} - /* ListAgentsDefaultBody list agents default body swagger:model ListAgentsDefaultBody diff --git a/api/management/v1/json/client/management_service/management_service_client.go b/api/management/v1/json/client/management_service/management_service_client.go index 8158a564ea9..2cf93a3a908 100644 --- a/api/management/v1/json/client/management_service/management_service_client.go +++ b/api/management/v1/json/client/management_service/management_service_client.go @@ -40,6 +40,8 @@ type ClientService interface { GetNode(params *GetNodeParams, opts ...ClientOption) (*GetNodeOK, error) + ListAgents(params *ListAgentsParams, opts ...ClientOption) (*ListAgentsOK, error) + ListNodes(params *ListNodesParams, opts ...ClientOption) (*ListNodesOK, error) ListServices(params *ListServicesParams, opts ...ClientOption) (*ListServicesOK, error) @@ -251,7 +253,7 @@ func (a *Client) DiscoverRDS(params *DiscoverRDSParams, opts ...ClientOption) (* /* GetNode gets node -Returns a single Node by ID. +Gets a single Node by ID. */ func (a *Client) GetNode(params *GetNodeParams, opts ...ClientOption) (*GetNodeOK, error) { // TODO: Validate the params before sending @@ -287,10 +289,49 @@ func (a *Client) GetNode(params *GetNodeParams, opts ...ClientOption) (*GetNodeO return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ListAgents lists agents + +Lists Agents with filter. +*/ +func (a *Client) ListAgents(params *ListAgentsParams, opts ...ClientOption) (*ListAgentsOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewListAgentsParams() + } + op := &runtime.ClientOperation{ + ID: "ListAgents", + Method: "GET", + PathPattern: "/v1/management/agents", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListAgentsReader{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.(*ListAgentsOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ListAgentsDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* ListNodes lists nodes -Returns a filtered list of Nodes. +Lists Nodes with filter. */ func (a *Client) ListNodes(params *ListNodesParams, opts ...ClientOption) (*ListNodesOK, error) { // TODO: Validate the params before sending diff --git a/api/management/v1/json/v1.json b/api/management/v1/json/v1.json index df6a7f2431b..8c2736972a7 100644 --- a/api/management/v1/json/v1.json +++ b/api/management/v1/json/v1.json @@ -15,6 +15,384 @@ "version": "v1" }, "paths": { + "/v1/management/agents": { + "get": { + "description": "Lists Agents with filter.", + "tags": [ + "ManagementService" + ], + "summary": "List Agents", + "operationId": "ListAgents", + "parameters": [ + { + "type": "string", + "description": "Return only Agents that relate to a specific ServiceID.", + "name": "service_id", + "in": "query" + }, + { + "type": "string", + "description": "Return only Agents that relate to a specific NodeID.", + "name": "node_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "agents": { + "description": "List of Agents.", + "type": "array", + "items": { + "type": "object", + "properties": { + "agent_id": { + "description": "Unique agent identifier.", + "type": "string", + "x-order": 0 + }, + "agent_type": { + "description": "Agent type.", + "type": "string", + "x-order": 2 + }, + "aws_access_key": { + "description": "AWS Access Key.", + "type": "string", + "x-order": 3 + }, + "azure_options": { + "type": "object", + "properties": { + "client_id": { + "description": "Azure client ID.", + "type": "string", + "x-order": 0 + }, + "is_client_secret_set": { + "description": "True if Azure client secret is set.", + "type": "boolean", + "x-order": 1 + }, + "resource_group": { + "description": "Azure resource group.", + "type": "string", + "x-order": 2 + }, + "subscription_id": { + "description": "Azure subscription ID.", + "type": "string", + "x-order": 3 + }, + "tenant_id": { + "description": "Azure tenant ID.", + "type": "string", + "x-order": 4 + } + }, + "x-order": 5 + }, + "comments_parsing_disabled": { + "description": "True if query comments parsing is disabled.", + "type": "boolean", + "x-order": 25 + }, + "created_at": { + "description": "Creation timestamp.", + "type": "string", + "format": "date-time", + "x-order": 6 + }, + "custom_labels": { + "description": "Custom user-assigned labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 7 + }, + "disabled": { + "description": "Desired Agent status: enabled (false) or disabled (true).", + "type": "boolean", + "x-order": 8 + }, + "disabled_collectors": { + "description": "List of disabled collector names.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 9 + }, + "expose_exporter": { + "description": "True if an exporter agent is exposed on all host addresses.", + "type": "boolean", + "x-order": 39 + }, + "is_agent_password_set": { + "description": "True if the agent password is set.", + "type": "boolean", + "x-order": 1 + }, + "is_aws_secret_key_set": { + "description": "True if AWS Secret Key is set.", + "type": "boolean", + "x-order": 4 + }, + "is_connected": { + "description": "True if Agent is running and connected to pmm-managed.", + "type": "boolean", + "x-order": 38 + }, + "is_password_set": { + "description": "True if password for connecting the agent to the database is set.", + "type": "boolean", + "x-order": 19 + }, + "listen_port": { + "description": "Listen port for scraping metrics.", + "type": "integer", + "format": "int64", + "x-order": 10 + }, + "log_level": { + "description": "Log level for exporter.", + "type": "string", + "x-order": 11 + }, + "max_query_length": { + "description": "Limit query length in QAN.", + "type": "integer", + "format": "int32", + "x-order": 12 + }, + "max_query_log_size": { + "description": "Limit query log size in QAN.", + "type": "string", + "format": "int64", + "x-order": 13 + }, + "metrics_path": { + "description": "Path under which metrics are exposed, used to generate URI.", + "type": "string", + "x-order": 14 + }, + "metrics_scheme": { + "description": "Scheme to generate URI to exporter metrics endpoints.", + "type": "string", + "x-order": 15 + }, + "mongo_db_options": { + "type": "object", + "properties": { + "authentication_database": { + "description": "MongoDB auth database.", + "type": "string", + "x-order": 3 + }, + "authentication_mechanism": { + "description": "MongoDB auth mechanism.", + "type": "string", + "x-order": 2 + }, + "collections_limit": { + "description": "MongoDB collections limit.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "enable_all_collectors": { + "description": "True if all collectors are enabled.", + "type": "boolean", + "x-order": 6 + }, + "is_tls_certificate_key_file_password_set": { + "description": "True if TLS certificate file password is set.", + "type": "boolean", + "x-order": 1 + }, + "is_tls_certificate_key_set": { + "description": "True if TLS certificate is set.", + "type": "boolean", + "x-order": 0 + }, + "stats_collections": { + "description": "MongoDB stats collections.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 4 + } + }, + "x-order": 16 + }, + "mysql_options": { + "type": "object", + "properties": { + "is_tls_key_set": { + "description": "True if TLS key is set.", + "type": "boolean", + "x-order": 0 + } + }, + "x-order": 17 + }, + "node_id": { + "description": "A unique node identifier.", + "type": "string", + "x-order": 18 + }, + "pmm_agent_id": { + "description": "The pmm-agent identifier.", + "type": "string", + "x-order": 20 + }, + "postgresql_options": { + "type": "object", + "properties": { + "auto_discovery_limit": { + "description": "Limit of databases for auto-discovery.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "is_ssl_key_set": { + "description": "True if TLS key is set.", + "type": "boolean", + "x-order": 0 + }, + "max_exporter_connections": { + "description": "Maximum number of connections from exporter to PostgreSQL instance.", + "type": "integer", + "format": "int32", + "x-order": 2 + } + }, + "x-order": 21 + }, + "process_exec_path": { + "description": "Path to exec process.", + "type": "string", + "x-order": 22 + }, + "push_metrics": { + "description": "True if exporter uses push metrics mode.", + "type": "boolean", + "x-order": 23 + }, + "query_examples_disabled": { + "description": "True if query examples are disabled.", + "type": "boolean", + "x-order": 24 + }, + "rds_basic_metrics_disabled": { + "description": "True if RDS basic metrics are disdabled.", + "type": "boolean", + "x-order": 26 + }, + "rds_enhanced_metrics_disabled": { + "description": "True if RDS enhanced metrics are disdabled.", + "type": "boolean", + "x-order": 27 + }, + "runs_on_node_id": { + "description": "Node identifier where this instance runs.", + "type": "string", + "x-order": 28 + }, + "service_id": { + "description": "Service identifier.", + "type": "string", + "x-order": 29 + }, + "status": { + "description": "Actual Agent status.", + "type": "string", + "x-order": 30 + }, + "table_count": { + "description": "Last known table count.", + "type": "integer", + "format": "int32", + "x-order": 31 + }, + "table_count_tablestats_group_limit": { + "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled.", + "type": "integer", + "format": "int32", + "x-order": 32 + }, + "tls": { + "description": "Use TLS for database connections.", + "type": "boolean", + "x-order": 33 + }, + "tls_skip_verify": { + "description": "Skip TLS certificate and hostname validation.", + "type": "boolean", + "x-order": 34 + }, + "updated_at": { + "description": "Last update timestamp.", + "type": "string", + "format": "date-time", + "x-order": 36 + }, + "username": { + "description": "HTTP basic auth username for collecting metrics.", + "type": "string", + "x-order": 35 + }, + "version": { + "description": "Agent version.", + "type": "string", + "x-order": 37 + } + } + }, + "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": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + }, + "message": { + "type": "string", + "x-order": 1 + } + } + } + } + } + } + }, "/v1/management/annotations": { "post": { "description": "Adds an annotation.", @@ -106,7 +484,7 @@ }, "/v1/management/nodes": { "get": { - "description": "Returns a filtered list of Nodes.", + "description": "Lists Nodes with filter.", "tags": [ "ManagementService" ], @@ -648,7 +1026,7 @@ }, "/v1/management/nodes/{node_id}": { "get": { - "description": "Returns a single Node by ID.", + "description": "Gets a single Node by ID.", "tags": [ "ManagementService" ], diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index 7431532770e..c3969552cc5 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -984,7 +984,7 @@ var file_management_v1_service_proto_rawDesc = []byte{ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x32, 0xb6, 0x10, 0x0a, 0x11, 0x4d, 0x61, 0x6e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x32, 0xc8, 0x11, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, @@ -996,138 +996,147 @@ var file_management_v1_service_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x41, 0x64, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0xb3, 0x01, - 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x38, 0x12, 0x0f, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x25, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x4e, - 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, - 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, - 0x64, 0x65, 0x73, 0x12, 0xbd, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x92, 0x41, 0x35, 0x12, 0x11, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x20, 0x55, 0x6e, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, - 0x61, 0x6e, 0x64, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x20, 0x2a, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, - 0x69, 0x64, 0x7d, 0x12, 0x9e, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x73, 0x12, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x92, 0x41, 0x2f, 0x12, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x20, - 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x1a, 0x21, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, - 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, - 0x66, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, - 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, - 0x6f, 0x64, 0x65, 0x73, 0x12, 0x9b, 0x01, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x51, 0x92, 0x41, 0x28, 0x12, 0x08, 0x47, 0x65, 0x74, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x1c, - 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, - 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x62, 0x79, 0x20, 0x49, 0x44, 0x2e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x12, 0xb2, 0x01, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x3a, 0x12, 0x0d, 0x41, 0x64, 0x64, - 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x29, 0x41, 0x64, 0x64, 0x73, - 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, - 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xb0, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, + 0x74, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x9b, 0x01, + 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x57, 0x92, 0x41, 0x35, 0x12, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x24, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, - 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, - 0x66, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xaf, 0x01, 0x0a, 0x0b, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x21, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x59, 0x92, 0x41, 0x28, 0x12, 0x0c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x20, 0x52, 0x44, 0x53, 0x1a, 0x18, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, - 0x52, 0x44, 0x53, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x28, 0x3a, 0x01, 0x2a, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x8f, 0x02, 0x0a, - 0x15, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2b, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, 0x75, 0x72, - 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x9a, 0x01, 0x92, 0x41, 0x67, 0x12, 0x17, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x20, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x1a, 0x4c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, 0x41, 0x7a, 0x75, 0x72, - 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4d, - 0x79, 0x53, 0x51, 0x4c, 0x2c, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x44, 0x42, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x20, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x2a, 0x3a, 0x01, 0x2a, 0x22, 0x25, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x12, 0xc6, - 0x01, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x26, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x61, 0x92, 0x41, 0x36, 0x12, 0x12, 0x41, 0x64, 0x64, 0x20, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, 0x20, 0x41, - 0x64, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x3a, 0x01, 0x2a, 0x22, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x12, 0xc7, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41, 0x3c, 0x12, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x28, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x61, - 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x2a, 0x24, 0x2f, 0x76, 0x31, - 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x7d, 0x42, 0xad, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x76, - 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x48, 0x92, 0x41, 0x28, 0x12, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x73, 0x1a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0xb3, 0x01, 0x0a, 0x0c, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x92, 0x41, 0x38, 0x12, 0x0f, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x25, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x4e, 0x6f, 0x64, + 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, + 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, + 0x73, 0x12, 0xbd, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x5e, 0x92, 0x41, 0x35, 0x12, 0x11, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x1a, 0x20, 0x55, 0x6e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x70, 0x6d, 0x6d, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x20, 0x2a, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, + 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x45, 0x92, 0x41, 0x26, 0x12, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x4e, 0x6f, + 0x64, 0x65, 0x73, 0x1a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x73, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x07, 0x47, 0x65, + 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x92, 0x41, 0x25, 0x12, 0x08, 0x47, 0x65, 0x74, 0x20, 0x4e, + 0x6f, 0x64, 0x65, 0x1a, 0x19, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, + 0x6c, 0x65, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x62, 0x79, 0x20, 0x49, 0x44, 0x2e, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x69, 0x64, 0x7d, 0x12, 0xb2, 0x01, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x3a, 0x12, 0x0d, 0x41, + 0x64, 0x64, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x29, 0x41, 0x64, + 0x64, 0x73, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x20, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, + 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xb0, 0x01, 0x0a, 0x0c, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x57, 0x92, 0x41, 0x35, 0x12, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x24, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, + 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0xaf, 0x01, 0x0a, + 0x0b, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x21, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x59, 0x92, 0x41, 0x28, 0x12, 0x0c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x20, 0x52, 0x44, 0x53, 0x1a, 0x18, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x73, 0x20, 0x52, 0x44, 0x53, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x3a, 0x01, 0x2a, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x44, 0x53, 0x12, 0x8f, + 0x02, 0x0a, 0x15, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2b, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x9a, 0x01, 0x92, 0x41, 0x67, 0x12, 0x17, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x20, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x1a, 0x4c, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x20, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x2c, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x44, 0x42, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x3a, 0x01, 0x2a, 0x22, 0x25, 0x2f, 0x76, 0x31, 0x2f, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x12, 0xc6, 0x01, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x26, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, + 0x64, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x61, 0x92, 0x41, 0x36, 0x12, 0x12, 0x41, 0x64, 0x64, + 0x20, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, + 0x20, 0x41, 0x64, 0x64, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x20, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x3a, 0x01, 0x2a, 0x22, 0x1d, 0x2f, 0x76, 0x31, 0x2f, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x12, 0xc7, 0x01, 0x0a, 0x0d, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41, 0x3c, 0x12, 0x10, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x28, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x2a, 0x24, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x7d, 0x42, 0xad, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, + 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x76, 0x31, + 0xa2, 0x02, 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1173,21 +1182,23 @@ var ( (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp (*UniversalAgent)(nil), // 25: management.v1.UniversalAgent (*AddAnnotationRequest)(nil), // 26: management.v1.AddAnnotationRequest - (*RegisterNodeRequest)(nil), // 27: management.v1.RegisterNodeRequest - (*UnregisterNodeRequest)(nil), // 28: management.v1.UnregisterNodeRequest - (*ListNodesRequest)(nil), // 29: management.v1.ListNodesRequest - (*GetNodeRequest)(nil), // 30: management.v1.GetNodeRequest - (*DiscoverRDSRequest)(nil), // 31: management.v1.DiscoverRDSRequest - (*DiscoverAzureDatabaseRequest)(nil), // 32: management.v1.DiscoverAzureDatabaseRequest - (*AddAzureDatabaseRequest)(nil), // 33: management.v1.AddAzureDatabaseRequest - (*AddAnnotationResponse)(nil), // 34: management.v1.AddAnnotationResponse - (*RegisterNodeResponse)(nil), // 35: management.v1.RegisterNodeResponse - (*UnregisterNodeResponse)(nil), // 36: management.v1.UnregisterNodeResponse - (*ListNodesResponse)(nil), // 37: management.v1.ListNodesResponse - (*GetNodeResponse)(nil), // 38: management.v1.GetNodeResponse - (*DiscoverRDSResponse)(nil), // 39: management.v1.DiscoverRDSResponse - (*DiscoverAzureDatabaseResponse)(nil), // 40: management.v1.DiscoverAzureDatabaseResponse - (*AddAzureDatabaseResponse)(nil), // 41: management.v1.AddAzureDatabaseResponse + (*ListAgentsRequest)(nil), // 27: management.v1.ListAgentsRequest + (*RegisterNodeRequest)(nil), // 28: management.v1.RegisterNodeRequest + (*UnregisterNodeRequest)(nil), // 29: management.v1.UnregisterNodeRequest + (*ListNodesRequest)(nil), // 30: management.v1.ListNodesRequest + (*GetNodeRequest)(nil), // 31: management.v1.GetNodeRequest + (*DiscoverRDSRequest)(nil), // 32: management.v1.DiscoverRDSRequest + (*DiscoverAzureDatabaseRequest)(nil), // 33: management.v1.DiscoverAzureDatabaseRequest + (*AddAzureDatabaseRequest)(nil), // 34: management.v1.AddAzureDatabaseRequest + (*AddAnnotationResponse)(nil), // 35: management.v1.AddAnnotationResponse + (*ListAgentsResponse)(nil), // 36: management.v1.ListAgentsResponse + (*RegisterNodeResponse)(nil), // 37: management.v1.RegisterNodeResponse + (*UnregisterNodeResponse)(nil), // 38: management.v1.UnregisterNodeResponse + (*ListNodesResponse)(nil), // 39: management.v1.ListNodesResponse + (*GetNodeResponse)(nil), // 40: management.v1.GetNodeResponse + (*DiscoverRDSResponse)(nil), // 41: management.v1.DiscoverRDSResponse + (*DiscoverAzureDatabaseResponse)(nil), // 42: management.v1.DiscoverAzureDatabaseResponse + (*AddAzureDatabaseResponse)(nil), // 43: management.v1.AddAzureDatabaseResponse } ) @@ -1215,29 +1226,31 @@ var file_management_v1_service_proto_depIdxs = []int32{ 23, // 20: management.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 5, // 21: management.v1.ListServicesResponse.services:type_name -> management.v1.UniversalService 26, // 22: management.v1.ManagementService.AddAnnotation:input_type -> management.v1.AddAnnotationRequest - 27, // 23: management.v1.ManagementService.RegisterNode:input_type -> management.v1.RegisterNodeRequest - 28, // 24: management.v1.ManagementService.UnregisterNode:input_type -> management.v1.UnregisterNodeRequest - 29, // 25: management.v1.ManagementService.ListNodes:input_type -> management.v1.ListNodesRequest - 30, // 26: management.v1.ManagementService.GetNode:input_type -> management.v1.GetNodeRequest - 1, // 27: management.v1.ManagementService.AddService:input_type -> management.v1.AddServiceRequest - 6, // 28: management.v1.ManagementService.ListServices:input_type -> management.v1.ListServicesRequest - 31, // 29: management.v1.ManagementService.DiscoverRDS:input_type -> management.v1.DiscoverRDSRequest - 32, // 30: management.v1.ManagementService.DiscoverAzureDatabase:input_type -> management.v1.DiscoverAzureDatabaseRequest - 33, // 31: management.v1.ManagementService.AddAzureDatabase:input_type -> management.v1.AddAzureDatabaseRequest - 3, // 32: management.v1.ManagementService.RemoveService:input_type -> management.v1.RemoveServiceRequest - 34, // 33: management.v1.ManagementService.AddAnnotation:output_type -> management.v1.AddAnnotationResponse - 35, // 34: management.v1.ManagementService.RegisterNode:output_type -> management.v1.RegisterNodeResponse - 36, // 35: management.v1.ManagementService.UnregisterNode:output_type -> management.v1.UnregisterNodeResponse - 37, // 36: management.v1.ManagementService.ListNodes:output_type -> management.v1.ListNodesResponse - 38, // 37: management.v1.ManagementService.GetNode:output_type -> management.v1.GetNodeResponse - 2, // 38: management.v1.ManagementService.AddService:output_type -> management.v1.AddServiceResponse - 7, // 39: management.v1.ManagementService.ListServices:output_type -> management.v1.ListServicesResponse - 39, // 40: management.v1.ManagementService.DiscoverRDS:output_type -> management.v1.DiscoverRDSResponse - 40, // 41: management.v1.ManagementService.DiscoverAzureDatabase:output_type -> management.v1.DiscoverAzureDatabaseResponse - 41, // 42: management.v1.ManagementService.AddAzureDatabase:output_type -> management.v1.AddAzureDatabaseResponse - 4, // 43: management.v1.ManagementService.RemoveService:output_type -> management.v1.RemoveServiceResponse - 33, // [33:44] is the sub-list for method output_type - 22, // [22:33] is the sub-list for method input_type + 27, // 23: management.v1.ManagementService.ListAgents:input_type -> management.v1.ListAgentsRequest + 28, // 24: management.v1.ManagementService.RegisterNode:input_type -> management.v1.RegisterNodeRequest + 29, // 25: management.v1.ManagementService.UnregisterNode:input_type -> management.v1.UnregisterNodeRequest + 30, // 26: management.v1.ManagementService.ListNodes:input_type -> management.v1.ListNodesRequest + 31, // 27: management.v1.ManagementService.GetNode:input_type -> management.v1.GetNodeRequest + 1, // 28: management.v1.ManagementService.AddService:input_type -> management.v1.AddServiceRequest + 6, // 29: management.v1.ManagementService.ListServices:input_type -> management.v1.ListServicesRequest + 32, // 30: management.v1.ManagementService.DiscoverRDS:input_type -> management.v1.DiscoverRDSRequest + 33, // 31: management.v1.ManagementService.DiscoverAzureDatabase:input_type -> management.v1.DiscoverAzureDatabaseRequest + 34, // 32: management.v1.ManagementService.AddAzureDatabase:input_type -> management.v1.AddAzureDatabaseRequest + 3, // 33: management.v1.ManagementService.RemoveService:input_type -> management.v1.RemoveServiceRequest + 35, // 34: management.v1.ManagementService.AddAnnotation:output_type -> management.v1.AddAnnotationResponse + 36, // 35: management.v1.ManagementService.ListAgents:output_type -> management.v1.ListAgentsResponse + 37, // 36: management.v1.ManagementService.RegisterNode:output_type -> management.v1.RegisterNodeResponse + 38, // 37: management.v1.ManagementService.UnregisterNode:output_type -> management.v1.UnregisterNodeResponse + 39, // 38: management.v1.ManagementService.ListNodes:output_type -> management.v1.ListNodesResponse + 40, // 39: management.v1.ManagementService.GetNode:output_type -> management.v1.GetNodeResponse + 2, // 40: management.v1.ManagementService.AddService:output_type -> management.v1.AddServiceResponse + 7, // 41: management.v1.ManagementService.ListServices:output_type -> management.v1.ListServicesResponse + 41, // 42: management.v1.ManagementService.DiscoverRDS:output_type -> management.v1.DiscoverRDSResponse + 42, // 43: management.v1.ManagementService.DiscoverAzureDatabase:output_type -> management.v1.DiscoverAzureDatabaseResponse + 43, // 44: management.v1.ManagementService.AddAzureDatabase:output_type -> management.v1.AddAzureDatabaseResponse + 4, // 45: management.v1.ManagementService.RemoveService:output_type -> management.v1.RemoveServiceResponse + 34, // [34:46] is the sub-list for method output_type + 22, // [22:34] is the sub-list for method input_type 22, // [22:22] is the sub-list for extension type_name 22, // [22:22] is the sub-list for extension extendee 0, // [0:22] is the sub-list for field type_name diff --git a/api/management/v1/service.pb.gw.go b/api/management/v1/service.pb.gw.go index 7e8b22c0f3d..b139cf1611c 100644 --- a/api/management/v1/service.pb.gw.go +++ b/api/management/v1/service.pb.gw.go @@ -57,6 +57,38 @@ func local_request_ManagementService_AddAnnotation_0(ctx context.Context, marsha return msg, metadata, err } +var filter_ManagementService_ListAgents_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_ManagementService_ListAgents_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListAgentsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ManagementService_ListAgents_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListAgents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_ManagementService_ListAgents_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListAgentsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ManagementService_ListAgents_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListAgents(ctx, &protoReq) + return msg, metadata, err +} + func request_ManagementService_RegisterNode_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq RegisterNodeRequest var metadata runtime.ServerMetadata @@ -452,6 +484,30 @@ func RegisterManagementServiceHandlerServer(ctx context.Context, mux *runtime.Se forward_ManagementService_AddAnnotation_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("GET", pattern_ManagementService_ListAgents_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, "/management.v1.ManagementService/ListAgents", runtime.WithHTTPPathPattern("/v1/management/agents")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ManagementService_ListAgents_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_ManagementService_ListAgents_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ManagementService_RegisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -753,6 +809,27 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se forward_ManagementService_AddAnnotation_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("GET", pattern_ManagementService_ListAgents_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, "/management.v1.ManagementService/ListAgents", runtime.WithHTTPPathPattern("/v1/management/agents")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ManagementService_ListAgents_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ManagementService_ListAgents_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle("POST", pattern_ManagementService_RegisterNode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -969,6 +1046,8 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se var ( pattern_ManagementService_AddAnnotation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "annotations"}, "")) + pattern_ManagementService_ListAgents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "agents"}, "")) + pattern_ManagementService_RegisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "management", "nodes"}, "")) pattern_ManagementService_UnregisterNode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "management", "nodes", "node_id"}, "")) @@ -993,6 +1072,8 @@ var ( var ( forward_ManagementService_AddAnnotation_0 = runtime.ForwardResponseMessage + forward_ManagementService_ListAgents_0 = runtime.ForwardResponseMessage + forward_ManagementService_RegisterNode_0 = runtime.ForwardResponseMessage forward_ManagementService_UnregisterNode_0 = runtime.ForwardResponseMessage diff --git a/api/management/v1/service.proto b/api/management/v1/service.proto index 84b1193cf84..a706a3c291c 100644 --- a/api/management/v1/service.proto +++ b/api/management/v1/service.proto @@ -134,6 +134,14 @@ service ManagementService { description: "Adds an annotation." }; } + // ListAgents returns a list of Agents filtered by service_id or node_id. + rpc ListAgents(ListAgentsRequest) returns (ListAgentsResponse) { + option (google.api.http) = {get: "/v1/management/agents"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List Agents" + description: "Lists Agents with filter." + }; + } // RegisterNode registers a new Node and a pmm-agent. rpc RegisterNode(RegisterNodeRequest) returns (RegisterNodeResponse) { option (google.api.http) = { @@ -158,7 +166,7 @@ service ManagementService { option (google.api.http) = {get: "/v1/management/nodes"}; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { summary: "List Nodes" - description: "Returns a filtered list of Nodes." + description: "Lists Nodes with filter." }; } // GetNode returns a single Node by ID. @@ -166,7 +174,7 @@ service ManagementService { option (google.api.http) = {get: "/v1/management/nodes/{node_id}"}; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { summary: "Get Node" - description: "Returns a single Node by ID." + description: "Gets a single Node by ID." }; } // AddExternal adds external service and adds external exporter. diff --git a/api/management/v1/service/json/client/management_v1_beta1_service/management_v1_beta1_service_client.go b/api/management/v1/service/json/client/management_v1_beta1_service/management_v1_beta1_service_client.go deleted file mode 100644 index 496ced0dc09..00000000000 --- a/api/management/v1/service/json/client/management_v1_beta1_service/management_v1_beta1_service_client.go +++ /dev/null @@ -1,78 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package management_v1_beta1_service - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" -) - -// New creates a new management v1 beta1 service API client. -func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { - return &Client{transport: transport, formats: formats} -} - -/* -Client for management v1 beta1 service API -*/ -type Client struct { - transport runtime.ClientTransport - formats strfmt.Registry -} - -// ClientOption is the option for Client methods -type ClientOption func(*runtime.ClientOperation) - -// ClientService is the interface for Client methods -type ClientService interface { - ListAgents(params *ListAgentsParams, opts ...ClientOption) (*ListAgentsOK, error) - - SetTransport(transport runtime.ClientTransport) -} - -/* -ListAgents lists agents - -Returns a filtered list of Agents. -*/ -func (a *Client) ListAgents(params *ListAgentsParams, opts ...ClientOption) (*ListAgentsOK, error) { - // TODO: Validate the params before sending - if params == nil { - params = NewListAgentsParams() - } - op := &runtime.ClientOperation{ - ID: "ListAgents", - Method: "POST", - PathPattern: "/v1/management/Agent/List", - ProducesMediaTypes: []string{"application/json"}, - ConsumesMediaTypes: []string{"application/json"}, - Schemes: []string{"http", "https"}, - Params: params, - Reader: &ListAgentsReader{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.(*ListAgentsOK) - if ok { - return success, nil - } - // unexpected success response - unexpectedSuccess := result.(*ListAgentsDefault) - return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) -} - -// SetTransport changes the transport on the client -func (a *Client) SetTransport(transport runtime.ClientTransport) { - a.transport = transport -} diff --git a/api/management/v1/service/json/client/pmm_management_service_api_client.go b/api/management/v1/service/json/client/pmm_management_service_api_client.go deleted file mode 100644 index ba2eedb94e7..00000000000 --- a/api/management/v1/service/json/client/pmm_management_service_api_client.go +++ /dev/null @@ -1,112 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package client - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "github.com/go-openapi/runtime" - httptransport "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" - - "github.com/percona/pmm/api/management/v1/service/json/client/management_v1_beta1_service" -) - -// Default PMM management service API HTTP client. -var Default = NewHTTPClient(nil) - -const ( - // DefaultHost is the default Host - // found in Meta (info) section of spec file - DefaultHost string = "localhost" - // DefaultBasePath is the default BasePath - // found in Meta (info) section of spec file - DefaultBasePath string = "/" -) - -// DefaultSchemes are the default schemes found in Meta (info) section of spec file -var DefaultSchemes = []string{"http", "https"} - -// NewHTTPClient creates a new PMM management service API HTTP client. -func NewHTTPClient(formats strfmt.Registry) *PMMManagementServiceAPI { - return NewHTTPClientWithConfig(formats, nil) -} - -// NewHTTPClientWithConfig creates a new PMM management service API HTTP client, -// using a customizable transport config. -func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *PMMManagementServiceAPI { - // ensure nullable parameters have default - if cfg == nil { - cfg = DefaultTransportConfig() - } - - // create transport and client - transport := httptransport.New(cfg.Host, cfg.BasePath, cfg.Schemes) - return New(transport, formats) -} - -// New creates a new PMM management service API client -func New(transport runtime.ClientTransport, formats strfmt.Registry) *PMMManagementServiceAPI { - // ensure nullable parameters have default - if formats == nil { - formats = strfmt.Default - } - - cli := new(PMMManagementServiceAPI) - cli.Transport = transport - cli.ManagementV1Beta1Service = management_v1_beta1_service.New(transport, formats) - return cli -} - -// DefaultTransportConfig creates a TransportConfig with the -// default settings taken from the meta section of the spec file. -func DefaultTransportConfig() *TransportConfig { - return &TransportConfig{ - Host: DefaultHost, - BasePath: DefaultBasePath, - Schemes: DefaultSchemes, - } -} - -// TransportConfig contains the transport related info, -// found in the meta section of the spec file. -type TransportConfig struct { - Host string - BasePath string - Schemes []string -} - -// WithHost overrides the default host, -// provided by the meta section of the spec file. -func (cfg *TransportConfig) WithHost(host string) *TransportConfig { - cfg.Host = host - return cfg -} - -// WithBasePath overrides the default basePath, -// provided by the meta section of the spec file. -func (cfg *TransportConfig) WithBasePath(basePath string) *TransportConfig { - cfg.BasePath = basePath - return cfg -} - -// WithSchemes overrides the default schemes, -// provided by the meta section of the spec file. -func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig { - cfg.Schemes = schemes - return cfg -} - -// PMMManagementServiceAPI is a client for PMM management service API -type PMMManagementServiceAPI struct { - ManagementV1Beta1Service management_v1_beta1_service.ClientService - - Transport runtime.ClientTransport -} - -// SetTransport changes the transport on the client and all its subresources -func (c *PMMManagementServiceAPI) SetTransport(transport runtime.ClientTransport) { - c.Transport = transport - c.ManagementV1Beta1Service.SetTransport(transport) -} diff --git a/api/management/v1/service/json/header.json b/api/management/v1/service/json/header.json deleted file mode 100644 index 1e955ace7bd..00000000000 --- a/api/management/v1/service/json/header.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "PMM Management Service API", - "version": "v1beta1" - }, - "schemes": ["https", "http"] -} diff --git a/api/management/v1/service/json/service.json b/api/management/v1/service/json/service.json deleted file mode 100644 index 045bdbde690..00000000000 --- a/api/management/v1/service/json/service.json +++ /dev/null @@ -1,412 +0,0 @@ -{ - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "schemes": [ - "https", - "http" - ], - "swagger": "2.0", - "info": { - "title": "PMM Management Service API", - "version": "v1beta1" - }, - "paths": { - "/v1/management/Agent/List": { - "post": { - "description": "Returns a filtered list of Agents.", - "tags": [ - "ManagementV1Beta1Service" - ], - "summary": "List Agents", - "operationId": "ListAgents", - "parameters": [ - { - "description": "Only one of the parameters below must be set.", - "name": "body", - "in": "body", - "required": true, - "schema": { - "description": "Only one of the parameters below must be set.", - "type": "object", - "properties": { - "node_id": { - "description": "Return only Agents that relate to a specific NodeID.", - "type": "string", - "x-order": 1 - }, - "service_id": { - "description": "Return only Agents that relate to a specific ServiceID.", - "type": "string", - "x-order": 0 - } - } - } - } - ], - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "type": "object", - "properties": { - "agents": { - "description": "List of Agents.", - "type": "array", - "items": { - "type": "object", - "properties": { - "agent_id": { - "description": "Unique agent identifier.", - "type": "string", - "x-order": 0 - }, - "agent_type": { - "description": "Agent type.", - "type": "string", - "x-order": 2 - }, - "aws_access_key": { - "description": "AWS Access Key.", - "type": "string", - "x-order": 3 - }, - "azure_options": { - "type": "object", - "properties": { - "client_id": { - "description": "Azure client ID.", - "type": "string", - "x-order": 0 - }, - "is_client_secret_set": { - "description": "True if Azure client secret is set.", - "type": "boolean", - "x-order": 1 - }, - "resource_group": { - "description": "Azure resource group.", - "type": "string", - "x-order": 2 - }, - "subscription_id": { - "description": "Azure subscription ID.", - "type": "string", - "x-order": 3 - }, - "tenant_id": { - "description": "Azure tenant ID.", - "type": "string", - "x-order": 4 - } - }, - "x-order": 5 - }, - "comments_parsing_disabled": { - "description": "True if query comments parsing is disabled.", - "type": "boolean", - "x-order": 25 - }, - "created_at": { - "description": "Creation timestamp.", - "type": "string", - "format": "date-time", - "x-order": 6 - }, - "custom_labels": { - "description": "Custom user-assigned labels.", - "type": "object", - "additionalProperties": { - "type": "string" - }, - "x-order": 7 - }, - "disabled": { - "description": "Desired Agent status: enabled (false) or disabled (true).", - "type": "boolean", - "x-order": 8 - }, - "disabled_collectors": { - "description": "List of disabled collector names.", - "type": "array", - "items": { - "type": "string" - }, - "x-order": 9 - }, - "expose_exporter": { - "description": "True if an exporter agent is exposed on all host addresses.", - "type": "boolean", - "x-order": 39 - }, - "is_agent_password_set": { - "description": "True if the agent password is set.", - "type": "boolean", - "x-order": 1 - }, - "is_aws_secret_key_set": { - "description": "True if AWS Secret Key is set.", - "type": "boolean", - "x-order": 4 - }, - "is_connected": { - "description": "True if Agent is running and connected to pmm-managed.", - "type": "boolean", - "x-order": 38 - }, - "is_password_set": { - "description": "True if password for connecting the agent to the database is set.", - "type": "boolean", - "x-order": 19 - }, - "listen_port": { - "description": "Listen port for scraping metrics.", - "type": "integer", - "format": "int64", - "x-order": 10 - }, - "log_level": { - "description": "Log level for exporter.", - "type": "string", - "x-order": 11 - }, - "max_query_length": { - "description": "Limit query length in QAN.", - "type": "integer", - "format": "int32", - "x-order": 12 - }, - "max_query_log_size": { - "description": "Limit query log size in QAN.", - "type": "string", - "format": "int64", - "x-order": 13 - }, - "metrics_path": { - "description": "Path under which metrics are exposed, used to generate URI.", - "type": "string", - "x-order": 14 - }, - "metrics_scheme": { - "description": "Scheme to generate URI to exporter metrics endpoints.", - "type": "string", - "x-order": 15 - }, - "mongo_db_options": { - "type": "object", - "properties": { - "authentication_database": { - "description": "MongoDB auth database.", - "type": "string", - "x-order": 3 - }, - "authentication_mechanism": { - "description": "MongoDB auth mechanism.", - "type": "string", - "x-order": 2 - }, - "collections_limit": { - "description": "MongoDB collections limit.", - "type": "integer", - "format": "int32", - "x-order": 5 - }, - "enable_all_collectors": { - "description": "True if all collectors are enabled.", - "type": "boolean", - "x-order": 6 - }, - "is_tls_certificate_key_file_password_set": { - "description": "True if TLS certificate file password is set.", - "type": "boolean", - "x-order": 1 - }, - "is_tls_certificate_key_set": { - "description": "True if TLS certificate is set.", - "type": "boolean", - "x-order": 0 - }, - "stats_collections": { - "description": "MongoDB stats collections.", - "type": "array", - "items": { - "type": "string" - }, - "x-order": 4 - } - }, - "x-order": 16 - }, - "mysql_options": { - "type": "object", - "properties": { - "is_tls_key_set": { - "description": "True if TLS key is set.", - "type": "boolean", - "x-order": 0 - } - }, - "x-order": 17 - }, - "node_id": { - "description": "A unique node identifier.", - "type": "string", - "x-order": 18 - }, - "pmm_agent_id": { - "description": "The pmm-agent identifier.", - "type": "string", - "x-order": 20 - }, - "postgresql_options": { - "type": "object", - "properties": { - "auto_discovery_limit": { - "description": "Limit of databases for auto-discovery.", - "type": "integer", - "format": "int32", - "x-order": 1 - }, - "is_ssl_key_set": { - "description": "True if TLS key is set.", - "type": "boolean", - "x-order": 0 - }, - "max_exporter_connections": { - "description": "Maximum number of connections from exporter to PostgreSQL instance.", - "type": "integer", - "format": "int32", - "x-order": 2 - } - }, - "x-order": 21 - }, - "process_exec_path": { - "description": "Path to exec process.", - "type": "string", - "x-order": 22 - }, - "push_metrics": { - "description": "True if exporter uses push metrics mode.", - "type": "boolean", - "x-order": 23 - }, - "query_examples_disabled": { - "description": "True if query examples are disabled.", - "type": "boolean", - "x-order": 24 - }, - "rds_basic_metrics_disabled": { - "description": "True if RDS basic metrics are disdabled.", - "type": "boolean", - "x-order": 26 - }, - "rds_enhanced_metrics_disabled": { - "description": "True if RDS enhanced metrics are disdabled.", - "type": "boolean", - "x-order": 27 - }, - "runs_on_node_id": { - "description": "Node identifier where this instance runs.", - "type": "string", - "x-order": 28 - }, - "service_id": { - "description": "Service identifier.", - "type": "string", - "x-order": 29 - }, - "status": { - "description": "Actual Agent status.", - "type": "string", - "x-order": 30 - }, - "table_count": { - "description": "Last known table count.", - "type": "integer", - "format": "int32", - "x-order": 31 - }, - "table_count_tablestats_group_limit": { - "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled.", - "type": "integer", - "format": "int32", - "x-order": 32 - }, - "tls": { - "description": "Use TLS for database connections.", - "type": "boolean", - "x-order": 33 - }, - "tls_skip_verify": { - "description": "Skip TLS certificate and hostname validation.", - "type": "boolean", - "x-order": 34 - }, - "updated_at": { - "description": "Last update timestamp.", - "type": "string", - "format": "date-time", - "x-order": 36 - }, - "username": { - "description": "HTTP basic auth username for collecting metrics.", - "type": "string", - "x-order": 35 - }, - "version": { - "description": "Agent version.", - "type": "string", - "x-order": 37 - } - } - }, - "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": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "x-order": 0 - } - }, - "additionalProperties": false - }, - "x-order": 2 - }, - "message": { - "type": "string", - "x-order": 1 - } - } - } - } - } - } - } - }, - "tags": [ - { - "name": "ManagementV1Beta1Service" - } - ] -} \ No newline at end of file diff --git a/api/management/v1/service/service.pb.go b/api/management/v1/service/service.pb.go deleted file mode 100644 index 0558bb587fe..00000000000 --- a/api/management/v1/service/service.pb.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.32.0 -// protoc (unknown) -// source: management/v1/service/service.proto - -package servicev1beta1 - -import ( - reflect "reflect" - - _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - _ "google.golang.org/genproto/googleapis/api/annotations" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - - v1 "github.com/percona/pmm/api/management/v1" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -var File_management_v1_service_service_proto protoreflect.FileDescriptor - -var file_management_v1_service_service_proto_rawDesc = []byte{ - 0x0a, 0x23, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, - 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, - 0xc8, 0x01, 0x0a, 0x18, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x31, - 0x42, 0x65, 0x74, 0x61, 0x31, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xab, 0x01, 0x0a, - 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x58, 0x92, 0x41, 0x31, 0x12, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x73, 0x1a, 0x22, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22, - 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x42, 0xc1, 0x01, 0x0a, 0x13, 0x63, - 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, - 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x0f, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0f, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1b, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var file_management_v1_service_service_proto_goTypes = []interface{}{ - (*v1.ListAgentsRequest)(nil), // 0: management.v1.ListAgentsRequest - (*v1.ListAgentsResponse)(nil), // 1: management.v1.ListAgentsResponse -} - -var file_management_v1_service_service_proto_depIdxs = []int32{ - 0, // 0: service.v1beta1.ManagementV1Beta1Service.ListAgents:input_type -> management.v1.ListAgentsRequest - 1, // 1: service.v1beta1.ManagementV1Beta1Service.ListAgents:output_type -> management.v1.ListAgentsResponse - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_management_v1_service_service_proto_init() } -func file_management_v1_service_service_proto_init() { - if File_management_v1_service_service_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_management_v1_service_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_management_v1_service_service_proto_goTypes, - DependencyIndexes: file_management_v1_service_service_proto_depIdxs, - }.Build() - File_management_v1_service_service_proto = out.File - file_management_v1_service_service_proto_rawDesc = nil - file_management_v1_service_service_proto_goTypes = nil - file_management_v1_service_service_proto_depIdxs = nil -} diff --git a/api/management/v1/service/service.pb.gw.go b/api/management/v1/service/service.pb.gw.go deleted file mode 100644 index 710ca29ca13..00000000000 --- a/api/management/v1/service/service.pb.gw.go +++ /dev/null @@ -1,157 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: management/v1/service/service.proto - -/* -Package servicev1beta1 is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package servicev1beta1 - -import ( - "context" - "io" - "net/http" - - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - - managementv1 "github.com/percona/pmm/api/management/v1" -) - -// Suppress "imported and not used" errors -var ( - _ codes.Code - _ io.Reader - _ status.Status - _ = runtime.String - _ = utilities.NewDoubleArray - _ = metadata.Join -) - -func request_ManagementV1Beta1Service_ListAgents_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementV1Beta1ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq managementv1.ListAgentsRequest - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.ListAgents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_ManagementV1Beta1Service_ListAgents_0(ctx context.Context, marshaler runtime.Marshaler, server ManagementV1Beta1ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq managementv1.ListAgentsRequest - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ListAgents(ctx, &protoReq) - return msg, metadata, err -} - -// RegisterManagementV1Beta1ServiceHandlerServer registers the http handlers for service ManagementV1Beta1Service to "mux". -// UnaryRPC :call ManagementV1Beta1ServiceServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterManagementV1Beta1ServiceHandlerFromEndpoint instead. -func RegisterManagementV1Beta1ServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ManagementV1Beta1ServiceServer) error { - mux.Handle("POST", pattern_ManagementV1Beta1Service_ListAgents_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, "/service.v1beta1.ManagementV1Beta1Service/ListAgents", runtime.WithHTTPPathPattern("/v1/management/Agent/List")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_ManagementV1Beta1Service_ListAgents_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_ManagementV1Beta1Service_ListAgents_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - return nil -} - -// RegisterManagementV1Beta1ServiceHandlerFromEndpoint is same as RegisterManagementV1Beta1ServiceHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterManagementV1Beta1ServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterManagementV1Beta1ServiceHandler(ctx, mux, conn) -} - -// RegisterManagementV1Beta1ServiceHandler registers the http handlers for service ManagementV1Beta1Service to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterManagementV1Beta1ServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterManagementV1Beta1ServiceHandlerClient(ctx, mux, NewManagementV1Beta1ServiceClient(conn)) -} - -// RegisterManagementV1Beta1ServiceHandlerClient registers the http handlers for service ManagementV1Beta1Service -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ManagementV1Beta1ServiceClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ManagementV1Beta1ServiceClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "ManagementV1Beta1ServiceClient" to call the correct interceptors. -func RegisterManagementV1Beta1ServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ManagementV1Beta1ServiceClient) error { - mux.Handle("POST", pattern_ManagementV1Beta1Service_ListAgents_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, "/service.v1beta1.ManagementV1Beta1Service/ListAgents", runtime.WithHTTPPathPattern("/v1/management/Agent/List")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ManagementV1Beta1Service_ListAgents_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_ManagementV1Beta1Service_ListAgents_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - return nil -} - -var pattern_ManagementV1Beta1Service_ListAgents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "management", "Agent", "List"}, "")) - -var forward_ManagementV1Beta1Service_ListAgents_0 = runtime.ForwardResponseMessage diff --git a/api/management/v1/service/service.pb.validate.go b/api/management/v1/service/service.pb.validate.go deleted file mode 100644 index a1349a350ce..00000000000 --- a/api/management/v1/service/service.pb.validate.go +++ /dev/null @@ -1,36 +0,0 @@ -// Code generated by protoc-gen-validate. DO NOT EDIT. -// source: management/v1/service/service.proto - -package servicev1beta1 - -import ( - "bytes" - "errors" - "fmt" - "net" - "net/mail" - "net/url" - "regexp" - "sort" - "strings" - "time" - "unicode/utf8" - - "google.golang.org/protobuf/types/known/anypb" -) - -// ensure the imports are used -var ( - _ = bytes.MinRead - _ = errors.New("") - _ = fmt.Print - _ = utf8.UTFMax - _ = (*regexp.Regexp)(nil) - _ = (*strings.Reader)(nil) - _ = net.IPv4len - _ = time.Duration(0) - _ = (*url.URL)(nil) - _ = (*mail.Address)(nil) - _ = anypb.Any{} - _ = sort.Sort -) diff --git a/api/management/v1/service/service.proto b/api/management/v1/service/service.proto deleted file mode 100644 index f8812b0d09c..00000000000 --- a/api/management/v1/service/service.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; - -package service.v1beta1; - -import "google/api/annotations.proto"; -import "management/v1/agent.proto"; -import "protoc-gen-openapiv2/options/annotations.proto"; - -// NOTE: the GA version of /agents will be integrated into management/v1/agent.proto. - -// ManagementV1Beta1Service service provides public methods for manipulating Services. -service ManagementV1Beta1Service { - // ListAgents returns a list of Agents filtered by service_id. - rpc ListAgents(management.v1.ListAgentsRequest) returns (management.v1.ListAgentsResponse) { - option (google.api.http) = { - post: "/v1/management/Agent/List" - body: "*" - }; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - summary: "List Agents" - description: "Returns a filtered list of Agents." - }; - } -} diff --git a/api/management/v1/service/service_grpc.pb.go b/api/management/v1/service/service_grpc.pb.go deleted file mode 100644 index aa48867d07a..00000000000 --- a/api/management/v1/service/service_grpc.pb.go +++ /dev/null @@ -1,115 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc (unknown) -// source: management/v1/service/service.proto - -package servicev1beta1 - -import ( - context "context" - - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - - v1 "github.com/percona/pmm/api/management/v1" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -const ( - ManagementV1Beta1Service_ListAgents_FullMethodName = "/service.v1beta1.ManagementV1Beta1Service/ListAgents" -) - -// ManagementV1Beta1ServiceClient is the client API for ManagementV1Beta1Service service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type ManagementV1Beta1ServiceClient interface { - // ListAgents returns a list of Agents filtered by service_id. - ListAgents(ctx context.Context, in *v1.ListAgentsRequest, opts ...grpc.CallOption) (*v1.ListAgentsResponse, error) -} - -type managementV1Beta1ServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewManagementV1Beta1ServiceClient(cc grpc.ClientConnInterface) ManagementV1Beta1ServiceClient { - return &managementV1Beta1ServiceClient{cc} -} - -func (c *managementV1Beta1ServiceClient) ListAgents(ctx context.Context, in *v1.ListAgentsRequest, opts ...grpc.CallOption) (*v1.ListAgentsResponse, error) { - out := new(v1.ListAgentsResponse) - err := c.cc.Invoke(ctx, ManagementV1Beta1Service_ListAgents_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ManagementV1Beta1ServiceServer is the server API for ManagementV1Beta1Service service. -// All implementations must embed UnimplementedManagementV1Beta1ServiceServer -// for forward compatibility -type ManagementV1Beta1ServiceServer interface { - // ListAgents returns a list of Agents filtered by service_id. - ListAgents(context.Context, *v1.ListAgentsRequest) (*v1.ListAgentsResponse, error) - mustEmbedUnimplementedManagementV1Beta1ServiceServer() -} - -// UnimplementedManagementV1Beta1ServiceServer must be embedded to have forward compatible implementations. -type UnimplementedManagementV1Beta1ServiceServer struct{} - -func (UnimplementedManagementV1Beta1ServiceServer) ListAgents(context.Context, *v1.ListAgentsRequest) (*v1.ListAgentsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListAgents not implemented") -} - -func (UnimplementedManagementV1Beta1ServiceServer) mustEmbedUnimplementedManagementV1Beta1ServiceServer() { -} - -// UnsafeManagementV1Beta1ServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ManagementV1Beta1ServiceServer will -// result in compilation errors. -type UnsafeManagementV1Beta1ServiceServer interface { - mustEmbedUnimplementedManagementV1Beta1ServiceServer() -} - -func RegisterManagementV1Beta1ServiceServer(s grpc.ServiceRegistrar, srv ManagementV1Beta1ServiceServer) { - s.RegisterService(&ManagementV1Beta1Service_ServiceDesc, srv) -} - -func _ManagementV1Beta1Service_ListAgents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(v1.ListAgentsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ManagementV1Beta1ServiceServer).ListAgents(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ManagementV1Beta1Service_ListAgents_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ManagementV1Beta1ServiceServer).ListAgents(ctx, req.(*v1.ListAgentsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// ManagementV1Beta1Service_ServiceDesc is the grpc.ServiceDesc for ManagementV1Beta1Service service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var ManagementV1Beta1Service_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "service.v1beta1.ManagementV1Beta1Service", - HandlerType: (*ManagementV1Beta1ServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "ListAgents", - Handler: _ManagementV1Beta1Service_ListAgents_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "management/v1/service/service.proto", -} diff --git a/api/management/v1/service_grpc.pb.go b/api/management/v1/service_grpc.pb.go index a40dd9c22b4..d85ad9ea429 100644 --- a/api/management/v1/service_grpc.pb.go +++ b/api/management/v1/service_grpc.pb.go @@ -21,6 +21,7 @@ const _ = grpc.SupportPackageIsVersion7 const ( ManagementService_AddAnnotation_FullMethodName = "/management.v1.ManagementService/AddAnnotation" + ManagementService_ListAgents_FullMethodName = "/management.v1.ManagementService/ListAgents" ManagementService_RegisterNode_FullMethodName = "/management.v1.ManagementService/RegisterNode" ManagementService_UnregisterNode_FullMethodName = "/management.v1.ManagementService/UnregisterNode" ManagementService_ListNodes_FullMethodName = "/management.v1.ManagementService/ListNodes" @@ -39,6 +40,8 @@ const ( type ManagementServiceClient interface { // AddAnnotation adds an annotation. AddAnnotation(ctx context.Context, in *AddAnnotationRequest, opts ...grpc.CallOption) (*AddAnnotationResponse, error) + // ListAgents returns a list of Agents filtered by service_id or node_id. + ListAgents(ctx context.Context, in *ListAgentsRequest, opts ...grpc.CallOption) (*ListAgentsResponse, error) // RegisterNode registers a new Node and a pmm-agent. RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) // UnregisterNode unregisters a Node, pmm-agent and removes the service account and its token. @@ -78,6 +81,15 @@ func (c *managementServiceClient) AddAnnotation(ctx context.Context, in *AddAnno return out, nil } +func (c *managementServiceClient) ListAgents(ctx context.Context, in *ListAgentsRequest, opts ...grpc.CallOption) (*ListAgentsResponse, error) { + out := new(ListAgentsResponse) + err := c.cc.Invoke(ctx, ManagementService_ListAgents_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *managementServiceClient) RegisterNode(ctx context.Context, in *RegisterNodeRequest, opts ...grpc.CallOption) (*RegisterNodeResponse, error) { out := new(RegisterNodeResponse) err := c.cc.Invoke(ctx, ManagementService_RegisterNode_FullMethodName, in, out, opts...) @@ -174,6 +186,8 @@ func (c *managementServiceClient) RemoveService(ctx context.Context, in *RemoveS type ManagementServiceServer interface { // AddAnnotation adds an annotation. AddAnnotation(context.Context, *AddAnnotationRequest) (*AddAnnotationResponse, error) + // ListAgents returns a list of Agents filtered by service_id or node_id. + ListAgents(context.Context, *ListAgentsRequest) (*ListAgentsResponse, error) // RegisterNode registers a new Node and a pmm-agent. RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) // UnregisterNode unregisters a Node, pmm-agent and removes the service account and its token. @@ -204,6 +218,10 @@ func (UnimplementedManagementServiceServer) AddAnnotation(context.Context, *AddA return nil, status.Errorf(codes.Unimplemented, "method AddAnnotation not implemented") } +func (UnimplementedManagementServiceServer) ListAgents(context.Context, *ListAgentsRequest) (*ListAgentsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAgents not implemented") +} + func (UnimplementedManagementServiceServer) RegisterNode(context.Context, *RegisterNodeRequest) (*RegisterNodeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterNode not implemented") } @@ -274,6 +292,24 @@ func _ManagementService_AddAnnotation_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _ManagementService_ListAgents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAgentsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ManagementServiceServer).ListAgents(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ManagementService_ListAgents_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ManagementServiceServer).ListAgents(ctx, req.(*ListAgentsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ManagementService_RegisterNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(RegisterNodeRequest) if err := dec(in); err != nil { @@ -465,6 +501,10 @@ var ManagementService_ServiceDesc = grpc.ServiceDesc{ MethodName: "AddAnnotation", Handler: _ManagementService_AddAnnotation_Handler, }, + { + MethodName: "ListAgents", + Handler: _ManagementService_ListAgents_Handler, + }, { MethodName: "RegisterNode", Handler: _ManagementService_RegisterNode_Handler, diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index e3ff40baea9..ac00c466d80 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -16336,36 +16336,26 @@ } } }, - "/v1/management/Agent/List": { - "post": { - "description": "Returns a filtered list of Agents.", + "/v1/management/agents": { + "get": { + "description": "Lists Agents with filter.", "tags": [ - "ManagementV1Beta1Service" + "ManagementService" ], "summary": "List Agents", - "operationId": "ListAgentsMixin4", + "operationId": "ListAgentsMixin3", "parameters": [ { - "description": "Only one of the parameters below must be set.", - "name": "body", - "in": "body", - "required": true, - "schema": { - "description": "Only one of the parameters below must be set.", - "type": "object", - "properties": { - "service_id": { - "description": "Return only Agents that relate to a specific ServiceID.", - "type": "string", - "x-order": 0 - }, - "node_id": { - "description": "Return only Agents that relate to a specific NodeID.", - "type": "string", - "x-order": 1 - } - } - } + "type": "string", + "description": "Return only Agents that relate to a specific ServiceID.", + "name": "service_id", + "in": "query" + }, + { + "type": "string", + "description": "Return only Agents that relate to a specific NodeID.", + "name": "node_id", + "in": "query" } ], "responses": { @@ -16815,7 +16805,7 @@ }, "/v1/management/nodes": { "get": { - "description": "Returns a filtered list of Nodes.", + "description": "Lists Nodes with filter.", "tags": [ "ManagementService" ], @@ -17357,7 +17347,7 @@ }, "/v1/management/nodes/{node_id}": { "get": { - "description": "Returns a single Node by ID.", + "description": "Gets a single Node by ID.", "tags": [ "ManagementService" ], @@ -26826,9 +26816,6 @@ { "name": "ManagementService" }, - { - "name": "ManagementV1Beta1Service" - }, { "name": "ActionsService" }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 3090e55bf0a..356b23f598f 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4565,6 +4565,384 @@ } } }, + "/v1/management/agents": { + "get": { + "description": "Lists Agents with filter.", + "tags": [ + "ManagementService" + ], + "summary": "List Agents", + "operationId": "ListAgents", + "parameters": [ + { + "type": "string", + "description": "Return only Agents that relate to a specific ServiceID.", + "name": "service_id", + "in": "query" + }, + { + "type": "string", + "description": "Return only Agents that relate to a specific NodeID.", + "name": "node_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "agents": { + "description": "List of Agents.", + "type": "array", + "items": { + "type": "object", + "properties": { + "agent_id": { + "description": "Unique agent identifier.", + "type": "string", + "x-order": 0 + }, + "is_agent_password_set": { + "description": "True if the agent password is set.", + "type": "boolean", + "x-order": 1 + }, + "agent_type": { + "description": "Agent type.", + "type": "string", + "x-order": 2 + }, + "aws_access_key": { + "description": "AWS Access Key.", + "type": "string", + "x-order": 3 + }, + "is_aws_secret_key_set": { + "description": "True if AWS Secret Key is set.", + "type": "boolean", + "x-order": 4 + }, + "azure_options": { + "type": "object", + "properties": { + "client_id": { + "description": "Azure client ID.", + "type": "string", + "x-order": 0 + }, + "is_client_secret_set": { + "description": "True if Azure client secret is set.", + "type": "boolean", + "x-order": 1 + }, + "resource_group": { + "description": "Azure resource group.", + "type": "string", + "x-order": 2 + }, + "subscription_id": { + "description": "Azure subscription ID.", + "type": "string", + "x-order": 3 + }, + "tenant_id": { + "description": "Azure tenant ID.", + "type": "string", + "x-order": 4 + } + }, + "x-order": 5 + }, + "created_at": { + "description": "Creation timestamp.", + "type": "string", + "format": "date-time", + "x-order": 6 + }, + "custom_labels": { + "description": "Custom user-assigned labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 7 + }, + "disabled": { + "description": "Desired Agent status: enabled (false) or disabled (true).", + "type": "boolean", + "x-order": 8 + }, + "disabled_collectors": { + "description": "List of disabled collector names.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 9 + }, + "listen_port": { + "description": "Listen port for scraping metrics.", + "type": "integer", + "format": "int64", + "x-order": 10 + }, + "log_level": { + "description": "Log level for exporter.", + "type": "string", + "x-order": 11 + }, + "max_query_length": { + "description": "Limit query length in QAN.", + "type": "integer", + "format": "int32", + "x-order": 12 + }, + "max_query_log_size": { + "description": "Limit query log size in QAN.", + "type": "string", + "format": "int64", + "x-order": 13 + }, + "metrics_path": { + "description": "Path under which metrics are exposed, used to generate URI.", + "type": "string", + "x-order": 14 + }, + "metrics_scheme": { + "description": "Scheme to generate URI to exporter metrics endpoints.", + "type": "string", + "x-order": 15 + }, + "mongo_db_options": { + "type": "object", + "properties": { + "is_tls_certificate_key_set": { + "description": "True if TLS certificate is set.", + "type": "boolean", + "x-order": 0 + }, + "is_tls_certificate_key_file_password_set": { + "description": "True if TLS certificate file password is set.", + "type": "boolean", + "x-order": 1 + }, + "authentication_mechanism": { + "description": "MongoDB auth mechanism.", + "type": "string", + "x-order": 2 + }, + "authentication_database": { + "description": "MongoDB auth database.", + "type": "string", + "x-order": 3 + }, + "stats_collections": { + "description": "MongoDB stats collections.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 4 + }, + "collections_limit": { + "description": "MongoDB collections limit.", + "type": "integer", + "format": "int32", + "x-order": 5 + }, + "enable_all_collectors": { + "description": "True if all collectors are enabled.", + "type": "boolean", + "x-order": 6 + } + }, + "x-order": 16 + }, + "mysql_options": { + "type": "object", + "properties": { + "is_tls_key_set": { + "description": "True if TLS key is set.", + "type": "boolean", + "x-order": 0 + } + }, + "x-order": 17 + }, + "node_id": { + "description": "A unique node identifier.", + "type": "string", + "x-order": 18 + }, + "is_password_set": { + "description": "True if password for connecting the agent to the database is set.", + "type": "boolean", + "x-order": 19 + }, + "pmm_agent_id": { + "description": "The pmm-agent identifier.", + "type": "string", + "x-order": 20 + }, + "postgresql_options": { + "type": "object", + "properties": { + "is_ssl_key_set": { + "description": "True if TLS key is set.", + "type": "boolean", + "x-order": 0 + }, + "auto_discovery_limit": { + "description": "Limit of databases for auto-discovery.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "max_exporter_connections": { + "description": "Maximum number of connections from exporter to PostgreSQL instance.", + "type": "integer", + "format": "int32", + "x-order": 2 + } + }, + "x-order": 21 + }, + "process_exec_path": { + "description": "Path to exec process.", + "type": "string", + "x-order": 22 + }, + "push_metrics": { + "description": "True if exporter uses push metrics mode.", + "type": "boolean", + "x-order": 23 + }, + "query_examples_disabled": { + "description": "True if query examples are disabled.", + "type": "boolean", + "x-order": 24 + }, + "comments_parsing_disabled": { + "description": "True if query comments parsing is disabled.", + "type": "boolean", + "x-order": 25 + }, + "rds_basic_metrics_disabled": { + "description": "True if RDS basic metrics are disdabled.", + "type": "boolean", + "x-order": 26 + }, + "rds_enhanced_metrics_disabled": { + "description": "True if RDS enhanced metrics are disdabled.", + "type": "boolean", + "x-order": 27 + }, + "runs_on_node_id": { + "description": "Node identifier where this instance runs.", + "type": "string", + "x-order": 28 + }, + "service_id": { + "description": "Service identifier.", + "type": "string", + "x-order": 29 + }, + "status": { + "description": "Actual Agent status.", + "type": "string", + "x-order": 30 + }, + "table_count": { + "description": "Last known table count.", + "type": "integer", + "format": "int32", + "x-order": 31 + }, + "table_count_tablestats_group_limit": { + "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled.", + "type": "integer", + "format": "int32", + "x-order": 32 + }, + "tls": { + "description": "Use TLS for database connections.", + "type": "boolean", + "x-order": 33 + }, + "tls_skip_verify": { + "description": "Skip TLS certificate and hostname validation.", + "type": "boolean", + "x-order": 34 + }, + "username": { + "description": "HTTP basic auth username for collecting metrics.", + "type": "string", + "x-order": 35 + }, + "updated_at": { + "description": "Last update timestamp.", + "type": "string", + "format": "date-time", + "x-order": 36 + }, + "version": { + "description": "Agent version.", + "type": "string", + "x-order": 37 + }, + "is_connected": { + "description": "True if Agent is running and connected to pmm-managed.", + "type": "boolean", + "x-order": 38 + }, + "expose_exporter": { + "description": "True if an exporter agent is exposed on all host addresses.", + "type": "boolean", + "x-order": 39 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/management/annotations": { "post": { "description": "Adds an annotation.", @@ -4656,7 +5034,7 @@ }, "/v1/management/nodes": { "get": { - "description": "Returns a filtered list of Nodes.", + "description": "Lists Nodes with filter.", "tags": [ "ManagementService" ], @@ -5198,7 +5576,7 @@ }, "/v1/management/nodes/{node_id}": { "get": { - "description": "Returns a single Node by ID.", + "description": "Gets a single Node by ID.", "tags": [ "ManagementService" ], diff --git a/descriptor.bin b/descriptor.bin index 478005932a8..f272dcdb3a5 100644 Binary files a/descriptor.bin and b/descriptor.bin differ diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 58615a64fab..180754accd3 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -68,7 +68,6 @@ import ( dumpv1beta1 "github.com/percona/pmm/api/dump/v1beta1" inventoryv1 "github.com/percona/pmm/api/inventory/v1" managementv1 "github.com/percona/pmm/api/management/v1" - managementv1beta1 "github.com/percona/pmm/api/management/v1/service" platformv1 "github.com/percona/pmm/api/platform/v1" serverv1 "github.com/percona/pmm/api/server/v1" uieventsv1 "github.com/percona/pmm/api/uievents/v1" @@ -264,7 +263,6 @@ func runGRPCServer(ctx context.Context, deps *gRPCServerDeps) { managementSvc := management.NewManagementService(deps.db, deps.agentsRegistry, deps.agentsStateUpdater, deps.connectionCheck, deps.serviceInfoBroker, deps.vmdb, deps.versionCache, deps.grafanaClient, v1.NewAPI(*deps.vmClient)) - managementv1beta1.RegisterManagementV1Beta1ServiceServer(gRPCServer, management.NewMgmtServiceService(deps.db, deps.agentsRegistry, deps.agentsStateUpdater, deps.vmdb, v1.NewAPI(*deps.vmClient))) managementv1.RegisterManagementServiceServer(gRPCServer, managementSvc) actionsv1.RegisterActionsServiceServer(gRPCServer, managementgrpc.NewActionsServer(deps.actions, deps.db)) advisorsv1.RegisterAdvisorServiceServer(gRPCServer, management.NewChecksAPIService(deps.checksService)) @@ -357,7 +355,6 @@ func runHTTP1Server(ctx context.Context, deps *http1ServerDeps) { inventoryv1.RegisterServicesServiceHandlerFromEndpoint, inventoryv1.RegisterAgentsServiceHandlerFromEndpoint, - managementv1beta1.RegisterManagementV1Beta1ServiceHandlerFromEndpoint, managementv1.RegisterManagementServiceHandlerFromEndpoint, actionsv1.RegisterActionsServiceHandlerFromEndpoint, advisorsv1.RegisterAdvisorServiceHandlerFromEndpoint, diff --git a/managed/services/grafana/auth_server.go b/managed/services/grafana/auth_server.go index 33adf7e87ad..62953b56d1e 100644 --- a/managed/services/grafana/auth_server.go +++ b/managed/services/grafana/auth_server.go @@ -50,7 +50,7 @@ var rules = map[string]role{ "/inventory.": admin, "/management.": admin, - "/actions/": viewer, + "/actions.": viewer, "/server.v1.ServerService/CheckUpdates": viewer, "/server.v1.ServerService/UpdateStatus": none, // special token-based auth "/server.v1.ServerService/AWSInstanceCheck": none, // special case - used before Grafana can be accessed @@ -64,7 +64,7 @@ var rules = map[string]role{ "/v1/backup": admin, // TODO: remove once we finish refactoring the whole backup API "/v1/backups": admin, "/v1/dump": admin, - "/v1/role": admin, + "/v1/accesscontrol": admin, "/v1/inventory/": admin, "/v1/inventory/services:getTypes": viewer, "/v1/management/": admin, diff --git a/managed/services/grafana/auth_server_test.go b/managed/services/grafana/auth_server_test.go index 00ce92f138b..ed757f2b182 100644 --- a/managed/services/grafana/auth_server_test.go +++ b/managed/services/grafana/auth_server_test.go @@ -203,7 +203,7 @@ func TestAuthServerAuthenticate(t *testing.T) { "/agent.Agent/Connect": admin, "/inventory.v1.Nodes/ListNodes": admin, - "/actions/StartMySQLShowTableStatusAction": viewer, + "/actions.v1.ActionsService/StartServiceAction": viewer, "/management.v1.ManagementService/RemoveService": admin, "/management.v1.ManagementService/ListServices": admin, "/management.v1.ManagementService/AddAnnotation": admin, @@ -212,19 +212,19 @@ func TestAuthServerAuthenticate(t *testing.T) { "/server.v1.ServerService/UpdateStatus": none, "/server.v1.ServerService/AWSInstanceCheck": none, - "/v1/inventory/nodes": admin, - "/v1/actions/StartMySQLShowTableStatus": viewer, - "/v1/management/Service/Remove": admin, - "/v1/management/Service/List": admin, - "/v1/management/Agent/List": admin, - "/v1/server/updates": viewer, - "/v1/server/updates:start": admin, - "/v1/server/updates:getStatus": none, - "/v1/server/settings": admin, - "/v1/server/AWSInstance": none, - "/v1/backups": admin, - "/v1/users": viewer, - "/v1/platform/Connect": admin, + "/v1/inventory/nodes": admin, + "/v1/actions:startServiceAction": viewer, + "/v1/management/services": admin, + "/v1/management/agents": admin, + "/v1/server/updates": viewer, + "/v1/server/updates:start": admin, + "/v1/server/updates:getStatus": none, + "/v1/server/settings": admin, + "/v1/server/AWSInstance": none, + "/v1/backups": admin, + "/v1/accesscontrol": admin, + "/v1/users": viewer, + "/v1/platform/Connect": admin, "/v1/server/AWSInstance/..%2f..%2finventory/Services/List": admin, "/v1/server/AWSInstance/..%2flogs.zip": admin, diff --git a/managed/services/management/agent.go b/managed/services/management/agent.go index 185dac8fff8..067de6660ef 100644 --- a/managed/services/management/agent.go +++ b/managed/services/management/agent.go @@ -29,7 +29,7 @@ import ( ) // ListAgents returns a filtered list of Agents. -func (s *MgmtServiceService) ListAgents(ctx context.Context, req *managementv1.ListAgentsRequest) (*managementv1.ListAgentsResponse, error) { +func (s *ManagementService) ListAgents(ctx context.Context, req *managementv1.ListAgentsRequest) (*managementv1.ListAgentsResponse, error) { var err error err = s.validateListAgentRequest(req) if err != nil { @@ -51,7 +51,7 @@ func (s *MgmtServiceService) ListAgents(ctx context.Context, req *managementv1.L } // listAgentsByServiceID returns a list of Agents filtered by ServiceID. -func (s *MgmtServiceService) listAgentsByServiceID(ctx context.Context, serviceID string) ([]*managementv1.UniversalAgent, error) { +func (s *ManagementService) listAgentsByServiceID(ctx context.Context, serviceID string) ([]*managementv1.UniversalAgent, error) { var agents []*models.Agent var service *models.Service @@ -91,7 +91,7 @@ func (s *MgmtServiceService) listAgentsByServiceID(ctx context.Context, serviceI } // listAgentsByNodeID returns a list of Agents filtered by NodeID. -func (s *MgmtServiceService) listAgentsByNodeID(nodeID string) ([]*managementv1.UniversalAgent, error) { +func (s *ManagementService) listAgentsByNodeID(nodeID string) ([]*managementv1.UniversalAgent, error) { agents, err := models.FindAgents(s.db.Querier, models.AgentFilters{}) if err != nil { return nil, err @@ -112,7 +112,7 @@ func (s *MgmtServiceService) listAgentsByNodeID(nodeID string) ([]*managementv1. return res, nil } -func (s *MgmtServiceService) agentToAPI(agent *models.Agent) (*managementv1.UniversalAgent, error) { +func (s *ManagementService) agentToAPI(agent *models.Agent) (*managementv1.UniversalAgent, error) { labels, err := agent.GetCustomLabels() if err != nil { return nil, err @@ -196,7 +196,7 @@ func (s *MgmtServiceService) agentToAPI(agent *models.Agent) (*managementv1.Univ return ua, nil } -func (s *MgmtServiceService) validateListAgentRequest(req *managementv1.ListAgentsRequest) error { +func (s *ManagementService) validateListAgentRequest(req *managementv1.ListAgentsRequest) error { if req.ServiceId == "" && req.NodeId == "" { return status.Error(codes.InvalidArgument, "Either service_id or node_id is expected.") } diff --git a/managed/services/management/agent_test.go b/managed/services/management/agent_test.go index 8bff862a5a5..8b9ec45f423 100644 --- a/managed/services/management/agent_test.go +++ b/managed/services/management/agent_test.go @@ -39,7 +39,7 @@ import ( var now time.Time -func setup(t *testing.T) (context.Context, *MgmtServiceService, func(t *testing.T)) { +func setup(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { t.Helper() now = models.Now() @@ -54,14 +54,26 @@ func setup(t *testing.T) (context.Context, *MgmtServiceService, func(t *testing. sqlDB := testdb.Open(t, models.SetupFixtures, nil) db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + vmdb := &mockPrometheusService{} + vmdb.Test(t) + state := &mockAgentsStateUpdater{} state.Test(t) ar := &mockAgentsRegistry{} ar.Test(t) - vmdb := &mockPrometheusService{} - vmdb.Test(t) + cc := &mockConnectionChecker{} + cc.Test(t) + + sib := &mockServiceInfoBroker{} + sib.Test(t) + + vc := &mockVersionCache{} + vc.Test(t) + + grafanaClient := &mockGrafanaClient{} + grafanaClient.Test(t) vmClient := &mockVictoriaMetricsClient{} vmClient.Test(t) @@ -72,13 +84,18 @@ func setup(t *testing.T) (context.Context, *MgmtServiceService, func(t *testing. uuid.SetRand(nil) require.NoError(t, sqlDB.Close()) - state.AssertExpectations(t) + ar.AssertExpectations(t) + state.AssertExpectations(t) + cc.AssertExpectations(t) + sib.AssertExpectations(t) vmdb.AssertExpectations(t) + vc.AssertExpectations(t) + grafanaClient.AssertExpectations(t) vmClient.AssertExpectations(t) } - s := NewMgmtServiceService(db, ar, state, vmdb, vmClient) + s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) return ctx, s, teardown } diff --git a/managed/services/management/node.go b/managed/services/management/node.go index 799bb2b116e..f3fbc04c18e 100644 --- a/managed/services/management/node.go +++ b/managed/services/management/node.go @@ -17,10 +17,15 @@ package management import ( "context" + "fmt" + "time" "github.com/AlekSi/pointer" + "github.com/pkg/errors" + "github.com/prometheus/common/model" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" inventoryv1 "github.com/percona/pmm/api/inventory/v1" @@ -156,3 +161,201 @@ func (s *ManagementService) Unregister(ctx context.Context, req *managementv1.Un Warning: warning, }, nil } + +const upQuery = `up{job=~".*_hr$"}` + +// ListNodes returns a filtered list of Nodes. +func (s *ManagementService) ListNodes(ctx context.Context, req *managementv1.ListNodesRequest) (*managementv1.ListNodesResponse, error) { + filters := models.NodeFilters{ + NodeType: services.ProtoToModelNodeType(req.NodeType), + } + + var ( + nodes []*models.Node + agents []*models.Agent + services []*models.Service + ) + + errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + var err error + + nodes, err = models.FindNodes(s.db.Querier, filters) + if err != nil { + return err + } + + agents, err = models.FindAgents(s.db.Querier, models.AgentFilters{}) + if err != nil { + return err + } + + services, err = models.FindServices(s.db.Querier, models.ServiceFilters{}) + if err != nil { + return err + } + + return nil + }) + + if errTX != nil { + return nil, errTX + } + + convertAgentToProto := func(agent *models.Agent) *managementv1.UniversalNode_Agent { + return &managementv1.UniversalNode_Agent{ + AgentId: agent.AgentID, + AgentType: string(agent.AgentType), + Status: agent.Status, + IsConnected: s.r.IsConnected(agent.AgentID), + } + } + + aMap := make(map[string][]*managementv1.UniversalNode_Agent, len(nodes)) + for _, a := range agents { + if a.NodeID != nil || a.RunsOnNodeID != nil { + var nodeID string + if a.NodeID != nil { + nodeID = pointer.GetString(a.NodeID) + } else { + nodeID = pointer.GetString(a.RunsOnNodeID) + } + aMap[nodeID] = append(aMap[nodeID], convertAgentToProto(a)) + } + } + + sMap := make(map[string][]*managementv1.UniversalNode_Service, len(services)) + for _, s := range services { + sMap[s.NodeID] = append(sMap[s.NodeID], &managementv1.UniversalNode_Service{ + ServiceId: s.ServiceID, + ServiceType: string(s.ServiceType), + ServiceName: s.ServiceName, + }) + } + + result, _, err := s.vmClient.Query(ctx, upQuery, time.Now()) + if err != nil { + return nil, errors.Wrap(err, "failed to execute an instant VM query") + } + + metrics := make(map[string]int, len(result.(model.Vector))) //nolint:forcetypeassert + for _, v := range result.(model.Vector) { //nolint:forcetypeassert + nodeID := string(v.Metric[model.LabelName("node_id")]) + // Sometimes we may see several metrics for the same node, so we just take the first one. + if _, ok := metrics[nodeID]; !ok { + metrics[nodeID] = int(v.Value) + } + } + + res := make([]*managementv1.UniversalNode, len(nodes)) + for i, node := range nodes { + labels, err := node.GetCustomLabels() + if err != nil { + return nil, err + } + + uNode := &managementv1.UniversalNode{ + Address: node.Address, + CustomLabels: labels, + NodeId: node.NodeID, + NodeName: node.NodeName, + NodeType: string(node.NodeType), + Az: node.AZ, + CreatedAt: timestamppb.New(node.CreatedAt), + ContainerId: pointer.GetString(node.ContainerID), + ContainerName: pointer.GetString(node.ContainerName), + Distro: node.Distro, + MachineId: pointer.GetString(node.MachineID), + NodeModel: node.NodeModel, + Region: pointer.GetString(node.Region), + UpdatedAt: timestamppb.New(node.UpdatedAt), + } + + if metric, ok := metrics[node.NodeID]; ok { + switch metric { + // We assume there can only be metric values of either 1(UP) or 0(DOWN). + case 0: + uNode.Status = managementv1.UniversalNode_STATUS_DOWN + case 1: + uNode.Status = managementv1.UniversalNode_STATUS_UP + } + } else { + uNode.Status = managementv1.UniversalNode_STATUS_UNKNOWN + } + + if uAgents, ok := aMap[node.NodeID]; ok { + uNode.Agents = uAgents + } + + if uServices, ok := sMap[node.NodeID]; ok { + uNode.Services = uServices + } + + res[i] = uNode + } + + return &managementv1.ListNodesResponse{ + Nodes: res, + }, nil +} + +const nodeUpQuery = `up{job=~".*_hr$",node_id=%q}` + +// GetNode returns a single Node by ID. +func (s *ManagementService) GetNode(ctx context.Context, req *managementv1.GetNodeRequest) (*managementv1.GetNodeResponse, error) { + node, err := models.FindNodeByID(s.db.Querier, req.NodeId) + if err != nil { + return nil, err + } + + result, _, err := s.vmClient.Query(ctx, fmt.Sprintf(nodeUpQuery, req.NodeId), time.Now()) + if err != nil { + return nil, errors.Wrap(err, "failed to execute an instant VM query") + } + + metrics := make(map[string]int, len(result.(model.Vector))) //nolint:forcetypeassert + for _, v := range result.(model.Vector) { //nolint:forcetypeassert + nodeID := string(v.Metric[model.LabelName("node_id")]) + // Sometimes we may see several metrics for the same node, so we just take the first one. + if _, ok := metrics[nodeID]; !ok { + metrics[nodeID] = int(v.Value) + } + } + + labels, err := node.GetCustomLabels() + if err != nil { + return nil, err + } + + uNode := &managementv1.UniversalNode{ + Address: node.Address, + Az: node.AZ, + CreatedAt: timestamppb.New(node.CreatedAt), + ContainerId: pointer.GetString(node.ContainerID), + ContainerName: pointer.GetString(node.ContainerName), + CustomLabels: labels, + Distro: node.Distro, + MachineId: pointer.GetString(node.MachineID), + NodeId: node.NodeID, + NodeName: node.NodeName, + NodeType: string(node.NodeType), + NodeModel: node.NodeModel, + Region: pointer.GetString(node.Region), + UpdatedAt: timestamppb.New(node.UpdatedAt), + } + + if metric, ok := metrics[node.NodeID]; ok { + switch metric { + // We assume there can only be metric values of either 1(UP) or 0(DOWN). + case 0: + uNode.Status = managementv1.UniversalNode_STATUS_DOWN + case 1: + uNode.Status = managementv1.UniversalNode_STATUS_UP + } + } else { + uNode.Status = managementv1.UniversalNode_STATUS_UNKNOWN + } + + return &managementv1.GetNodeResponse{ + Node: uNode, + }, nil +} diff --git a/managed/services/management/node_mgmt.go b/managed/services/management/node_mgmt.go deleted file mode 100644 index e944610fb95..00000000000 --- a/managed/services/management/node_mgmt.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package management - -import ( - "context" - "fmt" - "time" - - "github.com/AlekSi/pointer" - "github.com/pkg/errors" - "github.com/prometheus/common/model" - "google.golang.org/protobuf/types/known/timestamppb" - "gopkg.in/reform.v1" - - managementv1 "github.com/percona/pmm/api/management/v1" - "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/services" -) - -const upQuery = `up{job=~".*_hr$"}` - -// ListNodes returns a filtered list of Nodes. -func (s *ManagementService) ListNodes(ctx context.Context, req *managementv1.ListNodesRequest) (*managementv1.ListNodesResponse, error) { - filters := models.NodeFilters{ - NodeType: services.ProtoToModelNodeType(req.NodeType), - } - - var ( - nodes []*models.Node - agents []*models.Agent - services []*models.Service - ) - - errTX := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { - var err error - - nodes, err = models.FindNodes(s.db.Querier, filters) - if err != nil { - return err - } - - agents, err = models.FindAgents(s.db.Querier, models.AgentFilters{}) - if err != nil { - return err - } - - services, err = models.FindServices(s.db.Querier, models.ServiceFilters{}) - if err != nil { - return err - } - - return nil - }) - - if errTX != nil { - return nil, errTX - } - - convertAgentToProto := func(agent *models.Agent) *managementv1.UniversalNode_Agent { - return &managementv1.UniversalNode_Agent{ - AgentId: agent.AgentID, - AgentType: string(agent.AgentType), - Status: agent.Status, - IsConnected: s.r.IsConnected(agent.AgentID), - } - } - - aMap := make(map[string][]*managementv1.UniversalNode_Agent, len(nodes)) - for _, a := range agents { - if a.NodeID != nil || a.RunsOnNodeID != nil { - var nodeID string - if a.NodeID != nil { - nodeID = pointer.GetString(a.NodeID) - } else { - nodeID = pointer.GetString(a.RunsOnNodeID) - } - aMap[nodeID] = append(aMap[nodeID], convertAgentToProto(a)) - } - } - - sMap := make(map[string][]*managementv1.UniversalNode_Service, len(services)) - for _, s := range services { - sMap[s.NodeID] = append(sMap[s.NodeID], &managementv1.UniversalNode_Service{ - ServiceId: s.ServiceID, - ServiceType: string(s.ServiceType), - ServiceName: s.ServiceName, - }) - } - - result, _, err := s.vmClient.Query(ctx, upQuery, time.Now()) - if err != nil { - return nil, errors.Wrap(err, "failed to execute an instant VM query") - } - - metrics := make(map[string]int, len(result.(model.Vector))) //nolint:forcetypeassert - for _, v := range result.(model.Vector) { //nolint:forcetypeassert - nodeID := string(v.Metric[model.LabelName("node_id")]) - // Sometimes we may see several metrics for the same node, so we just take the first one. - if _, ok := metrics[nodeID]; !ok { - metrics[nodeID] = int(v.Value) - } - } - - res := make([]*managementv1.UniversalNode, len(nodes)) - for i, node := range nodes { - labels, err := node.GetCustomLabels() - if err != nil { - return nil, err - } - - uNode := &managementv1.UniversalNode{ - Address: node.Address, - CustomLabels: labels, - NodeId: node.NodeID, - NodeName: node.NodeName, - NodeType: string(node.NodeType), - Az: node.AZ, - CreatedAt: timestamppb.New(node.CreatedAt), - ContainerId: pointer.GetString(node.ContainerID), - ContainerName: pointer.GetString(node.ContainerName), - Distro: node.Distro, - MachineId: pointer.GetString(node.MachineID), - NodeModel: node.NodeModel, - Region: pointer.GetString(node.Region), - UpdatedAt: timestamppb.New(node.UpdatedAt), - } - - if metric, ok := metrics[node.NodeID]; ok { - switch metric { - // We assume there can only be metric values of either 1(UP) or 0(DOWN). - case 0: - uNode.Status = managementv1.UniversalNode_STATUS_DOWN - case 1: - uNode.Status = managementv1.UniversalNode_STATUS_UP - } - } else { - uNode.Status = managementv1.UniversalNode_STATUS_UNKNOWN - } - - if uAgents, ok := aMap[node.NodeID]; ok { - uNode.Agents = uAgents - } - - if uServices, ok := sMap[node.NodeID]; ok { - uNode.Services = uServices - } - - res[i] = uNode - } - - return &managementv1.ListNodesResponse{ - Nodes: res, - }, nil -} - -const nodeUpQuery = `up{job=~".*_hr$",node_id=%q}` - -// GetNode returns a single Node by ID. -func (s *ManagementService) GetNode(ctx context.Context, req *managementv1.GetNodeRequest) (*managementv1.GetNodeResponse, error) { - node, err := models.FindNodeByID(s.db.Querier, req.NodeId) - if err != nil { - return nil, err - } - - result, _, err := s.vmClient.Query(ctx, fmt.Sprintf(nodeUpQuery, req.NodeId), time.Now()) - if err != nil { - return nil, errors.Wrap(err, "failed to execute an instant VM query") - } - - metrics := make(map[string]int, len(result.(model.Vector))) //nolint:forcetypeassert - for _, v := range result.(model.Vector) { //nolint:forcetypeassert - nodeID := string(v.Metric[model.LabelName("node_id")]) - // Sometimes we may see several metrics for the same node, so we just take the first one. - if _, ok := metrics[nodeID]; !ok { - metrics[nodeID] = int(v.Value) - } - } - - labels, err := node.GetCustomLabels() - if err != nil { - return nil, err - } - - uNode := &managementv1.UniversalNode{ - Address: node.Address, - Az: node.AZ, - CreatedAt: timestamppb.New(node.CreatedAt), - ContainerId: pointer.GetString(node.ContainerID), - ContainerName: pointer.GetString(node.ContainerName), - CustomLabels: labels, - Distro: node.Distro, - MachineId: pointer.GetString(node.MachineID), - NodeId: node.NodeID, - NodeName: node.NodeName, - NodeType: string(node.NodeType), - NodeModel: node.NodeModel, - Region: pointer.GetString(node.Region), - UpdatedAt: timestamppb.New(node.UpdatedAt), - } - - if metric, ok := metrics[node.NodeID]; ok { - switch metric { - // We assume there can only be metric values of either 1(UP) or 0(DOWN). - case 0: - uNode.Status = managementv1.UniversalNode_STATUS_DOWN - case 1: - uNode.Status = managementv1.UniversalNode_STATUS_UP - } - } else { - uNode.Status = managementv1.UniversalNode_STATUS_UNKNOWN - } - - return &managementv1.GetNodeResponse{ - Node: uNode, - }, nil -} diff --git a/managed/services/management/node_mgmt_test.go b/managed/services/management/node_mgmt_test.go deleted file mode 100644 index 35d32e2042e..00000000000 --- a/managed/services/management/node_mgmt_test.go +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package management - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/google/uuid" - "github.com/prometheus/common/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/timestamppb" - "gopkg.in/reform.v1" - "gopkg.in/reform.v1/dialects/postgresql" - - inventoryv1 "github.com/percona/pmm/api/inventory/v1" - managementv1 "github.com/percona/pmm/api/management/v1" - "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/utils/testdb" - "github.com/percona/pmm/managed/utils/tests" - "github.com/percona/pmm/utils/logger" -) - -func TestMgmtNodeService(t *testing.T) { - t.Run("ListNodes", func(t *testing.T) { - now = models.Now() - - setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { - t.Helper() - - origNowF := models.Now - models.Now = func() time.Time { - return now - } - - ctx := logger.Set(context.Background(), t.Name()) - uuid.SetRand(&tests.IDReader{}) - - sqlDB := testdb.Open(t, models.SetupFixtures, nil) - db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) - - ar := &mockAgentsRegistry{} - ar.Test(t) - - vmdb := &mockPrometheusService{} - vmdb.Test(t) - - state := &mockAgentsStateUpdater{} - state.Test(t) - - cc := &mockConnectionChecker{} - cc.Test(t) - - sib := &mockServiceInfoBroker{} - sib.Test(t) - - vmClient := &mockVictoriaMetricsClient{} - vmClient.Test(t) - - vc := &mockVersionCache{} - vc.Test(t) - - grafanaClient := &mockGrafanaClient{} - grafanaClient.Test(t) - - s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) - - teardown := func(t *testing.T) { - t.Helper() - models.Now = origNowF - uuid.SetRand(nil) - - require.NoError(t, sqlDB.Close()) - ar.AssertExpectations(t) - state.AssertExpectations(t) - cc.AssertExpectations(t) - sib.AssertExpectations(t) - vmdb.AssertExpectations(t) - vc.AssertExpectations(t) - grafanaClient.AssertExpectations(t) - vmClient.AssertExpectations(t) - } - - return ctx, s, teardown - } - - const ( - nodeExporterID = "/agent_id/00000000-0000-4000-8000-000000000001" - postgresqlServiceID = "/service_id/00000000-0000-4000-8000-000000000002" - ) - - t.Run("should output an unfiltered list of all nodes", func(t *testing.T) { - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - metric := model.Vector{ - &model.Sample{ - Metric: model.Metric{ - "__name__": "up", - "node_id": "pmm-server", - }, - Timestamp: 1, - Value: 1, - }, - } - - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() - res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{}) - require.NoError(t, err) - - expected := &managementv1.ListNodesResponse{ - Nodes: []*managementv1.UniversalNode{ - { - NodeId: "pmm-server", - NodeType: "generic", - NodeName: "pmm-server", - MachineId: "", - Distro: "", - NodeModel: "", - ContainerId: "", - ContainerName: "", - Address: "127.0.0.1", - Region: "", - Az: "", - CustomLabels: nil, - CreatedAt: timestamppb.New(now), - UpdatedAt: timestamppb.New(now), - Agents: []*managementv1.UniversalNode_Agent{ - { - AgentId: nodeExporterID, - AgentType: "node_exporter", - Status: "AGENT_STATUS_UNKNOWN", - IsConnected: true, - }, - { - AgentId: models.PMMServerAgentID, - AgentType: "pmm-agent", - Status: "", - IsConnected: true, - }, - }, - Services: []*managementv1.UniversalNode_Service{ - { - ServiceId: postgresqlServiceID, - ServiceType: "postgresql", - ServiceName: "pmm-server-postgresql", - }, - }, - Status: managementv1.UniversalNode_STATUS_UP, - }, - }, - } - - assert.Equal(t, expected, res) - }) - - t.Run("should output an empty list of nodes when filter condition is not satisfied", func(t *testing.T) { - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() - - res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{ - NodeType: inventoryv1.NodeType_NODE_TYPE_REMOTE_NODE, - }) - - require.NoError(t, err) - assert.Empty(t, res.Nodes) - }) - - t.Run("should output a list of nodes when filter condition is satisfied", func(t *testing.T) { - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - metric := model.Vector{ - &model.Sample{ - Metric: model.Metric{ - "__name__": "up", - "node_id": "pmm-server", - }, - Timestamp: 1, - Value: 1, - }, - } - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() - - res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{ - NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, - }) - require.NoError(t, err) - - expected := &managementv1.ListNodesResponse{ - Nodes: []*managementv1.UniversalNode{ - { - NodeId: "pmm-server", - NodeType: "generic", - NodeName: "pmm-server", - MachineId: "", - Distro: "", - NodeModel: "", - ContainerId: "", - ContainerName: "", - Address: "127.0.0.1", - Region: "", - Az: "", - CustomLabels: nil, - CreatedAt: timestamppb.New(now), - UpdatedAt: timestamppb.New(now), - Agents: []*managementv1.UniversalNode_Agent{ - { - AgentId: nodeExporterID, - AgentType: "node_exporter", - Status: "AGENT_STATUS_UNKNOWN", - IsConnected: true, - }, - { - AgentId: models.PMMServerAgentID, - AgentType: "pmm-agent", - Status: "", - IsConnected: true, - }, - }, - Services: []*managementv1.UniversalNode_Service{ - { - ServiceId: postgresqlServiceID, - ServiceType: "postgresql", - ServiceName: "pmm-server-postgresql", - }, - }, - Status: managementv1.UniversalNode_STATUS_UP, - }, - }, - } - - assert.Equal(t, expected, res) - }) - }) - - t.Run("GetNode", func(t *testing.T) { - now := models.Now() - - setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { - t.Helper() - - origNowF := models.Now - models.Now = func() time.Time { - return now - } - ctx := logger.Set(context.Background(), t.Name()) - uuid.SetRand(&tests.IDReader{}) - - sqlDB := testdb.Open(t, models.SetupFixtures, nil) - db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) - - ar := &mockAgentsRegistry{} - ar.Test(t) - - vmdb := &mockPrometheusService{} - vmdb.Test(t) - - state := &mockAgentsStateUpdater{} - state.Test(t) - - cc := &mockConnectionChecker{} - cc.Test(t) - - sib := &mockServiceInfoBroker{} - sib.Test(t) - - vc := &mockVersionCache{} - vc.Test(t) - - grafanaClient := &mockGrafanaClient{} - grafanaClient.Test(t) - - vmClient := &mockVictoriaMetricsClient{} - vmClient.Test(t) - - s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) - - teardown := func(t *testing.T) { - t.Helper() - models.Now = origNowF - uuid.SetRand(nil) - - require.NoError(t, sqlDB.Close()) - - ar.AssertExpectations(t) - state.AssertExpectations(t) - cc.AssertExpectations(t) - sib.AssertExpectations(t) - vmdb.AssertExpectations(t) - vc.AssertExpectations(t) - grafanaClient.AssertExpectations(t) - vmClient.AssertExpectations(t) - } - - return ctx, s, teardown - } - - t.Run("should query the node by its id", func(t *testing.T) { - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - metric := model.Vector{ - &model.Sample{ - Metric: model.Metric{ - "__name__": "up", - "node_id": "pmm-server", - }, - Timestamp: 1, - Value: 1, - }, - } - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Times(1) - - expected := &managementv1.GetNodeResponse{ - Node: &managementv1.UniversalNode{ - NodeId: "pmm-server", - NodeType: "generic", - NodeName: "pmm-server", - MachineId: "", - Distro: "", - NodeModel: "", - ContainerId: "", - ContainerName: "", - Address: "127.0.0.1", - Region: "", - Az: "", - CustomLabels: nil, - CreatedAt: timestamppb.New(now), - UpdatedAt: timestamppb.New(now), - Status: managementv1.UniversalNode_STATUS_UP, - }, - } - - node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ - NodeId: models.PMMServerNodeID, - }) - - require.NoError(t, err) - assert.Equal(t, expected, node) - }) - - t.Run("should return an error if such node_id doesn't exist", func(t *testing.T) { - const nodeID = "00000000-0000-4000-8000-000000000000" - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ - NodeId: nodeID, - }) - - assert.Nil(t, node) - tests.AssertGRPCError(t, status.New(codes.NotFound, fmt.Sprintf("Node with ID %q not found.", nodeID)), err) - }) - - t.Run("should return an error if the node_id parameter is empty", func(t *testing.T) { - ctx, s, teardown := setup(t) - t.Cleanup(func() { teardown(t) }) - - node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ - NodeId: "", - }) - - assert.Nil(t, node) - tests.AssertGRPCError(t, status.New(codes.InvalidArgument, "Empty Node ID."), err) - }) - }) -} diff --git a/managed/services/management/node_test.go b/managed/services/management/node_test.go index 1b61a78cc05..91c68274365 100644 --- a/managed/services/management/node_test.go +++ b/managed/services/management/node_test.go @@ -17,14 +17,19 @@ package management import ( "context" + "fmt" "testing" + "time" "github.com/google/uuid" + "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" @@ -248,4 +253,356 @@ func TestNodeService(t *testing.T) { }) }) }) + + t.Run("ListNodes", func(t *testing.T) { + now = models.Now() + + setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { + t.Helper() + + origNowF := models.Now + models.Now = func() time.Time { + return now + } + + ctx := logger.Set(context.Background(), t.Name()) + uuid.SetRand(&tests.IDReader{}) + + sqlDB := testdb.Open(t, models.SetupFixtures, nil) + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + ar := &mockAgentsRegistry{} + ar.Test(t) + + vmdb := &mockPrometheusService{} + vmdb.Test(t) + + state := &mockAgentsStateUpdater{} + state.Test(t) + + cc := &mockConnectionChecker{} + cc.Test(t) + + sib := &mockServiceInfoBroker{} + sib.Test(t) + + vmClient := &mockVictoriaMetricsClient{} + vmClient.Test(t) + + vc := &mockVersionCache{} + vc.Test(t) + + grafanaClient := &mockGrafanaClient{} + grafanaClient.Test(t) + + s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) + + teardown := func(t *testing.T) { + t.Helper() + models.Now = origNowF + uuid.SetRand(nil) + + require.NoError(t, sqlDB.Close()) + ar.AssertExpectations(t) + state.AssertExpectations(t) + cc.AssertExpectations(t) + sib.AssertExpectations(t) + vmdb.AssertExpectations(t) + vc.AssertExpectations(t) + grafanaClient.AssertExpectations(t) + vmClient.AssertExpectations(t) + } + + return ctx, s, teardown + } + + const ( + nodeExporterID = "/agent_id/00000000-0000-4000-8000-000000000001" + postgresqlServiceID = "/service_id/00000000-0000-4000-8000-000000000002" + ) + + t.Run("should output an unfiltered list of all nodes", func(t *testing.T) { + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + metric := model.Vector{ + &model.Sample{ + Metric: model.Metric{ + "__name__": "up", + "node_id": "pmm-server", + }, + Timestamp: 1, + Value: 1, + }, + } + + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() + res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{}) + require.NoError(t, err) + + expected := &managementv1.ListNodesResponse{ + Nodes: []*managementv1.UniversalNode{ + { + NodeId: "pmm-server", + NodeType: "generic", + NodeName: "pmm-server", + MachineId: "", + Distro: "", + NodeModel: "", + ContainerId: "", + ContainerName: "", + Address: "127.0.0.1", + Region: "", + Az: "", + CustomLabels: nil, + CreatedAt: timestamppb.New(now), + UpdatedAt: timestamppb.New(now), + Agents: []*managementv1.UniversalNode_Agent{ + { + AgentId: nodeExporterID, + AgentType: "node_exporter", + Status: "AGENT_STATUS_UNKNOWN", + IsConnected: true, + }, + { + AgentId: models.PMMServerAgentID, + AgentType: "pmm-agent", + Status: "", + IsConnected: true, + }, + }, + Services: []*managementv1.UniversalNode_Service{ + { + ServiceId: postgresqlServiceID, + ServiceType: "postgresql", + ServiceName: "pmm-server-postgresql", + }, + }, + Status: managementv1.UniversalNode_STATUS_UP, + }, + }, + } + + assert.Equal(t, expected, res) + }) + + t.Run("should output an empty list of nodes when filter condition is not satisfied", func(t *testing.T) { + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() + + res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{ + NodeType: inventoryv1.NodeType_NODE_TYPE_REMOTE_NODE, + }) + + require.NoError(t, err) + assert.Empty(t, res.Nodes) + }) + + t.Run("should output a list of nodes when filter condition is satisfied", func(t *testing.T) { + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + metric := model.Vector{ + &model.Sample{ + Metric: model.Metric{ + "__name__": "up", + "node_id": "pmm-server", + }, + Timestamp: 1, + Value: 1, + }, + } + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", nodeExporterID).Return(true).Once() + + res, err := s.ListNodes(ctx, &managementv1.ListNodesRequest{ + NodeType: inventoryv1.NodeType_NODE_TYPE_GENERIC_NODE, + }) + require.NoError(t, err) + + expected := &managementv1.ListNodesResponse{ + Nodes: []*managementv1.UniversalNode{ + { + NodeId: "pmm-server", + NodeType: "generic", + NodeName: "pmm-server", + MachineId: "", + Distro: "", + NodeModel: "", + ContainerId: "", + ContainerName: "", + Address: "127.0.0.1", + Region: "", + Az: "", + CustomLabels: nil, + CreatedAt: timestamppb.New(now), + UpdatedAt: timestamppb.New(now), + Agents: []*managementv1.UniversalNode_Agent{ + { + AgentId: nodeExporterID, + AgentType: "node_exporter", + Status: "AGENT_STATUS_UNKNOWN", + IsConnected: true, + }, + { + AgentId: models.PMMServerAgentID, + AgentType: "pmm-agent", + Status: "", + IsConnected: true, + }, + }, + Services: []*managementv1.UniversalNode_Service{ + { + ServiceId: postgresqlServiceID, + ServiceType: "postgresql", + ServiceName: "pmm-server-postgresql", + }, + }, + Status: managementv1.UniversalNode_STATUS_UP, + }, + }, + } + + assert.Equal(t, expected, res) + }) + }) + + t.Run("GetNode", func(t *testing.T) { + now := models.Now() + + setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T)) { + t.Helper() + + origNowF := models.Now + models.Now = func() time.Time { + return now + } + ctx := logger.Set(context.Background(), t.Name()) + uuid.SetRand(&tests.IDReader{}) + + sqlDB := testdb.Open(t, models.SetupFixtures, nil) + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + ar := &mockAgentsRegistry{} + ar.Test(t) + + vmdb := &mockPrometheusService{} + vmdb.Test(t) + + state := &mockAgentsStateUpdater{} + state.Test(t) + + cc := &mockConnectionChecker{} + cc.Test(t) + + sib := &mockServiceInfoBroker{} + sib.Test(t) + + vc := &mockVersionCache{} + vc.Test(t) + + grafanaClient := &mockGrafanaClient{} + grafanaClient.Test(t) + + vmClient := &mockVictoriaMetricsClient{} + vmClient.Test(t) + + s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) + + teardown := func(t *testing.T) { + t.Helper() + models.Now = origNowF + uuid.SetRand(nil) + + require.NoError(t, sqlDB.Close()) + + ar.AssertExpectations(t) + state.AssertExpectations(t) + cc.AssertExpectations(t) + sib.AssertExpectations(t) + vmdb.AssertExpectations(t) + vc.AssertExpectations(t) + grafanaClient.AssertExpectations(t) + vmClient.AssertExpectations(t) + } + + return ctx, s, teardown + } + + t.Run("should query the node by its id", func(t *testing.T) { + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + metric := model.Vector{ + &model.Sample{ + Metric: model.Metric{ + "__name__": "up", + "node_id": "pmm-server", + }, + Timestamp: 1, + Value: 1, + }, + } + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(metric, nil, nil).Times(1) + + expected := &managementv1.GetNodeResponse{ + Node: &managementv1.UniversalNode{ + NodeId: "pmm-server", + NodeType: "generic", + NodeName: "pmm-server", + MachineId: "", + Distro: "", + NodeModel: "", + ContainerId: "", + ContainerName: "", + Address: "127.0.0.1", + Region: "", + Az: "", + CustomLabels: nil, + CreatedAt: timestamppb.New(now), + UpdatedAt: timestamppb.New(now), + Status: managementv1.UniversalNode_STATUS_UP, + }, + } + + node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ + NodeId: models.PMMServerNodeID, + }) + + require.NoError(t, err) + assert.Equal(t, expected, node) + }) + + t.Run("should return an error if such node_id doesn't exist", func(t *testing.T) { + const nodeID = "00000000-0000-4000-8000-000000000000" + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ + NodeId: nodeID, + }) + + assert.Nil(t, node) + tests.AssertGRPCError(t, status.New(codes.NotFound, fmt.Sprintf("Node with ID %q not found.", nodeID)), err) + }) + + t.Run("should return an error if the node_id parameter is empty", func(t *testing.T) { + ctx, s, teardown := setup(t) + t.Cleanup(func() { teardown(t) }) + + node, err := s.GetNode(ctx, &managementv1.GetNodeRequest{ + NodeId: "", + }) + + assert.Nil(t, node) + tests.AssertGRPCError(t, status.New(codes.InvalidArgument, "Empty Node ID."), err) + }) + }) } diff --git a/managed/services/management/service.go b/managed/services/management/service.go index 9f7adac1f48..a47f90fecf7 100644 --- a/managed/services/management/service.go +++ b/managed/services/management/service.go @@ -48,6 +48,11 @@ type ManagementService struct { //nolint:revive managementv1.UnimplementedManagementServiceServer } +type statusMetrics struct { + status int + serviceType string +} + // NewManagementService creates a ManagementService instance. func NewManagementService( db *reform.DB, diff --git a/managed/services/management/service_mgmt.go b/managed/services/management/service_mgmt.go deleted file mode 100644 index 302091181a8..00000000000 --- a/managed/services/management/service_mgmt.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package management - -import ( - "gopkg.in/reform.v1" - - managementv1 "github.com/percona/pmm/api/management/v1/service" -) - -// MgmtServiceService is a management service for working with services. -type MgmtServiceService struct { - db *reform.DB - r agentsRegistry - state agentsStateUpdater - vmdb prometheusService - vmClient victoriaMetricsClient - - managementv1.UnimplementedManagementV1Beta1ServiceServer -} - -type statusMetrics struct { - status int - serviceType string -} - -// NewMgmtServiceService creates MgmtServiceService instance. -func NewMgmtServiceService(db *reform.DB, r agentsRegistry, state agentsStateUpdater, vmdb prometheusService, vmClient victoriaMetricsClient) *MgmtServiceService { - return &MgmtServiceService{ - db: db, - r: r, - state: state, - vmdb: vmdb, - vmClient: vmClient, - } -} diff --git a/managed/services/management/service_mgmt_test.go b/managed/services/management/service_mgmt_test.go deleted file mode 100644 index e671f9a0bac..00000000000 --- a/managed/services/management/service_mgmt_test.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (C) 2023 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package management - -import ( - "context" - "testing" - - "github.com/AlekSi/pointer" - "github.com/google/uuid" - "github.com/prometheus/common/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/reform.v1" - "gopkg.in/reform.v1/dialects/postgresql" - - managementv1 "github.com/percona/pmm/api/management/v1" - "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/utils/testdb" - "github.com/percona/pmm/managed/utils/tests" - "github.com/percona/pmm/utils/logger" -) - -func TestMgmtServiceService(t *testing.T) { - t.Run("List", func(t *testing.T) { - setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T), *mockPrometheusService) { //nolint:unparam - t.Helper() - - ctx := logger.Set(context.Background(), t.Name()) - uuid.SetRand(&tests.IDReader{}) - - sqlDB := testdb.Open(t, models.SetupFixtures, nil) - db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) - - vmdb := &mockPrometheusService{} - vmdb.Test(t) - - state := &mockAgentsStateUpdater{} - state.Test(t) - - ar := &mockAgentsRegistry{} - ar.Test(t) - - cc := &mockConnectionChecker{} - cc.Test(t) - - sib := &mockServiceInfoBroker{} - sib.Test(t) - - vmClient := &mockVictoriaMetricsClient{} - vmClient.Test(t) - - vc := &mockVersionCache{} - vc.Test(t) - - grafanaClient := &mockGrafanaClient{} - grafanaClient.Test(t) - - teardown := func(t *testing.T) { - t.Helper() - uuid.SetRand(nil) - - require.NoError(t, sqlDB.Close()) - - ar.AssertExpectations(t) - state.AssertExpectations(t) - cc.AssertExpectations(t) - sib.AssertExpectations(t) - vmdb.AssertExpectations(t) - vc.AssertExpectations(t) - grafanaClient.AssertExpectations(t) - vmClient.AssertExpectations(t) - } - - s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) - - return ctx, s, teardown, vmdb - } - - const ( - pgExporterID = "/agent_id/00000000-0000-4000-8000-000000000003" - pgStatStatementID = "/agent_id/00000000-0000-4000-8000-000000000004" - PMMAgentID = "/agent_id/00000000-0000-4000-8000-000000000007" - ) - - t.Run("Basic", func(t *testing.T) { - ctx, s, teardown, _ := setup(t) - t.Cleanup(func() { teardown(t) }) - - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent - s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter - s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent - response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) - - require.NoError(t, err) - assert.Len(t, response.Services, 1) // PMM Server PostgreSQL service - assert.Len(t, response.Services[0].Agents, 3) - }) - - t.Run("RDS", func(t *testing.T) { - ctx, s, teardown, _ := setup(t) - t.Cleanup(func() { teardown(t) }) - - node, err := models.CreateNode(s.db.Querier, models.RemoteRDSNodeType, &models.CreateNodeParams{ - NodeName: "test", - Address: "test-address", - Region: pointer.ToString("test-region"), - }) - require.NoError(t, err) - - service, err := models.AddNewService(s.db.Querier, models.MySQLServiceType, &models.AddDBMSServiceParams{ - ServiceName: "test-mysql", - NodeID: node.NodeID, - Address: pointer.ToString("127.0.0.1"), - Port: pointer.ToUint16(3306), - }) - require.NoError(t, err) - - pmmAgent, err := models.CreatePMMAgent(s.db.Querier, models.PMMServerNodeID, nil) - require.NoError(t, err) - - mysqldExporter, err := models.CreateAgent(s.db.Querier, models.MySQLdExporterType, &models.CreateAgentParams{ - PMMAgentID: pmmAgent.AgentID, - ServiceID: service.ServiceID, - Password: "password", - Username: "username", - }) - require.NoError(t, err) - - rdsExporter, err := models.CreateAgent(s.db.Querier, models.RDSExporterType, &models.CreateAgentParams{ - PMMAgentID: pmmAgent.AgentID, - ServiceID: service.ServiceID, - }) - require.NoError(t, err) - - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent - s.r.(*mockAgentsRegistry).On("IsConnected", pmmAgent.AgentID).Return(true).Once() // PMM Agent - s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter - s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent - s.r.(*mockAgentsRegistry).On("IsConnected", PMMAgentID).Return(false) // PMM Agent 2 - s.r.(*mockAgentsRegistry).On("IsConnected", mysqldExporter.AgentID).Return(false).Once() // MySQLd exporter - s.r.(*mockAgentsRegistry).On("IsConnected", rdsExporter.AgentID).Return(false).Once() // RDS exporter - - response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) - - require.NoError(t, err) - assert.Len(t, response.Services, 2) // PMM Server PostgreSQL service, MySQL service - assert.Len(t, response.Services[0].Agents, 4) - assert.Len(t, response.Services[1].Agents, 2) - }) - - t.Run("Azure", func(t *testing.T) { - ctx, s, teardown, _ := setup(t) - t.Cleanup(func() { teardown(t) }) - - node, err := models.CreateNode(s.db.Querier, models.RemoteAzureDatabaseNodeType, &models.CreateNodeParams{ - NodeName: "test", - Address: "test-address", - Region: pointer.ToString("test-region"), - }) - require.NoError(t, err) - - service, err := models.AddNewService(s.db.Querier, models.MySQLServiceType, &models.AddDBMSServiceParams{ - ServiceName: "test-mysql", - NodeID: node.NodeID, - Address: pointer.ToString("127.0.0.1"), - Port: pointer.ToUint16(3306), - }) - require.NoError(t, err) - - pmmAgent, err := models.CreatePMMAgent(s.db.Querier, models.PMMServerNodeID, nil) - require.NoError(t, err) - - mysqldExporter, err := models.CreateAgent(s.db.Querier, models.MySQLdExporterType, &models.CreateAgentParams{ - PMMAgentID: pmmAgent.AgentID, - ServiceID: service.ServiceID, - Password: "password", - Username: "username", - }) - require.NoError(t, err) - - azureExporter, err := models.CreateAgent(s.db.Querier, models.AzureDatabaseExporterType, &models.CreateAgentParams{ - PMMAgentID: pmmAgent.AgentID, - ServiceID: service.ServiceID, - }) - require.NoError(t, err) - - s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() - s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent - s.r.(*mockAgentsRegistry).On("IsConnected", pmmAgent.AgentID).Return(true).Once() // PMM Agent - s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter - s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent - s.r.(*mockAgentsRegistry).On("IsConnected", PMMAgentID).Return(false) // PMM Agent 2 - s.r.(*mockAgentsRegistry).On("IsConnected", mysqldExporter.AgentID).Return(false).Once() // MySQLd exporter - s.r.(*mockAgentsRegistry).On("IsConnected", azureExporter.AgentID).Return(false).Once() // Azure exporter - - response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) - - require.NoError(t, err) - assert.Len(t, response.Services, 2) // PMM Server PostgreSQL service, MySQL service - assert.Len(t, response.Services[0].Agents, 4) - assert.Len(t, response.Services[1].Agents, 2) - }) - }) -} diff --git a/managed/services/management/service_test.go b/managed/services/management/service_test.go index 638fdcd8790..1c832065f25 100644 --- a/managed/services/management/service_test.go +++ b/managed/services/management/service_test.go @@ -22,7 +22,9 @@ import ( "github.com/AlekSi/pointer" "github.com/google/uuid" + "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -272,4 +274,187 @@ func TestServiceService(t *testing.T) { tests.AssertGRPCError(t, status.New(codes.NotFound, fmt.Sprintf(`Node with ID "%s" not found.`, node.NodeID)), err) }) }) + + t.Run("List", func(t *testing.T) { + setup := func(t *testing.T) (context.Context, *ManagementService, func(t *testing.T), *mockPrometheusService) { //nolint:unparam + t.Helper() + + ctx := logger.Set(context.Background(), t.Name()) + uuid.SetRand(&tests.IDReader{}) + + sqlDB := testdb.Open(t, models.SetupFixtures, nil) + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + vmdb := &mockPrometheusService{} + vmdb.Test(t) + + state := &mockAgentsStateUpdater{} + state.Test(t) + + ar := &mockAgentsRegistry{} + ar.Test(t) + + cc := &mockConnectionChecker{} + cc.Test(t) + + sib := &mockServiceInfoBroker{} + sib.Test(t) + + vmClient := &mockVictoriaMetricsClient{} + vmClient.Test(t) + + vc := &mockVersionCache{} + vc.Test(t) + + grafanaClient := &mockGrafanaClient{} + grafanaClient.Test(t) + + teardown := func(t *testing.T) { + t.Helper() + uuid.SetRand(nil) + + require.NoError(t, sqlDB.Close()) + + ar.AssertExpectations(t) + state.AssertExpectations(t) + cc.AssertExpectations(t) + sib.AssertExpectations(t) + vmdb.AssertExpectations(t) + vc.AssertExpectations(t) + grafanaClient.AssertExpectations(t) + vmClient.AssertExpectations(t) + } + + s := NewManagementService(db, ar, state, cc, sib, vmdb, vc, grafanaClient, vmClient) + + return ctx, s, teardown, vmdb + } + + const ( + pgExporterID = "/agent_id/00000000-0000-4000-8000-000000000003" + pgStatStatementID = "/agent_id/00000000-0000-4000-8000-000000000004" + PMMAgentID = "/agent_id/00000000-0000-4000-8000-000000000007" + ) + + t.Run("Basic", func(t *testing.T) { + ctx, s, teardown, _ := setup(t) + t.Cleanup(func() { teardown(t) }) + + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent + s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter + s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent + response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) + + require.NoError(t, err) + assert.Len(t, response.Services, 1) // PMM Server PostgreSQL service + assert.Len(t, response.Services[0].Agents, 3) + }) + + t.Run("RDS", func(t *testing.T) { + ctx, s, teardown, _ := setup(t) + t.Cleanup(func() { teardown(t) }) + + node, err := models.CreateNode(s.db.Querier, models.RemoteRDSNodeType, &models.CreateNodeParams{ + NodeName: "test", + Address: "test-address", + Region: pointer.ToString("test-region"), + }) + require.NoError(t, err) + + service, err := models.AddNewService(s.db.Querier, models.MySQLServiceType, &models.AddDBMSServiceParams{ + ServiceName: "test-mysql", + NodeID: node.NodeID, + Address: pointer.ToString("127.0.0.1"), + Port: pointer.ToUint16(3306), + }) + require.NoError(t, err) + + pmmAgent, err := models.CreatePMMAgent(s.db.Querier, models.PMMServerNodeID, nil) + require.NoError(t, err) + + mysqldExporter, err := models.CreateAgent(s.db.Querier, models.MySQLdExporterType, &models.CreateAgentParams{ + PMMAgentID: pmmAgent.AgentID, + ServiceID: service.ServiceID, + Password: "password", + Username: "username", + }) + require.NoError(t, err) + + rdsExporter, err := models.CreateAgent(s.db.Querier, models.RDSExporterType, &models.CreateAgentParams{ + PMMAgentID: pmmAgent.AgentID, + ServiceID: service.ServiceID, + }) + require.NoError(t, err) + + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent + s.r.(*mockAgentsRegistry).On("IsConnected", pmmAgent.AgentID).Return(true).Once() // PMM Agent + s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter + s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent + s.r.(*mockAgentsRegistry).On("IsConnected", PMMAgentID).Return(false) // PMM Agent 2 + s.r.(*mockAgentsRegistry).On("IsConnected", mysqldExporter.AgentID).Return(false).Once() // MySQLd exporter + s.r.(*mockAgentsRegistry).On("IsConnected", rdsExporter.AgentID).Return(false).Once() // RDS exporter + + response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) + + require.NoError(t, err) + assert.Len(t, response.Services, 2) // PMM Server PostgreSQL service, MySQL service + assert.Len(t, response.Services[0].Agents, 4) + assert.Len(t, response.Services[1].Agents, 2) + }) + + t.Run("Azure", func(t *testing.T) { + ctx, s, teardown, _ := setup(t) + t.Cleanup(func() { teardown(t) }) + + node, err := models.CreateNode(s.db.Querier, models.RemoteAzureDatabaseNodeType, &models.CreateNodeParams{ + NodeName: "test", + Address: "test-address", + Region: pointer.ToString("test-region"), + }) + require.NoError(t, err) + + service, err := models.AddNewService(s.db.Querier, models.MySQLServiceType, &models.AddDBMSServiceParams{ + ServiceName: "test-mysql", + NodeID: node.NodeID, + Address: pointer.ToString("127.0.0.1"), + Port: pointer.ToUint16(3306), + }) + require.NoError(t, err) + + pmmAgent, err := models.CreatePMMAgent(s.db.Querier, models.PMMServerNodeID, nil) + require.NoError(t, err) + + mysqldExporter, err := models.CreateAgent(s.db.Querier, models.MySQLdExporterType, &models.CreateAgentParams{ + PMMAgentID: pmmAgent.AgentID, + ServiceID: service.ServiceID, + Password: "password", + Username: "username", + }) + require.NoError(t, err) + + azureExporter, err := models.CreateAgent(s.db.Querier, models.AzureDatabaseExporterType, &models.CreateAgentParams{ + PMMAgentID: pmmAgent.AgentID, + ServiceID: service.ServiceID, + }) + require.NoError(t, err) + + s.vmClient.(*mockVictoriaMetricsClient).On("Query", ctx, mock.Anything, mock.Anything).Return(model.Vector{}, nil, nil).Once() + s.r.(*mockAgentsRegistry).On("IsConnected", models.PMMServerAgentID).Return(true).Once() // PMM Server Agent + s.r.(*mockAgentsRegistry).On("IsConnected", pmmAgent.AgentID).Return(true).Once() // PMM Agent + s.r.(*mockAgentsRegistry).On("IsConnected", pgExporterID).Return(false).Once() // PMM Server PostgreSQL exporter + s.r.(*mockAgentsRegistry).On("IsConnected", pgStatStatementID).Return(false).Once() // PMM Server PG Stat Statements agent + s.r.(*mockAgentsRegistry).On("IsConnected", PMMAgentID).Return(false) // PMM Agent 2 + s.r.(*mockAgentsRegistry).On("IsConnected", mysqldExporter.AgentID).Return(false).Once() // MySQLd exporter + s.r.(*mockAgentsRegistry).On("IsConnected", azureExporter.AgentID).Return(false).Once() // Azure exporter + + response, err := s.ListServices(ctx, &managementv1.ListServicesRequest{}) + + require.NoError(t, err) + assert.Len(t, response.Services, 2) // PMM Server PostgreSQL service, MySQL service + assert.Len(t, response.Services[0].Agents, 4) + assert.Len(t, response.Services[1].Agents, 2) + }) + }) }