Merge pull request #3696 from swordqiu/hotfix/qj-aliyun-delete-network-failed

fix: network-delete may fail immidiately after deleting vm
This commit is contained in:
Zexi Li
2019-11-15 18:41:30 +08:00
committed by GitHub
9 changed files with 235 additions and 2 deletions
+13 -1
View File
@@ -418,7 +418,7 @@ func init() {
})
type NetworkAddressOptions struct {
NETWORK string `help:"if of network to query"`
NETWORK string `help:"id or name of network to query"`
}
R(&NetworkAddressOptions{}, "network-addresses", "Query used addresses of network", func(s *mcclient.ClientSession, args *NetworkAddressOptions) error {
result, err := modules.Networks.GetSpecific(s, args.NETWORK, "addresses", nil)
@@ -433,4 +433,16 @@ func init() {
printList(&listResult, nil)
return nil
})
type NetworkSyncOptions struct {
NETWORK string `help:"id or name of network to sync"`
}
R(&NetworkSyncOptions{}, "network-sync", "Sync network status", func(s *mcclient.ClientSession, args *NetworkSyncOptions) error {
result, err := modules.Networks.PerformAction(s, args.NETWORK, "sync", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+9
View File
@@ -158,4 +158,13 @@ func init() {
printObject(result)
return nil
})
R(&VpcUpdateStatusOptions{}, "vpc-sync", "Synchronize the status of a vpc", func(s *mcclient.ClientSession, args *VpcUpdateStatusOptions) error {
result, err := modules.Vpcs.PerformAction(s, args.ID, "sync", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+2
View File
@@ -40,6 +40,8 @@ const (
NETWORK_STATUS_DELETING = "deleting"
NETWORK_STATUS_DELETED = "deleted"
NETWORK_STATUS_DELETE_FAILED = "delete_failed"
NETWORK_STATUS_START_SYNC = "start_sync"
NETWORK_STATUS_SYNCING = "sync"
)
var (
+2
View File
@@ -24,6 +24,8 @@ const (
VPC_STATUS_DELETE_FAILED = "delete_failed"
VPC_STATUS_DELETED = "deleted"
VPC_STATUS_UNKNOWN = "unknown"
VPC_STATUS_START_SYNC = "start_sync"
VPC_STATUS_SYNCING = "sync"
MAX_VPC_PER_REGION = 3
+25
View File
@@ -2418,3 +2418,28 @@ func (network *SNetwork) GetDetailsAddresses(ctx context.Context, userCred mccli
result.Add(jsonutils.Marshal(netAddrs), "addresses")
return result, nil
}
func (net *SNetwork) AllowPerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return net.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, net, "sync")
}
func (net *SNetwork) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
vpc := net.GetVpc()
if vpc != nil && vpc.IsManaged() {
err := net.StartNetworkSyncstatusTask(ctx, userCred, "")
return nil, err
} else {
return nil, httperrors.NewUnsupportOperationError("on-premise network cannot sync status")
}
}
func (net *SNetwork) StartNetworkSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "NetworkSyncstatusTask", net, userCred, nil, parentTaskId, "", nil)
if err != nil {
log.Errorf("create NetworkSyncstatusTask fail %s", err)
return err
}
net.SetStatus(userCred, api.NETWORK_STATUS_START_SYNC, "synchronize")
task.ScheduleRun(nil)
return nil
}
+24
View File
@@ -763,3 +763,27 @@ func (self *SVpc) SyncRemoteWires(ctx context.Context, userCred mcclient.TokenCr
}
return nil
}
func (vpc *SVpc) AllowPerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, vpc, "sync")
}
func (vpc *SVpc) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if vpc.IsManaged() {
err := vpc.StartVpcSyncstatusTask(ctx, userCred, "")
return nil, err
} else {
return nil, httperrors.NewUnsupportOperationError("on-premise vpc cannot sync status")
}
}
func (vpc *SVpc) StartVpcSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "VpcSyncstatusTask", vpc, userCred, nil, parentTaskId, "", nil)
if err != nil {
log.Errorf("create NetworkSyncstatusTask fail %s", err)
return err
}
vpc.SetStatus(userCred, api.VPC_STATUS_START_SYNC, "synchronize")
task.ScheduleRun(nil)
return nil
}
@@ -0,0 +1,73 @@
// Copyright 2019 Yunion
//
// 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 tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type NetworkSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(NetworkSyncstatusTask{})
}
func (self *NetworkSyncstatusTask) taskFail(ctx context.Context, net *models.SNetwork, msg string) {
net.SetStatus(self.UserCred, api.NETWORK_STATUS_UNKNOWN, msg)
db.OpsLog.LogEvent(net, db.ACT_SYNC_STATUS, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, net, logclient.ACT_SYNC_STATUS, msg, self.UserCred, false)
self.SetStageFailed(ctx, msg)
}
func (self *NetworkSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
net := obj.(*models.SNetwork)
net.SetStatus(self.UserCred, api.NETWORK_STATUS_SYNCING, "synchronize")
extNet, err := net.GetINetwork()
if err != nil {
msg := fmt.Sprintf("fail to find ICloudNetwork for network %s", err)
self.taskFail(ctx, net, msg)
return
}
err = extNet.Refresh()
if err != nil {
msg := fmt.Sprintf("fail to refresh ICloudNetwork status %s", err)
self.taskFail(ctx, net, msg)
return
}
err = net.SyncWithCloudNetwork(ctx, self.UserCred, extNet, nil)
if err != nil {
msg := fmt.Sprintf("fail to sync network status %s", err)
self.taskFail(ctx, net, msg)
return
}
logclient.AddActionLogWithStartable(self, net, logclient.ACT_SYNC_STATUS, nil, self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2019 Yunion
//
// 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 tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type VpcSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(VpcSyncstatusTask{})
}
func (self *VpcSyncstatusTask) taskFail(ctx context.Context, vpc *models.SVpc, msg string) {
vpc.SetStatus(self.UserCred, api.VPC_STATUS_UNKNOWN, msg)
db.OpsLog.LogEvent(vpc, db.ACT_SYNC_STATUS, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, vpc, logclient.ACT_SYNC_STATUS, msg, self.UserCred, false)
self.SetStageFailed(ctx, msg)
}
func (self *VpcSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
vpc := obj.(*models.SVpc)
vpc.SetStatus(self.UserCred, api.VPC_STATUS_SYNCING, "synchronize")
extVpc, err := vpc.GetIVpc()
if err != nil {
msg := fmt.Sprintf("fail to find ICloudVpc for vpc %s", err)
self.taskFail(ctx, vpc, msg)
return
}
err = extVpc.Refresh()
if err != nil {
msg := fmt.Sprintf("fail to refresh ICloudVpc status %s", err)
self.taskFail(ctx, vpc, msg)
return
}
err = vpc.SyncWithCloudVpc(ctx, self.UserCred, extVpc)
if err != nil {
msg := fmt.Sprintf("fail to sync vpc status %s", err)
self.taskFail(ctx, vpc, msg)
return
}
logclient.AddActionLogWithStartable(self, vpc, logclient.ACT_SYNC_STATUS, nil, self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
+14 -1
View File
@@ -186,7 +186,20 @@ func (self *SVSwitch) Delete() error {
log.Errorf("fail to dissociateWithSNAT")
return err
}
return self.wire.zone.region.DeleteVSwitch(self.VSwitchId)
err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) {
err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId)
if err != nil {
// delete network immediately after deleting vm on it
// \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"}
if isError(err, "DependencyViolation") {
return false, nil
}
return false, err
} else {
return true, nil
}
})
return err
}
func (self *SVSwitch) GetAllocTimeoutSeconds() int {