From dcbfb4d30912159c76051b56b6d354cc48d0afbc Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Thu, 11 May 2017 21:41:57 +0800 Subject: [PATCH] add scan job table and dao functions --- make/common/db/registry.sql | 11 +++++ make/common/db/registry_sqlite.sql | 11 +++++ src/common/dao/dao_test.go | 60 +++++++++++++++++++++++++++ src/common/dao/scan_job.go | 62 ++++++++++++++++++++++++++++ src/common/models/base.go | 1 + src/common/models/job.go | 34 +++++++++++++++ src/common/models/replication_job.go | 16 ------- src/common/models/scan_job.go | 33 +++++++++++++++ 8 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 src/common/dao/scan_job.go create mode 100644 src/common/models/job.go create mode 100644 src/common/models/scan_job.go diff --git a/make/common/db/registry.sql b/make/common/db/registry.sql index 0f7038c0ed..a7934076fe 100644 --- a/make/common/db/registry.sql +++ b/make/common/db/registry.sql @@ -170,6 +170,17 @@ create table replication_job ( INDEX poid_uptime (policy_id, update_time) ); +create table img_scan_job ( + id int NOT NULL AUTO_INCREMENT, + status varchar(64) NOT NULL, + repository varchar(256) NOT NULL, + tag varchar(128) NOT NULL, + digest varchar(64), + creation_time timestamp default CURRENT_TIMESTAMP, + update_time timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (id) + ); + create table properties ( k varchar(64) NOT NULL, v varchar(128) NOT NULL, diff --git a/make/common/db/registry_sqlite.sql b/make/common/db/registry_sqlite.sql index 2807455677..64308b0de1 100644 --- a/make/common/db/registry_sqlite.sql +++ b/make/common/db/registry_sqlite.sql @@ -162,6 +162,17 @@ create table replication_job ( update_time timestamp default CURRENT_TIMESTAMP ); + +create table img_scan_job ( + id INTEGER PRIMARY KEY, + status varchar(64) NOT NULL, + repository varchar(256) NOT NULL, + tag varchar(128) NOT NULL, + digest varchar(64), + creation_time timestamp default CURRENT_TIMESTAMP, + update_time timestamp default CURRENT_TIMESTAMP + ); + CREATE INDEX policy ON replication_job (policy_id); CREATE INDEX poid_uptime ON replication_job (policy_id, update_time); diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index de270dc851..20de7e365b 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -15,6 +15,7 @@ package dao import ( + "fmt" "os" "strconv" "testing" @@ -41,6 +42,13 @@ func execUpdate(o orm.Ormer, sql string, params ...interface{}) error { return nil } +func clearTable(table string) error { + o := GetOrmer() + sql := fmt.Sprintf("delete from %s where 1=1", table) + _, err := o.Raw(sql).Exec() + return err +} + func clearUp(username string) { var err error @@ -1649,3 +1657,55 @@ func TestDeleteRepository(t *testing.T) { t.Errorf("repository is not nil after deletion, repository: %+v", repository) } } + +var sj1 = models.ScanJob{ + Status: models.JobPending, + Repository: "library/ubuntu", + Tag: "14.04", +} + +var sj2 = models.ScanJob{ + Status: models.JobPending, + Repository: "library/ubuntu", + Tag: "15.10", + Digest: "sha256:1234567890", +} + +func TestAddScanJob(t *testing.T) { + assert := assert.New(t) + id, err := AddScanJob(sj1) + assert.Nil(err) + r1, err := GetScanJob(id) + assert.Nil(err) + assert.Equal(sj1.Tag, r1.Tag) + assert.Equal(sj1.Status, r1.Status) + assert.Equal(sj1.Repository, r1.Repository) + err = clearTable(ScanJobTable) + assert.Nil(err) +} + +func TestGetScanJobs(t *testing.T) { + assert := assert.New(t) + _, err := AddScanJob(sj1) + assert.Nil(err) + id2, err := AddScanJob(sj1) + assert.Nil(err) + _, err = AddScanJob(sj2) + assert.Nil(err) + r, err := GetScanJobsByImage("library/ubuntu", "14.04") + assert.Nil(err) + assert.Equal(2, len(r)) + assert.Equal(id2, r[0].ID) + r, err = GetScanJobsByImage("library/ubuntu", "14.04", 1) + assert.Nil(err) + assert.Equal(1, len(r)) + r, err = GetScanJobsByDigest("sha256:nono") + assert.Nil(err) + assert.Equal(0, len(r)) + r, err = GetScanJobsByDigest(sj2.Digest) + assert.Equal(1, len(r)) + assert.Equal(sj2.Tag, r[0].Tag) + assert.Nil(err) + err = clearTable(ScanJobTable) + assert.Nil(err) +} diff --git a/src/common/dao/scan_job.go b/src/common/dao/scan_job.go new file mode 100644 index 0000000000..4e4584d661 --- /dev/null +++ b/src/common/dao/scan_job.go @@ -0,0 +1,62 @@ +// copyright (c) 2017 vmware, inc. all rights reserved. +// +// 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 dao + +import ( + "github.com/astaxie/beego/orm" + "github.com/vmware/harbor/src/common/models" +) + +const ScanJobTable = "img_scan_job" + +// AddScanJob ... +func AddScanJob(job models.ScanJob) (int64, error) { + o := GetOrmer() + return o.Insert(&job) +} + +// GetScanJob ... +func GetScanJob(id int64) (*models.ScanJob, error) { + o := GetOrmer() + j := models.ScanJob{ID: id} + err := o.Read(&j) + if err == orm.ErrNoRows { + return nil, nil + } + return &j, nil +} + +// GetScanJobsByImage returns a list of scan jobs with given repository and tag +func GetScanJobsByImage(repository, tag string, limit ...int) ([]*models.ScanJob, error) { + var res []*models.ScanJob + _, err := scanJobQs(limit...).Filter("repository", repository).Filter("tag", tag).OrderBy("-id").All(&res) + return res, err +} + +// GetScanJobsByDigest returns a list of scan jobs with given digest +func GetScanJobsByDigest(digest string, limit ...int) ([]*models.ScanJob, error) { + var res []*models.ScanJob + _, err := scanJobQs(limit...).Filter("digest", digest).OrderBy("-id").All(&res) + return res, err +} + +func scanJobQs(limit ...int) orm.QuerySeter { + o := GetOrmer() + l := -1 + if len(limit) == 1 { + l = limit[0] + } + return o.QueryTable(ScanJobTable).Limit(l) +} diff --git a/src/common/models/base.go b/src/common/models/base.go index 0bfb79b365..f861399f21 100644 --- a/src/common/models/base.go +++ b/src/common/models/base.go @@ -26,5 +26,6 @@ func init() { new(Project), new(Role), new(AccessLog), + new(ScanJob), new(RepoRecord)) } diff --git a/src/common/models/job.go b/src/common/models/job.go new file mode 100644 index 0000000000..11ea3d00f1 --- /dev/null +++ b/src/common/models/job.go @@ -0,0 +1,34 @@ +// Copyright (c) 2017 VMware, Inc. All Rights Reserved. +// +// 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 models + +const ( + //JobPending ... + JobPending string = "pending" + //JobRunning ... + JobRunning string = "running" + //JobError ... + JobError string = "error" + //JobStopped ... + JobStopped string = "stopped" + //JobFinished ... + JobFinished string = "finished" + //JobCanceled ... + JobCanceled string = "canceled" + //JobRetrying indicate the job needs to be retried, it will be scheduled to the end of job queue by statemachine after an interval. + JobRetrying string = "retrying" + //JobContinue is the status returned by statehandler to tell statemachine to move to next possible state based on trasition table. + JobContinue string = "_continue" +) diff --git a/src/common/models/replication_job.go b/src/common/models/replication_job.go index bd391e9d19..b735c8a624 100644 --- a/src/common/models/replication_job.go +++ b/src/common/models/replication_job.go @@ -22,22 +22,6 @@ import ( ) const ( - //JobPending ... - JobPending string = "pending" - //JobRunning ... - JobRunning string = "running" - //JobError ... - JobError string = "error" - //JobStopped ... - JobStopped string = "stopped" - //JobFinished ... - JobFinished string = "finished" - //JobCanceled ... - JobCanceled string = "canceled" - //JobRetrying indicate the job needs to be retried, it will be scheduled to the end of job queue by statemachine after an interval. - JobRetrying string = "retrying" - //JobContinue is the status returned by statehandler to tell statemachine to move to next possible state based on trasition table. - JobContinue string = "_continue" //RepOpTransfer represents the operation of a job to transfer repository to a remote registry/harbor instance. RepOpTransfer string = "transfer" //RepOpDelete represents the operation of a job to remove repository from a remote registry/harbor instance. diff --git a/src/common/models/scan_job.go b/src/common/models/scan_job.go new file mode 100644 index 0000000000..b0299a861d --- /dev/null +++ b/src/common/models/scan_job.go @@ -0,0 +1,33 @@ +// Copyright (c) 2017 VMware, Inc. All Rights Reserved. +// +// 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 models + +import "time" + +//ScanJob is the model to represent a job for image scan in DB. +type ScanJob struct { + ID int64 `orm:"pk;auto;column(id)" json:"id"` + Status string `orm:"column(status)" json:"status"` + Repository string `orm:"column(repository)" json:"repository"` + Tag string `orm:"column(tag)" json:"tag"` + Digest string `orm:"column(digest)" json:"digest"` + CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"` + UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` +} + +//TableName is required by by beego orm to map ScanJob to table img_scan_job +func (s *ScanJob) TableName() string { + return "img_scan_job" +}