Alerting: Empty endpoints to manage alertmanager configurations (#106546)
This commit is contained in:
@@ -580,6 +580,12 @@
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/Config"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -1408,6 +1414,20 @@
|
||||
"title": "Frames is a slice of Frame pointers.",
|
||||
"type": "array"
|
||||
},
|
||||
"GettableAlertmanagerUserConfig": {
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"GettableAlertmanagers": {
|
||||
"properties": {
|
||||
"data": {
|
||||
@@ -2038,7 +2058,11 @@
|
||||
"description": "InhibitRule defines an inhibition rule that mutes alerts that match the\ntarget labels if an alert matching the source labels exists.\nBoth alerts have to have a set of labels being equal.",
|
||||
"properties": {
|
||||
"equal": {
|
||||
"$ref": "#/definitions/LabelNames"
|
||||
"description": "A set of labels that must be equal between the source and target alert\nfor them to be a match.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"source_match": {
|
||||
"additionalProperties": {
|
||||
@@ -2162,17 +2186,6 @@
|
||||
"title": "Label is a key/value pair of strings.",
|
||||
"type": "object"
|
||||
},
|
||||
"LabelName": {
|
||||
"description": "A LabelName is a key for a LabelSet or Metric. It has a value associated\ntherewith.",
|
||||
"type": "string"
|
||||
},
|
||||
"LabelNames": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LabelName"
|
||||
},
|
||||
"title": "LabelNames is a sortable LabelName slice. In implements sort.Interface.",
|
||||
"type": "array"
|
||||
},
|
||||
"LabelSet": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/LabelValue"
|
||||
@@ -3674,6 +3687,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Route": {
|
||||
"description": "A Route is a node that contains definitions of how to handle alerts. This is modified\nfrom the upstream alertmanager in that it adds the ObjectMatchers property.",
|
||||
"properties": {
|
||||
"active_time_intervals": {
|
||||
"items": {
|
||||
@@ -3715,6 +3729,12 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3728,7 +3748,6 @@
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "A Route is a node that contains definitions of how to handle alerts.",
|
||||
"type": "object"
|
||||
},
|
||||
"RouteExport": {
|
||||
|
||||
@@ -3,6 +3,7 @@ package definitions
|
||||
import (
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Route for mimirtool
|
||||
@@ -204,7 +205,10 @@ import (
|
||||
// Route for `mimirtool alertmanager load`
|
||||
// swagger:route POST /convert/api/v1/alerts convert_prometheus RouteConvertPrometheusPostAlertmanagerConfig
|
||||
//
|
||||
// Load Alertmanager configuration to Grafana and merge it with the existing configuration.
|
||||
// Load extra Alertmanager configuration to Grafana and merge it with the existing configuration.
|
||||
// This endpoint allows importing Alertmanager configurations to Grafana. Each configuration is identified by
|
||||
// a unique identifier and can include merge matchers to select which alerts should be handled by
|
||||
// this specific configuration.
|
||||
//
|
||||
// Produces:
|
||||
// - application/json
|
||||
@@ -216,6 +220,32 @@ import (
|
||||
// Extensions:
|
||||
// x-raw-request: true
|
||||
|
||||
// Route for `mimirtool alertmanager get`
|
||||
// swagger:route GET /convert/api/v1/alerts convert_prometheus RouteConvertPrometheusGetAlertmanagerConfig
|
||||
//
|
||||
// Get extra Alertmanager configuration from Grafana.
|
||||
// Returns a specific imported Alertmanager configuration by its identifier.
|
||||
//
|
||||
// Produces:
|
||||
// - application/yaml
|
||||
//
|
||||
// Responses:
|
||||
// 200: GettableAlertmanagerUserConfig
|
||||
// 403: ForbiddenError
|
||||
|
||||
// Route for `mimirtool alertmanager delete`
|
||||
// swagger:route DELETE /convert/api/v1/alerts convert_prometheus RouteConvertPrometheusDeleteAlertmanagerConfig
|
||||
//
|
||||
// Delete extra Alertmanager configuration from Grafana by its identifier.
|
||||
// The main Grafana Alertmanager configuration remains unaffected.
|
||||
//
|
||||
// Produces:
|
||||
// - application/json
|
||||
//
|
||||
// Responses:
|
||||
// 202: ConvertPrometheusResponse
|
||||
// 403: ForbiddenError
|
||||
|
||||
// swagger:parameters RouteConvertPrometheusPostRuleGroup RouteConvertPrometheusCortexPostRuleGroup
|
||||
type RouteConvertPrometheusPostRuleGroupParams struct {
|
||||
// in: path
|
||||
@@ -286,11 +316,64 @@ type ConvertPrometheusResponse struct {
|
||||
|
||||
// swagger:parameters RouteConvertPrometheusPostAlertmanagerConfig
|
||||
type RouteConvertPrometheusPostAlertmanagerConfigParams struct {
|
||||
// Unique identifier for this Alertmanager configuration.
|
||||
// This identifier is used to distinguish between different imported configurations.
|
||||
// in: header
|
||||
Identifier string `json:"x-grafana-alerting-config-identifier"`
|
||||
// Comma-separated list of label matchers in 'key=value' format.
|
||||
// These matchers determine which alerts this configuration should handle.
|
||||
// For example: 'environment=production,team=backend' will only apply this
|
||||
// configuration to alerts matching both environment=production AND team=backend.
|
||||
// in: header
|
||||
MergeMatchers string `json:"x-grafana-alerting-merge-matchers"`
|
||||
// Alertmanager configuration including routing rules, receivers, and template files
|
||||
// in:body
|
||||
Body AlertmanagerUserConfig
|
||||
}
|
||||
|
||||
// swagger:parameters RouteConvertPrometheusGetAlertmanagerConfig
|
||||
type RouteConvertPrometheusGetAlertmanagerConfigParams struct {
|
||||
// Unique identifier for the Alertmanager configuration to retrieve.
|
||||
// in: header
|
||||
Identifier string `json:"x-grafana-alerting-config-identifier"`
|
||||
}
|
||||
|
||||
// swagger:parameters RouteConvertPrometheusDeleteAlertmanagerConfig
|
||||
type RouteConvertPrometheusDeleteAlertmanagerConfigParams struct {
|
||||
// Unique identifier for the Alertmanager configuration to delete.
|
||||
// in: header
|
||||
Identifier string `json:"x-grafana-alerting-config-identifier"`
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type AlertmanagerUserConfig struct {
|
||||
AlertmanagerConfig config.Config `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
AlertmanagerConfig config.Config `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
}
|
||||
|
||||
func (c *AlertmanagerUserConfig) UnmarshalYAML(value *yaml.Node) error {
|
||||
// mimirtool sends alertmanager_config as a string
|
||||
type cortexAlertmanagerUserConfig struct {
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
}
|
||||
|
||||
var tmp cortexAlertmanagerUserConfig
|
||||
|
||||
if err := value.Decode(&tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal([]byte(tmp.AlertmanagerConfig), &c.AlertmanagerConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
c.TemplateFiles = tmp.TemplateFiles
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type GettableAlertmanagerUserConfig struct {
|
||||
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
}
|
||||
|
||||
@@ -580,6 +580,12 @@
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/Config"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -1408,6 +1414,20 @@
|
||||
"title": "Frames is a slice of Frame pointers.",
|
||||
"type": "array"
|
||||
},
|
||||
"GettableAlertmanagerUserConfig": {
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"GettableAlertmanagers": {
|
||||
"properties": {
|
||||
"data": {
|
||||
@@ -2038,7 +2058,11 @@
|
||||
"description": "InhibitRule defines an inhibition rule that mutes alerts that match the\ntarget labels if an alert matching the source labels exists.\nBoth alerts have to have a set of labels being equal.",
|
||||
"properties": {
|
||||
"equal": {
|
||||
"$ref": "#/definitions/LabelNames"
|
||||
"description": "A set of labels that must be equal between the source and target alert\nfor them to be a match.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"source_match": {
|
||||
"additionalProperties": {
|
||||
@@ -2162,17 +2186,6 @@
|
||||
"title": "Label is a key/value pair of strings.",
|
||||
"type": "object"
|
||||
},
|
||||
"LabelName": {
|
||||
"description": "A LabelName is a key for a LabelSet or Metric. It has a value associated\ntherewith.",
|
||||
"type": "string"
|
||||
},
|
||||
"LabelNames": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/LabelName"
|
||||
},
|
||||
"title": "LabelNames is a sortable LabelName slice. In implements sort.Interface.",
|
||||
"type": "array"
|
||||
},
|
||||
"LabelSet": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/LabelValue"
|
||||
@@ -3674,6 +3687,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Route": {
|
||||
"description": "A Route is a node that contains definitions of how to handle alerts. This is modified\nfrom the upstream alertmanager in that it adds the ObjectMatchers property.",
|
||||
"properties": {
|
||||
"active_time_intervals": {
|
||||
"items": {
|
||||
@@ -3715,6 +3729,12 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3728,7 +3748,6 @@
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "A Route is a node that contains definitions of how to handle alerts.",
|
||||
"type": "object"
|
||||
},
|
||||
"RouteExport": {
|
||||
@@ -6823,10 +6842,91 @@
|
||||
}
|
||||
},
|
||||
"/convert/api/v1/alerts": {
|
||||
"delete": {
|
||||
"description": "The main Grafana Alertmanager configuration remains unaffected.",
|
||||
"operationId": "RouteConvertPrometheusDeleteAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Unique identifier for the Alertmanager configuration to delete.",
|
||||
"in": "header",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "ConvertPrometheusResponse",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ConvertPrometheusResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Delete extra Alertmanager configuration from Grafana by its identifier.",
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"description": "Returns a specific imported Alertmanager configuration by its identifier.",
|
||||
"operationId": "RouteConvertPrometheusGetAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Unique identifier for the Alertmanager configuration to retrieve.",
|
||||
"in": "header",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/yaml"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "GettableAlertmanagerUserConfig",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GettableAlertmanagerUserConfig"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Get extra Alertmanager configuration from Grafana.",
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"description": "This endpoint allows importing Alertmanager configurations to Grafana. Each configuration is identified by\na unique identifier and can include merge matchers to select which alerts should be handled by\nthis specific configuration.",
|
||||
"operationId": "RouteConvertPrometheusPostAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Unique identifier for this Alertmanager configuration.\nThis identifier is used to distinguish between different imported configurations.",
|
||||
"in": "header",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Comma-separated list of label matchers in 'key=value' format.\nThese matchers determine which alerts this configuration should handle.",
|
||||
"example": "'environment=production,team=backend' will only apply this",
|
||||
"in": "header",
|
||||
"name": "x-grafana-alerting-merge-matchers",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Alertmanager configuration including routing rules, receivers, and template files",
|
||||
"in": "body",
|
||||
"name": "Body",
|
||||
"schema": {
|
||||
@@ -6851,7 +6951,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Load Alertmanager configuration to Grafana and merge it with the existing configuration.",
|
||||
"summary": "Load extra Alertmanager configuration to Grafana and merge it with the existing configuration.",
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
],
|
||||
|
||||
@@ -1361,17 +1361,65 @@
|
||||
}
|
||||
},
|
||||
"/convert/api/v1/alerts": {
|
||||
"get": {
|
||||
"description": "Returns a specific imported Alertmanager configuration by its identifier.",
|
||||
"produces": [
|
||||
"application/yaml"
|
||||
],
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
],
|
||||
"summary": "Get extra Alertmanager configuration from Grafana.",
|
||||
"operationId": "RouteConvertPrometheusGetAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the Alertmanager configuration to retrieve.",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"in": "header"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "GettableAlertmanagerUserConfig",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GettableAlertmanagerUserConfig"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "This endpoint allows importing Alertmanager configurations to Grafana. Each configuration is identified by\na unique identifier and can include merge matchers to select which alerts should be handled by\nthis specific configuration.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
],
|
||||
"summary": "Load Alertmanager configuration to Grafana and merge it with the existing configuration.",
|
||||
"summary": "Load extra Alertmanager configuration to Grafana and merge it with the existing configuration.",
|
||||
"operationId": "RouteConvertPrometheusPostAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Unique identifier for this Alertmanager configuration.\nThis identifier is used to distinguish between different imported configurations.",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"example": "'environment=production,team=backend' will only apply this",
|
||||
"description": "Comma-separated list of label matchers in 'key=value' format.\nThese matchers determine which alerts this configuration should handle.",
|
||||
"name": "x-grafana-alerting-merge-matchers",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"description": "Alertmanager configuration including routing rules, receivers, and template files",
|
||||
"name": "Body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
@@ -1394,6 +1442,39 @@
|
||||
}
|
||||
},
|
||||
"x-raw-request": "true"
|
||||
},
|
||||
"delete": {
|
||||
"description": "The main Grafana Alertmanager configuration remains unaffected.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"convert_prometheus"
|
||||
],
|
||||
"summary": "Delete extra Alertmanager configuration from Grafana by its identifier.",
|
||||
"operationId": "RouteConvertPrometheusDeleteAlertmanagerConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the Alertmanager configuration to delete.",
|
||||
"name": "x-grafana-alerting-config-identifier",
|
||||
"in": "header"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "ConvertPrometheusResponse",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ConvertPrometheusResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/convert/prometheus/config/v1/rules": {
|
||||
@@ -4788,6 +4869,12 @@
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/Config"
|
||||
},
|
||||
"template_files": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5616,6 +5703,20 @@
|
||||
"$ref": "#/definitions/Frame"
|
||||
}
|
||||
},
|
||||
"GettableAlertmanagerUserConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_files": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"GettableAlertmanagers": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6247,7 +6348,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"equal": {
|
||||
"$ref": "#/definitions/LabelNames"
|
||||
"description": "A set of labels that must be equal between the source and target alert\nfor them to be a match.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"source_match": {
|
||||
"description": "SourceMatch defines a set of labels that have to equal the given\nvalue for source alerts. Deprecated. Remove before v1.0 release.",
|
||||
@@ -6370,17 +6475,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"LabelName": {
|
||||
"description": "A LabelName is a key for a LabelSet or Metric. It has a value associated\ntherewith.",
|
||||
"type": "string"
|
||||
},
|
||||
"LabelNames": {
|
||||
"type": "array",
|
||||
"title": "LabelNames is a sortable LabelName slice. In implements sort.Interface.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LabelName"
|
||||
}
|
||||
},
|
||||
"LabelSet": {
|
||||
"description": "A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet\nmay be fully-qualified down to the point where it may resolve to a single\nMetric in the data store or not. All operations that occur within the realm\nof a LabelSet can emit a vector of Metric entities to which the LabelSet may\nmatch.",
|
||||
"type": "object",
|
||||
@@ -7883,8 +7977,8 @@
|
||||
}
|
||||
},
|
||||
"Route": {
|
||||
"description": "A Route is a node that contains definitions of how to handle alerts. This is modified\nfrom the upstream alertmanager in that it adds the ObjectMatchers property.",
|
||||
"type": "object",
|
||||
"title": "A Route is a node that contains definitions of how to handle alerts.",
|
||||
"properties": {
|
||||
"active_time_intervals": {
|
||||
"type": "array",
|
||||
@@ -7926,6 +8020,12 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user