|
package server
import (
"encoding/json"
"errors"
"net/http"
"github.com/RedHatInsights/insights-operator-utils/generators"
utypes "github.com/RedHatInsights/insights-operator-utils/types"
"github.com/rs/zerolog/log"
"github.com/RedHatInsights/insights-operator-utils/parsers"
types "github.com/RedHatInsights/insights-results-types"
)
|
HTTP response-related constants
|
const (
authTokenFormatError = "unable to read orgID and userID from auth. token!"
improperRuleSelectorFormat = "improper rule selector format"
readRuleStatusError = "read rule status error"
readRuleJustificationError = "can not retrieve rule disable justification from Aggregator"
aggregatorResponseError = "Problem retrieving response from aggregator endpoint"
)
|
method readAckList list acks from this account where the rule is active.
Will return an empty list if this account has no acks.
Response format should look like:
{
"meta": {
"count": 0
},
"data": [
{
"rule": "string",
"justification": "string",
"createdby": "string",
"createdat": "2021-09-04T17:11:35.130Z",
"updated_at": "2021-09-04T17:11:35.130Z"
}
]
}
|
func ( server * HTTPServer ) readAckList ( writer http . ResponseWriter , request * http . Request ) {
orgID , err := server . GetCurrentOrgID ( request )
if err != nil {
log . Error ( ) . Msg ( authTokenFormatError )
handleServerError ( writer , err )
return
}
acks , err := server . readListOfAckedRules ( orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( ackedRulesError )
handleServerError ( writer , err )
return
}
responseBody := prepareAckList ( acks )
|
serialize the above data structure into JSON format
|
bytes , err := json . MarshalIndent ( responseBody , "" , "\t" )
if err != nil {
handleServerError ( writer , err )
return
}
|
and send the serialized structure to client
|
_ , err = writer . Write ( bytes )
if err != nil {
handleServerError ( writer , err )
return
}
|
return 200 OK (default)
|
}
|
method getAcknowledge retrieves the info about rule acknowledgement made
from this account. Acks are created, deleted, and queired by Insights rule
ID, not by their own ack ID.
An example response:
{
"rule": "string",
"justification": "string", <- can not be set by this call!!!
"createdby": "string",
"createdat": "2021-09-04T17:52:48.976Z",
"updated_at": "2021-09-04T17:52:48.976Z"
}
|
func ( server * HTTPServer ) getAcknowledge ( writer http . ResponseWriter , request * http . Request ) {
writer . Header ( ) . Set ( contentTypeHeader , JSONContentType )
orgID , err := server . GetCurrentOrgID ( request )
if err != nil {
log . Error ( ) . Msg ( authTokenFormatError )
handleServerError ( writer , err )
return
}
ruleID , errorKey , err := readRuleIDWithErrorKey ( writer , request )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( improperRuleSelectorFormat )
|
server error has been handled already
|
return
}
|
we seem to have all data -> let's display them
|
logFullRuleSelector ( orgID , ruleID , errorKey )
|
test if the rule has been acknowledged already
|
ruleAck , found , err := server . readRuleDisableStatus ( types . Component ( ruleID ) , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleStatusError )
err = errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
rule was not acked -> nothing to return
|
if ! found {
writer . WriteHeader ( http . StatusNotFound )
log . Debug ( ) . Msg ( "Rule has not been disabled previously -> nothing to return!" )
return
}
|
we have the metadata about rule, let's send it into client in
response payload
|
returnRuleAckToClient ( writer , ruleAck )
}
|
method acknowledgePost acknowledges (and therefore hides) a rule from view
in an account. If there's already an acknowledgement of this rule by this
account, then return that. Otherwise, a new ack is created.
An example request:
{
"rule_id": "string",
"justification": "string"
}
An example response:
{
"rule": "string",
"justification": "string", <- can not be set by this call!!!
"createdby": "string",
"createdat": "2021-09-04T17:52:48.976Z",
"updated_at": "2021-09-04T17:52:48.976Z"
}
HTTP/1.1 200 OK is returned if rule has been already acked
HTTP/1.1 201 Created is returned if rule has been acked by this call
|
func ( server * HTTPServer ) acknowledgePost ( writer http . ResponseWriter , request * http . Request ) {
writer . Header ( ) . Set ( contentTypeHeader , JSONContentType )
orgID , err := server . GetCurrentOrgID ( request )
if err != nil {
log . Error ( ) . Msg ( authTokenFormatError )
handleServerError ( writer , err )
return
}
parameters , err := readRuleSelectorAndJustificationFromBody ( writer , request )
if err != nil {
|
everything's handled already
|
return
}
|
we seem to have all data -> let's display them
|
log . Debug ( ) .
Int ( "org" , int ( orgID ) ) .
Str ( "rule" , string ( parameters . RuleSelector ) ) .
Str ( "value" , parameters . Value ) .
Msg ( "Proper payload provided" )
|
check if rule selector has the proper format
|
ruleID , errorKey , err := parsers . ParseRuleSelector ( parameters . RuleSelector )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( improperRuleSelectorFormat )
|
return HTTP code 400 to client
|
http . Error ( writer , err . Error ( ) , http . StatusBadRequest )
return
}
|
display parsed rule ID and error key
|
log . Debug ( ) .
Str ( ruleIDStr , string ( ruleID ) ) .
Str ( errorKeyStr , string ( errorKey ) ) .
Msg ( "Parsed rule selector" )
|
test if the rule has been acknowledged already
|
_ , previouslyAcked , err := server . readRuleDisableStatus ( ruleID , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleStatusError )
err = errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
if acknowledgement has been found -> return 200 OK with the existing rule ack
if acknowledgement has NOT been found -> return 201 Created with the created rule ack
|
if previouslyAcked {
log . Debug ( ) . Msg ( "Rule has been already disabled" )
} else {
log . Debug ( ) . Msg ( "Rule has not been disabled previously" )
|
acknowledge rule
|
err := server . ackRuleSystemWide ( ruleID , errorKey , orgID , parameters . Value )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleJustificationError )
http . Error ( writer , err . Error ( ) , http . StatusBadRequest )
return
}
}
|
Aggregator REST API is source of truth - let's re-read rule status
from it
|
updatedAcknowledgement , _ , err := server . readRuleDisableStatus ( ruleID , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleJustificationError )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
if ! previouslyAcked {
|
client is expecting 201 CREATED to indicate new entry
|
writer . WriteHeader ( http . StatusCreated )
}
|
we have the metadata about rule, let's send it into client in
response payload
|
returnRuleAckToClient ( writer , updatedAcknowledgement )
}
|
method updateAcknowledge updates an acknowledgement for a rule, by rule ID.
A new justification can be supplied. The username is taken from the
authenticated request. The updated ack is returned.
An example of request:
{
"justification": "string"
}
An example response:
{
"rule": "string",
"justification": "string",
"createdby": "string",
"createdat": "2021-09-04T17:52:48.976Z",
"updated_at": "2021-09-04T17:52:48.976Z"
}
Additionally, if rule is not found, 404 is returned (not mentioned in
original REST API specification).
|
func ( server * HTTPServer ) updateAcknowledge ( writer http . ResponseWriter , request * http . Request ) {
orgID , err := server . GetCurrentOrgID ( request )
if err != nil {
log . Error ( ) . Msg ( authTokenFormatError )
handleServerError ( writer , err )
return
}
ruleID , errorKey , err := readRuleIDWithErrorKey ( writer , request )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( improperRuleSelectorFormat )
|
server error has been handled already
|
return
}
parameters , err := readJustificationFromBody ( request )
if err != nil {
handleServerError ( writer , err )
return
}
|
we seem to have all data -> let's display them
|
logFullRuleSelector ( orgID , ruleID , errorKey )
log . Debug ( ) .
Str ( "justification" , parameters . Value ) .
Msg ( "Justification to be set" )
|
test if the rule has been acknowledged already
|
_ , found , err := server . readRuleDisableStatus ( types . Component ( ruleID ) , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleStatusError )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
if acknowledgement has NOT been found -> return 404 NotFound
|
if ! found {
log . Debug ( ) . Msg ( "Rule ack can not be found" )
err := & utypes . ItemNotFoundError { ItemID : ( ruleID + "|" + types . RuleID ( errorKey ) ) }
handleServerError ( writer , err )
return
}
|
ok, rule has been found, so update it
|
err = server . updateAckRuleSystemWide ( types . Component ( ruleID ) , errorKey , orgID , parameters . Value )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( "Unable to update justification for rule acknowledgement" )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
Aggregator REST API is source of truth - let's re-read rule status
from it
|
updatedAcknowledgement , _ , err := server . readRuleDisableStatus ( types . Component ( ruleID ) , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleJustificationError )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
we have the metadata about rule, let's send it into client in
response payload
|
returnRuleAckToClient ( writer , updatedAcknowledgement )
}
|
method deleteAcknowledge deletes an acknowledgement for a rule, by its rule
ID. If the ack existed, it is deleted and a 204 is returned. Otherwise, a
404 is returned.
|
func ( server * HTTPServer ) deleteAcknowledge ( writer http . ResponseWriter , request * http . Request ) {
orgID , err := server . GetCurrentOrgID ( request )
if err != nil {
log . Error ( ) . Msg ( authTokenFormatError )
handleServerError ( writer , err )
return
}
ruleID , errorKey , err := readRuleIDWithErrorKey ( writer , request )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( improperRuleSelectorFormat )
|
server error has been handled already
|
return
}
|
we seem to have all data -> let's display them
|
logFullRuleSelector ( orgID , ruleID , errorKey )
|
test if the rule has been acknowledged already
|
_ , found , err := server . readRuleDisableStatus ( types . Component ( ruleID ) , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( readRuleStatusError )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
if ! found {
writer . WriteHeader ( http . StatusNotFound )
log . Debug ( ) . Msg ( "Rule has not been disabled previously -> ACK won't be deleted" )
return
}
|
rule has been found -> let's delete the ACK
delete acknowledgement for a rule
|
log . Debug ( ) . Msg ( "About to delete ACK for a rule" )
err = server . deleteAckRuleSystemWide ( types . Component ( ruleID ) , errorKey , orgID )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( "Unable to delete rule acknowledgement" )
err := errors . New ( aggregatorResponseError )
handleServerError ( writer , err )
return
}
|
return 204 -> rule ack has been deleted
|
writer . WriteHeader ( http . StatusNoContent )
}
func generateRuleAckMap ( acks [ ] types . SystemWideRuleDisable ) ( ruleAcksMap map [ types . RuleID ] bool ) {
ruleAcksMap = make ( map [ types . RuleID ] bool )
for i := range acks {
ack := & acks [ i ]
compositeRuleID , err := generators . GenerateCompositeRuleID ( types . RuleFQDN ( ack . RuleID ) , ack . ErrorKey )
if err == nil {
ruleAcksMap [ compositeRuleID ] = true
} else {
log . Error ( ) . Err ( err ) . Interface ( ruleIDStr , ack . RuleID ) .
Interface ( errorKeyStr , ack . ErrorKey ) . Msg ( compositeRuleIDError )
}
}
return
}
|