mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(region): vendor update (#18514)
This commit is contained in:
@@ -83,7 +83,7 @@ require (
|
||||
k8s.io/client-go v0.19.3
|
||||
k8s.io/cluster-bootstrap v0.19.3
|
||||
moul.io/http2curl/v2 v2.3.0
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231030120705-5126f7c5ebf9
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231031085052-d71eeaca4339
|
||||
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32
|
||||
yunion.io/x/jsonutils v1.0.1-0.20230613121553-0f3b41e2ef19
|
||||
yunion.io/x/log v1.0.1-0.20230411060016-feb3f46ab361
|
||||
|
||||
@@ -1179,8 +1179,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231030120705-5126f7c5ebf9 h1:e6Y3fZG62CKcu+Bz0zF6UuVng25q1KpBKOV+6WreCxw=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231030120705-5126f7c5ebf9/go.mod h1:McRjoG2gaOUisB+Qa41kLCNZhr0lsCu4apEjTiphXVY=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231031085052-d71eeaca4339 h1:uAlX4Be/OdE0wDCMkk3OdU/LXZT4AWP/+/bmjgfTiZY=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231031085052-d71eeaca4339/go.mod h1:McRjoG2gaOUisB+Qa41kLCNZhr0lsCu4apEjTiphXVY=
|
||||
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32 h1:v7POYkQwo1XzOxBoIoRVr/k0V9Y5JyjpshlIFa9raug=
|
||||
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
|
||||
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
|
||||
|
||||
@@ -826,7 +826,7 @@ func (cprvd *SCloudprovider) markEndSyncWithLock(ctx context.Context, userCred m
|
||||
return nil
|
||||
}
|
||||
|
||||
if cprvd.getSyncStatus2() != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
|
||||
if cprvd.GetSyncStatus2() != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1555,6 +1555,23 @@ func (provider *SCloudprovider) GetRegions() ([]SCloudregion, error) {
|
||||
return ret, db.FetchModelObjects(CloudregionManager, q, &ret)
|
||||
}
|
||||
|
||||
func (provider *SCloudprovider) GetUsableRegions() ([]SCloudregion, error) {
|
||||
q := CloudregionManager.Query()
|
||||
crcp := CloudproviderRegionManager.Query().SubQuery()
|
||||
q = q.Join(crcp, sqlchemy.Equals(q.Field("id"), crcp.Field("cloudregion_id"))).Filter(
|
||||
sqlchemy.AND(
|
||||
sqlchemy.Equals(crcp.Field("cloudprovider_id"), provider.Id),
|
||||
sqlchemy.IsTrue(crcp.Field("enabled")),
|
||||
),
|
||||
)
|
||||
ret := []SCloudregion{}
|
||||
err := db.FetchModelObjects(CloudregionManager, q, &ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (provider *SCloudprovider) resetAutoSync() {
|
||||
cprs := provider.GetCloudproviderRegions()
|
||||
for i := range cprs {
|
||||
@@ -1760,7 +1777,7 @@ func (manager *SCloudproviderManager) FilterByOwner(q *sqlchemy.SQuery, man db.F
|
||||
return q
|
||||
}
|
||||
|
||||
func (cprvd *SCloudprovider) getSyncStatus2() string {
|
||||
func (cprvd *SCloudprovider) GetSyncStatus2() string {
|
||||
q := CloudproviderRegionManager.Query()
|
||||
q = q.Equals("cloudprovider_id", cprvd.Id)
|
||||
q = q.NotEquals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
|
||||
|
||||
@@ -172,6 +172,29 @@ func (self *SCloudregion) GetGuestCount() (int, error) {
|
||||
return self.getGuestCountInternal(false)
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetManagedGuestsQuery(managerId string) *sqlchemy.SQuery {
|
||||
q := GuestManager.Query().IsNotEmpty("external_id")
|
||||
hosts := HostManager.Query().Equals("manager_id", managerId).SubQuery()
|
||||
zones := ZoneManager.Query().Equals("cloudregion_id", self.Id).SubQuery()
|
||||
q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id")))
|
||||
q = q.Join(zones, sqlchemy.Equals(hosts.Field("zone_id"), zones.Field("id")))
|
||||
return q
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetManagedGuests(managerId string) ([]SGuest, error) {
|
||||
q := self.GetManagedGuestsQuery(managerId)
|
||||
ret := []SGuest{}
|
||||
err := db.FetchModelObjects(GuestManager, q, &ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetManagedGuestsCount(managerId string) (int, error) {
|
||||
return self.GetManagedGuestsQuery(managerId).CountWithError()
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetGuestIncrementCount() (int, error) {
|
||||
return self.getGuestCountInternal(true)
|
||||
}
|
||||
|
||||
@@ -2879,7 +2879,7 @@ func (self *SGuest) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion,
|
||||
return host.GetIRegion(ctx)
|
||||
}
|
||||
|
||||
func (self *SGuest) syncRemoveCloudVM(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
func (self *SGuest) SyncRemoveCloudVM(ctx context.Context, userCred mcclient.TokenCredential, check bool) error {
|
||||
lockman.LockObject(ctx, self)
|
||||
defer lockman.ReleaseObject(ctx, self)
|
||||
|
||||
@@ -2903,32 +2903,43 @@ func (self *SGuest) syncRemoveCloudVM(ctx context.Context, userCred mcclient.Tok
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(self.ExternalId) == 0 {
|
||||
return self.purge(ctx, userCred)
|
||||
}
|
||||
iVM, err := iregion.GetIVMById(self.ExternalId)
|
||||
if err == nil { //漂移归位
|
||||
if hostId := iVM.GetIHostId(); len(hostId) > 0 {
|
||||
host, err := db.FetchByExternalIdAndManagerId(HostManager, hostId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
||||
host, _ := self.GetHost()
|
||||
if host != nil {
|
||||
return q.Equals("manager_id", host.ManagerId)
|
||||
}
|
||||
return q
|
||||
})
|
||||
if err == nil {
|
||||
_, err = db.Update(self, func() error {
|
||||
self.HostId = host.GetId()
|
||||
self.Status = iVM.GetStatus()
|
||||
self.PowerStates = iVM.GetPowerStates()
|
||||
self.inferPowerStates()
|
||||
return nil
|
||||
|
||||
if check {
|
||||
iVM, err := iregion.GetIVMById(self.ExternalId)
|
||||
if err == nil { //漂移归位
|
||||
if hostId := iVM.GetIHostId(); len(hostId) > 0 {
|
||||
host, err := db.FetchByExternalIdAndManagerId(HostManager, hostId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
||||
host, _ := self.GetHost()
|
||||
if host != nil {
|
||||
return q.Equals("manager_id", host.ManagerId)
|
||||
}
|
||||
return q
|
||||
})
|
||||
return err
|
||||
if err == nil {
|
||||
_, err = db.Update(self, func() error {
|
||||
self.HostId = host.GetId()
|
||||
self.Status = iVM.GetStatus()
|
||||
self.PowerStates = iVM.GetPowerStates()
|
||||
self.InferPowerStates()
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
return errors.Wrap(err, "GetIVMById")
|
||||
}
|
||||
} else if errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
return errors.Wrap(err, "GetIVMById")
|
||||
}
|
||||
|
||||
if !lostNamePattern.MatchString(self.Name) {
|
||||
db.Update(self, func() error {
|
||||
self.Name = fmt.Sprintf("%s-lost@%s", self.Name, timeutils.ShortDate(time.Now()))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if self.Status != api.VM_UNKNOWN {
|
||||
self.SetStatus(userCred, api.VM_UNKNOWN, "Sync lost")
|
||||
}
|
||||
|
||||
if options.Options.EnableSyncPurge {
|
||||
@@ -2943,16 +2954,6 @@ func (self *SGuest) syncRemoveCloudVM(ctx context.Context, userCred mcclient.Tok
|
||||
})
|
||||
}
|
||||
|
||||
if !lostNamePattern.MatchString(self.Name) {
|
||||
db.Update(self, func() error {
|
||||
self.Name = fmt.Sprintf("%s-lost@%s", self.Name, timeutils.ShortDate(time.Now()))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if self.Status != api.VM_UNKNOWN {
|
||||
self.SetStatus(userCred, api.VM_UNKNOWN, "Sync lost")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3009,7 +3010,7 @@ func (g *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.TokenCre
|
||||
if !g.IsFailureStatus() && syncStatus {
|
||||
g.Status = extVM.GetStatus()
|
||||
g.PowerStates = extVM.GetPowerStates()
|
||||
g.inferPowerStates()
|
||||
g.InferPowerStates()
|
||||
}
|
||||
|
||||
g.VcpuCount = extVM.GetVcpuCount()
|
||||
@@ -3103,7 +3104,7 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
|
||||
|
||||
guest.Status = extVM.GetStatus()
|
||||
guest.PowerStates = extVM.GetPowerStates()
|
||||
guest.inferPowerStates()
|
||||
guest.InferPowerStates()
|
||||
guest.ExternalId = extVM.GetGlobalId()
|
||||
guest.VcpuCount = extVM.GetVcpuCount()
|
||||
guest.BootOrder = extVM.GetBootOrder()
|
||||
@@ -6536,7 +6537,7 @@ func (self *SGuest) GetAddress() (string, error) {
|
||||
return "", errors.Wrapf(cloudprovider.ErrNotFound, "guest %s address", self.Name)
|
||||
}
|
||||
|
||||
func (guest *SGuest) inferPowerStates() {
|
||||
func (guest *SGuest) InferPowerStates() {
|
||||
if len(guest.PowerStates) == 0 {
|
||||
switch guest.Status {
|
||||
case api.VM_READY:
|
||||
|
||||
@@ -2502,6 +2502,10 @@ func IsNeedSkipSync(ext cloudprovider.ICloudResource) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (self *SGuest) Purge(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
return self.purge(ctx, userCred)
|
||||
}
|
||||
|
||||
func (hh *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCredential, iprovider cloudprovider.ICloudProvider, vms []cloudprovider.ICloudVM, syncOwnerId mcclient.IIdentityProvider, xor bool) ([]SGuestSyncResult, compare.SyncResult) {
|
||||
lockman.LockRawObject(ctx, GuestManager.Keyword(), hh.Id)
|
||||
defer lockman.ReleaseRawObject(ctx, GuestManager.Keyword(), hh.Id)
|
||||
@@ -2535,7 +2539,7 @@ func (hh *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCredent
|
||||
}
|
||||
|
||||
for i := 0; i < len(removed); i += 1 {
|
||||
err := removed[i].syncRemoveCloudVM(ctx, userCred)
|
||||
err := removed[i].SyncRemoveCloudVM(ctx, userCred, true)
|
||||
if err != nil {
|
||||
syncResult.DeleteError(err)
|
||||
} else {
|
||||
|
||||
@@ -109,6 +109,8 @@ type ComputeOptions struct {
|
||||
TimePointsLimit int `default:"1" help:"time point of every days, default 1 point"`
|
||||
RepeatWeekdaysLimit int `default:"7" help:"day point of every weekday, default 7 points"`
|
||||
|
||||
ServerStatusSyncIntervalMinutes int `default:"5" help:"Interval to sync server status, defualt is 5 minutes"`
|
||||
|
||||
ServerSkuSyncIntervalMinutes int `default:"60" help:"Interval to sync public cloud server skus, defualt is 1 hour"`
|
||||
SkuBatchSync int `default:"5" help:"How many skus can be sync in a batch"`
|
||||
|
||||
|
||||
@@ -53,6 +53,10 @@ import (
|
||||
)
|
||||
|
||||
func StartService() {
|
||||
StartServiceWithJobs(nil)
|
||||
}
|
||||
|
||||
func StartServiceWithJobs(jobs func(cron *cronman.SCronJobManager)) {
|
||||
opts := &options.Options
|
||||
commonOpts := &options.Options.CommonOptions
|
||||
baseOpts := &options.Options.BaseOptions
|
||||
@@ -195,6 +199,9 @@ func StartService() {
|
||||
cron.AddJobEveryFewHour("InspectAllTemplate", 1, 0, 0, models.GuestTemplateManager.InspectAllTemplate, true)
|
||||
|
||||
cron.AddJobEveryFewHour("CheckBillingResourceExpireAt", 1, 0, 0, models.CheckBillingResourceExpireAt, true)
|
||||
if jobs != nil {
|
||||
jobs(cron)
|
||||
}
|
||||
go cron.Start2(ctx, electObj)
|
||||
|
||||
// init auto scaling controller
|
||||
|
||||
Vendored
+1
-1
@@ -1438,7 +1438,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
|
||||
# sigs.k8s.io/yaml v1.2.0
|
||||
## explicit; go 1.12
|
||||
sigs.k8s.io/yaml
|
||||
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231030120705-5126f7c5ebf9
|
||||
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231031085052-d71eeaca4339
|
||||
## explicit; go 1.18
|
||||
yunion.io/x/cloudmux/pkg/apis
|
||||
yunion.io/x/cloudmux/pkg/apis/billing
|
||||
|
||||
+2
@@ -80,6 +80,8 @@ type ICloudRegion interface {
|
||||
GetIVpcById(id string) (ICloudVpc, error)
|
||||
GetIZoneById(id string) (ICloudZone, error)
|
||||
GetIEipById(id string) (ICloudEIP, error)
|
||||
// ICoudVM 的 GetGlobalId 接口不能panic
|
||||
GetIVMs() ([]ICloudVM, error)
|
||||
// Esxi没有zone,需要通过region确认vm是否被删除
|
||||
GetIVMById(id string) (ICloudVM, error)
|
||||
GetIDiskById(id string) (ICloudDisk, error)
|
||||
|
||||
+19
-32
@@ -41,43 +41,30 @@ func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, erro
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms := make([]SInstance, 0)
|
||||
for {
|
||||
parts, total, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, parts...)
|
||||
if len(vms) >= total {
|
||||
break
|
||||
}
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
vms[i].host = self
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
func (self *SHost) VMGlobalId2Id(gid string) string {
|
||||
return gid
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
|
||||
id := self.VMGlobalId2Id(gid)
|
||||
parts, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id}, 0, 1)
|
||||
vms, err := self.zone.region.GetInstances(self.zone.ZoneId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
ret := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
vms[i].host = self
|
||||
ret[i] = &vms[i]
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
return nil, cloudprovider.ErrDuplicateId
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
vms, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts[0].host = self
|
||||
return &parts[0], nil
|
||||
for i := range vms {
|
||||
if vms[i].InstanceId == id {
|
||||
vms[i].host = self
|
||||
return &vms[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (self *SHost) GetId() string {
|
||||
|
||||
+30
-23
@@ -138,14 +138,10 @@ type SInstance struct {
|
||||
|
||||
// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"}
|
||||
|
||||
func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) {
|
||||
if limit > 50 || limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
func (self *SRegion) GetInstances(zoneId string, ids []string) ([]SInstance, error) {
|
||||
params := make(map[string]string)
|
||||
params["RegionId"] = self.RegionId
|
||||
params["PageSize"] = fmt.Sprintf("%d", limit)
|
||||
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
|
||||
params["MaxResults"] = "100"
|
||||
|
||||
if len(zoneId) > 0 {
|
||||
params["ZoneId"] = zoneId
|
||||
@@ -155,20 +151,29 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
|
||||
params["InstanceIds"] = jsonutils.Marshal(ids).String()
|
||||
}
|
||||
|
||||
body, err := self.ecsRequest("DescribeInstances", params)
|
||||
if err != nil {
|
||||
log.Errorf("GetInstances fail %s", err)
|
||||
return nil, 0, err
|
||||
ret := make([]SInstance, 0)
|
||||
for {
|
||||
resp, err := self.ecsRequest("DescribeInstances", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "DescribeInstances")
|
||||
}
|
||||
part := struct {
|
||||
Instances struct {
|
||||
Instance []SInstance
|
||||
}
|
||||
NextToken string
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
ret = append(ret, part.Instances.Instance...)
|
||||
if len(part.Instances.Instance) == 0 || len(part.NextToken) == 0 {
|
||||
break
|
||||
}
|
||||
params["NextToken"] = part.NextToken
|
||||
}
|
||||
|
||||
instances := make([]SInstance, 0)
|
||||
err = body.Unmarshal(&instances, "Instances", "Instance")
|
||||
if err != nil {
|
||||
log.Errorf("Unmarshal security group details fail %s", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
total, _ := body.Int("TotalCount")
|
||||
return instances, int(total), nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetSecurityGroupIds() ([]string, error) {
|
||||
@@ -551,14 +556,16 @@ func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
|
||||
}
|
||||
|
||||
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
|
||||
instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1)
|
||||
instances, err := self.GetInstances("", []string{instanceId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(instances) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
for i := range instances {
|
||||
if instances[i].InstanceId == instanceId {
|
||||
return &instances[i], nil
|
||||
}
|
||||
}
|
||||
return &instances[0], nil
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, instanceId)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupIds []string,
|
||||
|
||||
+12
@@ -1220,3 +1220,15 @@ func (self *SRegion) trialRequest(apiName string, params map[string]string) (jso
|
||||
domain := fmt.Sprintf("actiontrail.%s.aliyuncs.com", self.RegionId)
|
||||
return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.debug)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
instances, err := self.GetInstances("", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range instances {
|
||||
ret = append(ret, &instances[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+19
@@ -1080,3 +1080,22 @@ func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, er
|
||||
func (region *SRegion) GetCapabilities() []string {
|
||||
return region.client.GetCapabilities()
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms := make([]SInstance, 0)
|
||||
for {
|
||||
parts, total, err := region.GetInstances("", nil, len(vms), 50)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, parts...)
|
||||
if len(vms) >= total {
|
||||
break
|
||||
}
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+13
@@ -805,3 +805,16 @@ func (region *SRegion) CreateInternetGateway() (cloudprovider.ICloudInternetGate
|
||||
}
|
||||
return igw, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("", "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetInstances")
|
||||
}
|
||||
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
-1
@@ -291,7 +291,6 @@ func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
for i := 0; i < len(vms); i++ {
|
||||
vms[i].host = self
|
||||
ivms[i] = &vms[i]
|
||||
log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName())
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+12
@@ -687,3 +687,15 @@ func (self *SRegion) list(resource string, params url.Values, retVal interface{}
|
||||
}
|
||||
return jsonutils.Update(retVal, ret)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i++ {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+21
@@ -244,3 +244,24 @@ func (self *SRegion) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
var vms []SInstance
|
||||
nextToken := ""
|
||||
for {
|
||||
part, _nextToken, err := region.GetInstances("", "", MAX_RESULT, nextToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, part...)
|
||||
if len(part) == 0 || len(_nextToken) == 0 {
|
||||
break
|
||||
}
|
||||
nextToken = _nextToken
|
||||
}
|
||||
var ret []cloudprovider.ICloudVM
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -459,3 +459,15 @@ func (self *SRegion) GetInstances(zoneId string, ids []string) ([]SInstance, err
|
||||
func (region *SRegion) GetCapabilities() []string {
|
||||
return region.client.GetCapabilities()
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -353,3 +353,15 @@ func (r *SRegion) FindZone(zoneRegion string) (*SZone, error) {
|
||||
}
|
||||
return findZone(zoneRegion), nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances(region.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetVMs")
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := range vms {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+16
@@ -47,6 +47,22 @@ func (cli *SESXiClient) GetIHosts() ([]cloudprovider.ICloudHost, error) {
|
||||
return ihosts, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
hosts, err := cli.GetIHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for _, host := range hosts {
|
||||
vm, err := host.GetIVMs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, vm...)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
hosts, err := cli.GetIHosts()
|
||||
if err != nil {
|
||||
|
||||
+12
@@ -831,3 +831,15 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
|
||||
}
|
||||
return rds, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
instances, err := region.GetInstances("", 0, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iVMs := []cloudprovider.ICloudVM{}
|
||||
for i := range instances {
|
||||
iVMs = append(iVMs, &instances[i])
|
||||
}
|
||||
return iVMs, nil
|
||||
}
|
||||
|
||||
+12
@@ -1029,3 +1029,15 @@ func (self *SRegion) GetServices() ([]jsonutils.JSONObject, error) {
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetInstances")
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -754,3 +754,15 @@ func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetInstances")
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+21
@@ -312,3 +312,24 @@ func (r *SRegion) GetCapabilities() []string {
|
||||
cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX,
|
||||
}
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms := make([]SInstance, 0)
|
||||
n := 1
|
||||
for {
|
||||
parts, total, err := region.GetInstances("", nil, n, 100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, parts...)
|
||||
if len(vms) >= total {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := range vms {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+12
@@ -216,3 +216,15 @@ func (self *SRegion) getTask(id string) (*STask, error) {
|
||||
task := &STask{}
|
||||
return task, self.get("tasks", id, nil, task)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetInstances")
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -610,3 +610,15 @@ func (region *SRegion) fetchrouters() error {
|
||||
region.routers = routers
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetInstances")
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+1
-2
@@ -819,12 +819,11 @@ func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) {
|
||||
}
|
||||
|
||||
for _, res := range resources {
|
||||
if res.NodeId == hostId {
|
||||
if res.NodeId == hostId || len(hostId) == 0 {
|
||||
instance, err := self.GetQemuConfig(res.Node, res.VmId)
|
||||
if err == nil {
|
||||
ret = append(ret, *instance)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -215,3 +215,15 @@ func (self *SRegion) put(res string, params url.Values, body jsonutils.JSONObjec
|
||||
func (self *SRegion) del(res string, params url.Values, retVal interface{}) error {
|
||||
return self.client.del(res, params, retVal)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetInstances")
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+19
@@ -1031,3 +1031,22 @@ func (r *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput
|
||||
}
|
||||
return r.GetIElasticcacheById(instanceId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms := make([]SInstance, 0)
|
||||
for {
|
||||
parts, total, err := region.GetInstances("", nil, len(vms), 50)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, parts...)
|
||||
if len(vms) >= total {
|
||||
break
|
||||
}
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i++ {
|
||||
ivms[i] = &vms[i]
|
||||
}
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
+4
@@ -67,6 +67,10 @@ func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIStorages")
|
||||
}
|
||||
|
||||
func (r *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIVMs")
|
||||
}
|
||||
|
||||
func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIVMById")
|
||||
}
|
||||
|
||||
+12
@@ -364,3 +364,15 @@ func (self *SRegion) GetIMiscResources() ([]cloudprovider.ICloudMiscResource, er
|
||||
func (self *SRegion) GetCapabilities() []string {
|
||||
return self.client.GetCapabilities()
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.client.GetInstances()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -578,3 +578,15 @@ func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket
|
||||
func (region *SRegion) GetCapabilities() []string {
|
||||
return region.client.GetCapabilities()
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+7
-23
@@ -126,18 +126,9 @@ func (host *SHost) GetVersion() string {
|
||||
}
|
||||
|
||||
func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms := make([]SInstance, 0)
|
||||
token := ""
|
||||
for {
|
||||
parts, nextToken, err := host.zone.region.GetInstances(host.zone.ZoneId, nil, 10, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vms = append(vms, parts...)
|
||||
if len(nextToken) == 0 {
|
||||
break
|
||||
}
|
||||
token = nextToken
|
||||
vms, err := host.zone.region.GetInstances(host.zone.ZoneId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ivms := make([]cloudprovider.ICloudVM, len(vms))
|
||||
for i := 0; i < len(vms); i += 1 {
|
||||
@@ -147,20 +138,13 @@ func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
return ivms, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
|
||||
id := gid
|
||||
parts, _, err := host.zone.region.GetInstances(host.zone.ZoneId, []string{id}, 1, "")
|
||||
func (host *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
vm, err := host.zone.region.GetInstance(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
return nil, cloudprovider.ErrDuplicateId
|
||||
}
|
||||
parts[0].host = host
|
||||
return &parts[0], nil
|
||||
vm.host = host
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
|
||||
|
||||
+26
-24
@@ -128,7 +128,7 @@ func (instance *SInstance) GetUserData() (string, error) {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
|
||||
instances, _, err := region.GetInstances("", []string{instanceId}, 1, "")
|
||||
instances, err := region.GetInstances("", []string{instanceId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -140,35 +140,37 @@ func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, instanceId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstances(zoneId string, ids []string, limit int, token string) ([]SInstance, string, error) {
|
||||
if limit > 10 || limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
func (region *SRegion) GetInstances(zoneId string, ids []string) ([]SInstance, error) {
|
||||
params := make(map[string]string)
|
||||
params["MaxResults"] = fmt.Sprintf("%d", limit)
|
||||
if len(token) > 0 {
|
||||
params["NextToken"] = token
|
||||
}
|
||||
params["MaxResults"] = "100"
|
||||
if len(zoneId) > 0 {
|
||||
params["ZoneId"] = zoneId
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
for index, id := range ids {
|
||||
key := fmt.Sprintf("InstanceIds.%d", index+1)
|
||||
params[key] = id
|
||||
for index, id := range ids {
|
||||
key := fmt.Sprintf("InstanceIds.%d", index+1)
|
||||
params[key] = id
|
||||
}
|
||||
ret := []SInstance{}
|
||||
for {
|
||||
resp, err := region.ecsRequest("DescribeInstances", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "DescribeInstances")
|
||||
}
|
||||
part := struct {
|
||||
Instances []SInstance
|
||||
NextToken string
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, part.Instances...)
|
||||
if len(part.NextToken) == 0 || len(part.Instances) == 0 {
|
||||
break
|
||||
}
|
||||
params["NextToken"] = part.NextToken
|
||||
}
|
||||
body, err := region.ecsRequest("DescribeInstances", params)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrapf(err, "GetInstances fail")
|
||||
}
|
||||
instances := make([]SInstance, 0)
|
||||
err = body.Unmarshal(&instances, "Instances")
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrapf(err, "Unmarshal details fail")
|
||||
}
|
||||
nextToken, _ := body.GetString("NextToken")
|
||||
return instances, nextToken, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetIHost() cloudprovider.ICloudHost {
|
||||
|
||||
+12
@@ -651,3 +651,15 @@ func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
return region.GetInstance(id)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
+12
@@ -344,3 +344,15 @@ func (region *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCre
|
||||
func (region *SRegion) GetCapabilities() []string {
|
||||
return region.client.GetCapabilities()
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
vms, err := region.GetInstances("", "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := []cloudprovider.ICloudVM{}
|
||||
for i := range vms {
|
||||
ret = append(ret, &vms[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user