diff --git a/cmd/climc/shell/compute/networkaddresses.go b/cmd/climc/shell/compute/networkaddresses.go index 5ba62926c2..9d129ee976 100644 --- a/cmd/climc/shell/compute/networkaddresses.go +++ b/cmd/climc/shell/compute/networkaddresses.go @@ -22,8 +22,8 @@ import ( func init() { cmd := shell.NewResourceCmd(&modules.NetworkAddresses).WithContextManager(&modules.Wires) - cmd.BatchCreate(&options.NetworkAddressCreateOptions{}) + // cmd.BatchCreate(&options.NetworkAddressCreateOptions{}) cmd.List(&options.NetworkAddressListOptions{}) cmd.Show(&options.NetworkAddressIdOptions{}) - cmd.Delete(&options.NetworkAddressIdOptions{}) + cmd.BatchDelete(&options.NetworkAddressIdsOptions{}) } diff --git a/cmd/climc/shell/compute/servers.go b/cmd/climc/shell/compute/servers.go index 7de0eef441..a3e8d193db 100644 --- a/cmd/climc/shell/compute/servers.go +++ b/cmd/climc/shell/compute/servers.go @@ -119,6 +119,7 @@ func init() { cmd.Perform("set-boot-index", &options.ServerSetBootIndexOptions{}) cmd.Perform("reset-nic-traffic-limit", &options.ServerNicTrafficLimitOptions{}) cmd.Perform("set-nic-traffic-limit", &options.ServerNicTrafficLimitOptions{}) + cmd.Perform("add-sub-ips", &options.ServerAddSubIpsOptions{}) cmd.Get("vnc", new(options.ServerVncOptions)) cmd.Get("desc", new(options.ServerIdOptions)) diff --git a/pkg/apis/compute/guestnetwork.go b/pkg/apis/compute/guestnetwork.go index ec86655c16..04785880c3 100644 --- a/pkg/apis/compute/guestnetwork.go +++ b/pkg/apis/compute/guestnetwork.go @@ -31,6 +31,8 @@ type GuestnetworkDetails struct { // EipAddr associate with this guestnetwork EipAddr string `json:"eip_addr"` + + NetworkAddresses []NetworkAddrConf `json:"network_addresses"` } type GuestnetworkShortDesc struct { diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 1ae7d434b2..cc732f3519 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -1029,3 +1029,22 @@ type ServerNicTrafficLimit struct { RxTrafficLimit *int64 `json:"rx_traffic_limit"` TxTrafficLimit *int64 `json:"tx_traffic_limit"` } + +type GuestAddSubIpsInput struct { + Mac string `json:"mac"` + IpAddr string `json:"ip_addr"` + Count int `json:"count"` + SubIps []string `json:"sub_ips"` + + Reserved bool `json:"reserved"` + + AllocDir IPAllocationDirection `json:"alloc_dir"` +} + +type NetworkAddrConf struct { + Id string `json:"id"` + Type string `json:"type"` + IpAddr string `json:"ip_addr"` + Masklen int `json:"masklen"` + Gateway string `json:"gateway"` +} diff --git a/pkg/apis/compute/networkaddress.go b/pkg/apis/compute/networkaddress.go index da3048ff36..0c3638e19e 100644 --- a/pkg/apis/compute/networkaddress.go +++ b/pkg/apis/compute/networkaddress.go @@ -45,7 +45,8 @@ type NetworkAddressCreateInput struct { Type string NetworkId string - IPAddr string + IPAddr string `json:"ip_addr"` + IPAddrs []string `json:"ip_addrs"` } type NetworkAddressListInput struct { diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index 443fe0f6ed..c4f950ec48 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -112,12 +112,12 @@ type SGuestnetwork struct { EipId string `width:"36" charset:"ascii" nullable:"true" list:"user"` } -func (self SGuestnetwork) GetIP() string { - return self.IpAddr +func (gn SGuestnetwork) GetIP() string { + return gn.IpAddr } -func (self SGuestnetwork) GetMAC() string { - return self.MacAddr +func (gn SGuestnetwork) GetMAC() string { + return gn.MacAddr } func (manager *SGuestnetworkManager) GetSlaveFieldName() string { @@ -142,6 +142,12 @@ func (manager *SGuestnetworkManager) FetchCustomizeColumns( GuestJointResourceDetails: guestRows[i], } netIds[i] = objs[i].(*SGuestnetwork).NetworkId + ipnets, err := NetworkAddressManager.fetchAddressesByGuestnetworkId(objs[i].(*SGuestnetwork).RowId) + if err != nil { + log.Errorln(err) + } else if len(ipnets) > 0 { + rows[i].NetworkAddresses = ipnets + } iNet, _ := NetworkManager.FetchById(netIds[i]) net := iNet.(*SNetwork) rows[i].WireId = net.WireId @@ -360,7 +366,7 @@ func (manager *SGuestnetworkManager) newGuestNetwork( return &gn, nil } -func (self *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, randomized bool) string { +func (gn *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, randomized bool) string { // It may happen that external networks when synced can miss ifname hint network.ensureIfnameHint() @@ -372,7 +378,7 @@ func (self *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, rando if virtual { return fmt.Sprintf("%s-%s", nName, randutil.String(3)) } else { - ip, _ := netutils.NewIPV4Addr(self.IpAddr) + ip, _ := netutils.NewIPV4Addr(gn.IpAddr) cliaddr := ip.CliAddr(network.GuestIpMask) return fmt.Sprintf("%s-%d", nName, uint32(cliaddr)) } @@ -407,18 +413,18 @@ func (man *SGuestnetworkManager) ifnameUsed(ifname string) bool { return count > 0 } -func (self *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname string) (string, error) { +func (gn *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname string) (string, error) { man := GuestnetworkManager if !man.ifnameUsed(preferIfname) { return preferIfname, nil } - ifname := self.generateIfname(network, self.Virtual, false) + ifname := gn.generateIfname(network, gn.Virtual, false) if !man.ifnameUsed(ifname) { return ifname, nil } - if !self.Virtual { - ifname = self.generateIfname(network, true, false) + if !gn.Virtual { + ifname = gn.generateIfname(network, true, false) } found := false for i := 0; i < 5; i++ { @@ -426,7 +432,7 @@ func (self *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname found = true break } - ifname = self.generateIfname(network, true, true) + ifname = gn.generateIfname(network, true, true) } if !found { return "", httperrors.NewConflictError("cannot allocate ifname") @@ -434,8 +440,8 @@ func (self *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname return ifname, nil } -func (self *SGuestnetwork) GetGuest() *SGuest { - guest, _ := GuestManager.FetchById(self.GuestId) +func (gn *SGuestnetwork) GetGuest() *SGuest { + guest, _ := GuestManager.FetchById(gn.GuestId) if guest != nil { return guest.(*SGuest) } @@ -450,20 +456,20 @@ func (gn *SGuestnetwork) GetNetwork() *SNetwork { return nil } -func (self *SGuestnetwork) GetTeamGuestnetwork() (*SGuestnetwork, error) { - if len(self.TeamWith) > 0 { - return GuestnetworkManager.FetchByIdsAndIpMac(self.GuestId, self.NetworkId, "", self.TeamWith) +func (gn *SGuestnetwork) GetTeamGuestnetwork() (*SGuestnetwork, error) { + if len(gn.TeamWith) > 0 { + return GuestnetworkManager.FetchByIdsAndIpMac(gn.GuestId, gn.NetworkId, "", gn.TeamWith) } return nil, nil } -func (self *SGuestnetwork) getJsonDescAtBaremetal(host *SHost) *api.GuestnetworkJsonDesc { - net := self.GetNetwork() +func (gn *SGuestnetwork) getJsonDescAtBaremetal(host *SHost) *api.GuestnetworkJsonDesc { + net := gn.GetNetwork() netif := guestGetHostNetifFromNetwork(host, net) if netif == nil { log.Errorf("fail to find a valid net interface on baremetal %s for network %s", host.String(), net.String()) } - return self.getJsonDescHostwire(netif) + return gn.getJsonDescHostwire(netif) } func guestGetHostNetifFromNetwork(host *SHost, network *SNetwork) *SNetInterface { @@ -479,13 +485,13 @@ func guestGetHostNetifFromNetwork(host *SHost, network *SNetwork) *SNetInterface return netif } -func (self *SGuestnetwork) getJsonDescAtHost(ctx context.Context, host *SHost) *api.GuestnetworkJsonDesc { +func (gn *SGuestnetwork) getJsonDescAtHost(ctx context.Context, host *SHost) *api.GuestnetworkJsonDesc { var ( ret *api.GuestnetworkJsonDesc = nil - network = self.GetNetwork() + network = gn.GetNetwork() ) if network.isOneCloudVpcNetwork() { - ret = self.getJsonDescOneCloudVpc(network) + ret = gn.getJsonDescOneCloudVpc(network) } else { netifs := host.getNetifsOnWire(network.WireId) var netif *SNetInterface @@ -499,10 +505,10 @@ func (self *SGuestnetwork) getJsonDescAtHost(ctx context.Context, host *SHost) * log.Errorf("fail to find a bridged net_interface on host %s for network %s?????", host.String(), network.String()) netif = &netifs[0] } - ret = self.getJsonDescHostwire(netif) + ret = gn.getJsonDescHostwire(netif) } { - ipnets, err := NetworkAddressManager.fetchAddressesByGuestnetworkId(ctx, self.RowId) + ipnets, err := NetworkAddressManager.fetchAddressesByGuestnetworkId(gn.RowId) if err != nil { log.Errorln(err) } @@ -513,8 +519,8 @@ func (self *SGuestnetwork) getJsonDescAtHost(ctx context.Context, host *SHost) * return ret } -func (self *SGuestnetwork) getJsonDescHostwire(netif *SNetInterface) *api.GuestnetworkJsonDesc { - desc := self.getJsonDesc() +func (gn *SGuestnetwork) getJsonDescHostwire(netif *SNetInterface) *api.GuestnetworkJsonDesc { + desc := gn.getJsonDesc() if netif != nil { desc.Bridge = netif.Bridge desc.WireId = netif.WireId @@ -523,50 +529,50 @@ func (self *SGuestnetwork) getJsonDescHostwire(netif *SNetInterface) *api.Guestn return desc } -func (self *SGuestnetwork) getJsonDescOneCloudVpc(network *SNetwork) *api.GuestnetworkJsonDesc { - if self.MappedIpAddr == "" { +func (gn *SGuestnetwork) getJsonDescOneCloudVpc(network *SNetwork) *api.GuestnetworkJsonDesc { + if gn.MappedIpAddr == "" { var ( err error addr string ) addr, err = GuestnetworkManager.allocMappedIpAddr(context.TODO()) if err != nil { - log.Errorf("getJsonDescOneCloudVpc: row %d: alloc mapped ipaddr: %v", self.RowId, err) + log.Errorf("getJsonDescOneCloudVpc: row %d: alloc mapped ipaddr: %v", gn.RowId, err) } else { - if _, err := db.Update(self, func() error { - self.MappedIpAddr = addr + if _, err := db.Update(gn, func() error { + gn.MappedIpAddr = addr return nil }); err != nil { - log.Errorf("getJsonDescOneCloudVpc: row %d: db update mapped addr: %v", self.RowId, err) - self.MappedIpAddr = "" + log.Errorf("getJsonDescOneCloudVpc: row %d: db update mapped addr: %v", gn.RowId, err) + gn.MappedIpAddr = "" } } } - desc := self.getJsonDesc() + desc := gn.getJsonDesc() vpc, _ := network.GetVpc() desc.Vpc.Id = vpc.Id desc.Vpc.Provider = api.VPC_PROVIDER_OVN - desc.Vpc.MappedIpAddr = self.MappedIpAddr + desc.Vpc.MappedIpAddr = gn.MappedIpAddr return desc } -func (self *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { - net := self.GetNetwork() +func (gn *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { + net := gn.GetNetwork() desc := &api.GuestnetworkJsonDesc{ GuestnetworkBaseDesc: api.GuestnetworkBaseDesc{ Net: net.Name, - NetId: self.NetworkId, - Mac: self.MacAddr, - Virtual: self.Virtual, + NetId: gn.NetworkId, + Mac: gn.MacAddr, + Virtual: gn.Virtual, }, } - if self.Virtual { - if len(self.TeamWith) > 0 { - teamGN, _ := self.GetTeamGuestnetwork() + if gn.Virtual { + if len(gn.TeamWith) > 0 { + teamGN, _ := gn.GetTeamGuestnetwork() if teamGN != nil { desc.Ip = teamGN.IpAddr } @@ -574,7 +580,7 @@ func (self *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { desc.Ip = net.GetNetAddr().String() } } else { - desc.Ip = self.IpAddr + desc.Ip = gn.IpAddr } desc.Gateway = net.GuestGateway desc.Dns = net.GetDNS() @@ -585,22 +591,22 @@ func (self *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { if routes != nil && len(routes) > 0 { desc.Routes = jsonutils.Marshal(routes) } - desc.Ifname = self.Ifname + desc.Ifname = gn.Ifname desc.Masklen = net.GuestIpMask - desc.Driver = self.Driver - desc.NumQueues = self.NumQueues - desc.RxTrafficLimit = self.RxTrafficLimit - desc.TxTrafficLimit = self.TxTrafficLimit + desc.Driver = gn.Driver + desc.NumQueues = gn.NumQueues + desc.RxTrafficLimit = gn.RxTrafficLimit + desc.TxTrafficLimit = gn.TxTrafficLimit desc.Vlan = net.VlanId - desc.Bw = self.getBandwidth() - desc.Mtu = self.getMtu(net) - desc.Index = self.Index - desc.VirtualIps = self.GetVirtualIPs() + desc.Bw = gn.getBandwidth() + desc.Mtu = gn.getMtu(net) + desc.Index = gn.Index + desc.VirtualIps = gn.GetVirtualIPs() desc.ExternalId = net.ExternalId - desc.TeamWith = self.TeamWith + desc.TeamWith = gn.TeamWith - guest := self.getGuest() - if guest.GetHypervisor() != api.HYPERVISOR_KVM || self.IsSriovWithoutOffload() { + guest := gn.getGuest() + if guest.GetHypervisor() != api.HYPERVISOR_KVM || gn.IsSriovWithoutOffload() { manual := true desc.Manual = &manual } @@ -608,32 +614,32 @@ func (self *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc { return desc } -func (self *SGuestnetwork) IsSriovWithoutOffload() bool { - if self.Driver != api.NETWORK_DRIVER_VFIO { +func (gn *SGuestnetwork) IsSriovWithoutOffload() bool { + if gn.Driver != api.NETWORK_DRIVER_VFIO { return false } - if dev, _ := self.GetIsolatedDevice(); dev != nil && dev.OvsOffloadInterface != "" { + if dev, _ := gn.GetIsolatedDevice(); dev != nil && dev.OvsOffloadInterface != "" { return false } return true } -func (self *SGuestnetwork) UpdateNicTrafficUsed(rx, tx int64) error { - _, err := db.Update(self, func() error { - self.RxTrafficUsed = rx - self.TxTrafficUsed = tx +func (gn *SGuestnetwork) UpdateNicTrafficUsed(rx, tx int64) error { + _, err := db.Update(gn, func() error { + gn.RxTrafficUsed = rx + gn.TxTrafficUsed = tx return nil }) return err } -func (self *SGuestnetwork) UpdateNicTrafficLimit(rx, tx *int64) error { - _, err := db.Update(self, func() error { +func (gn *SGuestnetwork) UpdateNicTrafficLimit(rx, tx *int64) error { + _, err := db.Update(gn, func() error { if rx != nil { - self.RxTrafficLimit = *rx + gn.RxTrafficLimit = *rx } if tx != nil { - self.TxTrafficLimit = *tx + gn.TxTrafficLimit = *tx } return nil }) @@ -657,13 +663,14 @@ func (manager *SGuestnetworkManager) GetGuestByAddress(address string) *SGuest { return nil } -func (self *SGuestnetwork) GetDetailedString() string { - network := self.GetNetwork() - return fmt.Sprintf("eth%d:%s/%d/%s/%d/%s/%s/%d", self.Index, self.IpAddr, network.GuestIpMask, - self.MacAddr, network.VlanId, network.Name, self.Driver, self.getBandwidth()) +func (gn *SGuestnetwork) GetDetailedString() string { + network := gn.GetNetwork() + naCount, _ := NetworkAddressManager.fetchAddressCountByGuestnetworkId(gn.RowId) + return fmt.Sprintf("eth%d:%s/%d/%s/%d/%s/%s/%d/%d", gn.Index, gn.IpAddr, network.GuestIpMask, + gn.MacAddr, network.VlanId, network.Name, gn.Driver, gn.getBandwidth(), naCount) } -func (self *SGuestnetwork) ValidateUpdateData( +func (gn *SGuestnetwork) ValidateUpdateData( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, @@ -672,8 +679,8 @@ func (self *SGuestnetwork) ValidateUpdateData( if input.Index != nil { index := *input.Index q := GuestnetworkManager.Query().SubQuery() - count, err := q.Query().Filter(sqlchemy.Equals(q.Field("guest_id"), self.GuestId)). - Filter(sqlchemy.NotEquals(q.Field("network_id"), self.NetworkId)). + count, err := q.Query().Filter(sqlchemy.Equals(q.Field("guest_id"), gn.GuestId)). + Filter(sqlchemy.NotEquals(q.Field("network_id"), gn.NetworkId)). Filter(sqlchemy.Equals(q.Field("index"), index)).CountWithError() if err != nil { return input, httperrors.NewInternalServerError("checkout nic index uniqueness fail %s", err) @@ -683,7 +690,7 @@ func (self *SGuestnetwork) ValidateUpdateData( } } var err error - input.GuestJointBaseUpdateInput, err = self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput) + input.GuestJointBaseUpdateInput, err = gn.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput) if err != nil { return input, errors.Wrap(err, "SGuestJointsBase.ValidateUpdateData") } @@ -744,23 +751,23 @@ func (manager *SGuestnetworkManager) getGuestNicByIP(ip string, networkId string return &gn, nil } -func (self *SGuestnetwork) LogDetachEvent(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, network *SNetwork) { +func (gn *SGuestnetwork) LogDetachEvent(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, network *SNetwork) { if network == nil { - netTmp, _ := NetworkManager.FetchById(self.NetworkId) + netTmp, _ := NetworkManager.FetchById(gn.NetworkId) network = netTmp.(*SNetwork) } db.OpsLog.LogDetachEvent(ctx, guest, network, userCred, nil) } -func (self *SGuestnetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { - if err := NetworkAddressManager.deleteByGuestnetworkId(ctx, userCred, self.RowId); err != nil { +func (gn *SGuestnetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + if err := NetworkAddressManager.deleteByGuestnetworkId(ctx, userCred, gn.RowId); err != nil { return errors.Wrap(err, "delete attached network addresses") } - return db.DeleteModel(ctx, userCred, self) + return db.DeleteModel(ctx, userCred, gn) } -func (self *SGuestnetwork) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { - return db.DetachJoint(ctx, userCred, self) +func (gn *SGuestnetwork) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DetachJoint(ctx, userCred, gn) } func totalGuestNicCount( @@ -837,28 +844,28 @@ func calculateNics(q *sqlchemy.SQuery) GuestnicsCount { return cnt } -func (self *SGuestnetwork) IsExit() bool { - if self.IpAddr != "" { - addr, err := netutils.NewIPV4Addr(self.IpAddr) +func (gn *SGuestnetwork) IsExit() bool { + if gn.IpAddr != "" { + addr, err := netutils.NewIPV4Addr(gn.IpAddr) if err == nil { return netutils.IsExitAddress(addr) } } - net := self.GetNetwork() + net := gn.GetNetwork() if net != nil { return net.IsExitNetwork() } return false } -func (self *SGuestnetwork) getBandwidth() int { - if self.BwLimit == 0 { +func (gn *SGuestnetwork) getBandwidth() int { + if gn.BwLimit == 0 { return 0 } - if self.BwLimit > 0 && self.BwLimit <= api.MAX_BANDWIDTH { - return self.BwLimit + if gn.BwLimit > 0 && gn.BwLimit <= api.MAX_BANDWIDTH { + return gn.BwLimit } else { - net := self.GetNetwork() + net := gn.GetNetwork() if net != nil { wire, _ := net.GetWire() if wire != nil { @@ -869,14 +876,14 @@ func (self *SGuestnetwork) getBandwidth() int { } } -func (self *SGuestnetwork) getMtu(net *SNetwork) int16 { +func (gn *SGuestnetwork) getMtu(net *SNetwork) int16 { return net.getMtu() } -func (self *SGuestnetwork) IsAllocated() bool { - region, _ := self.GetGuest().getRegion() +func (gn *SGuestnetwork) IsAllocated() bool { + region, _ := gn.GetGuest().getRegion() provider := region.Provider - if regutils.MatchMacAddr(self.MacAddr) && (self.Virtual || regutils.MatchIP4Addr(self.IpAddr) || (provider != api.CLOUD_PROVIDER_ONECLOUD && !options.Options.EnablePreAllocateIpAddr)) { + if regutils.MatchMacAddr(gn.MacAddr) && (gn.Virtual || regutils.MatchIP4Addr(gn.IpAddr) || (provider != api.CLOUD_PROVIDER_ONECLOUD && !options.Options.EnablePreAllocateIpAddr)) { return true } return false @@ -899,10 +906,10 @@ func GetIPTenantIdPairs() { */ } -func (self *SGuestnetwork) GetVirtualIPs() []string { +func (gn *SGuestnetwork) GetVirtualIPs() []string { ips := make([]string, 0) - guest := self.GetGuest() - net := self.GetNetwork() + guest := gn.GetGuest() + net := gn.GetNetwork() for _, guestgroup := range guest.GetGroups() { group := guestgroup.GetGroup() groupnets, err := group.GetNetworks() @@ -919,9 +926,9 @@ func (self *SGuestnetwork) GetVirtualIPs() []string { return ips } -func (self *SGuestnetwork) GetIsolatedDevice() (*SIsolatedDevice, error) { +func (gn *SGuestnetwork) GetIsolatedDevice() (*SIsolatedDevice, error) { dev := SIsolatedDevice{} - q := IsolatedDeviceManager.Query().Equals("guest_id", self.GuestId).Equals("network_index", self.Index) + q := IsolatedDeviceManager.Query().Equals("guest_id", gn.GuestId).Equals("network_index", gn.Index) if cnt, err := q.CountWithError(); err != nil { return nil, err } else if cnt == 0 { @@ -1021,39 +1028,39 @@ func (manager *SGuestnetworkManager) FetchByGuestIdIndex(guestId string, index i return nil, errors.ErrNotFound } -func (self *SGuestnetwork) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { +func (gn *SGuestnetwork) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc := api.GuestnetworkShortDesc{} - if len(self.IpAddr) > 0 { - desc.IpAddr = self.IpAddr - desc.IsExit = self.IsExit() + if len(gn.IpAddr) > 0 { + desc.IpAddr = gn.IpAddr + desc.IsExit = gn.IsExit() } - if len(self.Ip6Addr) > 0 { - desc.Ip6Addr = self.Ip6Addr + if len(gn.Ip6Addr) > 0 { + desc.Ip6Addr = gn.Ip6Addr } - desc.Mac = self.MacAddr - if len(self.TeamWith) > 0 { - desc.TeamWith = self.TeamWith + desc.Mac = gn.MacAddr + if len(gn.TeamWith) > 0 { + desc.TeamWith = gn.TeamWith } return jsonutils.Marshal(desc).(*jsonutils.JSONDict) } -func (self *SGuestnetwork) ToNetworkConfig() *api.NetworkConfig { - net := self.GetNetwork() +func (gn *SGuestnetwork) ToNetworkConfig() *api.NetworkConfig { + net := gn.GetNetwork() if net == nil { return nil } wire, _ := net.GetWire() ret := &api.NetworkConfig{ - Index: int(self.Index), + Index: int(gn.Index), Network: net.Id, Wire: wire.Id, - Mac: self.MacAddr, - Address: self.IpAddr, - Driver: self.Driver, - BwLimit: self.BwLimit, + Mac: gn.MacAddr, + Address: gn.IpAddr, + Driver: gn.Driver, + BwLimit: gn.BwLimit, Project: net.ProjectId, Domain: net.DomainId, - Ifname: self.Ifname, + Ifname: gn.Ifname, NetType: net.ServerType, Exit: net.IsExitNetwork(), } @@ -1081,7 +1088,11 @@ func (manager *SGuestnetworkManager) ListItemFilter( q = q.In("mac_addr", query.MacAddr) } if len(query.IpAddr) > 0 { - q = q.In("ip_addr", query.IpAddr) + naSubQ := NetworkAddressManager.Query("parent_id").Equals("type", api.NetworkAddressTypeSubIP).Equals("parent_type", api.NetworkAddressParentTypeGuestnetwork).In("ip_addr", query.IpAddr).SubQuery() + q = q.Filter(sqlchemy.OR( + sqlchemy.In(q.Field("ip_addr"), query.IpAddr), + sqlchemy.In(q.Field("row_id"), naSubQ), + )) } if len(query.Ip6Addr) > 0 { q = q.In("ip6_addr", query.Ip6Addr) diff --git a/pkg/compute/models/networkaddresses.go b/pkg/compute/models/networkaddresses.go index 4ded314ebe..6ea0c14bff 100644 --- a/pkg/compute/models/networkaddresses.go +++ b/pkg/compute/models/networkaddresses.go @@ -76,21 +76,21 @@ func (man *SNetworkAddressManager) InitializeData() error { return nil } -func (man *SNetworkAddressManager) queryByParentTypeId(ctx context.Context, typ string, id string) *sqlchemy.SQuery { +func (man *SNetworkAddressManager) queryByParentTypeId(typ string, id string) *sqlchemy.SQuery { q := NetworkAddressManager.Query(). Equals("parent_type", typ). Equals("parent_id", id) return q } -func (man *SNetworkAddressManager) queryByGuestnetworkId(ctx context.Context, rowid int64) *sqlchemy.SQuery { +func (man *SNetworkAddressManager) queryByGuestnetworkId(rowid int64) *sqlchemy.SQuery { id := strconv.FormatInt(rowid, 10) - return man.queryByParentTypeId(ctx, api.NetworkAddressParentTypeGuestnetwork, id) + return man.queryByParentTypeId(api.NetworkAddressParentTypeGuestnetwork, id) } -func (man *SNetworkAddressManager) fetchByParentTypeId(ctx context.Context, typ string, id string) ([]SNetworkAddress, error) { +func (man *SNetworkAddressManager) fetchByParentTypeId(typ string, id string) ([]SNetworkAddress, error) { var ( - q = man.queryByParentTypeId(ctx, typ, id) + q = man.queryByParentTypeId(typ, id) nas []SNetworkAddress ) if err := db.FetchModelObjects(man, q, &nas); err != nil { @@ -99,23 +99,22 @@ func (man *SNetworkAddressManager) fetchByParentTypeId(ctx context.Context, typ return nas, nil } -func (man *SNetworkAddressManager) fetchByGuestnetworkId(ctx context.Context, rowid int64) ([]SNetworkAddress, error) { +func (man *SNetworkAddressManager) fetchByGuestnetworkId(rowid int64) ([]SNetworkAddress, error) { id := strconv.FormatInt(rowid, 10) - return man.fetchByParentTypeId(ctx, api.NetworkAddressParentTypeGuestnetwork, id) + return man.fetchByParentTypeId(api.NetworkAddressParentTypeGuestnetwork, id) } -type addrConf struct { - Type string `json:"type"` - IpAddr string `json:"ip_addr"` - Masklen int `json:"masklen"` - Gateway string `json:"gateway"` +func (man *SNetworkAddressManager) fetchAddressCountByGuestnetworkId(rowid int64) (int, error) { + q := man.queryByGuestnetworkId(rowid) + return q.CountWithError() } -func (man *SNetworkAddressManager) fetchAddressesByGuestnetworkId(ctx context.Context, rowid int64) ([]addrConf, error) { +func (man *SNetworkAddressManager) fetchAddressesByGuestnetworkId(rowid int64) ([]api.NetworkAddrConf, error) { var ( - naq = man.queryByGuestnetworkId(ctx, rowid).SubQuery() + naq = man.queryByGuestnetworkId(rowid).SubQuery() nq = NetworkManager.Query().SubQuery() ipnetsq = naq.Query( + naq.Field("id"), naq.Field("type"), naq.Field("ip_addr"), nq.Field("guest_ip_mask").Label("masklen"), @@ -124,7 +123,7 @@ func (man *SNetworkAddressManager) fetchAddressesByGuestnetworkId(ctx context.Co naq.Field("network_id"), nq.Field("id")), ) - ipnets []addrConf + ipnets []api.NetworkAddrConf ) if err := ipnetsq.All(&ipnets); err != nil { return nil, errors.Wrapf(err, "fetch addresses ipnets by guestnetwork row id: %d", rowid) @@ -133,7 +132,7 @@ func (man *SNetworkAddressManager) fetchAddressesByGuestnetworkId(ctx context.Co } func (man *SNetworkAddressManager) deleteByGuestnetworkId(ctx context.Context, userCred mcclient.TokenCredential, rowid int64) error { - nas, err := NetworkAddressManager.fetchByGuestnetworkId(ctx, rowid) + nas, err := NetworkAddressManager.fetchByGuestnetworkId(rowid) if err != nil { return errors.Wrap(err, "fetch attached network addresses") } @@ -164,7 +163,7 @@ func (man *SNetworkAddressManager) syncGuestnetworkICloudNic(ctx context.Context } func (man *SNetworkAddressManager) syncGuestnetworkSubIPs(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, ipAddrs []string) error { - nas, err := man.fetchByGuestnetworkId(ctx, guestnetwork.RowId) + nas, err := man.fetchByGuestnetworkId(guestnetwork.RowId) if err != nil { return errors.Wrap(err, "fetchByGuestnetworkId") } @@ -207,7 +206,7 @@ func (man *SNetworkAddressManager) syncGuestnetworkSubIPs(ctx context.Context, u } func (man *SNetworkAddressManager) removeGuestnetworkSubIPs(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, ipAddrs []string) error { - q := man.queryByGuestnetworkId(ctx, guestnetwork.RowId) + q := man.queryByGuestnetworkId(guestnetwork.RowId) q = q.In("ip_addr", ipAddrs) var nas []SNetworkAddress @@ -262,7 +261,7 @@ func (man *SNetworkAddressManager) addGuestnetworkSubIPs(ctx context.Context, us return nil } -func (man *SNetworkAddressManager) BatchPreValidate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict, count int) error { +/*func (man *SNetworkAddressManager) BatchPreValidate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict, count int) error { var ( input api.NetworkAddressCreateInput err error @@ -279,13 +278,14 @@ func (man *SNetworkAddressManager) BatchPreValidate(ctx context.Context, userCre } data.Update(input.JSON(input)) return nil -} +}*/ func (man *SNetworkAddressManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NetworkAddressCreateInput) (api.NetworkAddressCreateInput, error) { - return man.validateCreateData(ctx, userCred, ownerId, query, input, 1) + // return man.validateCreateData(ctx, userCred, ownerId, query, input, 1) + return input, errors.Wrap(httperrors.ErrNotSupported, "no supported") } -func (man *SNetworkAddressManager) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NetworkAddressCreateInput, count int) (api.NetworkAddressCreateInput, error) { +/*func (man *SNetworkAddressManager) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NetworkAddressCreateInput, count int) (api.NetworkAddressCreateInput, error) { if _, err := man.SStandaloneAnonResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneAnonResourceCreateInput); err != nil { return input, err } @@ -350,7 +350,7 @@ func (man *SNetworkAddressManager) validateCreateData(ctx context.Context, userC } return input, nil -} +}*/ func (na *SNetworkAddress) parentIdInt64() int64 { r, err := strconv.ParseInt(na.ParentId, 10, 64) @@ -420,7 +420,7 @@ func (na *SNetworkAddress) getICloudNic(ctx context.Context, userCred mcclient.T return nil, errors.Wrapf(errors.ErrNotFound, "getICloudNic: no cloud nic with ip %s, mac %s", guestnetwork.IpAddr, guestnetwork.MacAddr) } -func (na *SNetworkAddress) remoteAssignAddress(ctx context.Context, userCred mcclient.TokenCredential) error { +/*func (na *SNetworkAddress) remoteAssignAddress(ctx context.Context, userCred mcclient.TokenCredential) error { if na.ParentType == api.NetworkAddressParentTypeGuestnetwork { guest, err := na.getGuest(ctx, userCred) if err != nil { @@ -442,7 +442,7 @@ func (na *SNetworkAddress) remoteAssignAddress(ctx context.Context, userCred mcc } } return nil -} +}*/ func (na *SNetworkAddress) remoteUnassignAddress(ctx context.Context, userCred mcclient.TokenCredential) error { if na.ParentType == api.NetworkAddressParentTypeGuestnetwork { @@ -471,12 +471,12 @@ func (na *SNetworkAddress) remoteUnassignAddress(ctx context.Context, userCred m return nil } -func (na *SNetworkAddress) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { +/*func (na *SNetworkAddress) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { if err := na.remoteAssignAddress(ctx, userCred); err != nil { return err } return nil -} +}*/ func (na *SNetworkAddress) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { if err := na.remoteUnassignAddress(ctx, userCred); err != nil { @@ -651,3 +651,99 @@ func (man *SNetworkAddressManager) submitGuestSyncTask(ctx context.Context, user }, }) } + +func (g *SGuest) PerformAddSubIps(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.GuestAddSubIpsInput) (jsonutils.JSONObject, error) { + gn, err := g.getGuestnetworkByIpOrMac(input.IpAddr, input.Mac) + if err != nil { + return nil, errors.Wrapf(err, "getGuestnetworkByIpOrMac ip=%s mac=%s", input.IpAddr, input.Mac) + } + net := gn.GetNetwork() + if net == nil { + return nil, httperrors.NewInternalServerError("cannot fetch network of guestnetwork %d", gn.RowId) + } + + if input.Count == 0 { + input.Count = len(input.SubIps) + } + if input.Count == 0 { + // nil operation + return nil, nil + } + + subIps := make([]string, 0) + + err = func() error { + + lockman.LockObject(ctx, net) + defer lockman.ReleaseObject(ctx, net) + + addrTable := net.GetUsedAddresses() + recentUsedAddrTable := GuestnetworkManager.getRecentlyReleasedIPAddresses(net.Id, net.getAllocTimoutDuration()) + + for i := 0; i < input.Count; i++ { + var candidate string + if i < len(input.SubIps) { + candidate = input.SubIps[i] + } + ipAddr, err := net.GetFreeIP(ctx, userCred, addrTable, recentUsedAddrTable, candidate, input.AllocDir, input.Reserved) + if err != nil { + return httperrors.NewInputParameterError("allocate ip addr: %v", err) + } + + na := SNetworkAddress{} + na.ParentType = api.NetworkAddressParentTypeGuestnetwork + na.Type = api.NetworkAddressTypeSubIP + na.IpAddr = ipAddr + na.ParentId = fmt.Sprintf("%d", gn.RowId) + na.NetworkId = net.Id + na.SetModelManager(NetworkAddressManager, &na) + + err = NetworkAddressManager.TableSpec().Insert(ctx, &na) + if err != nil { + return errors.Wrapf(err, "Insert Network Address %s", na.IpAddr) + } + subIps = append(subIps, ipAddr) + // update + addrTable[ipAddr] = true + } + return nil + }() + if err != nil { + return nil, errors.Wrap(err, "allocate") + } + + if g.ExternalId != "" { + // sync to cloud + iNic, err := g.getICloudNic(ctx, gn) + if err != nil { + return nil, errors.Wrap(err, "getICloudNic") + } + if err := iNic.AssignAddress(subIps); err != nil { + if errors.Cause(err) == cloudprovider.ErrAddressCountExceed { + return nil, httperrors.NewNotAcceptableError("exceed address count limit: %v", err) + } + return nil, errors.Wrapf(err, "AssignAddress %s", subIps) + } + } else { + NetworkAddressManager.submitGuestSyncTask(ctx, userCred, g) + } + + return nil, nil +} + +func (g *SGuest) getICloudNic(ctx context.Context, gn *SGuestnetwork) (cloudprovider.ICloudNic, error) { + ivm, err := g.GetIVM(ctx) + if err != nil { + return nil, errors.Wrap(err, "GetIVM") + } + iNics, err := ivm.GetINics() + if err != nil { + return nil, errors.Wrap(err, "GetINics %s") + } + for _, iNic := range iNics { + if iNic.GetIP() == gn.IpAddr && iNic.GetMAC() == gn.MacAddr { + return iNic, nil + } + } + return nil, errors.Wrapf(errors.ErrNotFound, "no nic of ip %s mac %s", gn.IpAddr, gn.MacAddr) +} diff --git a/pkg/mcclient/options/compute/servers.go b/pkg/mcclient/options/compute/servers.go index 84e33be506..0e94ba6c3f 100644 --- a/pkg/mcclient/options/compute/servers.go +++ b/pkg/mcclient/options/compute/servers.go @@ -1391,3 +1391,13 @@ type ServerIsoOptions struct { func (o *ServerIsoOptions) Params() (jsonutils.JSONObject, error) { return jsonutils.Marshal(o), nil } + +type ServerAddSubIpsOptions struct { + ServerIdOptions + + computeapi.GuestAddSubIpsInput +} + +func (o *ServerAddSubIpsOptions) Params() (jsonutils.JSONObject, error) { + return jsonutils.Marshal(o), nil +} diff --git a/pkg/mcclient/options/networkaddress.go b/pkg/mcclient/options/networkaddress.go index 64a4628296..4865abe346 100644 --- a/pkg/mcclient/options/networkaddress.go +++ b/pkg/mcclient/options/networkaddress.go @@ -73,3 +73,15 @@ func (opts *NetworkAddressIdOptions) GetId() string { func (opts *NetworkAddressIdOptions) Params() (jsonutils.JSONObject, error) { return nil, nil } + +type NetworkAddressIdsOptions struct { + ID []string +} + +func (opts *NetworkAddressIdsOptions) GetIds() []string { + return opts.ID +} + +func (opts *NetworkAddressIdsOptions) Params() (jsonutils.JSONObject, error) { + return nil, nil +}