diff --git a/go.mod b/go.mod index 4866a02fd4..2caee070bc 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/apache/thrift v0.12.0 // indirect github.com/aws/aws-sdk-go v1.39.0 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect - github.com/basgys/goxml2json v1.1.0 + github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 github.com/beevik/etree v1.1.0 // indirect github.com/benbjohnson/clock v1.0.0 github.com/bitly/go-simplejson v0.5.0 @@ -157,7 +157,7 @@ require ( yunion.io/x/jsonutils v0.0.0-20220106020632-953b71a4c3a8 yunion.io/x/log v0.0.0-20201210064738-43181789dc74 yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7 - yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97 + yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38 yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e yunion.io/x/sqlchemy v0.0.0-20220119131341-fadec84c0638 yunion.io/x/structarg v0.0.0-20220224030024-02b7582b2546 diff --git a/go.sum b/go.sum index fc371408a8..e13398675c 100644 --- a/go.sum +++ b/go.sum @@ -137,8 +137,8 @@ github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw= -github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw= +github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 h1:fKPpQHBQgt4dQuG6x+yH4gdgtodFDgN9rvHzwJzTKeg= +github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/benbjohnson/clock v1.0.0 h1:78Jk/r6m4wCi6sndMpty7A//t4dw/RW5fV4ZgDVfX1w= @@ -974,8 +974,8 @@ yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPB yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= -yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97 h1:lY+5NlWwO2aIkfNnVOGKHmZvMt6m4ZuGtarIjwNfUsg= -yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= +yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38 h1:QV3gVskJfi1J0e5kTs4oTx8D+Mc0JFik3Qe6c1PgO90= +yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo= yunion.io/x/sqlchemy v0.0.0-20220119131341-fadec84c0638 h1:Tc7bMp/mahI1Zua5dxBNrXSKl4hCUSA7CPBcqBnK8Uw= diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index 76a340da23..916a3c7940 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -17,6 +17,7 @@ package models import ( "context" "database/sql" + "strings" "time" "yunion.io/x/jsonutils" @@ -335,12 +336,18 @@ func (self *SCloudregion) GetServerSkus() ([]SServerSku, error) { return skus, nil } -func (manager *SCloudregionManager) GetRegionByExternalIdPrefix(prefix string) ([]SCloudregion, error) { - regions := make([]SCloudregion, 0) - q := manager.Query().Startswith("external_id", prefix) - err := db.FetchModelObjects(manager, q, ®ions) +func (self *SCloudprovider) GetRegionByExternalIdPrefix(prefix string) ([]SCloudregion, error) { + factory, err := self.GetProviderFactory() + if err != nil { + return nil, err + } + regions := make([]SCloudregion, 0) + q := CloudregionManager.Query().Startswith("external_id", prefix) + if !factory.IsPublicCloud() && !strings.Contains(prefix, "/") { + q = CloudregionManager.Query().Equals("manager_id", self.Id) + } + err = db.FetchModelObjects(CloudregionManager, q, ®ions) if err != nil { - log.Errorf("%s", err) return nil, err } return regions, nil @@ -386,7 +393,7 @@ func (manager *SCloudregionManager) SyncRegions( remoteRegions := make([]cloudprovider.ICloudRegion, 0) cloudProviderRegions := make([]SCloudproviderregion, 0) - dbRegions, err := manager.GetRegionByExternalIdPrefix(externalIdPrefix) + dbRegions, err := cloudProvider.GetRegionByExternalIdPrefix(externalIdPrefix) if err != nil { syncResult.Error(err) return nil, nil, nil, syncResult diff --git a/pkg/compute/regiondrivers/bingocloud.go b/pkg/compute/regiondrivers/bingocloud.go index f656e1c875..cd90e89825 100644 --- a/pkg/compute/regiondrivers/bingocloud.go +++ b/pkg/compute/regiondrivers/bingocloud.go @@ -17,10 +17,13 @@ package regiondrivers import ( "context" "fmt" + "strings" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" @@ -39,6 +42,29 @@ func (self *SBingoCloudRegionDriver) GetProvider() string { return api.CLOUD_PROVIDER_BINGO_CLOUD } +func (self *SBingoCloudRegionDriver) IsAllowSecurityGroupNameRepeat() bool { + return false +} + +func (self *SBingoCloudRegionDriver) GenerateSecurityGroupName(name string) string { + if strings.ToLower(name) == "default" { + return "DefaultGroup" + } + return name +} + +func (self *SBingoCloudRegionDriver) IsSecurityGroupBelongVpc() bool { + return false +} + +func (self *SBingoCloudRegionDriver) GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule { + return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("in:deny any")} +} + +func (self *SBingoCloudRegionDriver) GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule { + return cloudprovider.SecurityRule{SecurityRule: *secrules.MustParseSecurityRule("out:deny any")} +} + func (self *SBingoCloudRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { return nil, httperrors.NewUnsupportOperationError("%s does not support creating loadbalancer", self.GetProvider()) } diff --git a/pkg/compute/regiondrivers/google.go b/pkg/compute/regiondrivers/google.go index 9aa572fa20..ab5c0390fc 100644 --- a/pkg/compute/regiondrivers/google.go +++ b/pkg/compute/regiondrivers/google.go @@ -121,7 +121,7 @@ func (self *SGoogleRegionDriver) RequestCreateVpc(ctx context.Context, userCred } db.SetExternalId(vpc, userCred, ivpc.GetGlobalId()) - regions, err := models.CloudregionManager.GetRegionByExternalIdPrefix(self.GetProvider()) + regions, err := provider.GetRegionByExternalIdPrefix(self.GetProvider()) if err != nil { return nil, errors.Wrap(err, "GetRegionByExternalIdPrefix") } diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go index f68193efa3..cc0c9d622a 100644 --- a/pkg/mcclient/options/base.go +++ b/pkg/mcclient/options/base.go @@ -238,7 +238,7 @@ type BaseListOptions struct { Manager string `help:"List objects belonging to the cloud provider" json:"manager,omitempty"` Account string `help:"List objects belonging to the cloud account" json:"account,omitempty"` - Provider []string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack|Google|Ctyun|Cloudpods" json:"provider,omitempty"` + Provider []string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|OpenStack|Ucloud|ZStack|Google|Ctyun|Cloudpods|Nutanix|BingoCloud" json:"provider,omitempty"` Brand []string `help:"List objects belonging to a special brand"` CloudEnv string `help:"Cloud environment" choices:"public|private|onpremise|private_or_onpremise" json:"cloud_env,omitempty"` PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"` diff --git a/pkg/multicloud/bingocloud/bingo.go b/pkg/multicloud/bingocloud/bingo.go index 6fad8d6f84..79bf6ba561 100644 --- a/pkg/multicloud/bingocloud/bingo.go +++ b/pkg/multicloud/bingocloud/bingo.go @@ -15,11 +15,13 @@ package bingocloud import ( + "bytes" "context" "crypto/hmac" "crypto/sha256" "encoding/base64" "fmt" + "io/ioutil" "net/http" "net/url" "sort" @@ -136,6 +138,64 @@ func (self *SBingoCloudClient) sign(query string) string { return base64.StdEncoding.EncodeToString(hmac.Sum(nil)) } +func setItemToArray(obj jsonutils.JSONObject) jsonutils.JSONObject { + objDict, ok := obj.(*jsonutils.JSONDict) + if ok { + for k, v := range objDict.Value() { + if v.String() == `""` { + objDict.Remove(k) + continue + } + vDict, ok := v.(*jsonutils.JSONDict) + if ok { + if vDict.Contains("item") { + item, _ := vDict.Get("item") + _, ok := item.(*jsonutils.JSONArray) + if !ok { + if k != "instancesSet" { + item = setItemToArray(item) + objDict.Set(k, jsonutils.NewArray(item)) + } else { + objDict.Set(k, setItemToArray(item)) + } + } else { + items, _ := item.GetArray() + for i := range items { + items[i] = setItemToArray(items[i]) + } + objDict.Set(k, jsonutils.NewArray(items...)) + } + for _, nk := range []string{"nextToken", "NextToken"} { + nextToken, _ := vDict.GetString(nk) + if len(nextToken) > 0 { + objDict.Set(nk, jsonutils.NewString(nextToken)) + } + } + } else { + objDict.Set(k, setItemToArray(v)) + } + } else if _, ok = v.(*jsonutils.JSONArray); ok { + if ok { + arr, _ := v.GetArray() + for i := range arr { + arr[i] = setItemToArray(arr[i]) + } + objDict.Set(k, jsonutils.NewArray(arr...)) + } + } + } + } + _, ok = obj.(*jsonutils.JSONArray) + if ok { + arr, _ := obj.GetArray() + for i := range arr { + arr[i] = setItemToArray(arr[i]) + } + return jsonutils.NewArray(arr...) + } + return objDict +} + func (self *SBingoCloudClient) invoke(action string, params map[string]string) (jsonutils.JSONObject, error) { var encode = func(k, v string) string { d := url.Values{} @@ -161,13 +221,14 @@ func (self *SBingoCloudClient) invoke(action string, params map[string]string) ( } defer resp.Body.Close() - result, err := xj.Convert(resp.Body) + data, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } - if self.debug { - log.Debugf("response: %s", result.String()) + result, err := xj.Convert(bytes.NewReader(data)) + if err != nil { + return nil, err } obj, err := jsonutils.Parse([]byte(result.String())) @@ -175,6 +236,12 @@ func (self *SBingoCloudClient) invoke(action string, params map[string]string) ( return nil, errors.Wrapf(err, "jsonutils.Parse") } + obj = setItemToArray(obj) + + if self.debug { + log.Debugf("response: %s", obj.PrettyString()) + } + respKey := action + "Response" if obj.Contains(respKey) { obj, err = obj.Get(respKey) @@ -183,21 +250,42 @@ func (self *SBingoCloudClient) invoke(action string, params map[string]string) ( } } - // 处理请求单个资源情况 - if strings.HasPrefix(action, "Describe") && strings.HasSuffix(action, "s") { - objDict := obj.(*jsonutils.JSONDict) - for k, v := range objDict.Value() { - if (strings.HasSuffix(k, "Set") || k == "regionInfo") && v.Contains("item") { - value := v.(*jsonutils.JSONDict) - item, _ := v.Get("item") - _, ok := item.(*jsonutils.JSONArray) - if !ok { - value.Set("item", jsonutils.NewArray(item)) - objDict.Set(k, value) - } - } - } - } - return obj, nil } + +func (self *SBingoCloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + subAccount := cloudprovider.SSubAccount{ + Account: self.accessKey, + Name: self.cpcfg.Name, + + HealthStatus: api.CLOUD_PROVIDER_HEALTH_NORMAL, + } + return []cloudprovider.SSubAccount{subAccount}, nil + +} + +func (self *SBingoCloudClient) GetIRegions() []cloudprovider.ICloudRegion { + ret := []cloudprovider.ICloudRegion{} + for i := range self.regions { + self.regions[i].client = self + ret = append(ret, &self.regions[i]) + } + return ret +} + +func (self *SBingoCloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + iregions := self.GetIRegions() + for i := range iregions { + if iregions[i].GetGlobalId() == id { + return iregions[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SBingoCloudClient) GetCapabilities() []string { + return []string{ + cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, + } +} diff --git a/pkg/multicloud/bingocloud/disk.go b/pkg/multicloud/bingocloud/disk.go new file mode 100644 index 0000000000..44859c9b14 --- /dev/null +++ b/pkg/multicloud/bingocloud/disk.go @@ -0,0 +1,247 @@ +// 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 bingocloud + +import ( + "context" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SDisk struct { + multicloud.BingoTags + multicloud.SDisk + + storage *SStorage + + AttachmentSet []AttachmentSet `json:"attachmentSet"` + AvailabilityZone string `json:"availabilityZone"` + CreateTime string `json:"createTime"` + Description string `json:"description"` + DetachBehavior string `json:"detachBehavior"` + Goal string `json:"goal"` + Iops string `json:"iops"` + IsDeductQuota string `json:"isDeductQuota"` + IsEncrypt string `json:"isEncrypt"` + IsForSleepInst string `json:"isForSleepInst"` + IsMirrorVolume string `json:"isMirrorVolume"` + IsMultiAttach string `json:"isMultiAttach"` + IsOneInst string `json:"isOneInst"` + IsRoot string `json:"isRoot"` + Location string `json:"location"` + MirrorFrom string `json:"mirrorFrom"` + MirrorProcess string `json:"mirrorProcess"` + MirrorStatus string `json:"mirrorStatus"` + NodeId string `json:"nodeId"` + Owner string `json:"owner"` + Passphrase string `json:"passphrase"` + Readonly string `json:"readonly"` + Size int `json:"size"` + SnapshotId string `json:"snapshotId"` + Status string `json:"status"` + StorageId string `json:"storageId"` + VolumeId string `json:"volumeId"` + VolumeName string `json:"volumeName"` +} + +type AttachmentSet struct { + AttachTime string `json:"attachTime"` + Cache string `json:"cache"` + DeleteOnTermination string `json:"deleteOnTermination"` + Device string `json:"device"` + InstanceId string `json:"instanceId"` + Status string `json:"status"` + VolumeId string `json:"volumeId"` +} + +func (self *SDisk) GetName() string { + return self.VolumeName +} + +func (self *SDisk) GetId() string { + return self.VolumeId +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetIStorageId() string { + return self.StorageId +} + +func (self *SDisk) GetDiskFormat() string { + return "raw" +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.Size * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.IsRoot == "true" +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetDiskType() string { + if self.IsRoot == "true" { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + return "virtio" +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetMountpoint() string { + for _, att := range self.AttachmentSet { + return att.Device + } + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return []string{}, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetStatus() string { + switch self.Status { + case "available", "in-use": + return api.DISK_READY + default: + return self.Status + } +} + +func (self *SRegion) GetDisks(id, nextToken string) ([]SDisk, string, error) { + params := map[string]string{} + if len(id) > 0 { + params["volumeId"] = id + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeVolumes", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + VolumeSet []SDisk + }{} + resp.Unmarshal(&ret) + return ret.VolumeSet, ret.NextToken, nil +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + part, nextToken, err := self.zone.region.GetDisks("", "") + if err != nil { + return nil, err + } + disks := []SDisk{} + disks = append(disks, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.zone.region.GetDisks("", nextToken) + if err != nil { + return nil, err + } + disks = append(disks, part...) + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + if disks[i].StorageId == self.StorageId { + disks[i].storage = self + ret = append(ret, &disks[i]) + } + } + return ret, nil +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(id) + if err != nil { + return nil, err + } + if disk.StorageId != self.StorageId { + return nil, cloudprovider.ErrNotFound + } + disk.storage = self + return disk, nil +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + disks, _, err := self.GetDisks(id, "") + if err != nil { + return nil, err + } + for i := range disks { + if disks[i].GetGlobalId() == id { + return &disks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/pkg/multicloud/bingocloud/eip.go b/pkg/multicloud/bingocloud/eip.go new file mode 100644 index 0000000000..f6a6673b0b --- /dev/null +++ b/pkg/multicloud/bingocloud/eip.go @@ -0,0 +1,40 @@ +// 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 bingocloud + +import "github.com/pkg/errors" + +type SEip struct { +} + +func (self *SRegion) GetEips(ip, nextToken string) ([]SEip, string, error) { + params := map[string]string{} + if len(ip) > 0 { + params["publicIp"] = ip + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeAddresses", params) + if err != nil { + return nil, "", errors.Wrapf(err, "DescribeAddresses") + } + ret := struct { + AddressesSet []SEip + NextToken string + }{} + resp.Unmarshal(&ret) + return ret.AddressesSet, ret.NextToken, nil +} diff --git a/pkg/multicloud/bingocloud/host.go b/pkg/multicloud/bingocloud/host.go new file mode 100644 index 0000000000..55d41da72c --- /dev/null +++ b/pkg/multicloud/bingocloud/host.go @@ -0,0 +1,264 @@ +// 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 bingocloud + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + multicloud.STagBase + + zone *SZone + + CPUHz string `json:"CpuHz"` + ModelId string `json:"ModelId"` + MonitorType string `json:"MonitorType"` + IpmiMgrEnabled string `json:"IpmiMgrEnabled"` + JoinTime time.Time `json:"JoinTime"` + IsBareMetal string `json:"isBareMetal"` + BmcPwd string `json:"BmcPwd"` + Extra string `json:"Extra"` + InstanceId string `json:"instanceId"` + Manufacturer string `json:"Manufacturer"` + BaseBoardSerial string `json:"BaseBoardSerial"` + BareMetalHWInfo string `json:"BareMetalHWInfo"` + BmcPort string `json:"BmcPort"` + CPUCores int `json:"CpuCores"` + BmcIP string `json:"BmcIp"` + Cabinet string `json:"Cabinet"` + Memo string `json:"Memo"` + HostIP string `json:"HostIp"` + Memory int `json:"Memory"` + HostId string `json:"HostId"` + CPUKind string `json:"CpuKind"` + SystemSerial string `json:"SystemSerial"` + InCloud string `json:"InCloud"` + Location string `json:"Location"` + BmcUser string `json:"BmcUser"` + PublicIP string `json:"PublicIp"` + Status string `json:"Status"` + Room string `json:"Room"` + SSHMgrEnabled string `json:"SshMgrEnabled"` + BmState string `json:"bmState"` + HostName string `json:"HostName"` +} + +func (self *SHost) GetId() string { + return self.HostId +} + +func (self *SHost) GetGlobalId() string { + return self.HostId +} + +func (self *SHost) GetName() string { + return self.HostName +} + +func (self *SHost) GetAccessIp() string { + return self.HostIP +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SHost) GetSN() string { + return self.BaseBoardSerial +} + +func (self *SHost) GetCpuCount() int { + return self.CPUCores +} + +func (self *SHost) GetNodeCount() int8 { + return 1 +} + +func (self *SHost) GetCpuDesc() string { + return self.CPUKind +} + +func (self *SHost) GetCpuMhz() int { + return 0 +} + +func (self *SHost) GetCpuCmtbound() float32 { + return 1 +} + +func (self *SHost) GetMemSizeMB() int { + return self.Memory +} + +func (self *SHost) GetMemCmtbound() float32 { + return 1 +} + +func (self *SHost) GetReservedMemoryMb() int { + return 0 +} + +func (self *SHost) GetStorageSizeMB() int { + return 0 +} + +func (self *SHost) GetStorageType() string { + return api.STORAGE_LOCAL_SSD +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_BINGO_CLOUD +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorages() +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorageById(id) +} + +func (self *SHost) GetEnabled() bool { + return true +} + +func (self *SHost) GetHostStatus() string { + if self.Status == "available" { + return api.HOST_ONLINE + } + return api.HOST_OFFLINE +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := []SInstance{} + part, nextToken, err := self.zone.region.GetInstances("", self.zone.ZoneName, 100, "") + vms = append(vms, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.zone.region.GetInstances("", self.zone.ZoneName, 100, nextToken) + if err != nil { + return nil, err + } + vms = append(vms, part...) + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + if strings.HasSuffix(vms[i].InstancesSet.HostAddress, self.HostIP) { + vms[i].host = self + ret = append(ret, &vms[i]) + } + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetSchedtags() ([]string, error) { + return []string{}, nil +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return "" +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SRegion) GetHosts(nextToken string) ([]SHost, string, error) { + params := map[string]string{} + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribePhysicalHosts", params) + if err != nil { + return nil, "", err + } + ret := struct { + DescribePhysicalHostsResult struct { + PhysicalHostSet []SHost + } + NextToken string + }{} + resp.Unmarshal(&ret) + return ret.DescribePhysicalHostsResult.PhysicalHostSet, ret.NextToken, nil +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := self.region.GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts := []SHost{} + part, nextToken, err := self.region.GetHosts("") + if err != nil { + return nil, err + } + hosts = append(hosts, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.region.GetHosts(nextToken) + if err != nil { + return nil, err + } + hosts = append(hosts, part...) + } + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + hosts[i].zone = self + ret = append(ret, &hosts[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/bingocloud/image.go b/pkg/multicloud/bingocloud/image.go new file mode 100644 index 0000000000..9ff84d50a4 --- /dev/null +++ b/pkg/multicloud/bingocloud/image.go @@ -0,0 +1,225 @@ +// 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 bingocloud + +import ( + "context" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SImage struct { + multicloud.SResourceBase + multicloud.BingoTags + cache *SStoragecache + + Architecture string `json:"architecture"` + BlockDeviceMapping string `json:"blockDeviceMapping"` + Bootloader string `json:"bootloader"` + Clonemode string `json:"clonemode"` + ClusterId string `json:"clusterId"` + Contentmode string `json:"contentmode"` + DefaultStorageId string `json:"defaultStorageId"` + Description string `json:"description"` + DiskBus string `json:"diskBus"` + ExtendDisk string `json:"extendDisk"` + Features string `json:"features"` + Hypervisor string `json:"hypervisor"` + ImageId string `json:"imageId"` + ImageLocation string `json:"imageLocation"` + ImageOwnerId string `json:"imageOwnerId"` + ImagePath string `json:"imagePath"` + ImageSize int64 `json:"imageSize"` + ImageState string `json:"imageState"` + ImageType string `json:"imageType"` + IsBareMetal string `json:"isBareMetal"` + IsPublic bool `json:"isPublic"` + KernelId string `json:"kernelId"` + Name string `json:"name"` + OsId string `json:"osId"` + OSName string `json:"osName"` + Platform string `json:"platform"` + RamdiskId string `json:"ramdiskId"` + RootDeviceName string `json:"rootDeviceName"` + RootDeviceType string `json:"rootDeviceType"` + ScheduleTags string `json:"scheduleTags"` + Shared string `json:"shared"` + Sharemode string `json:"sharemode"` + StateReason string `json:"stateReason"` + StorageId string `json:"storageId"` +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetSizeByte() int64 { + return self.ImageSize +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + if self.IsPublic { + return cloudprovider.ImageTypeSystem + } + return cloudprovider.ImageTypeCustomized +} + +func (self *SImage) GetImageStatus() string { + return "" +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + if self.Platform == "linux" { + return cloudprovider.OsTypeLinux + } + return cloudprovider.OsTypeWindows +} + +func (self *SImage) GetOsDist() string { + return "" +} + +func (self *SImage) GetOsVersion() string { + return "" +} + +func (self *SImage) GetOsArch() string { + return self.Architecture +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return 0 +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetImageFormat() string { + return "raw" +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SImage) UEFI() bool { + return self.Bootloader == "uefi" +} + +func (self *SImage) GetPublicScope() rbacutils.TRbacScope { + if self.Shared == "true" { + return rbacutils.ScopeSystem + } + return rbacutils.ScopeDomain +} + +func (self *SImage) GetSubImages() []cloudprovider.SSubImage { + return []cloudprovider.SSubImage{} +} + +func (self *SImage) GetProjectId() string { + return "" +} + +func (self *SImage) GetStatus() string { + switch self.ImageState { + case "available": + return api.CACHED_IMAGE_STATUS_ACTIVE + default: + return self.ImageState + } +} + +func (self *SRegion) GetImages(id, nextToken string) ([]SImage, string, error) { + params := map[string]string{} + if len(id) > 0 { + params["imageId"] = id + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeImages", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + ImagesSet []SImage + }{} + resp.Unmarshal(&ret) + return ret.ImagesSet, ret.NextToken, nil +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + part, nextToken, err := self.region.GetImages("", "") + if err != nil { + return nil, err + } + images := []SImage{} + images = append(images, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.region.GetImages("", nextToken) + if err != nil { + return nil, err + } + images = append(images, part...) + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + if images[i].StorageId == self.storageId { + images[i].cache = self + ret = append(ret, &images[i]) + } + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + images, _, err := self.region.GetImages(id, "") + if err != nil { + return nil, err + } + for i := range images { + if images[i].GetGlobalId() == id && images[i].StorageId == self.storageId { + images[i].cache = self + return &images[i], nil + } + } + + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/pkg/multicloud/bingocloud/instance.go b/pkg/multicloud/bingocloud/instance.go index 546a19c5aa..569451a6a7 100644 --- a/pkg/multicloud/bingocloud/instance.go +++ b/pkg/multicloud/bingocloud/instance.go @@ -15,115 +15,315 @@ package bingocloud import ( + "context" "fmt" + "strings" "time" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type SInstance struct { + multicloud.BingoTags + multicloud.SInstanceBase + host *SHost + ReservationId string `json:"reservationId"` OwnerId string - GroupSet struct { - Item struct { - GroupId string - GroupName string - } + GroupSet []struct { + GroupId string + GroupName string } InstancesSet struct { - Item struct { - InstanceId string `json:"instanceId"` - InstanceName string `json:"instanceName"` - HostName string `json:"hostName"` - ImageId string `json:"imageId"` - InstanceState struct { - Code int `json:"code"` - Name string `json:"name"` - PendingProgress string `json:"pendingProgress"` - } `json:"instanceState"` - PrivateDNSName string `json:"privateDnsName"` - DNSName string `json:"dnsName"` - PrivateIPAddress string `json:"privateIpAddress"` - PrivateIPAddresses string `json:"privateIpAddresses"` - IPAddress string `json:"ipAddress"` - NifInfo string `json:"nifInfo"` - KeyName string `json:"keyName"` - AmiLaunchIndex int `json:"amiLaunchIndex"` - ProductCodesSet struct { - Item struct { - ProductCode string `json:"productCode"` - } `json:"item"` - } `json:"productCodesSet"` - InstanceType string `json:"instanceType"` - VmtypeCPU int `json:"vmtype_cpu"` - VmtypeMem int `json:"vmtype_mem"` - VmtypeDisk int `json:"vmtype_disk"` - VmtypeGpu int `json:"vmtype_gpu"` - VmtypeSsd int `json:"vmtype_ssd"` - VmtypeHdd int `json:"vmtype_hdd"` - VmtypeHba int `json:"vmtype_hba"` - VmtypeSriov int `json:"vmtype_sriov"` - LaunchTime time.Time `json:"launchTime"` - RootDeviceType string `json:"rootDeviceType"` - HostAddress string `json:"hostAddress"` - Platform string `json:"platform"` - UseCompactMode bool `json:"useCompactMode"` - ExtendDisk bool `json:"extendDisk"` - Placement struct { - AvailabilityZone string `json:"availabilityZone"` - } `json:"placement"` - Namespace string `json:"namespace"` - KernelId string `json:"kernelId"` - RamdiskId string `json:"ramdiskId"` - OperName string `json:"operName"` - OperProgress int `json:"operProgress"` - Features string `json:"features"` - Monitoring struct { - State string `json:"state"` - } `json:"monitoring"` - SubnetId string `json:"subnetId"` - VpcId string `json:"vpcId"` - StorageId string `json:"storageId"` - DisableAPITermination bool `json:"disableApiTermination"` - Vncdisabled bool `json:"vncdisabled"` - StartTime time.Time `json:"startTime"` - CustomStatus string `json:"customStatus"` - SystemStatus int `json:"systemStatus"` - NetworkStatus int `json:"networkStatus"` - ScheduleTags string `json:"scheduleTags"` - StorageScheduleTags string `json:"storageScheduleTags"` - IsEncrypt bool `json:"isEncrypt"` - IsImported bool `json:"isImported"` - Ec2Version string `json:"ec2Version"` - Passphrase string `json:"passphrase"` - DrsEnabled bool `json:"drs_enabled"` - LaunchPriority int `json:"launchPriority"` - CPUPriority int `json:"cpuPriority"` - MemPriority int `json:"memPriority"` - CPUQuota int `json:"cpuQuota"` - AutoMigrate bool `json:"autoMigrate"` - DrMirrorId string `json:"drMirrorId"` - BlockDeviceMapping struct { - Item struct { - DeviceName string `json:"deviceName"` - Ebs struct { - AttachTime time.Time `json:"attachTime"` - DeleteOnTermination bool `json:"deleteOnTermination"` - Status string `json:"status"` - VolumeId string `json:"volumeId"` - Size int `json:"size"` - } `json:"ebs"` - } `json:"item"` - } `json:"blockDeviceMapping"` - EnableLiveScaleup bool `json:"enableLiveScaleup"` - ImageBytes int64 `json:"imageBytes"` - StatusReason string `json:"statusReason"` - Hypervisor string `json:"hypervisor"` - Bootloader string `json:"bootloader"` - BmMachineId string `json:"bmMachineId"` - } + InstanceId string `json:"instanceId"` + InstanceName string `json:"instanceName"` + HostName string `json:"hostName"` + ImageId string `json:"imageId"` + InstanceState struct { + Code int `json:"code"` + Name string `json:"name"` + PendingProgress string `json:"pendingProgress"` + } `json:"instanceState"` + PrivateDNSName string `json:"privateDnsName"` + DNSName string `json:"dnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + PrivateIPAddresses string `json:"privateIpAddresses"` + IPAddress string `json:"ipAddress"` + NifInfo string `json:"nifInfo"` + KeyName string `json:"keyName"` + AmiLaunchIndex int `json:"amiLaunchIndex"` + ProductCodesSet []struct { + ProductCode string `json:"productCode"` + } `json:"productCodesSet"` + InstanceType string `json:"instanceType"` + VmtypeCPU int `json:"vmtype_cpu"` + VmtypeMem int `json:"vmtype_mem"` + VmtypeDisk int `json:"vmtype_disk"` + VmtypeGpu int `json:"vmtype_gpu"` + VmtypeSsd int `json:"vmtype_ssd"` + VmtypeHdd int `json:"vmtype_hdd"` + VmtypeHba int `json:"vmtype_hba"` + VmtypeSriov int `json:"vmtype_sriov"` + LaunchTime time.Time `json:"launchTime"` + RootDeviceType string `json:"rootDeviceType"` + HostAddress string `json:"hostAddress"` + Platform string `json:"platform"` + UseCompactMode bool `json:"useCompactMode"` + ExtendDisk bool `json:"extendDisk"` + Placement struct { + AvailabilityZone string `json:"availabilityZone"` + } `json:"placement"` + Namespace string `json:"namespace"` + KernelId string `json:"kernelId"` + RamdiskId string `json:"ramdiskId"` + OperName string `json:"operName"` + OperProgress int `json:"operProgress"` + Features string `json:"features"` + Monitoring struct { + State string `json:"state"` + } `json:"monitoring"` + SubnetId string `json:"subnetId"` + VpcId string `json:"vpcId"` + StorageId string `json:"storageId"` + DisableAPITermination bool `json:"disableApiTermination"` + Vncdisabled bool `json:"vncdisabled"` + StartTime time.Time `json:"startTime"` + CustomStatus string `json:"customStatus"` + SystemStatus int `json:"systemStatus"` + NetworkStatus int `json:"networkStatus"` + ScheduleTags string `json:"scheduleTags"` + StorageScheduleTags string `json:"storageScheduleTags"` + IsEncrypt bool `json:"isEncrypt"` + IsImported bool `json:"isImported"` + Ec2Version string `json:"ec2Version"` + Passphrase string `json:"passphrase"` + DrsEnabled bool `json:"drs_enabled"` + LaunchPriority int `json:"launchPriority"` + CPUPriority int `json:"cpuPriority"` + MemPriority int `json:"memPriority"` + CPUQuota int `json:"cpuQuota"` + AutoMigrate bool `json:"autoMigrate"` + DrMirrorId string `json:"drMirrorId"` + BlockDeviceMapping []struct { + DeviceName string `json:"deviceName"` + Ebs struct { + AttachTime time.Time `json:"attachTime"` + DeleteOnTermination bool `json:"deleteOnTermination"` + Status string `json:"status"` + VolumeId string `json:"volumeId"` + Size int `json:"size"` + } `json:"ebs"` + } `json:"blockDeviceMapping"` + EnableLiveScaleup bool `json:"enableLiveScaleup"` + ImageBytes int64 `json:"imageBytes"` + StatusReason string `json:"statusReason"` + Hypervisor string `json:"hypervisor"` + Bootloader string `json:"bootloader"` + BmMachineId string `json:"bmMachineId"` } } -func (self *SRegion) DescribeInstances(id string, maxResult int, nextToken string) ([]SInstance, string, error) { +func (self *SInstance) GetId() string { + return self.InstancesSet.InstanceId +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +func (self *SInstance) GetName() string { + if len(self.InstancesSet.InstanceName) > 0 { + return self.InstancesSet.InstanceName + } + return self.GetId() +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + ret := []string{} + for _, sec := range self.GroupSet { + ret = append(ret, sec.GroupId) + } + return ret, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetVcpuCount() int { + return self.InstancesSet.VmtypeCPU +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.InstancesSet.VmtypeMem +} + +func (self *SInstance) GetBootOrder() string { + return "cdn" +} + +func (self *SInstance) GetVga() string { + return "" +} + +func (self *SInstance) GetVdi() string { + return "" +} + +func (self *SInstance) GetOSArch() string { + return "x86" +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + if self.InstancesSet.Platform == "linux" { + return cloudprovider.OsTypeLinux + } + return cloudprovider.OsTypeWindows +} + +func (self *SInstance) GetOSName() string { + return "" +} + +func (self *SInstance) GetBios() string { + return strings.ToUpper(self.InstancesSet.Bootloader) +} + +func (self *SInstance) GetMachine() string { + return "" +} + +func (self *SInstance) GetInstanceType() string { + return self.InstancesSet.InstanceType +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) GetHostname() string { + return self.InstancesSet.HostName +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetIHostId() string { + info := strings.Split(self.InstancesSet.HostAddress, "@") + if len(info) == 2 { + return info[1] + } + return "" +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_BINGO_CLOUD +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + storages, err := self.host.zone.region.getStorages() + if err != nil { + return nil, err + } + storageMaps := map[string]SStorage{} + for i := range storages { + storageMaps[storages[i].StorageId] = storages[i] + } + ret := []cloudprovider.ICloudDisk{} + for _, _disk := range self.InstancesSet.BlockDeviceMapping { + disk, err := self.host.zone.region.GetDisk(_disk.Ebs.VolumeId) + if err != nil { + return nil, err + } + storage, ok := storageMaps[disk.StorageId] + if ok { + storage.zone = self.host.zone + disk.storage = &storage + ret = append(ret, disk) + } + } + return ret, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := self.host.zone.region.GetInstanceNics(self.InstancesSet.InstanceId) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNic{} + for i := range nics { + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetStatus() string { + switch self.InstancesSet.InstanceState.Name { + default: + return self.InstancesSet.InstanceState.Name + } +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetInstances(id, zoneId string, maxResult int, nextToken string) ([]SInstance, string, error) { params := map[string]string{} if len(id) > 0 { params["instanceId"] = id @@ -134,19 +334,25 @@ func (self *SRegion) DescribeInstances(id string, maxResult int, nextToken strin if len(nextToken) > 0 { params["nextToken"] = nextToken } + + idx := 1 + if len(zoneId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "availability-zone" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = zoneId + idx++ + } + resp, err := self.invoke("DescribeInstances", params) if err != nil { return nil, "", err } result := struct { NextToken string - ReservationSet struct { - Item []SInstance - } + ReservationSet []SInstance }{} err = resp.Unmarshal(&result) if err != nil { return nil, "", err } - return result.ReservationSet.Item, result.NextToken, nil + return result.ReservationSet, result.NextToken, nil } diff --git a/pkg/multicloud/bingocloud/instancenic.go b/pkg/multicloud/bingocloud/instancenic.go new file mode 100644 index 0000000000..66a52c323d --- /dev/null +++ b/pkg/multicloud/bingocloud/instancenic.go @@ -0,0 +1,113 @@ +// 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 bingocloud + +import "yunion.io/x/onecloud/pkg/cloudprovider" + +type SInstanceNic struct { + Association string `json:"association"` + Attachment struct { + AttachTime string `json:"attachTime"` + AttachmentId string `json:"attachmentId"` + DeleteOnTermination string `json:"deleteOnTermination"` + DeviceIndex string `json:"deviceIndex"` + InstanceId string `json:"instanceId"` + InstanceOwnerId string `json:"instanceOwnerId"` + Status string `json:"status"` + } `json:"attachment"` + AvailabilityZone string `json:"availabilityZone"` + Description string `json:"description"` + FirstPacketLimit string `json:"firstPacketLimit"` + MACAddress string `json:"macAddress"` + Model string `json:"model"` + NetworkInterfaceId string `json:"networkInterfaceId"` + NoMatchPort string `json:"noMatchPort"` + OwnerId string `json:"ownerId"` + PrivateDNSName string `json:"privateDnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + PrivateIPAddressesSet []struct { + Association string `json:"association"` + Primary string `json:"primary"` + PrivateDNSName string `json:"privateDnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + } `json:"privateIpAddressesSet"` + RequesterManaged string `json:"requesterManaged"` + SourceDestCheck string `json:"sourceDestCheck"` + Status string `json:"status"` + SubnetId string `json:"subnetId"` + VpcId string `json:"vpcId"` +} + +func (self *SInstanceNic) GetId() string { + return self.NetworkInterfaceId +} + +func (self *SInstanceNic) GetIP() string { + return self.PrivateIPAddress +} + +func (self *SInstanceNic) GetMAC() string { + return self.MACAddress +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetDriver() string { + return self.Model +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.SubnetId +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + ret := []string{} + for _, ip := range self.PrivateIPAddressesSet { + if ip.PrivateIPAddress != self.PrivateIPAddress { + ret = append(ret, ip.PrivateIPAddress) + } + } + return ret, nil +} + +func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetInstanceNics(insId string) ([]SInstanceNic, error) { + params := map[string]string{} + if len(insId) > 0 { + params["instanceId"] = insId + } + resp, err := self.invoke("DescribeNetworkInterfaces", params) + if err != nil { + return nil, err + } + ret := struct { + NetworkInterfaceSet []SInstanceNic + }{} + resp.Unmarshal(&ret) + return ret.NetworkInterfaceSet, nil +} diff --git a/pkg/multicloud/bingocloud/network.go b/pkg/multicloud/bingocloud/network.go new file mode 100644 index 0000000000..445f4f8537 --- /dev/null +++ b/pkg/multicloud/bingocloud/network.go @@ -0,0 +1,199 @@ +// 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 bingocloud + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + multicloud.STagBase + wire *SWire + + CidrBlock string `json:"cidrBlock"` + MapPublicIPOnLaunch string `json:"mapPublicIpOnLaunch"` + RouterId string `json:"routerId"` + NetworkFrom string `json:"networkFrom"` + NetworkNode string `json:"networkNode"` + IsManagedNetwork string `json:"isManagedNetwork"` + SubnetName string `json:"subnetName"` + NetworkMask string `json:"networkMask"` + NetName string `json:"netName"` + Index string `json:"index"` + VpcIsPublic string `json:"vpcIsPublic"` + Description string `json:"description"` + MicroSegmentation string `json:"microSegmentation"` + State string `json:"state"` + DefaultForAz string `json:"defaultForAz"` + Router string `json:"router"` + Active string `json:"active"` + VpcShared string `json:"vpcShared"` + DvswitchName string `json:"dvswitchName"` + AvailableIPAddressCount string `json:"availableIpAddressCount"` + VlanNum string `json:"vlanNum"` + RouterCc2 string `json:"router_cc2"` + ResStatus string `json:"res_status"` + IPAddressCount string `json:"ipAddressCount"` + RouterCc string `json:"router_cc"` + VpcId string `json:"vpcId"` + NetworkTo string `json:"networkTo"` + Broadcast string `json:"broadcast"` + UserName string `json:"userName"` + IPVersion string `json:"ipVersion"` + AvailabilityZone string `json:"availabilityZone"` + Network string `json:"network"` + RouterMac string `json:"router_mac"` + CheckIP string `json:"checkIp"` + FloatingPool string `json:"floatingPool"` + StaticPool string `json:"staticPool"` + DvsPortGroup string `json:"dvsPortGroup"` + SubnetId string `json:"subnetId"` +} + +func (self *SNetwork) GetId() string { + return self.SubnetId +} + +func (self *SNetwork) GetGlobalId() string { + return self.SubnetId +} + +func (self *SNetwork) GetName() string { + if len(self.SubnetName) > 0 { + return self.SubnetName + } + return self.SubnetId +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 300 +} + +func (self *SNetwork) GetGateway() string { + prefix, err := netutils.NewIPV4Prefix(self.CidrBlock) + if err == nil { + return prefix.Address.StepUp().String() + } + return "" +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + endIp = endIp.StepDown() // 253 + endIp = endIp.StepDown() // 252 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + return pref.MaskLen +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetStatus() string { + return strings.ToLower(self.State) +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + networks, err := self.vpc.region.GetNetworks("", self.zone.ZoneName, self.vpc.VpcId) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range networks { + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, err + } + for i := range networks { + if networks[i].GetGlobalId() == id { + return networks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetNetworks(id, zoneId, vpcId string) ([]SNetwork, error) { + params := map[string]string{} + if len(id) > 0 { + params["subnetId"] = id + } + idx := 1 + if len(zoneId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "availability-zone" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = zoneId + idx++ + } + if len(vpcId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId + idx++ + } + resp, err := self.invoke("DescribeSubnets", params) + if err != nil { + return nil, err + } + networks := []SNetwork{} + return networks, resp.Unmarshal(&networks, "subnetSet") +} diff --git a/pkg/multicloud/bingocloud/provider/provider.go b/pkg/multicloud/bingocloud/provider/provider.go index e4e55c93cf..50a39051e9 100644 --- a/pkg/multicloud/bingocloud/provider/provider.go +++ b/pkg/multicloud/bingocloud/provider/provider.go @@ -118,7 +118,7 @@ func (self *SBingoCloudProvider) GetVersion() string { } func (self *SBingoCloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return nil, cloudprovider.ErrNotImplemented + return self.client.GetSubAccounts() } func (self *SBingoCloudProvider) GetAccountId() string { @@ -126,12 +126,11 @@ func (self *SBingoCloudProvider) GetAccountId() string { } func (self *SBingoCloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - // TODO - return nil + return self.client.GetIRegions() } func (self *SBingoCloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return nil, cloudprovider.ErrNotImplemented + return self.client.GetIRegionById(id) } func (self *SBingoCloudProvider) GetBalance() (float64, string, error) { @@ -140,7 +139,6 @@ func (self *SBingoCloudProvider) GetBalance() (float64, string, error) { func (self *SBingoCloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { return []cloudprovider.ICloudProject{}, nil - //return self.client.GetIProjects() } func (self *SBingoCloudProvider) GetStorageClasses(regionId string) []string { @@ -156,5 +154,5 @@ func (self *SBingoCloudProvider) GetObjectCannedAcls(regionId string) []string { } func (self *SBingoCloudProvider) GetCapabilities() []string { - return []string{} + return self.client.GetCapabilities() } diff --git a/pkg/multicloud/bingocloud/region.go b/pkg/multicloud/bingocloud/region.go index 5d2c66bf6d..1bafd3de0b 100644 --- a/pkg/multicloud/bingocloud/region.go +++ b/pkg/multicloud/bingocloud/region.go @@ -14,9 +14,26 @@ package bingocloud -import "yunion.io/x/jsonutils" +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) type SRegion struct { + multicloud.SRegion + multicloud.SRegionEipBase + multicloud.SRegionLbBase + multicloud.SRegionOssBase + multicloud.SRegionSecurityGroupBase + multicloud.SRegionVpcBase + multicloud.SRegionZoneBase + client *SBingoCloudClient RegionId string @@ -26,10 +43,46 @@ type SRegion struct { RegionEndpoint string } +func (self *SRegion) GetId() string { + return self.RegionId +} + +func (self *SRegion) GetName() string { + return self.RegionName +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_BINGO_CLOUD, self.RegionId) +} + func (self *SRegion) GetClient() *SBingoCloudClient { return self.client } +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + return cloudprovider.SModelI18nTable{} +} + +func (self *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_BINGO_CLOUD +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + func (self *SRegion) invoke(action string, params map[string]string) (jsonutils.JSONObject, error) { return self.client.invoke(action, params) } @@ -39,14 +92,84 @@ func (self *SBingoCloudClient) GetRegions() ([]SRegion, error) { if err != nil { return nil, err } - result := struct { - RegionInfo struct { - Item []SRegion - } - }{} - err = resp.Unmarshal(&result) + ret := []SRegion{} + err = resp.Unmarshal(&ret, "regionInfo") if err != nil { return nil, err } - return result.RegionInfo.Item, nil + return ret, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storages := []SStorage{} + part, nextToken, err := self.GetStorages("") + if err != nil { + return nil, err + } + storages = append(storages, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.GetStorages(nextToken) + if err != nil { + return nil, err + } + storages = append(storages, part...) + } + ret := []cloudprovider.ICloudStoragecache{} + for i := range storages { + cache := SStoragecache{ + region: self, + storageName: storages[i].StorageName, + storageId: storages[i].StorageId, + } + ret = append(ret, &cache) + } + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + caches, err := self.GetIStoragecaches() + if err != nil { + return nil, err + } + for i := range caches { + if caches[i].GetGlobalId() == id { + return caches[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range zones { + hosts, err := zones[i].GetIHosts() + if err != nil { + return nil, err + } + ret = append(ret, hosts...) + } + return ret, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := range zones { + hosts, err := zones[i].GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) } diff --git a/pkg/multicloud/bingocloud/secgroup.go b/pkg/multicloud/bingocloud/secgroup.go new file mode 100644 index 0000000000..abd2ab084b --- /dev/null +++ b/pkg/multicloud/bingocloud/secgroup.go @@ -0,0 +1,190 @@ +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SResourceBase + multicloud.BingoTags + region *SRegion + + ComplexIPPermissions string `json:"complexIpPermissions"` + ComplexIPPermissionsEgress string `json:"complexIpPermissionsEgress"` + DisplayName string `json:"displayName"` + GroupDescription string `json:"groupDescription"` + GroupId string `json:"groupId"` + GroupName string `json:"groupName"` + IPPermissionType string `json:"ipPermissionType"` + IPPermissions string `json:"ipPermissions"` + IPPermissionsEgress []IPPermissionsEgress `json:"ipPermissionsEgress"` + OwnerId string `json:"ownerId"` +} + +type IPPermissionsEgress struct { + BoundType string `json:"boundType"` + Description string `json:"description"` + FromPort int `json:"fromPort"` + IPProtocol string `json:"ipProtocol"` + Groups []struct { + GroupId string + GroupName string + } `json:"groups"` + IPRanges []struct { + CIdRIP string `json:"cidrIp"` + } `json:"ipRanges"` + L2Accept string `json:"l2Accept"` + PermissionId string `json:"permissionId"` + Policy string `json:"policy"` + ToPort int `json:"toPort"` +} + +func (self *SSecurityGroup) GetId() string { + return self.GroupId +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SSecurityGroup) GetName() string { + return self.GroupName +} + +func (self *SSecurityGroup) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SSecurityGroup) GetDescription() string { + return self.GroupDescription +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + return []cloudprovider.SecurityGroupReference{}, nil +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + ret := []cloudprovider.SecurityRule{} + for _, _rule := range self.IPPermissionsEgress { + if len(_rule.Groups) > 0 { + continue + } + rule := cloudprovider.SecurityRule{} + rule.Direction = secrules.DIR_IN + rule.Priority = 1 + rule.Action = secrules.SecurityRuleAllow + rule.Protocol = secrules.PROTO_ANY + rule.Description = _rule.Description + if _rule.BoundType == "Out" { + rule.Direction = secrules.DIR_OUT + } + if _rule.Policy == "DROP" { + rule.Action = secrules.SecurityRuleDeny + } + if _rule.IPProtocol != "all" { + rule.Protocol = _rule.IPProtocol + } + if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { + rule.PortStart, rule.PortEnd = _rule.FromPort, _rule.ToPort + } + + for _, ip := range _rule.IPRanges { + if ip.CIdRIP == "::/0" { + ip.CIdRIP = "0.0.0.0/0" + } + rule.ParseCIDR(ip.CIdRIP) + err := rule.ValidateRule() + if err != nil { + return nil, err + } + ret = append(ret, rule) + } + } + return ret, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetStatus() string { + return api.SECGROUP_STATUS_READY +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetSecurityGroups(id, name, nextToken string) ([]SSecurityGroup, string, error) { + params := map[string]string{} + if len(id) > 0 { + params["groupId"] = id + } + if len(name) > 0 { + params["groupName"] = name + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeSecurityGroups", params) + if err != nil { + return nil, "", err + } + ret := struct { + SecurityGroupInfo []SSecurityGroup + NextToken string + }{} + resp.Unmarshal(&ret) + return ret.SecurityGroupInfo, ret.NextToken, nil +} + +func (self *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) { + groups, _, err := self.GetSecurityGroups(id, "", "") + if err != nil { + return nil, err + } + for i := range groups { + if groups[i].GetGlobalId() == id { + groups[i].region = self + return &groups[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + groups, _, err := self.GetSecurityGroups("", opts.Name, "") + if err != nil { + return nil, err + } + for i := range groups { + if groups[i].GetName() == opts.Name { + groups[i].region = self + return &groups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/bingocloud/shell/disk.go b/pkg/multicloud/bingocloud/shell/disk.go new file mode 100644 index 0000000000..a79f0503e3 --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/disk.go @@ -0,0 +1,35 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type DiskListOptions struct { + Id string + NextToken string + } + shellutils.R(&DiskListOptions{}, "disk-list", "list disks", func(cli *bingocloud.SRegion, args *DiskListOptions) error { + vms, _, err := cli.GetDisks(args.Id, args.NextToken) + if err != nil { + return err + } + printList(vms, 0, 0, 0, []string{}) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/eip.go b/pkg/multicloud/bingocloud/shell/eip.go new file mode 100644 index 0000000000..df2786ed6b --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/eip.go @@ -0,0 +1,35 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type EipListOptions struct { + Ip string + NextToken string + } + shellutils.R(&EipListOptions{}, "eip-list", "list eips", func(cli *bingocloud.SRegion, args *EipListOptions) error { + eips, _, err := cli.GetEips(args.Ip, args.NextToken) + if err != nil { + return err + } + printList(eips, 0, 0, 0, []string{}) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/host.go b/pkg/multicloud/bingocloud/shell/host.go new file mode 100644 index 0000000000..1c12b95d96 --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/host.go @@ -0,0 +1,34 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type HostListOptions struct { + NextToken string + } + shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *bingocloud.SRegion, args *HostListOptions) error { + hosts, _, err := cli.GetHosts(args.NextToken) + if err != nil { + return err + } + printList(hosts, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/image.go b/pkg/multicloud/bingocloud/shell/image.go new file mode 100644 index 0000000000..b3d1bb17ae --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/image.go @@ -0,0 +1,35 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ImageListOptions struct { + Id string + NextToken string + } + shellutils.R(&ImageListOptions{}, "image-list", "list images", func(cli *bingocloud.SRegion, args *ImageListOptions) error { + images, _, err := cli.GetImages(args.Id, args.NextToken) + if err != nil { + return err + } + printList(images, 0, 0, 0, []string{}) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/instance.go b/pkg/multicloud/bingocloud/shell/instance.go index 0b5ffff36c..c1142781b5 100644 --- a/pkg/multicloud/bingocloud/shell/instance.go +++ b/pkg/multicloud/bingocloud/shell/instance.go @@ -22,11 +22,12 @@ import ( func init() { type InstanceListOptions struct { Id string + ZoneId string MaxResult int NextToken string } shellutils.R(&InstanceListOptions{}, "instance-list", "list instances", func(cli *bingocloud.SRegion, args *InstanceListOptions) error { - vms, _, err := cli.DescribeInstances(args.Id, args.MaxResult, args.NextToken) + vms, _, err := cli.GetInstances(args.Id, args.ZoneId, args.MaxResult, args.NextToken) if err != nil { return err } @@ -34,18 +35,16 @@ func init() { return nil }) - type InstanceIdOptions struct { - ID string + type InstanceNicListOptions struct { + InstanceId string } - shellutils.R(&InstanceIdOptions{}, "instance-show", "show instance", func(cli *bingocloud.SRegion, args *InstanceIdOptions) error { - /* - vm, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(vm) - */ + shellutils.R(&InstanceNicListOptions{}, "instance-nic-list", "list instance nics", func(cli *bingocloud.SRegion, args *InstanceNicListOptions) error { + nics, err := cli.GetInstanceNics(args.InstanceId) + if err != nil { + return err + } + printList(nics, 0, 0, 0, []string{}) return nil }) diff --git a/pkg/multicloud/bingocloud/shell/network.go b/pkg/multicloud/bingocloud/shell/network.go new file mode 100644 index 0000000000..8000c69b01 --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/network.go @@ -0,0 +1,36 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type NetworkListOptions struct { + Id string + ZoneId string + VpcId string + } + shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *bingocloud.SRegion, args *NetworkListOptions) error { + networks, err := cli.GetNetworks(args.Id, args.ZoneId, args.VpcId) + if err != nil { + return err + } + printList(networks, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/secgroup.go b/pkg/multicloud/bingocloud/shell/secgroup.go new file mode 100644 index 0000000000..61e1a2866d --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/secgroup.go @@ -0,0 +1,36 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type SecurityGroupListOptions struct { + Id string + Name string + NextToken string + } + shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security-groups", func(cli *bingocloud.SRegion, args *SecurityGroupListOptions) error { + groups, _, err := cli.GetSecurityGroups(args.Id, args.Name, args.NextToken) + if err != nil { + return err + } + printList(groups, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/storage.go b/pkg/multicloud/bingocloud/shell/storage.go new file mode 100644 index 0000000000..39a4a978c1 --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/storage.go @@ -0,0 +1,34 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type StorageListOptions struct { + NextToken string + } + shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *bingocloud.SRegion, args *StorageListOptions) error { + storages, _, err := cli.GetStorages(args.NextToken) + if err != nil { + return err + } + printList(storages, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/vpc.go b/pkg/multicloud/bingocloud/shell/vpc.go new file mode 100644 index 0000000000..691b420294 --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/vpc.go @@ -0,0 +1,34 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type VpcListOptions struct { + Id string + } + shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *bingocloud.SRegion, args *VpcListOptions) error { + vpcs, err := cli.GetVpcs(args.Id) + if err != nil { + return err + } + printList(vpcs, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/shell/zone.go b/pkg/multicloud/bingocloud/shell/zone.go new file mode 100644 index 0000000000..9c2bf14c5b --- /dev/null +++ b/pkg/multicloud/bingocloud/shell/zone.go @@ -0,0 +1,33 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/multicloud/bingocloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ZoneListOptions struct { + } + shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *bingocloud.SRegion, args *ZoneListOptions) error { + zones, err := cli.GetZones() + if err != nil { + return err + } + printList(zones, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/bingocloud/storage.go b/pkg/multicloud/bingocloud/storage.go new file mode 100644 index 0000000000..d88ab9ba45 --- /dev/null +++ b/pkg/multicloud/bingocloud/storage.go @@ -0,0 +1,173 @@ +// 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 bingocloud + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SStorage struct { + multicloud.STagBase + multicloud.SStorageBase + zone *SZone + + StorageId string `json:"storageId"` + Location string `json:"location"` + UsedBy string `json:"usedBy"` + SpaceUsed int64 `json:"spaceUsed"` + StorageName string `json:"storageName"` + FileFormat string `json:"fileFormat"` + Disabled string `json:"disabled"` + SpaceMax int64 `json:"spaceMax"` + StorageType string `json:"storageType"` + DrCloudId string `json:"drCloudId"` + ParameterSet []struct { + Name string + Value string + } `json:"parameterSet"` + ClusterId string `json:"clusterId"` + IsDRStorage string `json:"isDRStorage"` + ResUsage string `json:"resUsage"` + ScheduleTags string `json:"scheduleTags"` +} + +func (self *SStorage) GetName() string { + return self.StorageName +} + +func (self *SStorage) GetId() string { + return self.StorageId +} + +func (self *SStorage) GetGlobalId() string { + return self.GetId() +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStorage) DisableSync() bool { + return false +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return &SStoragecache{storageId: self.StorageId, storageName: self.StorageName, region: self.zone.region} +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetStorageType() string { + return self.StorageType +} + +func (self *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetCapacityMB() int64 { + return self.SpaceMax * 1024 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return self.SpaceUsed * 1024 +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.Marshal(self.ParameterSet) +} + +func (self *SStorage) GetEnabled() bool { + return self.Disabled == "false" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) GetStorages(nextToken string) ([]SStorage, string, error) { + params := map[string]string{} + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeStorages", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + StorageSet []SStorage + }{} + resp.Unmarshal(&ret) + return ret.StorageSet, ret.NextToken, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := range storages { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.getStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SRegion) getStorages() ([]SStorage, error) { + storages := []SStorage{} + part, nextToken, err := self.GetStorages("") + if err != nil { + return nil, err + } + storages = append(storages, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.GetStorages(nextToken) + if err != nil { + return nil, err + } + storages = append(storages, part...) + } + return storages, nil +} diff --git a/pkg/multicloud/bingocloud/storagecache.go b/pkg/multicloud/bingocloud/storagecache.go new file mode 100644 index 0000000000..b2b34e1207 --- /dev/null +++ b/pkg/multicloud/bingocloud/storagecache.go @@ -0,0 +1,71 @@ +// 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 bingocloud + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + multicloud.STagBase + + region *SRegion + storageId string + storageName string +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.GetGlobalId(), self.storageId) +} + +func (self *SStoragecache) GetGlobalId() string { + return self.GetId() +} + +func (self *SStoragecache) GetName() string { + return self.storageName +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + return "", cloudprovider.ErrNotImplemented +} diff --git a/pkg/multicloud/bingocloud/vpc.go b/pkg/multicloud/bingocloud/vpc.go new file mode 100644 index 0000000000..ddb96f2b5f --- /dev/null +++ b/pkg/multicloud/bingocloud/vpc.go @@ -0,0 +1,142 @@ +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + multicloud.STagBase + + region *SRegion + + RequestId string `json:"requestId"` + VlanNum string `json:"vlanNum"` + AsGateway string `json:"asGateway"` + DhcpOptionsId string `json:"dhcpOptionsId"` + VpcName string `json:"vpcName"` + OwnerId string `json:"ownerId"` + WanCode string `json:"wanCode"` + Shared string `json:"shared"` + SubnetPolicy string `json:"subnetPolicy"` + Description string `json:"description"` + VpcId string `json:"vpcId"` + IsPublicNetwork string `json:"isPublicNetwork"` + GatewayId string `json:"gatewayId"` + IsDefault string `json:"isDefault"` + Provider string `json:"provider"` + State string `json:"state"` + CidrBlock string `json:"cidrBlock"` + InstanceTenancy string `json:"instanceTenancy"` +} + +func (self *SVpc) GetId() string { + return self.VpcId +} + +func (self *SVpc) GetGlobalId() string { + return self.VpcId +} + +func (self *SVpc) GetName() string { + return self.VpcName +} + +func (self *SVpc) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + part, nextToken, err := self.region.GetSecurityGroups("", "", "") + if err != nil { + return nil, err + } + groups := []SSecurityGroup{} + groups = append(groups, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.region.GetSecurityGroups("", "", nextToken) + if err != nil { + return nil, err + } + groups = append(groups, part...) + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range groups { + groups[i].region = self.region + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault == "true" +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + switch self.State { + case "available": + return api.VPC_STATUS_AVAILABLE + default: + return self.State + } +} + +func (self *SRegion) GetVpcs(id string) ([]SVpc, error) { + params := map[string]string{} + if len(id) > 0 { + params["vpcId"] = id + } + resp, err := self.invoke("DescribeVpcs", params) + if err != nil { + return nil, err + } + vpcs := []SVpc{} + return vpcs, resp.Unmarshal(&vpcs, "vpcSet") +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetVpcs("") + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/bingocloud/wire.go b/pkg/multicloud/bingocloud/wire.go new file mode 100644 index 0000000000..8b32397abb --- /dev/null +++ b/pkg/multicloud/bingocloud/wire.go @@ -0,0 +1,94 @@ +// 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 bingocloud + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SWire struct { + multicloud.STagBase + multicloud.SResourceBase + + zone *SZone + vpc *SVpc +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s/%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) +} + +func (self *SWire) GetGlobalId() string { + return self.GetId() +} + +func (self *SWire) GetName() string { + return fmt.Sprintf("%s-%s", self.vpc.GetName(), self.zone.GetName()) +} + +func (self *SWire) GetBandwidth() int { + return 1000 +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == id { + return wires[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + zones, err := self.region.GetZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range zones { + wire := &SWire{ + vpc: self, + zone: &zones[i], + } + ret = append(ret, wire) + } + return ret, nil +} diff --git a/pkg/multicloud/bingocloud/zone.go b/pkg/multicloud/bingocloud/zone.go new file mode 100644 index 0000000000..508d7bc5e7 --- /dev/null +++ b/pkg/multicloud/bingocloud/zone.go @@ -0,0 +1,95 @@ +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + multicloud.STagBase + + region *SRegion + ZoneName string + DisplayName string + ZoneState string +} + +func (self *SZone) GetGlobalId() string { + return self.ZoneName +} + +func (self *SZone) GetId() string { + return self.ZoneName +} + +func (self *SZone) GetName() string { + return self.DisplayName +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + return cloudprovider.SModelI18nTable{} +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetStatus() string { + if self.ZoneState == "available" { + return api.ZONE_ENABLE + } + return api.ZONE_DISABLE +} + +func (self *SRegion) GetZones() ([]SZone, error) { + resp, err := self.invoke("DescribeAvailabilityZones", nil) + if err != nil { + return nil, err + } + ret := []SZone{} + return ret, resp.Unmarshal(&ret, "availabilityZoneInfo") +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := self.GetZones() + if err != nil { + return nil, errors.Wrapf(err, "GetZones") + } + ret := []cloudprovider.ICloudZone{} + for i := range zones { + zones[i].region = self + ret = append(ret, &zones[i]) + } + return ret, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := range zones { + if zones[i].GetGlobalId() == id { + return zones[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/pkg/multicloud/tag_base.go b/pkg/multicloud/tag_base.go index 6a3915e48e..720133edf9 100644 --- a/pkg/multicloud/tag_base.go +++ b/pkg/multicloud/tag_base.go @@ -429,3 +429,26 @@ func (self *CloudpodsTags) GetSysTags() map[string]string { func (self *CloudpodsTags) SetTags(tags map[string]string, replace bool) error { return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") } + +type BingoTags struct { + TagSet []struct { + Key string + Value string + } +} + +func (self *BingoTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, tag := range self.TagSet { + tags[tag.Key] = tag.Value + } + return tags, nil +} + +func (self *BingoTags) GetSysTags() map[string]string { + return nil +} + +func (self *BingoTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/github.com/basgys/goxml2json/README.md b/vendor/github.com/basgys/goxml2json/README.md index 04e0b7faff..0abdfcda4a 100644 --- a/vendor/github.com/basgys/goxml2json/README.md +++ b/vendor/github.com/basgys/goxml2json/README.md @@ -53,7 +53,7 @@ Go package that converts XML to JSON ```json { "osm": { - "-version": "0.6", + "-version": 0.6, "-generator": "CGImap 0.0.2", "bounds": { "-minlat": "54.0889580", @@ -66,17 +66,42 @@ Go package that converts XML to JSON } ``` +**With type conversion** + +```go + package main + + import ( + "fmt" + "strings" + + xj "github.com/basgys/goxml2json" + ) + + func main() { + // xml is an io.Reader + xml := strings.NewReader(`19.95`) + json, err := xj.Convert(xml, xj.WithTypeConverter(xj.Float)) + if err != nil { + panic("That's embarrassing...") + } + + fmt.Println(json.String()) + // {"price": 19.95} + } +``` + ### Contributing Feel free to contribute to this project if you want to fix/extend/improve it. ### Contributors - [DirectX](https://github.com/directx) + - [powerslacker](https://github.com/powerslacker) - [samuelhug](https://github.com/samuelhug) ### TODO - * Extract data types in JSON (numbers, boolean, ...) * Categorise errors * Option to prettify the JSON output * Benchmark diff --git a/vendor/github.com/basgys/goxml2json/converter.go b/vendor/github.com/basgys/goxml2json/converter.go index 3e4cbce2ae..a1311ab805 100644 --- a/vendor/github.com/basgys/goxml2json/converter.go +++ b/vendor/github.com/basgys/goxml2json/converter.go @@ -6,17 +6,18 @@ import ( ) // Convert converts the given XML document to JSON -func Convert(r io.Reader) (*bytes.Buffer, error) { +func Convert(r io.Reader, ps ...plugin) (*bytes.Buffer, error) { // Decode XML document root := &Node{} - err := NewDecoder(r).Decode(root) + err := NewDecoder(r, ps...).Decode(root) if err != nil { return nil, err } // Then encode it in JSON buf := new(bytes.Buffer) - err = NewEncoder(buf).Encode(root) + e := NewEncoder(buf, ps...) + err = e.Encode(root) if err != nil { return nil, err } diff --git a/vendor/github.com/basgys/goxml2json/decoder.go b/vendor/github.com/basgys/goxml2json/decoder.go index af03356c95..a45079f47c 100644 --- a/vendor/github.com/basgys/goxml2json/decoder.go +++ b/vendor/github.com/basgys/goxml2json/decoder.go @@ -19,6 +19,8 @@ type Decoder struct { err error attributePrefix string contentPrefix string + excludeAttrs map[string]bool + formatters []nodeFormatter } type element struct { @@ -35,6 +37,16 @@ func (dec *Decoder) SetContentPrefix(prefix string) { dec.contentPrefix = prefix } +func (dec *Decoder) AddFormatters(formatters []nodeFormatter) { + dec.formatters = formatters +} + +func (dec *Decoder) ExcludeAttributes(attrs []string) { + for _, attr := range attrs { + dec.excludeAttrs[attr] = true + } +} + func (dec *Decoder) DecodeWithCustomPrefixes(root *Node, contentPrefix string, attributePrefix string) error { dec.contentPrefix = contentPrefix dec.attributePrefix = attributePrefix @@ -42,21 +54,17 @@ func (dec *Decoder) DecodeWithCustomPrefixes(root *Node, contentPrefix string, a } // NewDecoder returns a new decoder that reads from r. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{r: r} +func NewDecoder(r io.Reader, plugins ...plugin) *Decoder { + d := &Decoder{r: r, contentPrefix: contentPrefix, attributePrefix: attrPrefix, excludeAttrs: map[string]bool{}} + for _, p := range plugins { + d = p.AddToDecoder(d) + } + return d } // Decode reads the next JSON-encoded value from its // input and stores it in the value pointed to by v. func (dec *Decoder) Decode(root *Node) error { - - if dec.contentPrefix == "" { - dec.contentPrefix = contentPrefix - } - if dec.attributePrefix == "" { - dec.attributePrefix = attrPrefix - } - xmlDec := xml.NewDecoder(dec.r) // That will convert the charset if the provided XML is non-UTF-8 @@ -85,6 +93,9 @@ func (dec *Decoder) Decode(root *Node) error { // Extract attributes as children for _, a := range se.Attr { + if _, ok := dec.excludeAttrs[a.Name.Local]; ok { + continue + } elem.n.AddChild(dec.attributePrefix+a.Name.Local, &Node{Data: a.Value}) } case xml.CharData: @@ -101,6 +112,10 @@ func (dec *Decoder) Decode(root *Node) error { } } + for _, formatter := range dec.formatters { + formatter.Format(root) + } + return nil } diff --git a/vendor/github.com/basgys/goxml2json/encoder.go b/vendor/github.com/basgys/goxml2json/encoder.go index 0a542b8a84..61fafc57f3 100644 --- a/vendor/github.com/basgys/goxml2json/encoder.go +++ b/vendor/github.com/basgys/goxml2json/encoder.go @@ -12,25 +12,16 @@ type Encoder struct { err error contentPrefix string attributePrefix string + tc encoderTypeConverter } // NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w: w} -} - -func (enc *Encoder) SetAttributePrefix(prefix string) { - enc.attributePrefix = prefix -} - -func (enc *Encoder) SetContentPrefix(prefix string) { - enc.contentPrefix = prefix -} - -func (enc *Encoder) EncodeWithCustomPrefixes(root *Node, contentPrefix string, attributePrefix string) error { - enc.contentPrefix = contentPrefix - enc.attributePrefix = attributePrefix - return enc.Encode(root) +func NewEncoder(w io.Writer, plugins ...plugin) *Encoder { + e := &Encoder{w: w, contentPrefix: contentPrefix, attributePrefix: attrPrefix} + for _, p := range plugins { + e = p.AddToEncoder(e) + } + return e } // Encode writes the JSON encoding of v to the stream @@ -41,12 +32,6 @@ func (enc *Encoder) Encode(root *Node) error { if root == nil { return nil } - if enc.contentPrefix == "" { - enc.contentPrefix = contentPrefix - } - if enc.attributePrefix == "" { - enc.attributePrefix = attrPrefix - } enc.err = enc.format(root, 0) @@ -82,7 +67,7 @@ func (enc *Encoder) format(n *Node, lvl int) error { enc.write(label) enc.write("\": ") - if len(children) > 1 { + if n.ChildrenAlwaysAsArray || len(children) > 1 { // Array enc.write("[") for j, c := range children { @@ -106,8 +91,14 @@ func (enc *Encoder) format(n *Node, lvl int) error { enc.write("}") } else { - // TODO : Extract data type - enc.write(sanitiseString(n.Data)) + s := sanitiseString(n.Data) + if enc.tc == nil { + // do nothing + } else { + s = enc.tc.Convert(s) + } + enc.write(s) + } return nil @@ -124,6 +115,7 @@ func sanitiseString(s string) string { var buf bytes.Buffer buf.WriteByte('"') + start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { @@ -192,6 +184,8 @@ func sanitiseString(s string) string { if start < len(s) { buf.WriteString(s[start:]) } + buf.WriteByte('"') + return buf.String() } diff --git a/vendor/github.com/basgys/goxml2json/jstype.go b/vendor/github.com/basgys/goxml2json/jstype.go new file mode 100644 index 0000000000..c0c08cb5f0 --- /dev/null +++ b/vendor/github.com/basgys/goxml2json/jstype.go @@ -0,0 +1,74 @@ +package xml2json + +import ( + "strconv" + "strings" +) + +// https://cswr.github.io/JsonSchema/spec/basic_types/ +// JSType is a JavaScript extracted from a string +type JSType int + +const ( + Bool JSType = iota + Int + Float + String + Null +) + +// Str2JSType extract a JavaScript type from a string +func Str2JSType(s string) JSType { + var ( + output JSType + ) + s = strings.TrimSpace(s) // santize the given string + switch { + case isBool(s): + output = Bool + case isFloat(s): + output = Float + case isInt(s): + output = Int + case isNull(s): + output = Null + default: + output = String // if all alternatives have been eliminated, the input is a string + } + return output +} + +func isBool(s string) bool { + return s == "true" || s == "false" +} + +func isFloat(s string) bool { + var output = false + if strings.Contains(s, ".") { + _, err := strconv.ParseFloat(s, 64) + if err == nil { // the string successfully converts to a decimal + output = true + } + } + return output +} + +func isInt(s string) bool { + var output = false + if len(s) >= 1 { + _, err := strconv.Atoi(s) + if err == nil { // the string successfully converts to an int + if s != "0" && s[0] == '0' { + // if the first rune is '0' and there is more than 1 rune, then the input is most likely a float or intended to be + // a string value -- such as in the case of a guid, or an international phone number + } else { + output = true + } + } + } + return output +} + +func isNull(s string) bool { + return s == "null" +} diff --git a/vendor/github.com/basgys/goxml2json/plugins.go b/vendor/github.com/basgys/goxml2json/plugins.go new file mode 100644 index 0000000000..60137f05db --- /dev/null +++ b/vendor/github.com/basgys/goxml2json/plugins.go @@ -0,0 +1,161 @@ +package xml2json + +import ( + "strings" +) + +type ( + // an plugin is added to an encoder or/and to an decoder to allow custom functionality at runtime + plugin interface { + AddToEncoder(*Encoder) *Encoder + AddToDecoder(*Decoder) *Decoder + } + // a type converter overides the default string sanitization for encoding json + encoderTypeConverter interface { + Convert(string) string + } + // customTypeConverter converts strings to JSON types using a best guess approach, only parses the JSON types given + // when initialized via WithTypeConverter + customTypeConverter struct { + parseTypes []JSType + } + + attrPrefixer string + contentPrefixer string + + excluder []string + + nodesFormatter struct { + list []nodeFormatter + } + nodeFormatter struct { + path string + plugin nodePlugin + } + + nodePlugin interface { + AddTo(*Node) + } + + arrayFormatter struct{} +) + +// WithTypeConverter allows customized js type conversion behavior by passing in the desired JSTypes +func WithTypeConverter(ts ...JSType) *customTypeConverter { + return &customTypeConverter{parseTypes: ts} +} + +func (tc *customTypeConverter) parseAsString(t JSType) bool { + if t == String { + return true + } + for i := 0; i < len(tc.parseTypes); i++ { + if tc.parseTypes[i] == t { + return false + } + } + return true +} + +// Adds the type converter to the encoder +func (tc *customTypeConverter) AddToEncoder(e *Encoder) *Encoder { + e.tc = tc + return e +} + +func (tc *customTypeConverter) AddToDecoder(d *Decoder) *Decoder { + return d +} + +func (tc *customTypeConverter) Convert(s string) string { + // remove quotes if they exists + if strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { + s = s[1 : len(s)-1] + } + jsType := Str2JSType(s) + if tc.parseAsString(jsType) { + // add the quotes removed at the start of this func + s = `"` + s + `"` + } + return s +} + +// WithAttrPrefix appends the given prefix to the json output of xml attribute fields to preserve namespaces +func WithAttrPrefix(prefix string) *attrPrefixer { + ap := attrPrefixer(prefix) + return &ap +} + +func (a *attrPrefixer) AddToEncoder(e *Encoder) *Encoder { + e.attributePrefix = string((*a)) + return e +} + +func (a *attrPrefixer) AddToDecoder(d *Decoder) *Decoder { + d.attributePrefix = string((*a)) + return d +} + +// WithContentPrefix appends the given prefix to the json output of xml content fields to preserve namespaces +func WithContentPrefix(prefix string) *contentPrefixer { + c := contentPrefixer(prefix) + return &c +} + +func (c *contentPrefixer) AddToEncoder(e *Encoder) *Encoder { + e.contentPrefix = string((*c)) + return e +} + +func (c *contentPrefixer) AddToDecoder(d *Decoder) *Decoder { + d.contentPrefix = string((*c)) + return d +} + +// ExcludeAttributes excludes some xml attributes, for example, xmlns:xsi, xsi:noNamespaceSchemaLocation +func ExcludeAttributes(attrs []string) *excluder { + ex := excluder(attrs) + return &ex +} + +func (ex *excluder) AddToEncoder(e *Encoder) *Encoder { + return e +} + +func (ex *excluder) AddToDecoder(d *Decoder) *Decoder { + d.ExcludeAttributes([]string((*ex))) + return d +} + +// WithNodes formats specific nodes +func WithNodes(n ...nodeFormatter) *nodesFormatter { + return &nodesFormatter{list: n} +} + +func (nf *nodesFormatter) AddToEncoder(e *Encoder) *Encoder { + return e +} + +func (nf *nodesFormatter) AddToDecoder(d *Decoder) *Decoder { + d.AddFormatters(nf.list) + return d +} + +func NodePlugin(path string, plugin nodePlugin) nodeFormatter { + return nodeFormatter{path: path, plugin: plugin} +} + +func (nf *nodeFormatter) Format(node *Node) { + child := node.GetChild(nf.path) + if child != nil { + nf.plugin.AddTo(child) + } +} + +func ToArray() *arrayFormatter { + return &arrayFormatter{} +} + +func (af *arrayFormatter) AddTo(n *Node) { + n.ChildrenAlwaysAsArray = true +} diff --git a/vendor/github.com/basgys/goxml2json/struct.go b/vendor/github.com/basgys/goxml2json/struct.go index 1f423b1ce4..350e1ac724 100644 --- a/vendor/github.com/basgys/goxml2json/struct.go +++ b/vendor/github.com/basgys/goxml2json/struct.go @@ -1,9 +1,14 @@ package xml2json +import ( + "strings" +) + // Node is a data element on a tree type Node struct { - Children map[string]Nodes - Data string + Children map[string]Nodes + Data string + ChildrenAlwaysAsArray bool } // Nodes is a list of nodes @@ -23,3 +28,20 @@ func (n *Node) AddChild(s string, c *Node) { func (n *Node) IsComplex() bool { return len(n.Children) > 0 } + +// GetChild returns child by path if exists. Path looks like "grandparent.parent.child.grandchild" +func (n *Node) GetChild(path string) *Node { + result := n + names := strings.Split(path, ".") + for _, name := range names { + children, exists := result.Children[name] + if !exists { + return nil + } + if len(children) == 0 { + return nil + } + result = children[0] + } + return result +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0832e865e6..a6fa4fa4a4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -199,7 +199,7 @@ github.com/aws/aws-sdk-go/service/sso/ssoiface github.com/aws/aws-sdk-go/service/sts github.com/aws/aws-sdk-go/service/sts/stsiface github.com/aws/aws-sdk-go/service/wafv2 -# github.com/basgys/goxml2json v1.1.0 +# github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 github.com/basgys/goxml2json # github.com/beevik/etree v1.1.0 github.com/beevik/etree @@ -1234,7 +1234,7 @@ yunion.io/x/log/hooks yunion.io/x/ovsdb/cli_util yunion.io/x/ovsdb/schema/ovn_nb yunion.io/x/ovsdb/types -# yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97 +# yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38 yunion.io/x/pkg/errors yunion.io/x/pkg/gotypes yunion.io/x/pkg/prettytable diff --git a/vendor/yunion.io/x/pkg/util/regutils/regutils.go b/vendor/yunion.io/x/pkg/util/regutils/regutils.go index 06be8fb77d..f7c88459bf 100644 --- a/vendor/yunion.io/x/pkg/util/regutils/regutils.go +++ b/vendor/yunion.io/x/pkg/util/regutils/regutils.go @@ -35,6 +35,7 @@ var SIZE_REG *regexp.Regexp var MONTH_REG *regexp.Regexp var DATE_REG *regexp.Regexp var DATE_COMPACT_REG *regexp.Regexp +var DATE_EXCEL_REG *regexp.Regexp var ISO_TIME_REG *regexp.Regexp var ISO_NO_SECOND_TIME_REG *regexp.Regexp var FULLISO_TIME_REG *regexp.Regexp @@ -68,6 +69,7 @@ func init() { MONTH_REG = regexp.MustCompile(`^\d{4}-\d{2}$`) DATE_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`) DATE_COMPACT_REG = regexp.MustCompile(`^\d{8}$`) + DATE_EXCEL_REG = regexp.MustCompile(`^\d{2}-\d{2}-\d{2}$`) ISO_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`) ISO_NO_SECOND_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`) FULLISO_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3,9}(Z|[+-]\d{2}:\d{2})$`) @@ -192,6 +194,10 @@ func MatchDateCompact(str string) bool { return DATE_COMPACT_REG.MatchString(str) } +func MatchDateExcel(str string) bool { + return DATE_EXCEL_REG.MatchString(str) +} + func MatchZStackTime(str string) bool { return ZSTACK_TIME_REG.MatchString(str) } diff --git a/vendor/yunion.io/x/pkg/util/timeutils/timeutils.go b/vendor/yunion.io/x/pkg/util/timeutils/timeutils.go index c96393292c..d0ef7d1ad5 100644 --- a/vendor/yunion.io/x/pkg/util/timeutils/timeutils.go +++ b/vendor/yunion.io/x/pkg/util/timeutils/timeutils.go @@ -54,6 +54,7 @@ const ( CompactTimeFormat = "20060102150405" DateFormat = "2006-01-02" ShortDateFormat = "20060102" + DateExcelFormat = "01-02-06" MonthFormat = "2006-01" ShortMonthFormat = "200601" ZStackTimeFormat = "Jan 2, 2006 15:04:05 PM" @@ -101,6 +102,10 @@ func ShortDate(now time.Time) string { return Utcify(now).Format(ShortDateFormat) } +func DateExcelStr(now time.Time) string { + return Utcify(now).Format(DateExcelFormat) +} + func MonthStr(now time.Time) string { return Utcify(now).Format(MonthFormat) } @@ -187,6 +192,10 @@ func ParseShortDate(str string) (time.Time, error) { return time.Parse(ShortDateFormat, str) } +func ParseDateExcel(str string) (time.Time, error) { + return time.Parse(DateExcelFormat, str) +} + func ParseZStackDate(str string) (time.Time, error) { return time.ParseInLocation(ZStackTimeFormat, str, time.Local) } @@ -219,6 +228,8 @@ func ParseTimeStr(str string) (time.Time, error) { return ParseDate(str) } else if regutils.MatchDateCompact(str) { return ParseShortDate(str) + } else if regutils.MatchDateExcel(str) { + return ParseDateExcel(str) } else if regutils.MatchZStackTime(str) { return ParseZStackDate(str) } else {