@ -1258,7 +1258,7 @@ func TestAlertRuleCRUD(t *testing.T) {
// update the first rule and completely remove the other
{
interval , err := model . ParseDuration ( "30s" )
forValue , err := model . ParseDuration ( "30s" )
require . NoError ( t , err )
rules := apimodels . PostableRuleGroupConfig {
@ -1266,14 +1266,16 @@ func TestAlertRuleCRUD(t *testing.T) {
Rules : [ ] apimodels . PostableExtendedRuleNode {
{
ApiRuleNode : & apimodels . ApiRuleNode {
For : interval ,
For : forValue ,
Labels : map [ string ] string {
"label1" : "val42" ,
"foo" : "bar" ,
// delete foo label
"label1" : "val1" , // update label value
"label2" : "val2" , // new label
} ,
Annotations : map [ string ] string {
"annotation1" : "val42" ,
"foo" : "bar" ,
// delete foo annotation
"annotation1" : "val1" , // update annotation value
"annotation2" : "val2" , // new annotation
} ,
} ,
GrafanaManagedAlert : & apimodels . PostableGrafanaRule {
@ -1299,6 +1301,7 @@ func TestAlertRuleCRUD(t *testing.T) {
} ,
} ,
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
@ -1347,14 +1350,14 @@ func TestAlertRuleCRUD(t *testing.T) {
"rules" : [
{
"annotations" : {
"annotation1" : "val42 " ,
"foo" : "bar "
"annotation1" : "val1 " ,
"annotation2" : "val2 "
} ,
"expr" : "" ,
"for" : "30s" ,
"labels" : {
"foo" : "bar " ,
"label1 " : "val4 2"
"label1" : "val1 " ,
"label2 " : "val2"
} ,
"grafana_alert" : {
"id" : 1 ,
@ -1395,6 +1398,229 @@ func TestAlertRuleCRUD(t *testing.T) {
} ` , body )
}
// update the rule; delete labels and annotations
{
forValue , err := model . ParseDuration ( "30s" )
require . NoError ( t , err )
rules := apimodels . PostableRuleGroupConfig {
Name : "arulegroup" ,
Rules : [ ] apimodels . PostableExtendedRuleNode {
{
ApiRuleNode : & apimodels . ApiRuleNode {
For : forValue ,
} ,
GrafanaManagedAlert : & apimodels . PostableGrafanaRule {
UID : ruleUID , // Including the UID in the payload makes the endpoint update the existing rule.
Title : "AlwaysNormal" ,
Condition : "A" ,
Data : [ ] ngmodels . AlertQuery {
{
RefID : "A" ,
RelativeTimeRange : ngmodels . RelativeTimeRange {
From : ngmodels . Duration ( time . Duration ( 5 ) * time . Hour ) ,
To : ngmodels . Duration ( time . Duration ( 3 ) * time . Hour ) ,
} ,
DatasourceUID : "-100" ,
Model : json . RawMessage ( ` {
"type" : "math" ,
"expression" : "2 + 3 < 1"
} ` ) ,
} ,
} ,
NoDataState : apimodels . NoDataState ( ngmodels . Alerting ) ,
ExecErrState : apimodels . ExecutionErrorState ( ngmodels . AlertingErrState ) ,
} ,
} ,
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
body , m := rulesNamespaceWithoutVariableValues ( t , b )
returnedUIDs , ok := m [ "default,arulegroup" ]
assert . True ( t , ok )
assert . Equal ( t , 1 , len ( returnedUIDs ) )
assert . Equal ( t , ruleUID , returnedUIDs [ 0 ] )
assert . JSONEq ( t , `
{
"default" : [
{
"name" : "arulegroup" ,
"interval" : "1m" ,
"rules" : [
{
"expr" : "" ,
"for" : "30s" ,
"grafana_alert" : {
"id" : 1 ,
"orgId" : 1 ,
"title" : "AlwaysNormal" ,
"condition" : "A" ,
"data" : [
{
"refId" : "A" ,
"queryType" : "" ,
"relativeTimeRange" : {
"from" : 18000 ,
"to" : 10800
} ,
"datasourceUid" : "-100" ,
"model" : {
"expression" : "2 + 3 \u003C 1" ,
"intervalMs" : 1000 ,
"maxDataPoints" : 43200 ,
"type" : "math"
}
}
] ,
"updated" : "2021-02-21T01:10:30Z" ,
"intervalSeconds" : 60 ,
"version" : 3 ,
"uid" : "uid" ,
"namespace_uid" : "nsuid" ,
"namespace_id" : 1 ,
"rule_group" : "arulegroup" ,
"no_data_state" : "Alerting" ,
"exec_err_state" : "Alerting"
}
}
]
}
]
} ` , body )
}
// update the rule; keep title, condition, no data state, error state, queries and expressions if not provided
{
rules := apimodels . PostableRuleGroupConfig {
Name : "arulegroup" ,
Rules : [ ] apimodels . PostableExtendedRuleNode {
{
GrafanaManagedAlert : & apimodels . PostableGrafanaRule {
UID : ruleUID , // Including the UID in the payload makes the endpoint update the existing rule.
} ,
} ,
} ,
Interval : interval ,
}
buf := bytes . Buffer { }
enc := json . NewEncoder ( & buf )
err = enc . Encode ( & rules )
require . NoError ( t , err )
u := fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err := http . Post ( u , "application/json" , & buf )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
require . JSONEq ( t , ` { "message":"rule group updated successfully"} ` , string ( b ) )
// let's make sure that rule definitions are updated correctly.
u = fmt . Sprintf ( "http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default" , grafanaListedAddr )
// nolint:gosec
resp , err = http . Get ( u )
require . NoError ( t , err )
t . Cleanup ( func ( ) {
err := resp . Body . Close ( )
require . NoError ( t , err )
} )
b , err = ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
assert . Equal ( t , resp . StatusCode , 202 )
body , m := rulesNamespaceWithoutVariableValues ( t , b )
returnedUIDs , ok := m [ "default,arulegroup" ]
assert . True ( t , ok )
assert . Equal ( t , 1 , len ( returnedUIDs ) )
assert . Equal ( t , ruleUID , returnedUIDs [ 0 ] )
assert . JSONEq ( t , `
{
"default" : [
{
"name" : "arulegroup" ,
"interval" : "1m" ,
"rules" : [
{
"expr" : "" ,
"grafana_alert" : {
"id" : 1 ,
"orgId" : 1 ,
"title" : "AlwaysNormal" ,
"condition" : "A" ,
"data" : [
{
"refId" : "A" ,
"queryType" : "" ,
"relativeTimeRange" : {
"from" : 18000 ,
"to" : 10800
} ,
"datasourceUid" : "-100" ,
"model" : {
"expression" : "2 + 3 \u003C 1" ,
"intervalMs" : 1000 ,
"maxDataPoints" : 43200 ,
"type" : "math"
}
}
] ,
"updated" : "2021-02-21T01:10:30Z" ,
"intervalSeconds" : 60 ,
"version" : 4 ,
"uid" : "uid" ,
"namespace_uid" : "nsuid" ,
"namespace_id" : 1 ,
"rule_group" : "arulegroup" ,
"no_data_state" : "Alerting" ,
"exec_err_state" : "Alerting"
}
}
]
}
]
} ` , body )
}
client := & http . Client { }
// Finally, make sure we can delete it.
{