2022-10-10 15:05:55 +03:00
//go:build search
// +build search
2020-10-14 14:47:20 -07:00
package extensions
import (
2023-02-27 21:25:47 +02:00
"net/http"
2023-03-02 19:43:54 +02:00
"sync"
2020-10-14 14:47:20 -07:00
"time"
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
2021-10-15 18:05:00 +03:00
"github.com/gorilla/mux"
2022-10-20 19:39:20 +03:00
2021-12-04 03:50:58 +00:00
"zotregistry.io/zot/pkg/api/config"
2022-02-24 12:31:36 -08:00
"zotregistry.io/zot/pkg/api/constants"
2023-05-25 21:44:54 +03:00
zcommon "zotregistry.io/zot/pkg/common"
2021-12-04 03:50:58 +00:00
"zotregistry.io/zot/pkg/extensions/search"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
2022-07-15 11:10:51 +00:00
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
2021-12-04 03:50:58 +00:00
"zotregistry.io/zot/pkg/log"
2023-01-09 22:37:44 +02:00
"zotregistry.io/zot/pkg/meta/repodb"
2023-03-02 19:43:54 +02:00
"zotregistry.io/zot/pkg/scheduler"
2021-12-04 03:50:58 +00:00
"zotregistry.io/zot/pkg/storage"
2020-10-14 14:47:20 -07:00
)
2023-03-02 19:43:54 +02:00
type (
CveInfo cveinfo . CveInfo
state int
)
const (
pending state = iota
running
done
)
2022-09-28 21:39:54 +03:00
2023-05-25 14:46:52 +03:00
func IsBuiltWithSearchExtension ( ) bool {
return true
}
2023-02-10 07:04:52 +02:00
func GetCVEInfo ( config * config . Config , storeController storage . StoreController ,
2023-01-09 22:37:44 +02:00
repoDB repodb . RepoDB , log log . Logger ,
2023-02-10 07:04:52 +02:00
) CveInfo {
if config . Extensions . Search == nil || ! * config . Extensions . Search . Enable || config . Extensions . Search . CVE == nil {
return nil
}
dbRepository := ""
if config . Extensions . Search . CVE . Trivy != nil {
dbRepository = config . Extensions . Search . CVE . Trivy . DBRepository
}
return cveinfo . NewCVEInfo ( storeController , repoDB , dbRepository , log )
}
func EnableSearchExtension ( config * config . Config , storeController storage . StoreController ,
2023-03-02 19:43:54 +02:00
repoDB repodb . RepoDB , taskScheduler * scheduler . Scheduler , cveInfo CveInfo , log log . Logger ,
2023-01-09 22:37:44 +02:00
) {
2021-12-28 15:29:30 +02:00
if config . Extensions . Search != nil && * config . Extensions . Search . Enable && config . Extensions . Search . CVE != nil {
2020-10-14 14:47:20 -07:00
defaultUpdateInterval , _ := time . ParseDuration ( "2h" )
2021-06-08 23:11:18 +03:00
if config . Extensions . Search . CVE . UpdateInterval < defaultUpdateInterval {
config . Extensions . Search . CVE . UpdateInterval = defaultUpdateInterval
2020-10-14 14:47:20 -07:00
2022-03-21 17:37:23 +00:00
log . Warn ( ) . Msg ( "CVE update interval set to too-short interval < 2h, changing update duration to 2 hours and continuing." ) //nolint:lll // gofumpt conflicts with lll
2020-10-14 14:47:20 -07:00
}
2023-03-02 19:43:54 +02:00
updateInterval := config . Extensions . Search . CVE . UpdateInterval
downloadTrivyDB ( updateInterval , taskScheduler , cveInfo , log )
2020-10-14 14:47:20 -07:00
} else {
2020-10-22 17:31:16 -07:00
log . Info ( ) . Msg ( "CVE config not provided, skipping CVE update" )
2020-10-14 14:47:20 -07:00
}
2022-04-27 09:00:20 +03:00
}
2021-06-08 23:11:18 +03:00
2023-03-02 19:43:54 +02:00
func downloadTrivyDB ( interval time . Duration , sch * scheduler . Scheduler , cveInfo CveInfo , log log . Logger ) {
2023-03-22 18:52:48 +02:00
generator := NewTrivyTaskGenerator ( interval , cveInfo , log )
2021-10-28 12:10:01 +03:00
2023-03-02 19:43:54 +02:00
sch . SubmitGenerator ( generator , interval , scheduler . HighPriority )
}
2021-10-28 12:10:01 +03:00
2023-03-22 18:52:48 +02:00
func NewTrivyTaskGenerator ( interval time . Duration , cveInfo CveInfo , log log . Logger ) * TrivyTaskGenerator {
generator := & TrivyTaskGenerator { interval , cveInfo , log , pending , 0 , time . Now ( ) , & sync . Mutex { } }
return generator
}
type TrivyTaskGenerator struct {
2023-03-02 19:43:54 +02:00
interval time . Duration
cveInfo CveInfo
log log . Logger
status state
waitTime time . Duration
lastTaskTime time . Time
lock * sync . Mutex
}
2023-03-22 18:52:48 +02:00
func ( gen * TrivyTaskGenerator ) GenerateTask ( ) ( scheduler . Task , error ) {
2023-03-02 19:43:54 +02:00
var newTask scheduler . Task
2022-04-27 09:00:20 +03:00
2023-03-02 19:43:54 +02:00
gen . lock . Lock ( )
2023-03-10 20:08:53 +02:00
if gen . status == pending && time . Since ( gen . lastTaskTime ) >= gen . waitTime {
2023-03-02 19:43:54 +02:00
newTask = newTrivyTask ( gen . interval , gen . cveInfo , gen , gen . log )
gen . status = running
2021-06-08 23:11:18 +03:00
}
2023-03-02 19:43:54 +02:00
gen . lock . Unlock ( )
return newTask , nil
}
2023-03-22 18:52:48 +02:00
func ( gen * TrivyTaskGenerator ) IsDone ( ) bool {
2023-03-02 19:43:54 +02:00
gen . lock . Lock ( )
status := gen . status
gen . lock . Unlock ( )
return status == done
}
2023-03-22 18:52:48 +02:00
func ( gen * TrivyTaskGenerator ) Reset ( ) {
2023-03-02 19:43:54 +02:00
gen . lock . Lock ( )
gen . status = pending
gen . waitTime = 0
gen . lock . Unlock ( )
}
type trivyTask struct {
interval time . Duration
cveInfo cveinfo . CveInfo
2023-03-22 18:52:48 +02:00
generator * TrivyTaskGenerator
2023-03-02 19:43:54 +02:00
log log . Logger
}
func newTrivyTask ( interval time . Duration , cveInfo cveinfo . CveInfo ,
2023-03-22 18:52:48 +02:00
generator * TrivyTaskGenerator , log log . Logger ,
2023-03-02 19:43:54 +02:00
) * trivyTask {
return & trivyTask { interval , cveInfo , generator , log }
}
func ( trivyT * trivyTask ) DoWork ( ) error {
trivyT . log . Info ( ) . Msg ( "updating the CVE database" )
err := trivyT . cveInfo . UpdateDB ( )
if err != nil {
trivyT . generator . lock . Lock ( )
trivyT . generator . status = pending
2023-03-22 18:52:48 +02:00
if trivyT . generator . waitTime == 0 {
trivyT . generator . waitTime = time . Second
}
trivyT . generator . waitTime *= 2
2023-03-02 19:43:54 +02:00
trivyT . generator . lastTaskTime = time . Now ( )
trivyT . generator . lock . Unlock ( )
return err
}
trivyT . generator . lock . Lock ( )
trivyT . generator . lastTaskTime = time . Now ( )
trivyT . generator . status = done
trivyT . generator . lock . Unlock ( )
trivyT . log . Info ( ) . Str ( "DB update completed, next update scheduled after" , trivyT . interval . String ( ) ) . Msg ( "" )
return nil
2020-10-14 14:47:20 -07:00
}
2022-04-27 09:00:20 +03:00
func SetupSearchRoutes ( config * config . Config , router * mux . Router , storeController storage . StoreController ,
2023-02-10 07:04:52 +02:00
repoDB repodb . RepoDB , cveInfo CveInfo , log log . Logger ,
2022-04-27 09:00:20 +03:00
) {
log . Info ( ) . Msg ( "setting up search routes" )
2022-03-04 09:37:06 +02:00
2022-04-27 09:00:20 +03:00
if config . Extensions . Search != nil && * config . Extensions . Search . Enable {
2023-02-10 07:04:52 +02:00
resConfig := search . GetResolverConfig ( log , storeController , repoDB , cveInfo )
2022-04-27 09:00:20 +03:00
2023-05-25 21:44:54 +03:00
allowedMethods := zcommon . AllowedMethods ( http . MethodGet , http . MethodPost )
2023-05-11 16:05:14 +03:00
2023-05-25 21:44:54 +03:00
extRouter := router . PathPrefix ( constants . ExtSearch ) . Subrouter ( )
extRouter . Use ( zcommon . ACHeadersHandler ( allowedMethods ... ) )
extRouter . Use ( zcommon . AddExtensionSecurityHeaders ( ) )
extRouter . Methods ( allowedMethods ... ) .
Handler ( gqlHandler . NewDefaultServer ( gql_generated . NewExecutableSchema ( resConfig ) ) )
2023-05-11 16:05:14 +03:00
}
}