diff --git a/cmd/climc/shell/elasticips.go b/cmd/climc/shell/elasticips.go index cb5d12073f..054283940c 100644 --- a/cmd/climc/shell/elasticips.go +++ b/cmd/climc/shell/elasticips.go @@ -12,6 +12,7 @@ func init() { type ElasticipListOptions struct { Manager string `help:"Show servers imported from manager"` Region string `help:"Show servers in cloudregion"` + Usable bool `help:"List all zones that is usable"` options.BaseListOptions } @@ -30,6 +31,9 @@ func init() { if len(args.Region) > 0 { params.Add(jsonutils.NewString(args.Region), "region") } + if args.Usable { + params.Add(jsonutils.JSONTrue, "usable") + } results, err := modules.Elasticips.List(s, params) if err != nil { return err diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index 8ba88c35bd..87f812c6e8 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -12,7 +12,6 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" - "strings" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -109,6 +108,14 @@ func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("cloudregion_id", regionObj.GetId()) } + if query.Contains("usable") { + usable := jsonutils.QueryBoolean(query, "usable", false) + if usable { + q = q.Equals("status", EIP_STATUS_READY) + q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("associate_id")), sqlchemy.IsEmpty(q.Field("associate_id")))) + } + } + return q, nil } @@ -612,12 +619,12 @@ func (self *SElasticip) AllowPerformSync(ctx context.Context, userCred mcclient. } func (self *SElasticip) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if self.Status != EIP_STATUS_READY && !strings.HasSuffix(self.Status, "_fail") { + /*if self.Status != EIP_STATUS_READY && !strings.HasSuffix(self.Status, "_fail") { return nil, httperrors.NewInvalidStatusError("eip cannot syncstatus in status %s", self.Status) - } + }*/ if self.Mode == EIP_MODE_INSTANCE_PUBLICIP { - return nil, httperrors.NewUnsupportOperationError("fixed eip cannot be dissociated") + return nil, httperrors.NewUnsupportOperationError("fixed eip cannot sync status") } err := self.StartEipSyncstatusTask(ctx, userCred, "") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7af81276a6..9c58205648 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -988,6 +988,7 @@ func (self *SGuest) GetCustomizeColumns(ctx context.Context, userCred mcclient.T eip, _ := self.GetEip() if eip != nil { extra.Add(jsonutils.NewString(eip.IpAddr), "eip") + extra.Add(jsonutils.NewString(eip.Mode), "eip_mode") } extra.Add(jsonutils.NewInt(int64(self.getDiskSize())), "disk") // flavor?? @@ -1062,6 +1063,7 @@ func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.Token eip, _ := self.GetEip() if eip != nil { extra.Add(jsonutils.NewString(eip.IpAddr), "eip") + extra.Add(jsonutils.NewString(eip.Mode), "eip_mode") } return self.moreExtraInfo(extra) } @@ -4369,6 +4371,9 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke if err != nil { return nil, httperrors.NewGeneralError(err) } + + self.SetStatus(userCred, VM_ASSOCIATE_EIP, "allocate and associate EIP") + return nil, nil } diff --git a/pkg/compute/tasks/eip_associate_task.go b/pkg/compute/tasks/eip_associate_task.go index 77bf7077d5..f4d3aa4e41 100644 --- a/pkg/compute/tasks/eip_associate_task.go +++ b/pkg/compute/tasks/eip_associate_task.go @@ -19,14 +19,21 @@ func init() { taskman.RegisterTask(EipAssociateTask{}) } +func (self *EipAssociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg string, vm *models.SGuest) { + eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) + self.SetStageFailed(ctx, msg) + if vm != nil { + vm.StartSyncstatus(ctx, self.UserCred, "") + } +} + func (self *EipAssociateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { eip := obj.(*models.SElasticip) extEip, err := eip.GetIEip() if err != nil { msg := fmt.Sprintf("fail to find iEIP for eip %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, nil) return } @@ -39,24 +46,21 @@ func (self *EipAssociateTask) OnInit(ctx context.Context, obj db.IStandaloneMode if server == nil { msg := fmt.Sprintf("fail to find server for instanceId %s", instanceId) - eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, nil) return } err = extEip.Associate(server.ExternalId) if err != nil { msg := fmt.Sprintf("fail to remote associate EIP %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, server) return } err = eip.AssociateVM(self.UserCred, server) if err != nil { msg := fmt.Sprintf("fail to local associate EIP %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, server) return } diff --git a/pkg/compute/tasks/eip_change_bandwidth_task.go b/pkg/compute/tasks/eip_change_bandwidth_task.go index 2900a7cdf8..fa61b92fe8 100644 --- a/pkg/compute/tasks/eip_change_bandwidth_task.go +++ b/pkg/compute/tasks/eip_change_bandwidth_task.go @@ -25,6 +25,7 @@ func (self *EipChangeBandwidthTask) OnInit(ctx context.Context, obj db.IStandalo extEip, err := eip.GetIEip() if err != nil { + eip.SetStatus(self.UserCred, models.EIP_STATUS_READY, "fail to change bandwidth") msg := fmt.Sprintf("fail to find iEip %s", err) self.SetStageFailed(ctx, msg) return @@ -32,6 +33,7 @@ func (self *EipChangeBandwidthTask) OnInit(ctx context.Context, obj db.IStandalo bandwidth, _ := self.Params.Int("bandwidth") if bandwidth <= 0 { + eip.SetStatus(self.UserCred, models.EIP_STATUS_READY, "fail to change bandwidth") msg := fmt.Sprintf("invalid bandwidth %d", bandwidth) self.SetStageFailed(ctx, msg) return @@ -40,6 +42,7 @@ func (self *EipChangeBandwidthTask) OnInit(ctx context.Context, obj db.IStandalo err = extEip.ChangeBandwidth(int(bandwidth)) if err != nil { + eip.SetStatus(self.UserCred, models.EIP_STATUS_READY, "fail to change bandwidth") msg := fmt.Sprintf("fail to find iEip %s", err) self.SetStageFailed(ctx, msg) return diff --git a/pkg/compute/tasks/eip_dissociate_task.go b/pkg/compute/tasks/eip_dissociate_task.go index cc77e02e8e..30658ead59 100644 --- a/pkg/compute/tasks/eip_dissociate_task.go +++ b/pkg/compute/tasks/eip_dissociate_task.go @@ -20,6 +20,14 @@ func init() { taskman.RegisterTask(EipDissociateTask{}) } +func (self *EipDissociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg string, vm *models.SGuest) { + eip.SetStatus(self.UserCred, models.EIP_STATUS_DISSOCIATE_FAIL, msg) + self.SetStageFailed(ctx, msg) + if vm != nil { + vm.StartSyncstatus(ctx, self.UserCred, "") + } +} + func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { eip := obj.(*models.SElasticip) @@ -33,8 +41,7 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod extEip, err := eip.GetIEip() if err != nil { msg := fmt.Sprintf("fail to find iEIP for eip %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_DISSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, server) return } @@ -42,8 +49,7 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod err = extEip.Dissociate() if err != nil { msg := fmt.Sprintf("fail to remote dissociate eip %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_DISSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, server) return } } @@ -51,8 +57,7 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod err = eip.Dissociate(ctx, self.UserCred) if err != nil { msg := fmt.Sprintf("fail to local dissociate eip %s", err) - eip.SetStatus(self.UserCred, models.EIP_STATUS_DISSOCIATE_FAIL, msg) - self.SetStageFailed(ctx, msg) + self.TaskFail(ctx, eip, msg, server) return }