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:
Daniel Jiang 2019-07-25 17:51:26 +08:00
parent 12fb643f0a
commit eec4fc2798
4 changed files with 0 additions and 138 deletions

View File

@ -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

View File

@ -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

View File

@ -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", &registry.NotificationHandler{}) beego.Router("/service/notifications", &registry.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")

View File

@ -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)
}
}