|
|
Package storage contains an implementation of interface between Go code and
(almost any) SQL database like PostgreSQL, SQLite, or MariaDB. An implementation
named DBStorage is constructed via New function and it is mandatory to call Close
for any opened connection to database. The storage might be initialized by Init
method if database schema is empty.
|
package storage
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/RedHatInsights/insights-results-aggregator-mock/types"
)
|
Storage represents an interface to almost any database or storage system
|
type Storage interface {
Init ( ) error
Close ( ) error
ListOfOrgs ( ) ( [ ] types . OrgID , error )
ListOfClustersForOrg ( orgID types . OrgID ) ( [ ] types . ClusterName , error )
ReadReportForCluster ( clusterName types . ClusterName ) ( types . ClusterReport , error )
ReadReportForOrganizationAndCluster ( orgID types . OrgID , clusterName types . ClusterName ) ( types . ClusterReport , error )
ReadReportForClusterByClusterName ( clusterName types . ClusterName ) ( types . ClusterReport , types . Timestamp , error )
ReportsCount ( ) ( int , error )
VoteOnRule (
clusterID types . ClusterName ,
ruleID types . RuleID ,
userID types . UserID ,
userVote types . UserVote ,
) error
AddOrUpdateFeedbackOnRule (
clusterID types . ClusterName ,
ruleID types . RuleID ,
userID types . UserID ,
message string ,
) error
GetUserFeedbackOnRule (
clusterID types . ClusterName , ruleID types . RuleID , userID types . UserID ,
) ( * UserFeedbackOnRule , error )
GetContentForRules (
rules types . ReportRules ,
userID types . UserID ,
clusterName types . ClusterName ,
) ( [ ] types . RuleContentResponse , error )
ToggleRuleForCluster (
clusterID types . ClusterName ,
ruleID types . RuleID ,
userID types . UserID ,
ruleToggle RuleToggle ,
) error
ListDisabledRulesForCluster (
clusterID types . ClusterName ,
userID types . UserID ,
) ( [ ] types . DisabledRuleResponse , error )
GetFromClusterRuleToggle (
types . ClusterName ,
types . RuleID ,
types . UserID ,
) ( * ClusterRuleToggle , error )
DeleteFromRuleClusterToggle (
clusterID types . ClusterName ,
ruleID types . RuleID ,
userID types . UserID ,
) error
GetRuleByID ( ruleID types . RuleID ) ( * types . Rule , error )
GetOrgIDByClusterID ( cluster types . ClusterName ) ( types . OrgID , error )
GetUserFeedbackOnRules (
clusterID types . ClusterName ,
rulesContent [ ] types . RuleContentResponse ,
userID types . UserID ,
) ( map [ types . RuleID ] types . UserVote , error )
GetRuleWithContent ( ruleID types . RuleID , ruleErrorKey types . ErrorKey ) ( * types . RuleWithContent , error )
}
|
MemoryStorage data structure represents configuration of memory storage used
to store mock data.
|
type MemoryStorage struct {
}
|
Special clusters can change results in given time period, for example each
10 minutes or so. This is to simulate real world behaviour.
|
const changingClustersPeriodInMinutes = 15
var reports map [ string ] string = make ( map [ string ] string )
func readReport ( path string , clusterName string ) ( string , error ) {
absPath , err := filepath . Abs ( path + "/report_" + clusterName + ".json" )
if err != nil {
return "" , err
}
|
disable "G304 (CWE-22): Potential file inclusion via variable"
nosec G304
|
report , err := ioutil . ReadFile ( absPath )
if err != nil {
return "" , err
}
return string ( report ) , nil
}
func init ( ) {
log . Logger = log . Output ( zerolog . ConsoleWriter { Out : os . Stderr } )
}
func initStorage ( path string ) error {
clusters := [ ] string {
"34c3ecc5-624a-49a5-bab8-4fdc5e51a266" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a267" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a268" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a269" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26a" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26b" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26c" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26d" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26e" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a26f" ,
"74ae54aa-6577-4e80-85e7-697cb646ff37" ,
"a7467445-8d6a-43cc-b82c-7007664bdf69" ,
"ee7d2bf4-8933-4a3a-8634-3328fe806e08" ,
"eeeeeeee-eeee-eeee-eeee-000000000001" ,
"00000001-624a-49a5-bab8-4fdc5e51a266" ,
"00000001-624a-49a5-bab8-4fdc5e51a267" ,
"00000001-624a-49a5-bab8-4fdc5e51a268" ,
"00000001-624a-49a5-bab8-4fdc5e51a269" ,
"00000001-624a-49a5-bab8-4fdc5e51a26a" ,
"00000001-624a-49a5-bab8-4fdc5e51a26b" ,
"00000001-624a-49a5-bab8-4fdc5e51a26c" ,
"00000001-624a-49a5-bab8-4fdc5e51a26d" ,
"00000001-624a-49a5-bab8-4fdc5e51a26e" ,
"00000001-624a-49a5-bab8-4fdc5e51a26f" ,
"00000001-6577-4e80-85e7-697cb646ff37" ,
"00000001-8933-4a3a-8634-3328fe806e08" ,
"00000001-8d6a-43cc-b82c-7007664bdf69" ,
"00000001-eeee-eeee-eeee-000000000001" ,
"00000002-624a-49a5-bab8-4fdc5e51a266" ,
"00000002-6577-4e80-85e7-697cb646ff37" ,
"00000002-8933-4a3a-8634-3328fe806e08" ,
"00000003-8933-4a3a-8634-3328fe806e08" ,
"00000003-8d6a-43cc-b82c-7007664bdf69" ,
"00000003-eeee-eeee-eeee-000000000001" ,
}
for _ , cluster := range clusters {
report , err := readReport ( path , cluster )
if err != nil {
return err
}
reports [ cluster ] = report
}
return nil
}
|
New function creates and initializes a new instance of Storage interface
|
func New ( path string ) ( * MemoryStorage , error ) {
err := initStorage ( path )
return & MemoryStorage { } , err
}
|
Init performs all database initialization
tasks necessary for further service operation.
|
func ( storage MemoryStorage ) Init ( ) error {
log . Info ( ) . Msg ( "Initializing connection to data storage" )
return nil
}
|
Close method closes the connection to database. Needs to be called at the end of application lifecycle.
|
func ( storage MemoryStorage ) Close ( ) error {
log . Info ( ) . Msg ( "Closing connection to data storage" )
return nil
}
|
Report represents one (latest) cluster report.
Org: organization ID
Name: cluster GUID in the following format:
c8590f31-e97e-4b85-b506-c45ce1911a12
|
type Report struct {
Org types . OrgID `json:"org"`
Name types . ClusterName `json:"cluster"`
Report types . ClusterReport `json:"report"`
ReportedAt types . Timestamp `json:"reported_at"`
}
|
ListOfOrgs reads list of all organizations that have at least one cluster report
|
func ( storage MemoryStorage ) ListOfOrgs ( ) ( [ ] types . OrgID , error ) {
orgs := [ ] types . OrgID {
11789772 ,
11940171 ,
}
return orgs , nil
}
func clustersForOrganization11789772 ( ) [ ] types . ClusterName {
clusters := make ( [ ] types . ClusterName , 0 )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a266" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a267" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a268" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a269" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26a" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26b" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26c" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26d" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26e" )
clusters = append ( clusters , "34c3ecc5-624a-49a5-bab8-4fdc5e51a26f" )
clusters = append ( clusters , "74ae54aa-6577-4e80-85e7-697cb646ff37" )
clusters = append ( clusters , "a7467445-8d6a-43cc-b82c-7007664bdf69" )
clusters = append ( clusters , "ee7d2bf4-8933-4a3a-8634-3328fe806e08" )
clusters = append ( clusters , "eeeeeeee-eeee-eeee-eeee-000000000001" )
return clusters
}
|
ListOfClustersForOrg reads list of all clusters fro given organization
|
func ( storage MemoryStorage ) ListOfClustersForOrg ( orgID types . OrgID ) ( [ ] types . ClusterName , error ) {
clusters := make ( [ ] types . ClusterName , 0 )
switch orgID {
case 11940171 :
return clusters , errors . New ( "You have no permissions to get or change info about this organization" )
case 11789772 :
return clustersForOrganization11789772 ( ) , nil
case 1 :
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a266" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a267" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a268" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a269" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26a" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26b" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26c" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26d" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26e" )
clusters = append ( clusters , "00000001-624a-49a5-bab8-4fdc5e51a26f" )
clusters = append ( clusters , "00000001-6577-4e80-85e7-697cb646ff37" )
clusters = append ( clusters , "00000001-8933-4a3a-8634-3328fe806e08" )
clusters = append ( clusters , "00000001-8d6a-43cc-b82c-7007664bdf69" )
clusters = append ( clusters , "00000001-eeee-eeee-eeee-000000000001" )
case 2 :
clusters = append ( clusters , "00000002-624a-49a5-bab8-4fdc5e51a266" )
clusters = append ( clusters , "00000002-6577-4e80-85e7-697cb646ff37" )
clusters = append ( clusters , "00000002-8933-4a3a-8634-3328fe806e08" )
case 3 :
clusters = append ( clusters , "00000003-8933-4a3a-8634-3328fe806e08" )
clusters = append ( clusters , "00000003-8d6a-43cc-b82c-7007664bdf69" )
clusters = append ( clusters , "00000003-eeee-eeee-eeee-000000000001" )
}
return clusters , nil
}
|
GetOrgIDByClusterID reads OrgID for specified cluster
|
func ( storage MemoryStorage ) GetOrgIDByClusterID ( cluster types . ClusterName ) ( types . OrgID , error ) {
var orgID uint64 = 42
return types . OrgID ( orgID ) , nil
}
func getReportForCluster ( clusterName types . ClusterName ) string {
report , ok := reports [ string ( clusterName ) ]
if ! ok {
return ""
}
return report
}
|
ReadReportForCluster reads result (health status) for selected cluster
|
func ( storage MemoryStorage ) ReadReportForCluster (
clusterName types . ClusterName ,
) ( types . ClusterReport , error ) {
var report string
|
clusters that can change its output (report)
please note that these clusters have special name:
"cccccccc-cccc-cccc-cccc-{index}"
Mnemotechnic: c - changing
|
changingClusters := map [ string ] [ ] string {
"cccccccc-cccc-cccc-cccc-000000000001" : {
"34c3ecc5-624a-49a5-bab8-4fdc5e51a266" ,
"74ae54aa-6577-4e80-85e7-697cb646ff37" ,
"a7467445-8d6a-43cc-b82c-7007664bdf69" } ,
"cccccccc-cccc-cccc-cccc-000000000002" : {
"74ae54aa-6577-4e80-85e7-697cb646ff37" ,
"a7467445-8d6a-43cc-b82c-7007664bdf69" ,
"ee7d2bf4-8933-4a3a-8634-3328fe806e08" } ,
"cccccccc-cccc-cccc-cccc-000000000003" : {
"ee7d2bf4-8933-4a3a-8634-3328fe806e08" ,
"ee7d2bf4-8933-4a3a-8634-3328fe806e08" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a266" } ,
"cccccccc-cccc-cccc-cccc-000000000004" : {
"eeeeeeee-eeee-eeee-eeee-000000000001" ,
"eeeeeeee-eeee-eeee-eeee-000000000001" ,
"34c3ecc5-624a-49a5-bab8-4fdc5e51a266" } ,
}
reportName := clusterName
|
handling for clusters that can change its report
|
if changingCluster , found := changingClusters [ string ( clusterName ) ] ; found {
reportName = chooseReport ( changingCluster )
}
report = getReportForCluster ( reportName )
return types . ClusterReport ( report ) , nil
}
|
chooseReport for "changing cluster"
|
func chooseReport ( variants [ ] string ) types . ClusterName {
const operationName = "changingCluster"
|
first we need to get the minute in hour
|
currentTime := time . Now ( )
minute := currentTime . Minute ( )
log . Info ( ) . Int ( "Minute in hour" , minute ) . Msg ( operationName )
|
then compute index of report
|
i := minute / changingClustersPeriodInMinutes
i %= len ( variants )
|
and choose the report according to the index
|
cluster := variants [ i ]
log . Info ( ) . Int ( "Index" , i ) . Msg ( operationName )
log . Info ( ) . Str ( "Cluster" , cluster ) . Msg ( operationName )
return types . ClusterName ( cluster )
}
|
ReadReportForOrganizationAndCluster reads result (health status) for
selected cluster for given organization
|
func ( storage MemoryStorage ) ReadReportForOrganizationAndCluster (
orgID types . OrgID , clusterName types . ClusterName ,
) ( types . ClusterReport , error ) {
var report string
switch orgID {
case 11940171 :
return types . ClusterReport ( report ) , errors . New ( "You have no permissions to get or change info about this organization" )
case 1 :
fallthrough
case 2 :
fallthrough
case 3 :
fallthrough
case 11789772 :
report = getReportForCluster ( clusterName )
}
return types . ClusterReport ( report ) , nil
}
|
ReadReportForClusterByClusterName reads result (health status) for selected cluster for given organization
|
func ( storage MemoryStorage ) ReadReportForClusterByClusterName (
clusterName types . ClusterName ,
) ( types . ClusterReport , types . Timestamp , error ) {
var report string
var lastChecked time . Time
return types . ClusterReport ( report ) , types . Timestamp ( lastChecked . UTC ( ) . Format ( time . RFC3339 ) ) , nil
}
|
GetContentForRules retrieves content for rules that were hit in the report
|
func ( storage MemoryStorage ) GetContentForRules (
reportRules types . ReportRules ,
userID types . UserID ,
clusterName types . ClusterName ,
) ( [ ] types . RuleContentResponse , error ) {
rules := make ( [ ] types . RuleContentResponse , 0 )
return rules , nil
}
|
ReportsCount reads number of all records stored in database
|
func ( storage MemoryStorage ) ReportsCount ( ) ( int , error ) {
count := - 1
return count , nil
}
|
GetRuleByID gets a rule by ID
|
func ( storage MemoryStorage ) GetRuleByID ( ruleID types . RuleID ) ( * types . Rule , error ) {
var rule types . Rule
return & rule , nil
}
|