mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-23 00:57:44 +01:00
Remove clair notifier
The way Harbor handles notification is problematic. It currently triggers rescan, which will cause problem when there are lot of images in the registry. Such as #7316 This commit removes the notifier and we need to revisit the notification to figure out how to map the notification to a particular image if need the notification mechanism in future. Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
parent
12fb643f0a
commit
eec4fc2798
@ -17,9 +17,3 @@ clair:
|
|||||||
timeout: 300s
|
timeout: 300s
|
||||||
updater:
|
updater:
|
||||||
interval: {{clair_updaters_interval}}h
|
interval: {{clair_updaters_interval}}h
|
||||||
|
|
||||||
notifier:
|
|
||||||
attempts: 3
|
|
||||||
renotifyinterval: 2h
|
|
||||||
http:
|
|
||||||
endpoint: http://core:8080/service/notifications/clair
|
|
||||||
|
@ -15,10 +15,7 @@
|
|||||||
package clair
|
package clair
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/goharbor/harbor/src/common/dao"
|
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,26 +38,6 @@ func ParseClairSev(clairSev string) models.Severity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateScanOverview qeuries the vulnerability based on the layerName and update the record in img_scan_overview table based on digest.
|
|
||||||
func UpdateScanOverview(digest, layerName string, clairEndpoint string, l ...*log.Logger) error {
|
|
||||||
var logger *log.Logger
|
|
||||||
if len(l) > 1 {
|
|
||||||
return fmt.Errorf("More than one logger specified")
|
|
||||||
} else if len(l) == 1 {
|
|
||||||
logger = l[0]
|
|
||||||
} else {
|
|
||||||
logger = log.DefaultLogger()
|
|
||||||
}
|
|
||||||
client := NewClient(clairEndpoint, logger)
|
|
||||||
res, err := client.GetResult(layerName)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to get result from Clair, error: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
compOverview, sev := transformVuln(res)
|
|
||||||
return dao.UpdateImgScanOverview(digest, layerName, sev, compOverview)
|
|
||||||
}
|
|
||||||
|
|
||||||
func transformVuln(clairVuln *models.ClairLayerEnvelope) (*models.ComponentsOverview, models.Severity) {
|
func transformVuln(clairVuln *models.ClairLayerEnvelope) (*models.ComponentsOverview, models.Severity) {
|
||||||
vulnMap := make(map[models.Severity]int)
|
vulnMap := make(map[models.Severity]int)
|
||||||
features := clairVuln.Layer.Features
|
features := clairVuln.Layer.Features
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/goharbor/harbor/src/core/controllers"
|
"github.com/goharbor/harbor/src/core/controllers"
|
||||||
"github.com/goharbor/harbor/src/core/service/notifications/admin"
|
"github.com/goharbor/harbor/src/core/service/notifications/admin"
|
||||||
"github.com/goharbor/harbor/src/core/service/notifications/clair"
|
|
||||||
"github.com/goharbor/harbor/src/core/service/notifications/jobs"
|
"github.com/goharbor/harbor/src/core/service/notifications/jobs"
|
||||||
"github.com/goharbor/harbor/src/core/service/notifications/registry"
|
"github.com/goharbor/harbor/src/core/service/notifications/registry"
|
||||||
"github.com/goharbor/harbor/src/core/service/notifications/scheduler"
|
"github.com/goharbor/harbor/src/core/service/notifications/scheduler"
|
||||||
@ -131,7 +130,6 @@ func initRouters() {
|
|||||||
|
|
||||||
// external service that hosted on harbor process:
|
// external service that hosted on harbor process:
|
||||||
beego.Router("/service/notifications", ®istry.NotificationHandler{})
|
beego.Router("/service/notifications", ®istry.NotificationHandler{})
|
||||||
beego.Router("/service/notifications/clair", &clair.Handler{}, "post:Handle")
|
|
||||||
beego.Router("/service/notifications/jobs/scan/:id([0-9]+)", &jobs.Handler{}, "post:HandleScan")
|
beego.Router("/service/notifications/jobs/scan/:id([0-9]+)", &jobs.Handler{}, "post:HandleScan")
|
||||||
beego.Router("/service/notifications/jobs/adminjob/:id([0-9]+)", &admin.Handler{}, "post:HandleAdminJob")
|
beego.Router("/service/notifications/jobs/adminjob/:id([0-9]+)", &admin.Handler{}, "post:HandleAdminJob")
|
||||||
beego.Router("/service/notifications/jobs/replication/:id([0-9]+)", &jobs.Handler{}, "post:HandleReplicationScheduleJob")
|
beego.Router("/service/notifications/jobs/replication/:id([0-9]+)", &jobs.Handler{}, "post:HandleReplicationScheduleJob")
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
// Copyright 2018 Project Harbor Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package clair
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/dao"
|
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/clair"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
|
||||||
"github.com/goharbor/harbor/src/core/api"
|
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
rescanInterval = 15 * time.Minute
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
clairClient *clair.Client
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handler handles reqeust on /service/notifications/clair/, which listens to clair's notifications.
|
|
||||||
// When there's unexpected error it will silently fail without removing the notification such that it will be triggered again.
|
|
||||||
type Handler struct {
|
|
||||||
api.BaseController
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle ...
|
|
||||||
func (h *Handler) Handle() {
|
|
||||||
if clairClient == nil {
|
|
||||||
clairClient = clair.NewClient(config.ClairEndpoint(), nil)
|
|
||||||
}
|
|
||||||
var ne models.ClairNotificationEnvelope
|
|
||||||
if err := json.Unmarshal(h.Ctx.Input.CopyBody(1<<32), &ne); err != nil {
|
|
||||||
log.Errorf("Failed to decode the request: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Debugf("Received notification from Clair, name: %s", ne.Notification.Name)
|
|
||||||
notification, err := clairClient.GetNotification(ne.Notification.Name)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to get notification details from Clair, name: %s, err: %v", ne.Notification.Name, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ns := make(map[string]bool)
|
|
||||||
if old := notification.Old; old != nil {
|
|
||||||
if vuln := old.Vulnerability; vuln != nil {
|
|
||||||
log.Debugf("old vulnerability namespace: %s", vuln.NamespaceName)
|
|
||||||
ns[vuln.NamespaceName] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if newNotification := notification.New; newNotification != nil {
|
|
||||||
if vuln := newNotification.Vulnerability; vuln != nil {
|
|
||||||
log.Debugf("new vulnerability namespace: %s", vuln.NamespaceName)
|
|
||||||
ns[vuln.NamespaceName] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range ns {
|
|
||||||
if v {
|
|
||||||
if err := dao.SetClairVulnTimestamp(k, time.Now()); err == nil {
|
|
||||||
log.Debugf("Updated the timestamp for namespaces: %s", k)
|
|
||||||
} else {
|
|
||||||
log.Warningf("Failed to update the timestamp for namespaces: %s, error: %v", k, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if utils.ScanOverviewMarker().Check() {
|
|
||||||
go func() {
|
|
||||||
<-time.After(rescanInterval)
|
|
||||||
l, err := dao.ListImgScanOverviews()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to list scan overview records, error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, e := range l {
|
|
||||||
if err := clair.UpdateScanOverview(e.Digest, e.DetailsKey, config.ClairEndpoint()); err != nil {
|
|
||||||
log.Errorf("Failed to refresh scan overview for image: %s", e.Digest)
|
|
||||||
} else {
|
|
||||||
log.Debugf("Refreshed scan overview for record with digest: %s", e.Digest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
utils.ScanOverviewMarker().Mark()
|
|
||||||
} else {
|
|
||||||
log.Debugf("There is a rescan scheduled at %v already, skip.", utils.ScanOverviewMarker().Next())
|
|
||||||
}
|
|
||||||
if err := clairClient.DeleteNotification(ne.Notification.Name); err != nil {
|
|
||||||
log.Warningf("Failed to remove notification from Clair, name: %s", ne.Notification.Name)
|
|
||||||
} else {
|
|
||||||
log.Debugf("Removed notification from Clair, name: %s", ne.Notification.Name)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user