1.only target of disabled policy can be modified 2.duplicated policy can not be created

This commit is contained in:
Wenkai Yin 2016-06-22 14:19:19 +08:00
parent 0a0b206863
commit b985c5bed4
5 changed files with 205 additions and 57 deletions

View File

@ -1,16 +1,16 @@
/*
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.
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
@ -121,6 +121,16 @@ func (pa *RepPolicyAPI) Post() {
pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("target %d does not exist", policy.TargetID))
}
policies, err := dao.GetRepPolicyByProjectAndTarget(policy.ProjectID, policy.TargetID)
if err != nil {
log.Errorf("failed to get policy [project ID: %d,targetID: %d]: %v", policy.ProjectID, policy.TargetID, err)
pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if len(policies) > 0 {
pa.CustomAbort(http.StatusConflict, "policy already exists with the same project and target")
}
pid, err := dao.AddRepPolicy(*policy)
if err != nil {
log.Errorf("Failed to add policy to DB, error: %v", err)
@ -159,6 +169,7 @@ func (pa *RepPolicyAPI) Put() {
policy.ProjectID = originalPolicy.ProjectID
pa.Validate(policy)
// check duplicate name
if policy.Name != originalPolicy.Name {
po, err := dao.GetRepPolicyByName(policy.Name)
if err != nil {
@ -172,6 +183,12 @@ func (pa *RepPolicyAPI) Put() {
}
if policy.TargetID != originalPolicy.TargetID {
//target of policy can not be modified when the policy is enabled
if originalPolicy.Enabled == 1 {
pa.CustomAbort(http.StatusBadRequest, "target of policy can not be modified when the policy is enabled")
}
// check the existance of target
target, err := dao.GetRepTarget(policy.TargetID)
if err != nil {
log.Errorf("failed to get target %d: %v", policy.TargetID, err)
@ -181,67 +198,90 @@ func (pa *RepPolicyAPI) Put() {
if target == nil {
pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("target %d does not exist", policy.TargetID))
}
// check duplicate policy with the same project and target
policies, err := dao.GetRepPolicyByProjectAndTarget(policy.ProjectID, policy.TargetID)
if err != nil {
log.Errorf("failed to get policy [project ID: %d,targetID: %d]: %v", policy.ProjectID, policy.TargetID, err)
pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if len(policies) > 0 {
pa.CustomAbort(http.StatusConflict, "policy already exists with the same project and target")
}
}
policy.ID = id
isTargetChanged := !(policy.TargetID == originalPolicy.TargetID)
isEnablementChanged := !(policy.Enabled == policy.Enabled)
/*
isTargetChanged := !(policy.TargetID == originalPolicy.TargetID)
isEnablementChanged := !(policy.Enabled == policy.Enabled)
var shouldStop, shouldTrigger bool
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
// 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 {
// 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
// both target and enablement are changed
// enablement: 1 -> 0
if policy.Enabled == 0 {
shouldStop = true
shouldTrigger = false
} else {
shouldStop = false
shouldTrigger = true
// 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)
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))
}
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 shouldTrigger {
go func() {
if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil {
log.Errorf("failed to trigger replication of %d: %v", id, err)
} else {
log.Infof("replication of %d triggered", id)
}
}()
}
*/
if shouldTrigger {
if policy.Enabled != originalPolicy.Enabled && policy.Enabled == 1 {
go func() {
if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil {
log.Errorf("failed to trigger replication of %d: %v", id, err)

View File

@ -190,6 +190,16 @@ func (t *TargetAPI) Post() {
t.CustomAbort(http.StatusConflict, "name is already used")
}
ta, err = dao.GetRepTargetByConnInfo(target.URL, target.Username)
if err != nil {
log.Errorf("failed to get target [ %s %s ]: %v", target.URL, target.Username, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if ta != nil {
t.CustomAbort(http.StatusConflict, "the connection information[ endpoint, username ] is conflict with other target")
}
if len(target.Password) != 0 {
target.Password = utils.ReversibleEncrypt(target.Password)
}
@ -217,6 +227,24 @@ func (t *TargetAPI) Put() {
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))
}
hasEnabledPolicy := false
for _, policy := range policies {
if policy.Enabled == 1 {
hasEnabledPolicy = true
break
}
}
if hasEnabledPolicy {
t.CustomAbort(http.StatusBadRequest, "the target is associated with policy which is enabled")
}
target := &models.RepTarget{}
t.DecodeJSONReqAndValidate(target)
@ -232,6 +260,18 @@ func (t *TargetAPI) Put() {
}
}
if target.URL != originalTarget.URL || target.Username != originalTarget.Username {
ta, err := dao.GetRepTargetByConnInfo(target.URL, target.Username)
if err != nil {
log.Errorf("failed to get target [ %s %s ]: %v", target.URL, target.Username, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if ta != nil {
t.CustomAbort(http.StatusConflict, "the connection information[ endpoint, username ] is conflict with other target")
}
}
target.ID = id
if len(target.Password) != 0 {
@ -273,3 +313,27 @@ func (t *TargetAPI) Delete() {
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
}
// ListPolicies ...
func (t *TargetAPI) ListPolicies() {
id := t.GetIDFromURL()
target, err := dao.GetRepTarget(id)
if err != nil {
log.Errorf("failed to get target %d: %v", id, err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if target == nil {
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))
}
t.Data["json"] = policies
t.ServeJSON()
}

View File

@ -926,6 +926,21 @@ func TestGetRepPolicyByTarget(t *testing.T) {
}
}
func TestGetRepPolicyByProjectAndTarget(t *testing.T) {
policies, err := GetRepPolicyByProjectAndTarget(1, targetID)
if err != nil {
t.Fatalf("failed to get policy according project %d and target %d: %v", 1, targetID, err)
}
if len(policies) == 0 {
t.Fatal("unexpected length of policies 0, expected is >0")
}
if policies[0].ID != policyID {
t.Fatalf("unexpected policy: %d, expected: %d", policies[0].ID, policyID)
}
}
func TestGetRepPolicyByName(t *testing.T) {
policy, err := GetRepPolicy(policyID)
if err != nil {

View File

@ -52,6 +52,20 @@ func GetRepTargetByName(name string) (*models.RepTarget, error) {
return &t, err
}
// GetRepTargetByConnInfo ...
func GetRepTargetByConnInfo(endpoint, username string) (*models.RepTarget, error) {
o := GetOrmer()
t := models.RepTarget{
URL: endpoint,
Username: username,
}
err := o.Read(&t, "URL", "Username")
if err == orm.ErrNoRows {
return nil, nil
}
return &t, err
}
// DeleteRepTarget ...
func DeleteRepTarget(id int64) error {
o := GetOrmer()
@ -206,6 +220,20 @@ func GetRepPolicyByTarget(targetID int64) ([]*models.RepPolicy, error) {
return policies, nil
}
// GetRepPolicyByProjectAndTarget ...
func GetRepPolicyByProjectAndTarget(projectID, targetID int64) ([]*models.RepPolicy, error) {
o := GetOrmer()
sql := `select * from replication_policy where project_id = ? and target_id = ?`
var policies []*models.RepPolicy
if _, err := o.Raw(sql, projectID, targetID).QueryRows(&policies); err != nil {
return nil, err
}
return policies, nil
}
// UpdateRepPolicy ...
func UpdateRepPolicy(policy *models.RepPolicy) error {
o := GetOrmer()

View File

@ -76,6 +76,7 @@ func initRouters() {
beego.Router("/api/targets/", &api.TargetAPI{}, "get:List")
beego.Router("/api/targets/", &api.TargetAPI{}, "post:Post")
beego.Router("/api/targets/:id([0-9]+)", &api.TargetAPI{})
beego.Router("/api/targets/:id([0-9]+)/policies/", &api.TargetAPI{}, "get:ListPolicies")
beego.Router("/api/targets/ping", &api.TargetAPI{}, "post:Ping")
beego.Router("/api/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")
beego.Router("/api/repositories/top", &api.RepositoryAPI{}, "get:GetTopRepos")