diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index 1ddf75db9f..f87f205bcf 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -905,6 +905,34 @@ func (self *SElasticip) PerformDissociate(ctx context.Context, userCred mcclient return nil, httperrors.NewUnsupportOperationError("fixed public eip cannot be dissociated") } + if self.AssociateType == api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY { + model, err := NatGatewayManager.FetchById(self.AssociateId) + if err != nil { + return nil, errors.Wrapf(err, "fail to fetch natgateway %s", self.AssociateId) + } + natgateway := model.(*SNatGateway) + sCount, err := natgateway.GetSTableSize(func(q *sqlchemy.SQuery) *sqlchemy.SQuery { + return q.Equals("ip", self.IpAddr) + }) + if err != nil { + return nil, errors.Wrapf(err, "fail to get stable size of natgateway %s", self.AssociateId) + } + if sCount > 0 { + return nil, httperrors.NewUnsupportOperationError( + "the associated natgateway has corresponding snat rules with eip %s, please delete them firstly", self.IpAddr) + } + dCount, err := natgateway.GetDTableSize(func(q *sqlchemy.SQuery) *sqlchemy.SQuery { + return q.Equals("external_ip", self.IpAddr) + }) + if err != nil { + return nil, errors.Wrapf(err, "fail to get dtable size of natgateway %s", self.AssociateId) + } + if dCount > 0 { + return nil, httperrors.NewUnsupportOperationError( + "the associated natgateway has corresponding dnat rules with eip %s, please delete them firstly", self.IpAddr) + } + } + autoDelete := jsonutils.QueryBoolean(data, "auto_delete", false) err := self.StartEipDissociateTask(ctx, userCred, autoDelete, "") @@ -992,9 +1020,9 @@ func (self *SElasticip) GetCustomizeColumns(ctx context.Context, userCred mcclie func (self *SElasticip) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict { info := self.getCloudProviderInfo() extra.Update(jsonutils.Marshal(&info)) - vm := self.GetAssociateVM() - if vm != nil { - extra.Add(jsonutils.NewString(vm.GetName()), "associate_name") + instance := self.GetAssociateResource() + if instance != nil { + extra.Add(jsonutils.NewString(instance.GetName()), "associate_name") } return extra } diff --git a/pkg/compute/models/natgateways.go b/pkg/compute/models/natgateways.go index fe2a92128a..d2b9d13ca6 100644 --- a/pkg/compute/models/natgateways.go +++ b/pkg/compute/models/natgateways.go @@ -230,6 +230,18 @@ func (self *SNatGateway) GetSTable() ([]SNatSEntry, error) { return tables, nil } +func (self *SNatGateway) GetSTableSize(filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) (int, error) { + q := NatSEntryManager.Query().Equals("natgateway_id", self.Id) + q = filter(q) + return q.CountWithError() +} + +func (self *SNatGateway) GetDTableSize(filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) (int, error) { + q := NatDEntryManager.Query().Equals("natgateway_id", self.Id) + q = filter(q) + return q.CountWithError() +} + func (self *SNatGateway) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) { extra, err := self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query) if err != nil { diff --git a/pkg/compute/tasks/eip_associate_task.go b/pkg/compute/tasks/eip_associate_task.go index 615acf8ae7..7ef1caf53e 100644 --- a/pkg/compute/tasks/eip_associate_task.go +++ b/pkg/compute/tasks/eip_associate_task.go @@ -43,6 +43,7 @@ func (self *EipAssociateTask) TaskFail(ctx context.Context, eip *models.SElastic db.OpsLog.LogEvent(vm, db.ACT_EIP_ATTACH, msg, self.GetUserCred()) logclient.AddActionLogWithStartable(self, vm, logclient.ACT_EIP_ASSOCIATE, msg, self.UserCred, false) } + logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, msg, self.UserCred, false) } func (self *EipAssociateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -86,6 +87,7 @@ func (self *EipAssociateTask) OnInit(ctx context.Context, obj db.IStandaloneMode server.StartSyncstatus(ctx, self.UserCred, "") logclient.AddActionLogWithStartable(self, server, logclient.ACT_EIP_ASSOCIATE, nil, self.UserCred, true) + logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, nil, self.UserCred, true) self.SetStageComplete(ctx, nil) } diff --git a/pkg/compute/tasks/eip_dissociate_task.go b/pkg/compute/tasks/eip_dissociate_task.go index 318fd733e6..fdd32ad219 100644 --- a/pkg/compute/tasks/eip_dissociate_task.go +++ b/pkg/compute/tasks/eip_dissociate_task.go @@ -39,13 +39,22 @@ func init() { func (self *EipDissociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg string, model db.IModel) { eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, msg) self.SetStageFailed(ctx, msg) + var logOp string if model != nil { switch srv := model.(type) { case *models.SGuest: srv.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, msg) + logOp = logclient.ACT_VM_DISSOCIATE + case *models.SNatGateway: + srv.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, msg) + logOp = logclient.ACT_NATGATEWAY_DISSOCIATE + case *models.SLoadbalancer: + srv.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, msg) + logOp = logclient.ACT_LOADBALANCER_DISSOCIATE } db.OpsLog.LogEvent(model, db.ACT_EIP_DETACH, msg, self.GetUserCred()) logclient.AddActionLogWithStartable(self, model, logclient.ACT_EIP_DISSOCIATE, msg, self.UserCred, false) + logclient.AddActionLogWithStartable(self, model, logOp, msg, self.UserCred, false) } } @@ -54,17 +63,23 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod if eip.IsAssociated() { - var model db.IModel + var ( + model db.IModel + logOp string + ) if server := eip.GetAssociateVM(); server != nil { if server.Status != api.VM_DISSOCIATE_EIP { server.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP, "dissociate eip") } model = server + logOp = logclient.ACT_VM_DISSOCIATE } else if lb := eip.GetAssociateLoadbalancer(); lb != nil { model = lb + logOp = logclient.ACT_LOADBALANCER_DISSOCIATE } else if nat := eip.GetAssociateNatGateway(); nat != nil { model = nat + logOp = logclient.ACT_NATGATEWAY_DISSOCIATE } else { self.TaskFail(ctx, eip, "unsupported associate type", nil) return @@ -96,6 +111,7 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, "dissociate") logclient.AddActionLogWithStartable(self, model, logclient.ACT_EIP_DISSOCIATE, nil, self.UserCred, true) + logclient.AddActionLogWithStartable(self, eip, logOp, nil, self.UserCred, true) switch srv := model.(type) { case *models.SGuest: diff --git a/pkg/util/logclient/consts.go b/pkg/util/logclient/consts.go index 19ebbb64a1..7d3248d1c6 100644 --- a/pkg/util/logclient/consts.go +++ b/pkg/util/logclient/consts.go @@ -164,4 +164,9 @@ const ( ACT_SET_PRIVILEGES = "设置权限" ACT_RESTORE = "备份恢复" ACT_RESET_PASSWORD = "重置密码" + + ACT_VM_ASSOCIATE = "绑定虚拟机" + ACT_VM_DISSOCIATE = "解绑虚拟机" + ACT_NATGATEWAY_DISSOCIATE = "解绑NAT网关" + ACT_LOADBALANCER_DISSOCIATE = "解绑负载均衡" )