fix: allow vmware network associate with multiple wires (#18318)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2023-10-19 09:15:30 +08:00
committed by GitHub
parent 1d99d8edc5
commit f4d8afef46
17 changed files with 690 additions and 93 deletions
+1
View File
@@ -43,6 +43,7 @@ func init() {
cmd.Get("change-owner-candidate-domains", &compute_options.NetworkIdOptions{})
cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{})
cmd.Perform("switch-wire", &compute_options.NetworkSwitchWireOptions{})
cmd.Perform("sync-additional-wires", &compute_options.NetworkSyncAdditionalWiresOptions{})
type NetworkShareOptions struct {
ID string `help:"ID or Name of the zone to show"`
+8
View File
@@ -309,6 +309,8 @@ type NetworkDetails struct {
Schedtags []SchedtagShortDescDetails `json:"schedtags"`
IsClassic bool `json:"is_classic"`
AdditionalWires []SSimpleWire `json:"additional_wires"`
}
type NetworkIpMacDetails struct {
@@ -452,3 +454,9 @@ type NetworkSwitchWireInput struct {
// example: bcast0
WireId string `json:"wire_id"`
}
type NetworSyncAdditionalWiresInput struct {
apis.Meta
WireIds []string `json:"wire_ids"`
}
+5
View File
@@ -88,6 +88,11 @@ type WireResourceInfo struct {
Zone string `json:"zone"`
}
type SSimpleWire struct {
Wire string
WireId string
}
type WireUpdateInput struct {
apis.InfrasResourceBaseUpdateInput
+4 -4
View File
@@ -889,8 +889,8 @@ func (gn *SGuestnetwork) IsAllocated() bool {
return false
}
func GetIPTenantIdPairs() {
/*
/* func GetIPTenantIdPairs() {
from guests import Guests
from hosts import Hosts
from sqlalchemy.sql.expression import bindparam
@@ -903,8 +903,8 @@ func GetIPTenantIdPairs() {
.join(Hosts, and_(Hosts.id==Guests.host_id,
Hosts.deleted==False))
return q.all()
*/
}
} */
func (gn *SGuestnetwork) GetVirtualIPs() []string {
ips := make([]string, 0)
+11 -4
View File
@@ -3382,6 +3382,8 @@ func (self *SGuest) Attach2Network(
userCred mcclient.TokenCredential,
args Attach2NetworkArgs,
) ([]SGuestnetwork, error) {
log.Debugf("Attach2Network %s", jsonutils.Marshal(args))
onceArgs := args.onceArgs(0)
firstNic, err := self.attach2NetworkOnce(ctx, userCred, onceArgs)
if err != nil {
@@ -3522,11 +3524,10 @@ func getCloudNicNetwork(ctx context.Context, vnic cloudprovider.ICloudNic, host
return host.getNetworkOfIPOnHost(ip)
}
localNetObj, err := db.FetchByExternalIdAndManagerId(NetworkManager, vnetId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
vpc := VpcManager.Query().SubQuery()
// vpc := VpcManager.Query().SubQuery()
wire := WireManager.Query().SubQuery()
return q.Join(wire, sqlchemy.Equals(q.Field("wire_id"), wire.Field("id"))).
Join(vpc, sqlchemy.Equals(wire.Field("vpc_id"), vpc.Field("id"))).
Filter(sqlchemy.Equals(vpc.Field("manager_id"), host.ManagerId))
Filter(sqlchemy.Equals(wire.Field("manager_id"), host.ManagerId))
})
if err != nil {
return nil, errors.Wrapf(err, "Cannot find network of external_id %s", vnetId)
@@ -3566,6 +3567,8 @@ func (self *SGuest) SyncVMNics(
return result
}
log.Debugf("SyncVMNics: removed: %d common: %d add: %d", len(removed), len(commondb), len(added))
for i := 0; i < len(removed); i += 1 {
err = self.detachNetworks(ctx, userCred, []SGuestnetwork{removed[i]}, false, false)
if err != nil {
@@ -3638,13 +3641,17 @@ func (self *SGuest) SyncVMNics(
TryReserved: true,
AllocDir: api.IPAllocationDefault,
RequireDesignatedIP: true,
UseDesignatedIP: true,
UseDesignatedIP: false,
NicConfs: []SNicConfig{nicConf},
})
if err != nil {
result.AddError(err)
continue
}
if len(ipList) > 0 {
// shift
ipList = ipList[1:]
}
result.Add()
for i := range guestnetworks {
guestnetwork := &guestnetworks[i]
@@ -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 models
import (
"context"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
type SNetworkAdditionalWireManager struct {
db.SModelBaseManager
}
var NetworkAdditionalWireManager *SNetworkAdditionalWireManager
func init() {
NetworkAdditionalWireManager = &SNetworkAdditionalWireManager{
SModelBaseManager: db.NewModelBaseManager(
SNetworkAdditionalWire{},
"network_additional_wire_tbl",
"network_additional_wire",
"network_additional_wires",
),
}
NetworkAdditionalWireManager.SetVirtualObject(NetworkAdditionalWireManager)
}
type SNetworkAdditionalWire struct {
db.SModelBase
NetworkId string `width:"36" charset:"ascii" nullable:"false" primary:"true"`
WireId string `width:"36" charset:"ascii" nullable:"false" primary:"true"`
Synced *bool
Marked *bool
}
func (manager *SNetworkAdditionalWireManager) newRecord(ctx context.Context, netId, wireId string, synced *bool, marked *bool) error {
rec := &SNetworkAdditionalWire{
NetworkId: netId,
WireId: wireId,
Synced: synced,
Marked: marked,
}
err := manager.TableSpec().InsertOrUpdate(ctx, rec)
return errors.Wrap(err, "InsertOrUpdate")
}
func (manager *SNetworkAdditionalWireManager) networkIdQuery(wireId string) *sqlchemy.SQuery {
q := manager.Query("network_id").Equals("wire_id", wireId)
q = q.Filter(sqlchemy.OR(
sqlchemy.IsTrue(q.Field("synced")),
sqlchemy.IsTrue(q.Field("marked")),
))
return q
}
func (manager *SNetworkAdditionalWireManager) fetchNetworkAdditionalWireIdsQuery(netId string) *sqlchemy.SQuery {
q := manager.Query("wire_id").Equals("network_id", netId)
q = q.Filter(sqlchemy.OR(
sqlchemy.IsTrue(q.Field("synced")),
sqlchemy.IsTrue(q.Field("marked")),
))
return q
}
func (manager *SNetworkAdditionalWireManager) DeleteNetwork(ctx context.Context, netId string) error {
False := false
wireIds, err := manager.FetchNetworkAdditionalWireIds(netId)
if err != nil {
return errors.Wrap(err, "FetchNetworkAdditionalWireIds")
}
for _, wireId := range wireIds {
err := manager.newRecord(ctx, netId, wireId, &False, &False)
if err != nil {
return errors.Wrap(err, "newRecord")
}
}
return nil
}
func (manager *SNetworkAdditionalWireManager) DeleteWire(ctx context.Context, wireId string) error {
False := false
netIds, err := manager.FetchWireAdditionalNetworkIds(wireId)
if err != nil {
return errors.Wrap(err, "FetchWireAdditionalNetworkIds")
}
for _, netId := range netIds {
err := manager.newRecord(ctx, netId, wireId, &False, &False)
if err != nil {
return errors.Wrap(err, "newRecord")
}
}
return nil
}
func (manager *SNetworkAdditionalWireManager) FetchNetworkAdditionalWireIds(netId string) ([]string, error) {
q := manager.fetchNetworkAdditionalWireIdsQuery(netId)
ret := make([]SNetworkAdditionalWire, 0)
err := db.FetchModelObjects(manager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
wireIds := make([]string, len(ret))
for i := range ret {
wireIds[i] = ret[i].WireId
}
return wireIds, nil
}
func (manager *SNetworkAdditionalWireManager) FetchWireAdditionalNetworkIds(wireId string) ([]string, error) {
q := manager.networkIdQuery(wireId)
ret := make([]SNetworkAdditionalWire, 0)
err := db.FetchModelObjects(manager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
netIds := make([]string, len(ret))
for i := range ret {
netIds[i] = ret[i].NetworkId
}
return netIds, nil
}
func (manager *SNetworkAdditionalWireManager) FetchNetworkAdditionalWires(netId string) ([]api.SSimpleWire, error) {
subq := manager.fetchNetworkAdditionalWireIdsQuery(netId).SubQuery()
q := WireManager.Query("id", "name")
q = q.Join(subq, sqlchemy.Equals(q.Field("id"), subq.Field("wire_id")))
ret := make([]SWire, 0)
err := db.FetchModelObjects(WireManager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
wires := make([]api.SSimpleWire, len(ret))
for i := range ret {
wires[i].WireId = ret[i].Id
wires[i].Wire = ret[i].Name
}
return wires, nil
}
func (net *SNetwork) syncAdditionalWires(ctx context.Context, wireIds []string) error {
// find out all vmware wires in the same zone
wires, err := WireManager.FetchWires(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
managersQ := CloudproviderManager.Query().Equals("provider", api.CLOUD_PROVIDER_VMWARE).SubQuery()
q = q.Join(managersQ, sqlchemy.Equals(q.Field("manager_id"), managersQ.Field("id")))
return q
})
if err != nil {
return errors.Wrap(err, "FetchWires")
}
for i := range wires {
w := &wires[i]
if net.WireId == w.Id {
continue
}
connected := net.checkNetWireConnectivity(ctx, w)
var markedPtr *bool
if wireIds != nil {
marked := false
if utils.IsInArray(w.Id, wireIds) {
marked = true
}
markedPtr = &marked
}
err := NetworkAdditionalWireManager.newRecord(ctx, net.Id, w.Id, &connected, markedPtr)
if err != nil {
return errors.Wrap(err, "NetworkAdditionalWireManager.newRecord")
}
}
return nil
}
func (net *SNetwork) checkNetWireConnectivity(ctx context.Context, wire *SWire) bool {
vmIps := wire.GetMetadata(ctx, "vm_ips", nil)
if len(vmIps) > 0 {
ips, err := netutils2.ExpandCompactIps(vmIps)
if err != nil {
log.Errorf("ExpandCompactIps net %s wire %s vm_ips %s fail %s", net.Name, wire.Name, vmIps, err)
} else {
for _, ip := range ips {
if net.Contains(ip) {
return true
}
}
}
}
vmMacs := wire.GetMetadata(ctx, "vm_macs", nil)
if len(vmMacs) > 0 {
macs := strings.Split(vmMacs, ",")
for _, mac := range macs {
gns, err := GuestnetworkManager.fetchGuestNetworks(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Equals("network_id", net.Id).Equals("mac_addr", mac)
return q
})
if err != nil {
log.Errorf("fetchGuestNetworks net %s wire %s mac %s fail %s", net.Name, wire.Name, mac, err)
} else if len(gns) > 0 {
return true
}
}
}
return false
}
+106 -22
View File
@@ -1074,6 +1074,7 @@ func (manager *SNetworkManager) FetchCustomizeColumns(
rows[i].Routes = network.GetRoutes()
rows[i].Schedtags = GetSchedtagsDetailsToResourceV2(network, ctx)
rows[i].Dns = network.GetDNS(rows[i].Zone)
rows[i].AdditionalWires = network.fetchAdditionalWires()
netIds[i] = network.Id
}
@@ -1890,19 +1891,25 @@ func (self *SNetwork) CustomizeCreate(ctx context.Context, userCred mcclient.Tok
return self.SSharableVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (self *SNetwork) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
vpc, _ := self.GetVpc()
func (net *SNetwork) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
net.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
vpc, _ := net.GetVpc()
if vpc != nil && vpc.IsManaged() {
task, err := taskman.TaskManager.NewTask(ctx, "NetworkCreateTask", self, userCred, data.(*jsonutils.JSONDict), "", "", nil)
task, err := taskman.TaskManager.NewTask(ctx, "NetworkCreateTask", net, userCred, data.(*jsonutils.JSONDict), "", "", nil)
if err != nil {
log.Errorf("networkcreateTask create fail: %s", err)
} else {
task.ScheduleRun(nil)
}
} else {
self.SetStatus(userCred, api.NETWORK_STATUS_AVAILABLE, "")
if err := self.ClearSchedDescCache(); err != nil {
{
err := net.syncAdditionalWires(ctx, nil)
if err != nil {
log.Errorf("syncAdditionalWires error: %s", err)
}
}
net.SetStatus(userCred, api.NETWORK_STATUS_AVAILABLE, "")
if err := net.ClearSchedDescCache(); err != nil {
log.Errorf("network post create clear schedcache error: %v", err)
}
}
@@ -1965,6 +1972,9 @@ func (self *SNetwork) RealDelete(ctx context.Context, userCred mcclient.TokenCre
if err := self.SSharableVirtualResourceBase.Delete(ctx, userCred); err != nil {
return err
}
if err := NetworkAdditionalWireManager.DeleteNetwork(ctx, self.Id); err != nil {
return errors.Wrap(err, "NetworkAdditionalWireManager.DeleteNetwork")
}
self.ClearSchedDescCache()
return nil
}
@@ -2039,9 +2049,31 @@ func (manager *SNetworkManager) ListItemFilter(
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, input.WireFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter")
{
wireFilter := input.WireResourceInput
input.Wire = ""
input.WireId = ""
q, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, input.WireFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter")
}
if len(wireFilter.WireId) > 0 {
wireObj, err := WireManager.FetchByIdOrName(userCred, wireFilter.WireId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), wireFilter.WireId)
} else {
return nil, errors.Wrapf(err, "WireManager.FetchByIdOrName %s", wireFilter.WireId)
}
}
wireFilter.WireId = wireObj.GetId()
wireFilter.Wire = wireObj.GetName()
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("wire_id"), wireFilter.WireId),
sqlchemy.In(q.Field("id"), NetworkAdditionalWireManager.networkIdQuery(wireFilter.WireId).SubQuery()),
))
}
input.WireResourceInput = wireFilter
}
if len(input.RouteTableId) > 0 {
@@ -2380,9 +2412,15 @@ func (self *SNetwork) ValidateUpdateCondition(ctx context.Context) error {
return self.SSharableVirtualResourceBase.ValidateUpdateCondition(ctx)
}
func (self *SNetwork) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query, data jsonutils.JSONObject) {
self.SSharableVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
self.ClearSchedDescCache()
func (net *SNetwork) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query, data jsonutils.JSONObject) {
net.SSharableVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
net.ClearSchedDescCache()
if net.IsClassic() {
err := net.syncAdditionalWires(ctx, nil)
if err != nil {
log.Errorf("syncAdditionalWires error %s", err)
}
}
}
// 清除IP子网数据
@@ -2392,9 +2430,9 @@ func (self *SNetwork) PerformPurge(ctx context.Context, userCred mcclient.TokenC
if err != nil {
return nil, err
}
vpc, _ := self.GetVpc()
if vpc != nil && len(vpc.ExternalId) > 0 {
provider := vpc.GetCloudprovider()
wire, _ := self.GetWire()
if wire != nil && len(wire.ExternalId) > 0 {
provider := wire.GetCloudprovider()
if provider != nil && provider.GetEnabled() {
return nil, httperrors.NewInvalidStatusError("Cannot purge network on enabled cloud provider")
}
@@ -3004,8 +3042,6 @@ func (net *SNetwork) IsClassic() bool {
}
func (net *SNetwork) getAttachedHosts() ([]SHost, error) {
// hns := HostnetworkManager.Query().Equals("network_id", net.Id)
// hns = hns.AppendField(hns.Field("baremetal_id").Label("host_id"))
guestsQ := GuestManager.Query()
gnsQ := GuestnetworkManager.Query().Equals("network_id", net.Id).SubQuery()
guestsQ = guestsQ.Join(gnsQ, sqlchemy.Equals(guestsQ.Field("id"), gnsQ.Field("guest_id")))
@@ -3033,11 +3069,7 @@ func (net *SNetwork) PerformSwitchWire(
input *api.NetworkSwitchWireInput,
) (jsonutils.JSONObject, error) {
vpc, err := net.GetVpc()
if err != nil {
return nil, errors.Wrap(err, "GetVpc")
}
if !vpc.IsDefault {
if !net.IsClassic() {
return nil, errors.Wrap(httperrors.ErrNotSupported, "default vpc only")
}
@@ -3064,6 +3096,9 @@ func (net *SNetwork) PerformSwitchWire(
}
unreachedHost := make([]string, 0)
for i := range hosts {
if hosts[i].HostType == api.HOST_TYPE_ESXI {
continue
}
if !hosts[i].IsAttach2Wire(wire.Id) {
unreachedHost = append(unreachedHost, hosts[i].Name)
}
@@ -3080,6 +3115,13 @@ func (net *SNetwork) PerformSwitchWire(
return nil, errors.Wrap(err, "update wire_id")
}
{
err := net.syncAdditionalWires(ctx, nil)
if err != nil {
log.Errorf("syncAdditionalWires fail %s", err)
}
}
logclient.AddActionLogWithContext(ctx, net, logclient.ACT_UPDATE, diff, userCred, true)
db.OpsLog.LogEvent(net, db.ACT_UPDATE, diff, userCred)
@@ -3112,3 +3154,45 @@ func (net *SNetwork) PerformSwitchWire(
return nil, nil
}
func (net *SNetwork) fetchAdditionalWires() []api.SSimpleWire {
wires, err := NetworkAdditionalWireManager.FetchNetworkAdditionalWires(net.Id)
if err != nil {
log.Errorf("NetworkAdditionalWireManager.FetchNetworkAdditionalWires error %s", err)
}
return wires
}
func (net *SNetwork) PerformSyncAdditionalWires(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input *api.NetworSyncAdditionalWiresInput,
) (jsonutils.JSONObject, error) {
if !net.IsClassic() {
return nil, errors.Wrap(httperrors.ErrNotSupported, "default vpc only")
}
wireIds := make([]string, 0)
errs := make([]error, 0)
for _, wireId := range input.WireIds {
wireObj, err := WireManager.FetchByIdOrName(userCred, wireId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
errs = append(errs, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), wireId))
} else {
errs = append(errs, errors.Wrapf(err, "WireManager.FetchByIdOrNam %s", wireId))
}
}
wireIds = append(wireIds, wireObj.GetId())
}
if len(errs) > 0 {
return nil, errors.NewAggregate(errs)
}
err := net.syncAdditionalWires(ctx, wireIds)
if err != nil {
return nil, errors.Wrap(err, "syncAdditionalWires")
}
return nil, nil
}
+9 -4
View File
@@ -561,6 +561,10 @@ func (self *purgePair) purgeAll(ctx context.Context) error {
"delete from %s where %s in (%s)",
self.manager.TableSpec().Name(), self.key, placeholder,
)
case NetworkAdditionalWireManager.Keyword():
sql = fmt.Sprintf("delete from `%s` where `wire_id` in (%s)",
self.manager.TableSpec().Name(), placeholder,
)
default:
vars = append([]interface{}{time.Now()}, vars...)
}
@@ -815,10 +819,10 @@ func (self *SGuest) purge(ctx context.Context, userCred mcclient.TokenCredential
}
func (self *SZone) purgeWires(ctx context.Context, managerId string) error {
wires := WireManager.Query("id").Equals("zone_id", self.Id)
vpcs := VpcManager.Query().SubQuery()
wires = wires.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))).
Filter(sqlchemy.Equals(vpcs.Field("manager_id"), managerId))
wires := WireManager.Query("id").Equals("zone_id", self.Id).Equals("manager_id", managerId)
// vpcs := VpcManager.Query().SubQuery()
// wires = wires.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))).
// Filter(sqlchemy.Equals(vpcs.Field("manager_id"), managerId))
hostwires := HostwireManagerDeprecated.Query("row_id").In("wire_id", wires.SubQuery())
isolateds := IsolatedDeviceManager.Query("id").In("wire_id", wires.SubQuery())
@@ -848,6 +852,7 @@ func (self *SZone) purgeWires(ctx context.Context, managerId string) error {
{manager: NetworkManager, key: "id", q: networks},
{manager: IsolatedDeviceManager, key: "id", q: isolateds},
{manager: HostwireManagerDeprecated, key: "row_id", q: hostwires},
{manager: NetworkAdditionalWireManager, key: "id", q: wires},
{manager: WireManager, key: "id", q: wires},
}
for i := range pairs {
+4 -2
View File
@@ -349,11 +349,11 @@ func (svpc *SVpc) GetRouteTableCount() (int, error) {
return svpc.GetRouteTableQuery().CountWithError()
}
func (svpc *SVpc) getCloudProviderInfo() SCloudProviderInfo {
/*func (svpc *SVpc) getCloudProviderInfo() SCloudProviderInfo {
region, _ := svpc.GetRegion()
provider := svpc.GetCloudprovider()
return MakeCloudProviderInfo(region, nil, provider)
}
}*/
func (svpc *SVpc) GetRegion() (*SCloudregion, error) {
region, err := CloudregionManager.FetchById(svpc.CloudregionId)
@@ -1375,6 +1375,8 @@ func (svpc *SVpc) initWire(ctx context.Context, zone *SZone, externalId string)
wire.IsPublic = svpc.IsPublic
wire.PublicScope = svpc.PublicScope
wire.ManagerId = svpc.ManagerId
wire.SetModelManager(WireManager, wire)
err := WireManager.TableSpec().Insert(ctx, wire)
if err != nil {
+42 -20
View File
@@ -55,40 +55,48 @@ func ValidateWireResourceInput(userCred mcclient.TokenCredential, input api.Wire
return wireObj.(*SWire), input, nil
}
func (self *SWireResourceBase) GetWire() (*SWire, error) {
w, err := WireManager.FetchById(self.WireId)
func (wireRes *SWireResourceBase) GetWire() (*SWire, error) {
w, err := WireManager.FetchById(wireRes.WireId)
if err != nil {
return nil, errors.Wrapf(err, "GetWire(%s)", self.WireId)
return nil, errors.Wrapf(err, "GetWire(%s)", wireRes.WireId)
}
return w.(*SWire), nil
}
func (self *SWireResourceBase) GetCloudproviderId() string {
vpc, _ := self.GetVpc()
if vpc != nil {
return vpc.ManagerId
func (wireRes *SWireResourceBase) GetCloudproviderId() string {
wire, _ := wireRes.GetWire()
if wire != nil {
return wire.ManagerId
}
return ""
}
func (self *SWireResourceBase) GetVpc() (*SVpc, error) {
wire, err := self.GetWire()
func (wireRes *SWireResourceBase) GetProviderName() string {
wire, _ := wireRes.GetWire()
if wire == nil {
return wire.GetProviderName()
}
return ""
}
func (wireRes *SWireResourceBase) GetVpc() (*SVpc, error) {
wire, err := wireRes.GetWire()
if err != nil {
return nil, errors.Wrapf(err, "GetWire")
}
return wire.GetVpc()
}
func (self *SWireResourceBase) GetRegion() (*SCloudregion, error) {
vpc, err := self.GetVpc()
func (wireRes *SWireResourceBase) GetRegion() (*SCloudregion, error) {
vpc, err := wireRes.GetVpc()
if err != nil {
return nil, errors.Wrapf(err, "GetVpc")
}
return vpc.GetRegion()
}
func (self *SWireResourceBase) GetZone() (*SZone, error) {
wire, err := self.GetWire()
func (wireRes *SWireResourceBase) GetZone() (*SZone, error) {
wire, err := wireRes.GetWire()
if err != nil {
return nil, errors.Wrapf(err, "GetWire")
}
@@ -125,6 +133,7 @@ func (manager *SWireResourceBaseManager) FetchCustomizeColumns(
vpcList := make([]interface{}, len(rows))
zoneList := make([]interface{}, len(rows))
managerList := make([]interface{}, len(rows))
for i := range rows {
rows[i] = api.WireResourceInfo{}
if _, ok := wires[wireIds[i]]; ok {
@@ -135,14 +144,17 @@ func (manager *SWireResourceBaseManager) FetchCustomizeColumns(
}
vpcList[i] = &SVpcResourceBase{rows[i].VpcId}
zoneList[i] = &SZoneResourceBase{rows[i].ZoneId}
managerList[i] = &SManagedResourceBase{wires[wireIds[i]].ManagerId}
}
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList)
zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList)
managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList)
for i := range rows {
rows[i].VpcResourceInfo = vpcRows[i]
rows[i].Zone = zoneRows[i].Zone
rows[i].ManagedResourceInfo = managerRows[i]
}
return rows
}
@@ -153,7 +165,6 @@ func (manager *SWireResourceBaseManager) ListItemFilter(
userCred mcclient.TokenCredential,
query api.WireFilterListInput,
) (*sqlchemy.SQuery, error) {
var err error
if len(query.WireId) > 0 {
wireObj, _, err := ValidateWireResourceInput(userCred, query.WireResourceInput)
if err != nil {
@@ -164,9 +175,20 @@ func (manager *SWireResourceBaseManager) ListItemFilter(
wireQ := WireManager.Query("id").Snapshot()
wireQ, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, wireQ, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
{
var err error
mangedFilter := query.ManagedResourceListInput
query.ManagedResourceListInput = api.ManagedResourceListInput{}
wireQ, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, wireQ, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
}
wireQ, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, wireQ, userCred, mangedFilter)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
}
// recover managed filter
query.ManagedResourceListInput = mangedFilter
}
if len(query.ZoneList()) > 0 {
@@ -244,7 +266,7 @@ func (manager *SWireResourceBaseManager) OrderByExtraFields(
}
orderQ := WireManager.Query("id")
orderSubQ := orderQ.SubQuery()
orderQ, orders, fields := manager.GetOrderBySubQuery(orderQ, orderSubQ, orderQ.Field("id"), userCred, query, nil, nil)
_, orders, fields := manager.GetOrderBySubQuery(orderQ, orderSubQ, orderQ.Field("id"), userCred, query, nil, nil)
q = q.LeftJoin(orderSubQ, sqlchemy.Equals(q.Field("wire_id"), orderSubQ.Field("id")))
q = db.OrderByFields(q, orders, fields)
return q, nil
@@ -323,8 +345,8 @@ func (manager *SWireResourceBaseManager) GetExportKeys() []string {
return keys
}
func (self *SWireResourceBase) GetChangeOwnerCandidateDomainIds() []string {
wire, _ := self.GetWire()
func (wireRes *SWireResourceBase) GetChangeOwnerCandidateDomainIds() []string {
wire, _ := wireRes.GetWire()
if wire != nil {
return wire.GetChangeOwnerCandidateDomainIds()
}
+143 -35
View File
@@ -72,6 +72,8 @@ type SWire struct {
db.SStatusInfrasResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SVpcResourceBase `wdith:"36" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" update:""`
SZoneResourceBase `width:"36" charset:"ascii" nullable:"true" list:"domain" create:"domain_required" update:""`
@@ -204,14 +206,14 @@ func (manager *SWireManager) GetOrCreateWireForClassicNetwork(ctx context.Contex
name = fmt.Sprintf("emulate for zone %s vpc %s classic network", zone.Name, vpc.Id)
}
_wire, err := db.FetchByExternalIdAndManagerId(manager, externalId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
sq := VpcManager.Query().SubQuery()
return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("vpc_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), vpc.ManagerId))
q = q.Equals("manager_id", vpc.ManagerId)
return q
})
if err == nil {
return _wire.(*SWire), nil
}
if errors.Cause(err) != sql.ErrNoRows {
return nil, errors.Wrap(err, "db.FetchByExternalId")
return nil, errors.Wrap(err, "db.FetchByExternalIdAndManagerId")
}
wire := &SWire{}
wire.VpcId = vpc.Id
@@ -220,6 +222,7 @@ func (manager *SWireManager) GetOrCreateWireForClassicNetwork(ctx context.Contex
wire.ExternalId = externalId
wire.IsEmulated = true
wire.Name = name
wire.ManagerId = vpc.ManagerId
err = manager.TableSpec().Insert(ctx, wire)
if err != nil {
return nil, errors.Wrap(err, "Insert wire for classic network")
@@ -376,6 +379,8 @@ func (swire *SWire) syncWithCloudWire(ctx context.Context, userCred mcclient.Tok
swire.Description = extWire.GetDescription()
}
swire.ManagerId = provider.Id
if zone != nil {
swire.ZoneId = zone.Id
} else {
@@ -436,6 +441,7 @@ func (manager *SWireManager) newFromCloudWire(ctx context.Context, userCred mccl
wire.Status = extWire.GetStatus()
wire.Description = extWire.GetDescription()
wire.VpcId = vpc.Id
wire.ManagerId = provider.Id
region, err := vpc.GetRegion()
if err != nil {
return nil, errors.Wrapf(err, "GetRegion for vpc %s(%s)", vpc.Name, vpc.Id)
@@ -765,8 +771,8 @@ func filterWiresCountQuery(q *sqlchemy.SQuery, hostTypes, providers, brands []st
if len(rangeObjs) > 0 || len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
vpcs := VpcManager.Query().SubQuery()
q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id")))
q = CloudProviderFilter(q, vpcs.Field("manager_id"), providers, brands, cloudEnv)
q = RangeObjectsFilter(q, rangeObjs, vpcs.Field("cloudregion_id"), q.Field("zone_id"), vpcs.Field("manager_id"), nil, nil)
q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv)
q = RangeObjectsFilter(q, rangeObjs, vpcs.Field("cloudregion_id"), q.Field("zone_id"), q.Field("manager_id"), nil, nil)
}
return q
@@ -862,7 +868,12 @@ func (manager *SWireManager) TotalCount(
}
func (swire *SWire) getNetworkQuery(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
q := NetworkManager.Query().Equals("wire_id", swire.Id)
additionalNicIds := NetworkAdditionalWireManager.networkIdQuery(swire.Id)
q := NetworkManager.Query()
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("wire_id"), swire.Id),
sqlchemy.In(q.Field("id"), additionalNicIds.SubQuery()),
))
if ownerId != nil {
q = NetworkManager.FilterByOwner(q, NetworkManager, userCred, ownerId, scope)
}
@@ -1044,15 +1055,37 @@ func chooseCandidateNetworksByNetworkType(nets []SNetwork, isExit bool, serverTy
}
func (manager *SWireManager) InitializeData() error {
wires := make([]SWire, 0)
q := manager.Query()
q.Filter(sqlchemy.OR(sqlchemy.IsEmpty(q.Field("vpc_id")), sqlchemy.IsEmpty(q.Field("status")), sqlchemy.Equals(q.Field("status"), "init"), sqlchemy.Equals(q.Field("status"), api.WIRE_STATUS_READY_DEPRECATED)))
err := db.FetchModelObjects(manager, q, &wires)
if err != nil {
return err
{
err := manager.initVpcId()
if err != nil {
return errors.Wrap(err, "initVpcId")
}
}
for _, w := range wires {
db.Update(&w, func() error {
{
err := manager.initManagerId()
if err != nil {
return errors.Wrap(err, "initManagerId")
}
}
return nil
}
func (manager *SWireManager) initVpcId() error {
wires, err := manager.FetchWires(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Filter(sqlchemy.OR(
sqlchemy.IsEmpty(q.Field("vpc_id")),
sqlchemy.IsEmpty(q.Field("status")),
sqlchemy.Equals(q.Field("status"), "init"),
sqlchemy.Equals(q.Field("status"), api.WIRE_STATUS_READY_DEPRECATED),
))
return q
})
if err != nil {
return errors.Wrap(err, "FetchWires")
}
for i := range wires {
w := wires[i]
_, err := db.Update(&w, func() error {
if len(w.VpcId) == 0 {
w.VpcId = api.DEFAULT_VPC_ID
}
@@ -1061,10 +1094,55 @@ func (manager *SWireManager) InitializeData() error {
}
return nil
})
if err != nil {
return errors.Wrap(err, "Update")
}
}
return nil
}
func (manager *SWireManager) initManagerId() error {
wires, err := manager.FetchWires(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
vpcs := VpcManager.Query().SubQuery()
q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id")))
q = q.Filter(sqlchemy.OR(
sqlchemy.IsNull(q.Field("manager_id")),
sqlchemy.NotEquals(q.Field("manager_id"), vpcs.Field("manager_id")),
))
q = q.IsNullOrEmpty("manager_id")
return q
})
if err != nil {
return errors.Wrap(err, "FetchWires")
}
for i := range wires {
w := wires[i]
vpc, err := w.GetVpc()
if err != nil {
return errors.Wrap(err, "GetVpc")
}
_, err = db.Update(&w, func() error {
w.ManagerId = vpc.ManagerId
return nil
})
if err != nil {
return errors.Wrap(err, "Update")
}
}
return nil
}
func (manager *SWireManager) FetchWires(filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) ([]SWire, error) {
wires := make([]SWire, 0)
q := manager.Query()
q = filter(q)
err := db.FetchModelObjects(manager, q, &wires)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
return wires, nil
}
func (wire *SWire) isOneCloudVpcWire() bool {
return IsOneCloudVpcResource(wire)
}
@@ -1129,17 +1207,12 @@ func (manager *SWireManager) FetchWireById(wireId string) *SWire {
}
func (manager *SWireManager) FetchWireByExternalId(managerId, extId string) (*SWire, error) {
vpcsQ := VpcManager.Query("id")
vpcsQ = vpcsQ.Filter(sqlchemy.OR(
sqlchemy.Equals(vpcsQ.Field("manager_id"), managerId),
sqlchemy.Equals(vpcsQ.Field("id"), api.DEFAULT_VPC_ID),
))
vpcs := vpcsQ.SubQuery()
q := manager.Query().In("vpc_id", vpcs).Equals("external_id", extId)
wires := make([]SWire, 0)
err := db.FetchModelObjects(manager, q, &wires)
wires, err := manager.FetchWires(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Equals("manager_id", managerId).Equals("external_id", extId)
return q
})
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
return nil, errors.Wrap(err, "FetchWires")
}
switch len(wires) {
case 0:
@@ -1338,9 +1411,18 @@ func (manager *SWireManager) ListItemFilter(
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
{
managedFilter := query.ManagedResourceListInput
query.ManagedResourceListInput = api.ManagedResourceListInput{}
q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
}
q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, managedFilter)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
}
query.ManagedResourceListInput = managedFilter
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
@@ -1505,6 +1587,8 @@ func (manager *SWireManager) FetchCustomizeColumns(
stdRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
managerList := make([]interface{}, len(rows))
wireIds := make([]string, len(objs))
for i := range rows {
rows[i] = api.WireDetails{
@@ -1514,26 +1598,30 @@ func (manager *SWireManager) FetchCustomizeColumns(
}
wire := objs[i].(*SWire)
wireIds[i] = wire.Id
managerList[i] = &SManagedResourceBase{wire.ManagerId}
}
managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList)
usage, err := manager.TotalResourceCount(wireIds)
if err != nil {
log.Errorf("TotalResourceCount error: %v", err)
return rows
}
for i := range rows {
rows[i].WireUsage, _ = usage[wireIds[i]]
rows[i].WireUsage = usage[wireIds[i]]
rows[i].ManagedResourceInfo = managerRows[i]
}
return rows
}
func (man *SWireManager) removeWiresByVpc(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc) error {
wires := []SWire{}
q := man.Query().Equals("vpc_id", vpc.Id)
err := db.FetchModelObjects(man, q, &wires)
wires, err := man.FetchWires(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Equals("vpc_id", vpc.Id)
return q
})
if err != nil {
return err
return errors.Wrap(err, "FetchWires")
}
var errs []error
for i := range wires {
@@ -1545,17 +1633,17 @@ func (man *SWireManager) removeWiresByVpc(ctx context.Context, userCred mcclient
return errors.NewAggregate(errs)
}
func (swire *SWire) IsManaged() bool {
/*func (swire *SWire) IsManaged() bool {
vpc, _ := swire.GetVpc()
if vpc == nil {
return false
}
return vpc.IsManaged()
}
}*/
func (model *SWire) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
vpc, _ := model.GetVpc()
if !data.Contains("public_scope") {
vpc, _ := model.GetVpc()
if !model.IsManaged() && db.IsAdminAllowPerform(ctx, userCred, model, "public") && ownerId.GetProjectDomainId() == userCred.GetProjectDomainId() && vpc != nil && vpc.IsPublic && vpc.PublicScope == string(rbacscope.ScopeSystem) {
model.SetShare(rbacscope.ScopeSystem)
} else {
@@ -1564,6 +1652,7 @@ func (model *SWire) CustomizeCreate(ctx context.Context, userCred mcclient.Token
data.(*jsonutils.JSONDict).Set("public_scope", jsonutils.NewString(model.PublicScope))
}
model.Status = api.WIRE_STATUS_AVAILABLE
model.ManagerId = vpc.ManagerId
return model.SInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
@@ -1714,3 +1803,22 @@ func (swire *SWire) GetDetailsTopology(ctx context.Context, userCred mcclient.To
}
return ret, nil
}
func (wire *SWire) GetCloudproviderId() string {
return wire.SManagedResourceBase.GetCloudproviderId()
}
func (wire *SWire) GetCloudprovider() *SCloudprovider {
return wire.SManagedResourceBase.GetCloudprovider()
}
func (wire *SWire) GetProviderName() string {
return wire.SManagedResourceBase.GetProviderName()
}
func (wire *SWire) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
if err := NetworkAdditionalWireManager.DeleteWire(ctx, wire.Id); err != nil {
return errors.Wrap(err, "NetworkAdditionalWireManager.DeleteWire")
}
return wire.SStatusInfrasResourceBase.Delete(ctx, userCred)
}
+1
View File
@@ -66,6 +66,7 @@ func InitHandlers(app *appsrv.Application) {
models.GuestcdromManager,
models.GuestFloppyManager,
models.NetInterfaceManager,
models.NetworkAdditionalWireManager,
models.QuotaManager,
models.QuotaUsageManager,
+14
View File
@@ -230,3 +230,17 @@ func (opts *NetworkSwitchWireOptions) GetId() string {
func (opts *NetworkSwitchWireOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type NetworkSyncAdditionalWiresOptions struct {
ID string `help:"ID or Name of resource to update"`
api.NetworSyncAdditionalWiresInput
}
func (opts *NetworkSyncAdditionalWiresOptions) GetId() string {
return opts.ID
}
func (opts *NetworkSyncAdditionalWiresOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
+6 -1
View File
@@ -634,7 +634,12 @@ func (b *BaseHostDesc) fillNetworks(host *computemodels.SHost, netGetter *networ
nets := make([]computemodels.SNetwork, 0)
allNets := network.Manager.GetStore().GetAll()
for _, net := range allNets {
if wireIds.Has(net.WireId) {
netAdditionalWireIds, err := computemodels.NetworkAdditionalWireManager.FetchNetworkAdditionalWireIds(net.Id)
if err != nil {
log.Errorf("NetworkAdditionalWireManager.FetchNetworkAdditionalWireIds %s error %s", net.Id, err)
netAdditionalWireIds = []string{}
}
if wireIds.Has(net.WireId) || wireIds.HasAny(netAdditionalWireIds...) {
nets = append(nets, net)
}
}
+57
View File
@@ -0,0 +1,57 @@
// 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 netutils2
import (
"fmt"
"strconv"
"strings"
"yunion.io/x/pkg/errors"
)
func ExpandCompactIps(ipstr string) ([]string, error) {
ips := make([]string, 0)
ipSegs := strings.Split(strings.TrimSpace(ipstr), ";")
for _, ipSeg := range ipSegs {
parts := strings.Split(ipSeg, ".")
if len(parts) <= 3 {
return nil, errors.Wrap(errors.ErrInvalidFormat, ipSeg)
}
hosts := strings.Split(parts[3], ",")
for _, host := range hosts {
if strings.Index(host, "-") > 0 {
subhosts := strings.Split(host, "-")
if len(subhosts) != 2 {
return nil, errors.Wrap(errors.ErrInvalidFormat, ipSeg)
}
start, err := strconv.Atoi(subhosts[0])
if err != nil {
return nil, errors.Wrap(errors.ErrInvalidFormat, ipSeg)
}
end, err := strconv.Atoi(subhosts[1])
if err != nil {
return nil, errors.Wrap(errors.ErrInvalidFormat, ipSeg)
}
for i := start; i <= end; i++ {
ips = append(ips, fmt.Sprintf("%s.%s.%s.%d", parts[0], parts[1], parts[2], i))
}
} else {
ips = append(ips, fmt.Sprintf("%s.%s.%s.%s", parts[0], parts[1], parts[2], host))
}
}
}
return ips, nil
}
+53
View File
@@ -0,0 +1,53 @@
// 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 netutils2
import (
"reflect"
"testing"
)
func TestExpandCompactIpds(t *testing.T) {
cases := []struct {
in string
want []string
}{
{
in: "192.168.100.2",
want: []string{
"192.168.100.2",
},
},
{
in: "192.168.100.2,9,10;10.168.200.1",
want: []string{
"192.168.100.2",
"192.168.100.9",
"192.168.100.10",
"10.168.200.1",
},
},
}
for _, c := range cases {
out, err := ExpandCompactIps(c.in)
if err != nil {
t.Errorf("expand %s error %s", c.in, err)
} else {
if !reflect.DeepEqual(c.want, out) {
t.Errorf("expand %s want %s got %s", c.in, c.want, out)
}
}
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ func getIfaceIPs(iface *net.Interface) ([]net.IP, error) {
func WaitIfaceIps(ifname string) (*net.Interface, []net.IP, error) {
iface, err := net.InterfaceByName(ifname)
if err != nil {
return nil, nil, errors.Wrap(err, "net.InterfaceByName")
return nil, nil, errors.Wrapf(err, "net.InterfaceByName %s", ifname)
}
var ips []net.IP
MAX := 60