From 8939b544489dcf88864df0ac71582584c0086b25 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Thu, 16 Jun 2016 14:18:23 +0800 Subject: [PATCH 1/3] 1. support updating the target of policy 2. can not delete a target if it is being used --- api/replication_policy.go | 81 +++++++++++++++++++++++++++++++-------- api/target.go | 10 +++++ dao/dao_test.go | 15 ++++++++ dao/replication_job.go | 16 +++++++- 4 files changed, 105 insertions(+), 17 deletions(-) diff --git a/api/replication_policy.go b/api/replication_policy.go index 884f566c1..ab94deb15 100644 --- a/api/replication_policy.go +++ b/api/replication_policy.go @@ -126,7 +126,7 @@ func (pa *RepPolicyAPI) Post() { pa.Redirect(http.StatusCreated, strconv.FormatInt(pid, 10)) } -// Put modifies name and description of policy +// Put modifies name, description, target and enablement of policy func (pa *RepPolicyAPI) Put() { id := pa.GetIDFromURL() originalPolicy, err := dao.GetRepPolicy(id) @@ -142,7 +142,6 @@ func (pa *RepPolicyAPI) Put() { policy := &models.RepPolicy{} pa.DecodeJSONReq(policy) policy.ProjectID = originalPolicy.ProjectID - policy.TargetID = originalPolicy.TargetID pa.Validate(policy) if policy.Name != originalPolicy.Name { @@ -157,19 +156,77 @@ func (pa *RepPolicyAPI) Put() { } } + if policy.TargetID != originalPolicy.TargetID { + target, err := dao.GetRepTarget(policy.TargetID) + if err != nil { + log.Errorf("failed to get target %d: %v", policy.TargetID, err) + pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + } + + if target == nil { + pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("target %d does not exist", policy.TargetID)) + } + } + policy.ID = id + isTargetChanged := !(policy.TargetID == originalPolicy.TargetID) + isEnablementChanged := !(policy.Enabled == policy.Enabled) + + var shouldStop, shouldTrigger bool + + // if target and enablement are not changed, do nothing + if !isTargetChanged && !isEnablementChanged { + shouldStop = false + shouldTrigger = false + } else if !isTargetChanged && isEnablementChanged { + // target is not changed, but enablement is changed + if policy.Enabled == 0 { + shouldStop = true + shouldTrigger = false + } else { + shouldStop = false + shouldTrigger = true + } + } else if isTargetChanged && !isEnablementChanged { + // target is changed, but enablement is not changed + if policy.Enabled == 0 { + // enablement is 0, do nothing + shouldStop = false + shouldTrigger = false + } else { + // enablement is 1, so stop original target's jobs + // and trigger new target's jobs + shouldStop = true + shouldTrigger = true + } + } else { + // both target and enablement are changed + + // enablement: 1 -> 0 + if policy.Enabled == 0 { + shouldStop = true + shouldTrigger = false + } else { + shouldStop = false + shouldTrigger = true + } + } + + if shouldStop { + if err := postReplicationAction(id, "stop"); err != nil { + log.Errorf("failed to stop replication of %d: %v", id, err) + pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + } + log.Infof("replication of %d has been stopped", id) + } + if err = dao.UpdateRepPolicy(policy); err != nil { log.Errorf("failed to update policy %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } - if policy.Enabled == originalPolicy.Enabled { - return - } - - //enablement has been modified - if policy.Enabled == 1 { + if shouldTrigger { go func() { if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil { log.Errorf("failed to trigger replication of %d: %v", id, err) @@ -177,14 +234,6 @@ func (pa *RepPolicyAPI) Put() { log.Infof("replication of %d triggered", id) } }() - } else { - go func() { - if err := postReplicationAction(id, "stop"); err != nil { - log.Errorf("failed to stop replication of %d: %v", id, err) - } else { - log.Infof("try to stop replication of %d", id) - } - }() } } diff --git a/api/target.go b/api/target.go index 7d94e12f1..089771c2b 100644 --- a/api/target.go +++ b/api/target.go @@ -258,6 +258,16 @@ func (t *TargetAPI) Delete() { t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound)) } + policies, err := dao.GetRepPolicyByTarget(id) + if err != nil { + log.Errorf("failed to get policies according target %d: %v", id, err) + t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + } + + if len(policies) > 0 { + t.CustomAbort(http.StatusBadRequest, "the target is used by policies, can not be deleted") + } + if err = dao.DeleteRepTarget(id); err != nil { log.Errorf("failed to delete target %d: %v", id, err) t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) diff --git a/dao/dao_test.go b/dao/dao_test.go index 343c38b57..e69855842 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -911,6 +911,21 @@ func TestAddRepPolicy(t *testing.T) { } +func TestGetRepPolicyByTarget(t *testing.T) { + policies, err := GetRepPolicyByTarget(targetID) + if err != nil { + t.Fatalf("failed to get policy according target %d: %v", targetID, err) + } + + if len(policies) == 0 { + t.Fatal("unexpected length of policies 0, expected is >0") + } + + if policies[0].ID != policyID { + t.Fatal("unexpected policy: %d, expected: %d", policies[0].ID, policyID) + } +} + func TestGetRepPolicyByName(t *testing.T) { policy, err := GetRepPolicy(policyID) if err != nil { diff --git a/dao/replication_job.go b/dao/replication_job.go index f0dc7fb15..4f49ac486 100644 --- a/dao/replication_job.go +++ b/dao/replication_job.go @@ -177,10 +177,24 @@ func GetRepPolicyByProject(projectID int64) ([]*models.RepPolicy, error) { return policies, nil } +// GetRepPolicyByTarget ... +func GetRepPolicyByTarget(targetID int64) ([]*models.RepPolicy, error) { + o := GetOrmer() + sql := `select * from replication_policy where target_id = ?` + + var policies []*models.RepPolicy + + if _, err := o.Raw(sql, targetID).QueryRows(&policies); err != nil { + return nil, err + } + + return policies, nil +} + // UpdateRepPolicy ... func UpdateRepPolicy(policy *models.RepPolicy) error { o := GetOrmer() - _, err := o.Update(policy, "Name", "Enabled", "Description", "CronStr") + _, err := o.Update(policy, "TargetID", "Name", "Enabled", "Description", "CronStr") return err } From 3450b0160b2a4b3187a08e1c1624f141c471c671 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Thu, 16 Jun 2016 14:24:35 +0800 Subject: [PATCH 2/3] pass govet --- dao/dao_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index e69855842..f1908229f 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -922,7 +922,7 @@ func TestGetRepPolicyByTarget(t *testing.T) { } if policies[0].ID != policyID { - t.Fatal("unexpected policy: %d, expected: %d", policies[0].ID, policyID) + t.Fatalf("unexpected policy: %d, expected: %d", policies[0].ID, policyID) } } From d909405c1157965cfae1fc855f304ab72347d64a Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Thu, 16 Jun 2016 14:57:45 +0800 Subject: [PATCH 3/3] add header comment --- api/jobs/replication.go | 15 ++++++++ api/replication_job.go | 15 ++++++++ api/replication_policy.go | 15 ++++++++ dao/replication_job.go | 15 ++++++++ job/config/config.go | 15 ++++++++ job/replication/runner.go | 76 --------------------------------------- job/scheduler.go | 15 ++++++++ job/statehandlers.go | 15 ++++++++ job/statemachine.go | 15 ++++++++ job/utils/logger.go | 15 ++++++++ job/workerpool.go | 15 ++++++++ jobservice/main.go | 15 ++++++++ jobservice/router.go | 15 ++++++++ models/base.go | 15 ++++++++ models/replication_job.go | 15 ++++++++ 15 files changed, 210 insertions(+), 76 deletions(-) delete mode 100644 job/replication/runner.go diff --git a/api/jobs/replication.go b/api/jobs/replication.go index a9dda69b3..d62d4e4fe 100644 --- a/api/jobs/replication.go +++ b/api/jobs/replication.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 api import ( diff --git a/api/replication_job.go b/api/replication_job.go index 3edd63771..c5126bf95 100644 --- a/api/replication_job.go +++ b/api/replication_job.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 api import ( diff --git a/api/replication_policy.go b/api/replication_policy.go index 884f566c1..6eefaa087 100644 --- a/api/replication_policy.go +++ b/api/replication_policy.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 api import ( diff --git a/dao/replication_job.go b/dao/replication_job.go index f0dc7fb15..83a5b9d11 100644 --- a/dao/replication_job.go +++ b/dao/replication_job.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 ( diff --git a/job/config/config.go b/job/config/config.go index 650fa1188..fb5d86fbd 100644 --- a/job/config/config.go +++ b/job/config/config.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 config import ( diff --git a/job/replication/runner.go b/job/replication/runner.go deleted file mode 100644 index 075a1ee99..000000000 --- a/job/replication/runner.go +++ /dev/null @@ -1,76 +0,0 @@ -package replication - -/* -import ( - "encoding/json" - //"github.com/vmware/harbor/dao" - "github.com/vmware/harbor/job" - "github.com/vmware/harbor/models" - "time" -) - -const ( - jobType = "transfer_img_out" -) - -type Runner struct { - job.JobSM - Logger job.Logger - parm ImgOutParm -} - -type ImgPuller struct { - job.DummyHandler - img string - logger job.Logger -} - -func (ip ImgPuller) Enter() (string, error) { - ip.logger.Infof("I'm pretending to pull img:%s, then sleep 30s", ip.img) - time.Sleep(30 * time.Second) - ip.logger.Infof("wake up from sleep....") - return "push-img", nil -} - -type ImgPusher struct { - job.DummyHandler - targetURL string - logger job.Logger -} - -func (ip ImgPusher) Enter() (string, error) { - ip.logger.Infof("I'm pretending to push img to:%s, then sleep 30s", ip.targetURL) - time.Sleep(30 * time.Second) - ip.logger.Infof("wake up from sleep....") - return job.JobContinue, nil -} - -func init() { - job.Register(jobType, Runner{}) -} - -func (r Runner) Run(je models.JobEntry) error { - err := r.init(je) - if err != nil { - return err - } - r.Start(job.JobRunning) - return nil -} - -func (r *Runner) init(je models.JobEntry) error { - r.JobID = je.ID - r.InitJobSM() - err := json.Unmarshal([]byte(je.ParmsStr), &r.parm) - if err != nil { - return err - } - r.Logger = job.Logger{je.ID} - r.AddTransition(job.JobRunning, "pull-img", ImgPuller{DummyHandler: job.DummyHandler{JobID: r.JobID}, img: r.parm.Image, logger: r.Logger}) - //only handle on target for now - url := r.parm.Targets[0].URL - r.AddTransition("pull-img", "push-img", ImgPusher{DummyHandler: job.DummyHandler{JobID: r.JobID}, targetURL: url, logger: r.Logger}) - r.AddTransition("push-img", job.JobFinished, job.StatusUpdater{job.DummyHandler{JobID: r.JobID}, job.JobFinished}) - return nil -} -*/ diff --git a/job/scheduler.go b/job/scheduler.go index 387d92942..fddfdcafe 100644 --- a/job/scheduler.go +++ b/job/scheduler.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 job var jobQueue = make(chan int64) diff --git a/job/statehandlers.go b/job/statehandlers.go index 15907396b..60e852422 100644 --- a/job/statehandlers.go +++ b/job/statehandlers.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 job import ( diff --git a/job/statemachine.go b/job/statemachine.go index 5c8233988..94c892a70 100644 --- a/job/statemachine.go +++ b/job/statemachine.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 job import ( diff --git a/job/utils/logger.go b/job/utils/logger.go index 0a245753c..47c9f72a0 100644 --- a/job/utils/logger.go +++ b/job/utils/logger.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 utils import ( diff --git a/job/workerpool.go b/job/workerpool.go index 0d6d2e352..c01273ba3 100644 --- a/job/workerpool.go +++ b/job/workerpool.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 job import ( diff --git a/jobservice/main.go b/jobservice/main.go index 10ea2ae79..6f17eb9c5 100644 --- a/jobservice/main.go +++ b/jobservice/main.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 main import ( diff --git a/jobservice/router.go b/jobservice/router.go index e917fcc90..f1705d1af 100644 --- a/jobservice/router.go +++ b/jobservice/router.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 main import ( diff --git a/models/base.go b/models/base.go index 52ac63925..a36300955 100644 --- a/models/base.go +++ b/models/base.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 ( diff --git a/models/replication_job.go b/models/replication_job.go index c3bf6be86..80eb1b36b 100644 --- a/models/replication_job.go +++ b/models/replication_job.go @@ -1,3 +1,18 @@ +/* + Copyright (c) 2016 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 (