2022-02-04 13:23:19 -06:00
package store
import (
"context"
"fmt"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
type provenanceRecord struct {
Id int ` xorm:"pk autoincr 'id'" `
OrgID int64 ` xorm:"'org_id'" `
RecordKey string
RecordType string
Provenance models . Provenance
}
func ( pr provenanceRecord ) TableName ( ) string {
return "provenance_type"
}
// GetProvenance gets the provenance status for a provisionable object.
2022-04-26 10:30:57 -05:00
func ( st DBstore ) GetProvenance ( ctx context . Context , o models . Provisionable , org int64 ) ( models . Provenance , error ) {
2022-02-04 13:23:19 -06:00
recordType := o . ResourceType ( )
recordKey := o . ResourceID ( )
provenance := models . ProvenanceNone
err := st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
filter := "record_key = ? AND record_type = ? AND org_id = ?"
var result models . Provenance
2022-04-26 10:30:57 -05:00
has , err := sess . Table ( provenanceRecord { } ) . Where ( filter , recordKey , recordType , org ) . Desc ( "id" ) . Cols ( "provenance" ) . Get ( & result )
2022-02-04 13:23:19 -06:00
if err != nil {
return fmt . Errorf ( "failed to query for existing provenance status: %w" , err )
}
if has {
provenance = result
}
return nil
} )
if err != nil {
return models . ProvenanceNone , err
}
return provenance , nil
}
2022-04-13 15:15:55 -05:00
// GetProvenance gets the provenance status for a provisionable object.
2022-04-26 10:30:57 -05:00
func ( st DBstore ) GetProvenances ( ctx context . Context , org int64 , resourceType string ) ( map [ string ] models . Provenance , error ) {
2022-04-13 15:15:55 -05:00
resultMap := make ( map [ string ] models . Provenance )
err := st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
filter := "record_type = ? AND org_id = ?"
2022-04-26 10:30:57 -05:00
rawData , err := sess . Table ( provenanceRecord { } ) . Where ( filter , resourceType , org ) . Desc ( "id" ) . Cols ( "record_key" , "provenance" ) . QueryString ( )
2022-04-13 15:15:55 -05:00
if err != nil {
return fmt . Errorf ( "failed to query for existing provenance status: %w" , err )
}
for _ , data := range rawData {
resultMap [ data [ "record_key" ] ] = models . Provenance ( data [ "provenance" ] )
}
return nil
} )
return resultMap , err
}
2022-02-04 13:23:19 -06:00
// SetProvenance changes the provenance status for a provisionable object.
2022-04-26 10:30:57 -05:00
func ( st DBstore ) SetProvenance ( ctx context . Context , o models . Provisionable , org int64 , p models . Provenance ) error {
2022-02-04 13:23:19 -06:00
recordType := o . ResourceType ( )
recordKey := o . ResourceID ( )
return st . SQLStore . WithTransactionalDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
// TODO: Add a unit-of-work pattern, so updating objects + provenance will happen consistently with rollbacks across stores.
// TODO: Need to make sure that writing a record where our concurrency key fails will also fail the whole transaction. That way, this gets rolled back too. can't just check that 0 updates happened inmemory. Check with jp. If not possible, we need our own concurrency key.
// TODO: Clean up stale provenance records periodically.
filter := "record_key = ? AND record_type = ? AND org_id = ?"
2022-04-26 10:30:57 -05:00
_ , err := sess . Table ( provenanceRecord { } ) . Where ( filter , recordKey , recordType , org ) . Delete ( provenanceRecord { } )
2022-02-04 13:23:19 -06:00
if err != nil {
return fmt . Errorf ( "failed to delete pre-existing provisioning status: %w" , err )
}
record := provenanceRecord {
RecordKey : recordKey ,
RecordType : recordType ,
Provenance : p ,
2022-04-26 10:30:57 -05:00
OrgID : org ,
2022-02-04 13:23:19 -06:00
}
if _ , err := sess . Insert ( record ) ; err != nil {
return fmt . Errorf ( "failed to store provisioning status: %w" , err )
}
return nil
} )
}
2022-04-13 15:15:55 -05:00
// DeleteProvenance deletes the provenance record from the table
2022-04-26 10:30:57 -05:00
func ( st DBstore ) DeleteProvenance ( ctx context . Context , o models . Provisionable , org int64 ) error {
2022-04-13 15:15:55 -05:00
return st . SQLStore . WithTransactionalDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
_ , err := sess . Delete ( provenanceRecord {
RecordKey : o . ResourceID ( ) ,
RecordType : o . ResourceType ( ) ,
2022-04-26 10:30:57 -05:00
OrgID : org ,
2022-04-13 15:15:55 -05:00
} )
return err
} )
}