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 }