Compare commits

...

16 Commits

Author SHA1 Message Date
Zexi Li
301006e213 Merge pull request #8331 from ioito/automated-cherry-pick-of-#8330-upstream-release-3.4
Automated cherry pick of #8330: fix: hostname for instance
2020-10-16 17:43:22 +08:00
Qu Xuan
950a2c29fb fix: hostname for instance 2020-10-16 17:12:40 +08:00
yunion-ci-robot
558872db27 Merge pull request #8324 from zhasm/automated-cherry-pick-of-#8323-upstream-release-3.4
Automated cherry pick of #8323: remove alpine build cache before make image
2020-10-16 15:14:46 +08:00
yunion-ci-robot
6386391bf4 Merge pull request #8327 from zexi/automated-cherry-pick-of-#8326-upstream-release-3.4
Automated cherry pick of #8326: fix: get images distinct field
2020-10-16 14:35:40 +08:00
Zexi Li
d298c75448 fix: get images distinct field 2020-10-16 12:01:01 +08:00
Zhang Dongliang
28cb75f41b remove alpine build cache before make image 2020-10-16 12:00:10 +08:00
yunion-ci-robot
560a68d379 Merge pull request #8320 from swordqiu/automated-cherry-pick-of-#8319-upstream-release-3.4
Automated cherry pick of #8319: fix: resolve with_meta filter conflict
2020-10-16 11:39:33 +08:00
yunion-ci-robot
9e597db90a Merge pull request #8315 from rainzm/automated-cherry-pick-of-#8314-upstream-release-3.4
Automated cherry pick of #8314: feat(esxi): do not specify portkey in NewVNIC
2020-10-16 10:38:34 +08:00
Qiu Jian
9c9cb17d32 fix: resolve with_meta filter conflict 2020-10-16 10:34:04 +08:00
rainzm
cc96c01c00 feat(esxi): do not specify portkey in NewVNIC 2020-10-16 08:22:58 +08:00
yunion-ci-robot
cb22077722 Merge pull request #8313 from swordqiu/automated-cherry-pick-of-#8312-upstream-release-3.4
Automated cherry pick of #8312: feature: filter storages by image
2020-10-15 23:10:33 +08:00
yunion-ci-robot
8e3c173373 Merge pull request #8309 from ioito/automated-cherry-pick-of-#8308-upstream-release-3.4
Automated cherry pick of #8308: fix: 避免并发同步安全组导致规则混乱
2020-10-15 23:02:32 +08:00
Qiu Jian
45e092bd2d feature: filter storages by image 2020-10-15 22:57:13 +08:00
Qu Xuan
4b2d67de42 fix: 避免并发同步安全组导致规则混乱 2020-10-15 22:26:54 +08:00
yunion-ci-robot
6677c30a5d Merge pull request #8306 from zexi/automated-cherry-pick-of-#8305-upstream-release-3.4
Automated cherry pick of #8305: stringutils2: add RemoveUtf8Strings func
2020-10-15 21:46:36 +08:00
Zexi Li
64593fc882 stringutils2: add RemoveUtf8Strings func 2020-10-15 19:37:00 +08:00
23 changed files with 332 additions and 134 deletions

View File

@@ -313,7 +313,7 @@ REGISTRY ?= "registry.cn-beijing.aliyuncs.com/yunionio"
VERSION ?= $(shell git describe --exact-match 2> /dev/null || \
git describe --match=$(git rev-parse --short=8 HEAD) --always --dirty --abbrev=8)
image: clean
image:
mkdir -p $(ROOT_DIR)/_output
DEBUG=$(DEBUG) ARCH=$(ARCH) TAG=$(VERSION) REGISTRY=$(REGISTRY) $(ROOT_DIR)/scripts/docker_push.sh $(filter-out $@,$(MAKECMDGOALS))

View File

@@ -37,6 +37,7 @@ func init() {
Schedtag string `help:"filter storage by schedtag"`
HostSchedtagId string `help:"filter storage by host schedtag"`
ImageId string `help:"filter storage by image"`
}
R(&StorageListOptions{}, "storage-list", "List storages", func(s *mcclient.ClientSession, opts *StorageListOptions) error {
params, err := options.ListStructToParams(opts)

View File

@@ -186,4 +186,7 @@ type StorageListInput struct {
// filter by host schedtag
HostSchedtagId string `json:"host_schedtag_id"`
// filter by cachedimage
ImageId string `json:"image_id"`
}

View File

@@ -199,12 +199,15 @@ type MetadataResourceListInput struct {
// 返回资源的标签不包含用户标签
WithoutUserMeta *bool `json:"without_user_meta"`
// 返回资源的标签包含用户标签
// 返回包含用户标签的资源
WithUserMeta *bool `json:"with_user_meta"`
// 返回资源的标签包含外部标签
// 返回包含外部标签的资源
WithCloudMeta *bool `json:"with_cloud_meta"`
// 返回包含任意标签的资源
WithAnyMeta *bool `json:"with_any_meta"`
// 返回列表数据中包含资源的标签数据Metadata
WithMeta *bool `json:"with_meta"`
}

View File

@@ -107,12 +107,7 @@ func (manager *SDomainizedResourceBaseManager) ListItemFilter(
) (*sqlchemy.SQuery, error) {
if len(query.ProjectDomainIds) > 0 {
// make sure ids are not utf8 string
idList := make([]string, 0)
for _, pid := range query.ProjectDomainIds {
if !stringutils2.IsUtf8(pid) {
idList = append(idList, pid)
}
}
idList := stringutils2.RemoveUtf8Strings(query.ProjectDomainIds)
tenants := TenantCacheManager.GetDomainQuery().SubQuery()
subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(tenants.Field("id"), idList),

View File

@@ -90,10 +90,10 @@ func (meta *SMetadataResourceBaseModelManager) ListItemFilter(
}
}
if input.WithMeta != nil {
if input.WithAnyMeta != nil {
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
sq := metadatas.Query(metadatas.Field("obj_id")).Distinct().SubQuery()
if *input.WithMeta {
if *input.WithAnyMeta {
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
} else {
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))

View File

@@ -102,12 +102,7 @@ func (manager *SProjectizedResourceBaseManager) ListItemFilter(
}
if len(query.ProjectIds) > 0 {
// make sure ids are not utf8 string
idList := make([]string, 0)
for _, pid := range query.ProjectIds {
if !stringutils2.IsUtf8(pid) {
idList = append(idList, pid)
}
}
idList := stringutils2.RemoveUtf8Strings(query.ProjectIds)
tenants := TenantCacheManager.GetTenantQuery().SubQuery()
subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(tenants.Field("id"), idList),

View File

@@ -518,7 +518,7 @@ func _managedResourceFilterByAccount(managerIdFieldName string, q *sqlchemy.SQue
if len(cloudaccountArr) > 0 {
cpq := CloudaccountManager.Query().SubQuery()
subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(cpq.Field("id"), cloudaccountArr),
sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(cloudaccountArr)),
sqlchemy.In(cpq.Field("name"), cloudaccountArr),
)).SubQuery()
subq := CloudproviderManager.Query("id").In("cloudaccount_id", subcpq).SubQuery()

View File

@@ -1399,6 +1399,17 @@ func (manager *SStorageManager) ListItemFilter(
q = q.In("id", subq.SubQuery())
}
if len(query.ImageId) > 0 {
image, err := CachedimageManager.getImageInfo(ctx, userCred, query.ImageId, false)
if err != nil {
return nil, errors.Wrap(err, "CachedimageManager.getImageInfo")
}
subq := StorageManager.Query("id")
storagecaches := StoragecachedimageManager.Query("storagecache_id").Equals("cachedimage_id", image.Id).SubQuery()
subq = subq.Join(storagecaches, sqlchemy.Equals(subq.Field("storagecache_id"), storagecaches.Field("storagecache_id")))
q = q.In("id", subq.SubQuery())
}
return q, err
}

View File

@@ -26,9 +26,10 @@ import (
)
var (
syncAccountWorker *appsrv.SWorkerManager
syncWorkers []*appsrv.SWorkerManager
syncWorkerRing *hashring.HashRing
syncSecgroupWorker *appsrv.SWorkerManager
syncAccountWorker *appsrv.SWorkerManager
syncWorkers []*appsrv.SWorkerManager
syncWorkerRing *hashring.HashRing
)
func InitSyncWorkers(count int) {
@@ -50,6 +51,12 @@ func InitSyncWorkers(count int) {
2048,
true,
)
syncSecgroupWorker = appsrv.NewWorkerManager(
"syncSecgroupProbeWorkerManager",
1,
2048,
true,
)
}
func RunSyncCloudproviderRegionTask(key string, syncFunc func()) {
@@ -62,3 +69,7 @@ func RunSyncCloudproviderRegionTask(key string, syncFunc func()) {
func RunSyncCloudAccountTask(probeFunc func()) {
syncAccountWorker.Run(probeFunc, nil, nil)
}
func RunSyncSecgroupTask(syncFunc func()) {
syncAccountWorker.Run(syncFunc, nil, nil)
}

View File

@@ -1480,95 +1480,109 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
return "", errors.Wrap(err, "SSecurityGroupCache.Register")
}
iRegion, err := vpc.GetIRegion()
if err != nil {
return "", errors.Wrap(err, "vpc.GetIRegion")
}
waitChan := make(chan error)
var iSecgroup cloudprovider.ICloudSecurityGroup = nil
if len(cache.ExternalId) > 0 {
iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId)
if err != nil {
if errors.Cause(err) != cloudprovider.ErrNotFound {
return "", errors.Wrap(err, "iRegion.GetSecurityGroupById")
}
cache.ExternalId = ""
}
}
if len(cache.ExternalId) == 0 {
if strings.ToLower(secgroup.Name) == "default" { //避免有些云不支持default关键字
secgroup.Name = "DefaultGroup"
}
// 避免有的云不支持重名安全组
randomString := func(prefix string, length int) string {
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
}
opts := &cloudprovider.SecurityGroupFilterOptions{
Name: randomString(secgroup.Name, 1),
VpcId: vpcId,
ProjectId: remoteProjectId,
}
for i := 2; i < 30; i++ {
_, err := iRegion.GetISecurityGroupByName(opts)
models.RunSyncSecgroupTask(func() {
err := func() error {
iRegion, err := vpc.GetIRegion()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
break
}
if errors.Cause(err) != cloudprovider.ErrDuplicateId {
return "", err
return errors.Wrap(err, "vpc.GetIRegion")
}
var iSecgroup cloudprovider.ICloudSecurityGroup = nil
if len(cache.ExternalId) > 0 {
iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId)
if err != nil {
if errors.Cause(err) != cloudprovider.ErrNotFound {
return errors.Wrap(err, "iRegion.GetSecurityGroupById")
}
cache.ExternalId = ""
}
}
opts.Name = randomString(secgroup.Name, i)
}
conf := &cloudprovider.SecurityGroupCreateInput{
Name: opts.Name,
Desc: secgroup.Description,
VpcId: vpcId,
ProjectId: remoteProjectId,
Rules: secgroup.GetSecRules(""),
}
iSecgroup, err = iRegion.CreateISecurityGroup(conf)
if err != nil {
return "", errors.Wrap(err, "iRegion.CreateISecurityGroup")
}
}
_, err = db.Update(cache, func() error {
cache.ExternalId = iSecgroup.GetGlobalId()
cache.Name = iSecgroup.GetName()
cache.Status = api.SECGROUP_CACHE_STATUS_READY
return nil
if len(cache.ExternalId) == 0 {
if strings.ToLower(secgroup.Name) == "default" { //避免有些云不支持default关键字
secgroup.Name = "DefaultGroup"
}
// 避免有的云不支持重名安全组
randomString := func(prefix string, length int) string {
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
}
opts := &cloudprovider.SecurityGroupFilterOptions{
Name: randomString(secgroup.Name, 1),
VpcId: vpcId,
ProjectId: remoteProjectId,
}
for i := 2; i < 30; i++ {
_, err := iRegion.GetISecurityGroupByName(opts)
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
break
}
if errors.Cause(err) != cloudprovider.ErrDuplicateId {
return errors.Wrapf(err, "GetISecurityGroupByName")
}
}
opts.Name = randomString(secgroup.Name, i)
}
conf := &cloudprovider.SecurityGroupCreateInput{
Name: opts.Name,
Desc: secgroup.Description,
VpcId: vpcId,
ProjectId: remoteProjectId,
Rules: secgroup.GetSecRules(""),
}
iSecgroup, err = iRegion.CreateISecurityGroup(conf)
if err != nil {
return errors.Wrapf(err, "iRegion.CreateISecurityGroup")
}
}
_, err = db.Update(cache, func() error {
cache.ExternalId = iSecgroup.GetGlobalId()
cache.Name = iSecgroup.GetName()
cache.Status = api.SECGROUP_CACHE_STATUS_READY
return nil
})
if err != nil {
return errors.Wrapf(err, "db.Update")
}
rules, err := iSecgroup.GetRules()
if err != nil {
return errors.Wrapf(err, "iSecgroup.GetRules")
}
maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority()
minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority()
defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule()
defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule()
order := region.GetDriver().GetSecurityGroupRuleOrder()
onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules()
localRules := secrules.SecurityRuleSet(secgroup.GetSecRules(""))
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 {
return nil
}
return iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels)
}()
waitChan <- err
})
err = <-waitChan
if err != nil {
return "", errors.Wrap(err, "db.Update")
return "", err
}
rules, err := iSecgroup.GetRules()
cache, err = models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId, remoteProjectId)
if err != nil {
return "", errors.Wrap(err, "iSecgroup.GetRules")
}
maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority()
minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority()
defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule()
defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule()
order := region.GetDriver().GetSecurityGroupRuleOrder()
onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules()
localRules := secrules.SecurityRuleSet(secgroup.GetSecRules(""))
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 {
return cache.ExternalId, nil
}
err = iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels)
if err != nil {
return "", errors.Wrap(err, "iSecgroup.SyncRules")
return "", errors.Wrap(err, "SSecurityGroupCache.Register")
}
return cache.ExternalId, nil

View File

@@ -133,12 +133,7 @@ func (manager *SIdentityBaseResourceManager) ListItemFilter(
// override manager.SDomainizedResourceBaseManager.ListItemFilter()
if len(query.ProjectDomainIds) > 0 {
// make sure ids are not utf8 string
idList := make([]string, 0)
for _, pid := range query.ProjectDomainIds {
if !stringutils2.IsUtf8(pid) {
idList = append(idList, pid)
}
}
idList := stringutils2.RemoveUtf8Strings(query.ProjectDomainIds)
domains := DomainManager.Query().SubQuery()
subq := domains.Query(domains.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(domains.Field("id"), idList),

View File

@@ -93,6 +93,12 @@ func (this *ImageManager) GetByName(session *mcclient.ClientSession, id string,
}
func (this *ImageManager) Get(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
// hack: some GetPropertiesMethod must use HTTP GET action like:
// - GET /images/distinct-field
// hard code this id currently, should found a better solution
if ok, _ := utils.InStringArray(id, []string{"distinct-field"}); ok {
return this.ResourceManager.Get(session, id, params)
}
r, e := this.GetById(session, id, params)
if e == nil {
return r, e

View File

@@ -179,7 +179,7 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
}
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, desc.ProjectId)
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, desc.ProjectId, desc.OsType)
if err != nil {
return nil, err
}
@@ -194,7 +194,7 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string,
vswitchId string, ipAddr string, desc string, passwd string,
dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string,
userData string, bc *billing.SBillingCycle, projectId string) (string, error) {
userData string, bc *billing.SBillingCycle, projectId, osType string) (string, error) {
net := self.zone.getNetworkById(vswitchId)
if net == nil {
return "", fmt.Errorf("invalid switch ID %s", vswitchId)
@@ -249,7 +249,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
if len(instanceType) > 0 {
log.Debugf("Try instancetype : %s", instanceType)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType)
if err != nil {
log.Errorf("Failed for %s: %s", instanceType, err)
return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error())
@@ -269,7 +269,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
for _, instType := range instanceTypes {
instanceTypeId := instType.InstanceTypeId
log.Debugf("Try instancetype : %s", instanceTypeId)
vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId)
vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType)
if err != nil {
log.Errorf("Failed for %s: %s", instanceTypeId, err)
} else {

View File

@@ -32,6 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
const (
@@ -480,7 +481,7 @@ func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
}
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
return self.host.zone.region.UpdateVM(self.InstanceId, name)
return self.host.zone.region.UpdateVM(self.InstanceId, name, self.OSType)
}
func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
@@ -548,7 +549,7 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, securityGroupId string,
zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string,
keypair string, userData string, bc *billing.SBillingCycle, projectId string) (string, error) {
keypair string, userData string, bc *billing.SBillingCycle, projectId, osType string) (string, error) {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["ImageId"] = imageId
@@ -560,7 +561,7 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
params["InternetChargeType"] = "PayByTraffic"
params["InternetMaxBandwidthIn"] = "200"
params["InternetMaxBandwidthOut"] = "100"
params["HostName"] = name
params["HostName"] = stringutils2.GenerateHostName(name, osType)
if len(passwd) > 0 {
params["Password"] = passwd
} else {
@@ -776,7 +777,7 @@ func (self *SRegion) DeployVM(instanceId string, name string, password string, k
if len(name) > 0 && instance.InstanceName != name {
params["InstanceName"] = name
params["HostName"] = name
params["HostName"] = stringutils2.GenerateHostName(name, instance.OSType)
}
if len(description) > 0 && instance.Description != description {
@@ -808,14 +809,14 @@ func (self *SInstance) DeleteVM(ctx context.Context) error {
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
}
func (self *SRegion) UpdateVM(instanceId string, hostname string) error {
func (self *SRegion) UpdateVM(instanceId string, name, osType string) error {
/*
api: ModifyInstanceAttribute
https://help.aliyun.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW
*/
params := make(map[string]string)
params["HostName"] = hostname
params["InstanceName"] = hostname
params["HostName"] = stringutils2.GenerateHostName(name, osType)
params["InstanceName"] = name
return self.modifyInstanceAttribute(instanceId, params)
}

View File

@@ -173,18 +173,23 @@ func NewVNICDev(host *SHost, mac, driver string, bridge string, vlanId int32, ke
var backing types.BaseVirtualDeviceBackingInfo
switch inet.(type) {
case *SDistributedVirtualPortgroup:
// net := inet.(*SDistributedVirtualPortgroup)
// port, err := net.FindPort()
//if err != nil {
// return nil, errors.Wrap(err, "net.FindPort")
// }
// if port == nil {
// return nil, fmt.Errorf("no active port for dvportgroup %q", net.GetName())
// }
net := inet.(*SDistributedVirtualPortgroup)
port, err := net.FindPort()
dvpg := net.getMODVPortgroup()
uuid, err := net.GetDVSUuid()
if err != nil {
return nil, errors.Wrap(err, "net.FindPort")
}
if port == nil {
return nil, errors.Error("no valid port on DVS, exhausted")
return nil, errors.Wrap(err, "GetDVSUuid")
}
portCon := types.DistributedVirtualSwitchPortConnection{
PortgroupKey: port.PortgroupKey,
SwitchUuid: port.DvsUuid,
PortKey: port.Key,
PortgroupKey: dvpg.Key,
SwitchUuid: uuid,
}
backing = &types.VirtualEthernetCardDistributedVirtualPortBackingInfo{Port: portCon}
case *SNetwork:

View File

@@ -44,7 +44,7 @@ const (
)
var NETWORK_PROPS = []string{"name", "parent", "summary", "host", "vm"}
var DVPORTGROUP_PROPS = []string{"name", "parent", "summary", "host", "vm", "config"}
var DVPORTGROUP_PROPS = []string{"name", "parent", "summary", "host", "vm", "config", "key"}
type SNetwork struct {
SManagedObject
@@ -185,6 +185,16 @@ func (net *SDistributedVirtualPortgroup) Uplink() bool {
return *dvpg.Config.Uplink
}
func (net *SDistributedVirtualPortgroup) GetDVSUuid() (string, error) {
dvgp := net.getMODVPortgroup()
var dvs mo.DistributedVirtualSwitch
err := net.manager.reference2Object(*dvgp.Config.DistributedVirtualSwitch, []string{"uuid"}, &dvs)
if err != nil {
return "", errors.Wrap(err, "reference2Object")
}
return dvs.Uuid, nil
}
func (net *SDistributedVirtualPortgroup) FindPort() (*types.DistributedVirtualPort, error) {
dvgp := net.getMODVPortgroup()
odvs := object.NewDistributedVirtualSwitch(net.manager.client.Client, *dvgp.Config.DistributedVirtualSwitch)

View File

@@ -64,7 +64,7 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
desc.InstanceType, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, desc.Password,
desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId,
desc.UserData, desc.BillingCycle, desc.ProjectId, desc.PublicIpBw, desc.PublicIpChargeType, desc.Tags)
desc.UserData, desc.BillingCycle, desc.ProjectId, desc.PublicIpBw, desc.PublicIpChargeType, desc.Tags, desc.OsType)
if err != nil {
return nil, err
}
@@ -79,7 +79,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
networkId string, ipAddr string, desc string, passwd string,
diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string, bc *billing.SBillingCycle, projectId string,
publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType,
tags map[string]string,
tags map[string]string, osType string,
) (string, error) {
net := self.zone.getNetworkById(networkId)
if net == nil {
@@ -130,7 +130,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
if len(instanceType) > 0 {
log.Debugf("Try instancetype : %s", instanceType)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType)
if err != nil {
return "", errors.Wrapf(err, "Failed to create specification %s", instanceType)
}
@@ -149,7 +149,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
for _, instType := range instanceTypes {
instanceTypeId := instType.InstanceType
log.Debugf("Try instancetype : %s", instanceTypeId)
vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags)
vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType)
if err != nil {
log.Errorf("Failed for %s: %s", instanceTypeId, err)
} else {

View File

@@ -31,6 +31,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
const (
@@ -419,7 +420,7 @@ func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
}
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
return self.host.zone.region.UpdateVM(self.InstanceId, name)
return self.host.zone.region.UpdateVM(self.InstanceId, name, self.GetOSType())
}
func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
@@ -496,7 +497,7 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
zoneId string, desc string, passwd string, disks []SDisk, networkId string, ipAddr string,
keypair string, userData string, bc *billing.SBillingCycle, projectId string,
publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType,
tags map[string]string,
tags map[string]string, osType string,
) (string, error) {
params := make(map[string]string)
params["Region"] = self.Region
@@ -508,7 +509,7 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
params["Placement.ProjectId"] = projectId
}
params["InstanceName"] = name
params["HostName"] = name
params["HostName"] = stringutils2.GenerateHostName(name, osType)
bandwidth := publicIpBw
if publicIpBw == 0 {
@@ -717,9 +718,9 @@ func (self *SInstance) DeleteVM(ctx context.Context) error {
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
}
func (self *SRegion) UpdateVM(instanceId string, hostname string) error {
func (self *SRegion) UpdateVM(instanceId string, name, osType string) error {
params := make(map[string]string)
params["HostName"] = hostname
params["HostName"] = stringutils2.GenerateHostName(name, osType)
return self.modifyInstanceAttribute(instanceId, params)
}

View File

@@ -23,6 +23,16 @@ func IsUtf8(str string) bool {
return false
}
func RemoveUtf8Strings(idOrNames []string) []string {
ids := make([]string, 0)
for _, idOrName := range idOrNames {
if !IsUtf8(idOrName) {
ids = append(ids, idOrName)
}
}
return ids
}
func IsPrintableAscii(b byte) bool {
if b >= 32 && b <= 126 {
return true

View File

@@ -15,6 +15,7 @@
package stringutils2
import (
"reflect"
"testing"
)
@@ -34,6 +35,31 @@ func TestIsUtf8(t *testing.T) {
}
}
func TestRemoveUtf8Strings(t *testing.T) {
cases := []struct {
in []string
want []string
}{
{
in: []string{},
want: []string{},
},
{
in: []string{"en", "中文"},
want: []string{"en"},
},
{
in: []string{"中文"},
want: []string{},
},
}
for _, c := range cases {
if got := RemoveUtf8Strings(c.in); !reflect.DeepEqual(got, c.want) {
t.Errorf("RemoveUtf8Strings %s got %v want %v", c.in, got, c.want)
}
}
}
func TestIsPrintableAscii(t *testing.T) {
cases := []struct {
in string

View File

@@ -18,7 +18,11 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"strconv"
"strings"
"unicode"
"yunion.io/x/pkg/util/osprofile"
)
func GetMD5Hash(text string) string {
@@ -120,3 +124,64 @@ func SplitByQuotation(line string) ([]string, error) {
}
return segs, nil
}
func GenerateHostName(name string, osType string) string {
if len(name) < 2 {
name = fmt.Sprintf("hostname-for-%s-%s", name, osType)
}
// ()英文句号(.)和短横线(-)不能作为首尾字符,更不能连续使用。
// 点号(.)和短横线(-)不能作为 HostName 的首尾字符,不能连续使用。
var init = func(s string) string {
for {
if strings.Contains(s, "..") || strings.Contains(s, "--") {
s = strings.ReplaceAll(s, "..", ".")
s = strings.ReplaceAll(s, "--", "-")
continue
}
if strings.HasPrefix(s, ".") || strings.HasPrefix(s, "-") {
s = strings.TrimPrefix(s, ".")
s = strings.TrimPrefix(s, "-")
continue
}
if strings.HasSuffix(s, ".") || strings.HasSuffix(s, "-") {
s = strings.TrimSuffix(s, ".")
s = strings.TrimSuffix(s, "-")
continue
}
break
}
return s
}
name = init(name)
// (阿里云)Windows实例字符长度为2~15不支持英文句号.),不能全是数字。允许大小写英文字母、数字和短横线(-)。
// (腾讯云)Windows 实例:名字符长度为[2, 15],允许字母(不限制大小写)、数字和短横线(-)组成,不支持点号(.),不能全是数字
var forWindows = func(s string) string {
s = strings.ReplaceAll(s, ".", "")
ret := ""
for _, c := range s {
if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' {
ret += string(c)
}
}
_, err := strconv.Atoi(ret)
if err == nil {
ret = "host-" + ret
}
if len(ret) > 15 {
ret = init(ret[:15])
}
return ret
}
// (阿里云)其他类型实例Linux等字符长度为2~64支持多个英文句号.),英文句号之间为一段,每段允许大小写英文字母、数字和短横线(-)。
// (腾讯云)其他类型Linux 等)实例:字符长度为[2, 60],允许支持多个点号,点之间为一段,每段允许字母(不限制大小写)、数字和短横线(-)组成。
var forOther = func(s string) string {
if len(s) > 60 {
return init(s[:60])
}
return s
}
if strings.ToLower(osType) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) {
return forWindows(name)
}
return forOther(name)
}

View File

@@ -17,6 +17,8 @@ package stringutils2
import (
"reflect"
"testing"
"yunion.io/x/pkg/util/osprofile"
)
func TestEscapeString(t *testing.T) {
@@ -120,3 +122,47 @@ func TestEscapeEchoString(t *testing.T) {
})
}
}
func TestGenerateHostName(t *testing.T) {
type input struct {
name string
osType string
hostName string
}
for _, pair := range []input{
input{
name: "--test-host-name.......",
hostName: "test-host-name",
},
input{
name: "--test-host-1234567890-name.......",
osType: osprofile.OS_TYPE_WINDOWS,
hostName: "test-host-12345",
},
input{
name: "--test-host-1234-67890-name.......",
osType: osprofile.OS_TYPE_WINDOWS,
hostName: "test-host-1234",
},
input{
name: "1234567890123456",
osType: osprofile.OS_TYPE_WINDOWS,
hostName: "host-1234567890",
},
input{
name: "001234567890123456",
osType: osprofile.OS_TYPE_WINDOWS,
hostName: "host-0012345678",
},
input{
name: "",
hostName: "hostname-for",
},
} {
hostName := GenerateHostName(pair.name, pair.osType)
if hostName != pair.hostName {
t.Fatalf("%s hostName should be %s, current is %s", pair.name, pair.hostName, hostName)
}
}
}