harbor/src/controller/event/topic.go

371 lines
10 KiB
Go

// Copyright 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 event
import (
"fmt"
"time"
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/lib/selector"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/audit/model"
proModels "github.com/goharbor/harbor/src/pkg/project/models"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
)
// the event consumers can refer to this file to find all topics and the corresponding event structures
// const definition
const (
TopicCreateProject = "CREATE_PROJECT"
TopicDeleteProject = "DELETE_PROJECT"
TopicPushArtifact = "PUSH_ARTIFACT"
TopicPullArtifact = "PULL_ARTIFACT"
TopicDeleteArtifact = "DELETE_ARTIFACT"
TopicDeleteRepository = "DELETE_REPOSITORY"
TopicCreateTag = "CREATE_TAG"
TopicDeleteTag = "DELETE_TAG"
TopicScanningFailed = "SCANNING_FAILED"
TopicScanningStopped = "SCANNING_STOPPED"
TopicScanningCompleted = "SCANNING_COMPLETED"
// QuotaExceedTopic is topic for quota warning event, the usage reaches the warning bar of limitation, like 85%
TopicQuotaWarning = "QUOTA_WARNING"
TopicQuotaExceed = "QUOTA_EXCEED"
TopicReplication = "REPLICATION"
TopicArtifactLabeled = "ARTIFACT_LABELED"
TopicTagRetention = "TAG_RETENTION"
)
// CreateProjectEvent is the creating project event
type CreateProjectEvent struct {
EventType string
ProjectID int64
Project string
Operator string
OccurAt time.Time
}
// ResolveToAuditLog ...
func (c *CreateProjectEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "project",
Resource: c.Project}
return auditLog, nil
}
func (c *CreateProjectEvent) String() string {
return fmt.Sprintf("ID-%d Name-%s Operator-%s OccurAt-%s",
c.ProjectID, c.Project, c.Operator, c.OccurAt.Format("2006-01-02 15:04:05"))
}
// DeleteProjectEvent is the deleting project event
type DeleteProjectEvent struct {
EventType string
ProjectID int64
Project string
Operator string
OccurAt time.Time
}
// ResolveToAuditLog ...
func (d *DeleteProjectEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "project",
Resource: d.Project}
return auditLog, nil
}
func (d *DeleteProjectEvent) String() string {
return fmt.Sprintf("ID-%d Name-%s Operator-%s OccurAt-%s",
d.ProjectID, d.Project, d.Operator, d.OccurAt.Format("2006-01-02 15:04:05"))
}
// DeleteRepositoryEvent is the deleting repository event
type DeleteRepositoryEvent struct {
EventType string
ProjectID int64
Repository string
Operator string
OccurAt time.Time
}
// ResolveToAuditLog ...
func (d *DeleteRepositoryEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "repository",
Resource: d.Repository,
}
return auditLog, nil
}
func (d *DeleteRepositoryEvent) String() string {
return fmt.Sprintf("ID-%d Repository-%s Operator-%s OccurAt-%s",
d.ProjectID, d.Repository, d.Operator, d.OccurAt.Format("2006-01-02 15:04:05"))
}
// ArtifactEvent is the pushing/pulling artifact event
type ArtifactEvent struct {
EventType string
Repository string
Artifact *artifact.Artifact
Tags []string // when the artifact is pushed by digest, the tag here will be null
Operator string
OccurAt time.Time
}
func (a *ArtifactEvent) String() string {
return fmt.Sprintf("ID-%d, Repository-%s Tags-%s Digest-%s Operator-%s OccurAt-%s",
a.Artifact.ID, a.Repository, a.Tags, a.Artifact.Digest, a.Operator,
a.OccurAt.Format("2006-01-02 15:04:05"))
}
// PushArtifactEvent is the pushing artifact event
type PushArtifactEvent struct {
*ArtifactEvent
}
// ResolveToAuditLog ...
func (p *PushArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: p.Operator,
ResourceType: "artifact"}
if len(p.Tags) == 0 {
auditLog.Resource = fmt.Sprintf("%s:%s",
p.Artifact.RepositoryName, p.Artifact.Digest)
} else {
auditLog.Resource = fmt.Sprintf("%s:%s",
p.Artifact.RepositoryName, p.Tags[0])
}
return auditLog, nil
}
func (p *PushArtifactEvent) String() string {
return p.ArtifactEvent.String()
}
// PullArtifactEvent is the pulling artifact event
type PullArtifactEvent struct {
*ArtifactEvent
}
// ResolveToAuditLog ...
func (p *PullArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionPull.String(),
Username: p.Operator,
ResourceType: "artifact"}
if len(p.Tags) == 0 {
auditLog.Resource = fmt.Sprintf("%s@%s",
p.Artifact.RepositoryName, p.Artifact.Digest)
} else {
auditLog.Resource = fmt.Sprintf("%s:%s",
p.Artifact.RepositoryName, p.Tags[0])
}
// for pull public resource
if p.Operator == "" {
auditLog.Username = "anonymous"
} else {
auditLog.Username = p.Operator
}
return auditLog, nil
}
func (p *PullArtifactEvent) String() string {
return p.ArtifactEvent.String()
}
// DeleteArtifactEvent is the deleting artifact event
type DeleteArtifactEvent struct {
*ArtifactEvent
}
// ResolveToAuditLog ...
func (d *DeleteArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.Artifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "artifact",
Resource: fmt.Sprintf("%s:%s", d.Artifact.RepositoryName, d.Artifact.Digest)}
return auditLog, nil
}
func (d *DeleteArtifactEvent) String() string {
return d.ArtifactEvent.String()
}
// CreateTagEvent is the creating tag event
type CreateTagEvent struct {
EventType string
Repository string
Tag string
AttachedArtifact *artifact.Artifact
Operator string
OccurAt time.Time
}
// ResolveToAuditLog ...
func (c *CreateTagEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.AttachedArtifact.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "tag",
Resource: fmt.Sprintf("%s:%s", c.Repository, c.Tag)}
return auditLog, nil
}
func (c *CreateTagEvent) String() string {
return fmt.Sprintf("ArtifactID-%d, Repository-%s Tag-%s Digest-%s Operator-%s OccurAt-%s",
c.AttachedArtifact.ID, c.Repository, c.Tag, c.AttachedArtifact.Digest, c.Operator,
c.OccurAt.Format("2006-01-02 15:04:05"))
}
// DeleteTagEvent is the deleting tag event
type DeleteTagEvent struct {
EventType string
Repository string
Tag string
AttachedArtifact *artifact.Artifact
Operator string
OccurAt time.Time
}
// ResolveToAuditLog ...
func (d *DeleteTagEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.AttachedArtifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "tag",
Resource: fmt.Sprintf("%s:%s", d.Repository, d.Tag)}
return auditLog, nil
}
func (d *DeleteTagEvent) String() string {
return fmt.Sprintf("ArtifactID-%d, Repository-%s Tag-%s Digest-%s Operator-%s OccurAt-%s",
d.AttachedArtifact.ID, d.Repository, d.Tag, d.AttachedArtifact.Digest, d.Operator,
d.OccurAt.Format("2006-01-02 15:04:05"))
}
// ScanImageEvent is scanning image related event data to publish
type ScanImageEvent struct {
EventType string
Artifact *v1.Artifact
OccurAt time.Time
Operator string
}
func (s *ScanImageEvent) String() string {
return fmt.Sprintf("Artifact-%+v Operator-%s OccurAt-%s",
s.Artifact, s.Operator, s.OccurAt.Format("2006-01-02 15:04:05"))
}
// QuotaEvent is project quota related event data to publish
type QuotaEvent struct {
EventType string
Project *proModels.Project
Resource *ImgResource
OccurAt time.Time
RepoName string
Msg string
Operator string
}
func (q *QuotaEvent) String() string {
return fmt.Sprintf("ProjectID-%d RepoName-%s Resource-%+v Msg-%s OccurAt-%s",
q.Project.ProjectID, q.RepoName, q.Resource, q.Msg, q.OccurAt.Format("2006-01-02 15:04:05"))
}
// ImgResource include image digest and tag
type ImgResource struct {
Digest string
Tag string
}
// ReplicationEvent is replication related event data to publish
type ReplicationEvent struct {
EventType string
ReplicationTaskID int64
OccurAt time.Time
Status string
}
func (r *ReplicationEvent) String() string {
return fmt.Sprintf("ReplicationTaskID-%d Status-%s OccurAt-%s",
r.ReplicationTaskID, r.Status, r.OccurAt.Format("2006-01-02 15:04:05"))
}
// ArtifactLabeledEvent is event data of artifact labeled
type ArtifactLabeledEvent struct {
ArtifactID int64
LabelID int64
OccurAt time.Time
Operator string
}
func (al *ArtifactLabeledEvent) String() string {
return fmt.Sprintf("ArtifactID-%d LabelID-%d Operator-%s OccurAt-%s",
al.ArtifactID, al.LabelID, al.Operator, al.OccurAt.Format("2006-01-02 15:04:05"))
}
// RetentionEvent is tag retention related event data to publish
type RetentionEvent struct {
TaskID int64
EventType string
OccurAt time.Time
Status string
Deleted []*selector.Result
Total int
Retained int
}
func (r *RetentionEvent) String() string {
candidates := []string{}
for _, candidate := range r.Deleted {
candidates = append(candidates, fmt.Sprintf("%s:%s:%s", candidate.Target.Namespace,
candidate.Target.Repository, candidate.Target.Tags))
}
return fmt.Sprintf("TaskID-%d Status-%s Deleted-%s OccurAt-%s",
r.TaskID, r.Status, candidates, r.OccurAt.Format("2006-01-02 15:04:05"))
}