2017-12-11 13:46:59 +00:00
package cli
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"time"
2017-12-22 10:17:13 +00:00
"github.com/alecthomas/kingpin"
2017-12-11 13:46:59 +00:00
"github.com/prometheus/alertmanager/cli/format"
"github.com/prometheus/alertmanager/types"
)
type getResponse struct {
Status string ` json:"status" `
Data types . Silence ` json:"data,omitempty" `
ErrorType string ` json:"errorType,omitempty" `
Error string ` json:"error,omitempty" `
}
2017-12-22 10:17:13 +00:00
var (
updateCmd = silenceCmd . Command ( "update" , "Update silences" )
updateExpires = updateCmd . Flag ( "expires" , "Duration of silence" ) . Short ( 'e' ) . Duration ( )
updateExpiresOn = updateCmd . Flag ( "expire-on" , "Expire at a certain time (Overwrites expires) RFC3339 format 2006-01-02T15:04:05Z07:00" ) . Time ( time . RFC3339 )
updateComment = updateCmd . Flag ( "comment" , "A comment to help describe the silence" ) . Short ( 'c' ) . String ( )
updateIds = updateCmd . Arg ( "update-ids" , "Silence IDs to update" ) . Strings ( )
)
2017-12-11 13:46:59 +00:00
func init ( ) {
2017-12-22 10:17:13 +00:00
updateCmd . Action ( update )
longHelpText [ "silence update" ] = ` Extend or update existing silence in Alertmanager. `
2017-12-11 13:46:59 +00:00
}
2017-12-22 10:17:13 +00:00
func update ( element * kingpin . ParseElement , ctx * kingpin . ParseContext ) error {
if len ( * updateIds ) < 1 {
2017-12-11 13:46:59 +00:00
return fmt . Errorf ( "no silence IDs specified" )
}
2017-12-22 10:17:13 +00:00
alertmanagerUrl := GetAlertmanagerURL ( "/api/v1/silence" )
2017-12-11 13:46:59 +00:00
var updatedSilences [ ] types . Silence
2017-12-22 10:17:13 +00:00
for _ , silenceId := range * updateIds {
silence , err := getSilenceById ( silenceId , alertmanagerUrl )
2017-12-11 13:46:59 +00:00
if err != nil {
return err
}
silence , err = updateSilence ( silence )
if err != nil {
return err
}
updatedSilences = append ( updatedSilences , * silence )
}
2017-12-22 10:17:13 +00:00
if * silenceQuiet {
2017-12-11 13:46:59 +00:00
for _ , silence := range updatedSilences {
fmt . Println ( silence . ID )
}
} else {
2017-12-22 10:17:13 +00:00
formatter , found := format . Formatters [ * output ]
2017-12-11 13:46:59 +00:00
if ! found {
return fmt . Errorf ( "unknown output formatter" )
}
formatter . FormatSilences ( updatedSilences )
}
return nil
}
// This takes an url.URL and not a pointer as we will modify it for our API call.
func getSilenceById ( silenceId string , baseUrl url . URL ) ( * types . Silence , error ) {
2017-12-22 10:17:13 +00:00
baseUrl . Path = path . Join ( baseUrl . Path , silenceId )
2017-12-11 13:46:59 +00:00
res , err := http . Get ( baseUrl . String ( ) )
if err != nil {
return nil , err
}
defer res . Body . Close ( )
body , err := ioutil . ReadAll ( res . Body )
if err != nil {
return nil , fmt . Errorf ( "couldn't read response body: %v" , err )
}
if res . StatusCode == 404 {
return nil , fmt . Errorf ( "no silence found with id: %v" , silenceId )
}
if res . StatusCode != 200 {
return nil , fmt . Errorf ( "received %d response from Alertmanager: %v" , res . StatusCode , body )
}
var response getResponse
err = json . Unmarshal ( body , & response )
return & response . Data , nil
}
func updateSilence ( silence * types . Silence ) ( * types . Silence , error ) {
2017-12-22 10:17:13 +00:00
if * updateExpires != 0 {
silence . EndsAt = time . Now ( ) . UTC ( ) . Add ( * updateExpires )
2017-12-11 13:46:59 +00:00
}
// expire-on will override expires value if both are specified
2017-12-22 10:17:13 +00:00
if ! ( * updateExpiresOn ) . IsZero ( ) {
silence . EndsAt = * updateExpiresOn
2017-12-11 13:46:59 +00:00
}
2018-01-10 16:05:03 +00:00
if * updateComment != "" {
silence . Comment = * updateComment
2017-12-11 13:46:59 +00:00
}
// addSilence can also be used to update an existing silence
_ , err := addSilence ( silence )
if err != nil {
return nil , err
}
return silence , nil
}