diff --git a/pkg/cloudcommon/db/opslog_const.go b/pkg/cloudcommon/db/opslog_const.go index 4442e10970..49eecba633 100644 --- a/pkg/cloudcommon/db/opslog_const.go +++ b/pkg/cloudcommon/db/opslog_const.go @@ -75,8 +75,9 @@ const ( ACT_VM_CONVERTING = "vm_converting" ACT_VM_CONVERT_FAIL = "vm_convert_fail" - ACT_SPLIT = "net_split" - ACT_MERGE = "net_merge" + ACT_SPLIT = "net_split" + ACT_MERGE = "net_merge" + ACT_IP_MAC_BIND = "ip_mac_bind" ACT_SAVING = "saving" ACT_SAVE = "save" diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index 5c3af09c1d..08ad95fc34 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -287,16 +287,6 @@ func (manager *SGuestnetworkManager) newGuestNetwork( } provider := vpc.GetProviderName() - - macAddr, err := manager.GenerateMac(mac) - if err != nil { - return nil, err - } - if len(macAddr) == 0 { - log.Errorf("Mac address generate fails") - return nil, fmt.Errorf("mac address generate fails") - } - gn.MacAddr = macAddr if !virtual { if len(address) > 0 && reUseAddr { ipAddr, err := netutils.NewIPV4Addr(address) @@ -332,6 +322,21 @@ func (manager *SGuestnetworkManager) newGuestNetwork( } } } + var err error + if ipBindMac := NetworkIpMacManager.GetMacFromIp(network.Id, gn.IpAddr); ipBindMac != "" { + gn.MacAddr = ipBindMac + } else { + gn.MacAddr, err = manager.GenerateMac(mac) + if err != nil { + return nil, err + } + } + + if len(gn.MacAddr) == 0 { + log.Errorf("Mac address generate fails") + return nil, fmt.Errorf("mac address generate fails") + } + ifname, err = gn.checkOrAllocateIfname(network, ifname) if err != nil { return nil, err diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 348e6d82db..b11168620d 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3194,9 +3194,6 @@ func (args *Attach2NetworkArgs) onceArgs(i int) attach2NetworkOnceArgs { pendingUsage: args.PendingUsage, } - if ipBindMac := NetworkIpMacManager.GetMacFromIp(r.network.Id, r.ipAddr); ipBindMac != "" { - r.nicConf.Mac = ipBindMac - } if i > 0 { r.ipAddr = "" r.bwLimit = 0 diff --git a/pkg/compute/models/network_ip_mac.go b/pkg/compute/models/network_ip_mac.go index 0766f0a0f7..11e35093d4 100644 --- a/pkg/compute/models/network_ip_mac.go +++ b/pkg/compute/models/network_ip_mac.go @@ -3,11 +3,13 @@ package models import ( "context" "database/sql" + "fmt" "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/rbacscope" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -15,6 +17,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) @@ -54,6 +57,18 @@ type SNetworkIpMac struct { IpAddr string `width:"16" charset:"ascii" nullable:"false" list:"user" index:"true" create:"required"` } +func (manager *SNetworkIpMacManager) ResourceScope() rbacscope.TRbacScope { + return rbacscope.ScopeProject +} + +func (self *SNetworkIpMac) GetOwnerId() mcclient.IIdentityProvider { + iNetwork, _ := NetworkManager.FetchById(self.NetworkId) + if iNetwork != nil { + return iNetwork.GetOwnerId() + } + return nil +} + func (manager *SNetworkIpMacManager) NetworkMacAddrInUse(networkId, macAddr string) (bool, error) { count, err := manager.Query(). Equals("network_id", networkId). @@ -112,7 +127,7 @@ func (self *SNetworkIpMac) ValidateUpdateData( return input, httperrors.NewInputParameterError("missing update field") } - if input.IpAddr != "" { + if input.IpAddr != "" && input.IpAddr != self.IpAddr { iNetwork, err := NetworkManager.FetchByIdOrName(userCred, self.NetworkId) if err != nil { return input, errors.Wrap(err, "fetch network") @@ -124,21 +139,21 @@ func (self *SNetworkIpMac) ValidateUpdateData( if ipInUse, err := NetworkIpMacManager.NetworkIpAddrInUse(self.NetworkId, input.IpAddr); err != nil { return input, errors.Wrap(err, "check ip addr in use") } else if ipInUse { - return input, errors.Errorf("ip addr %s is in use", input.IpAddr) + return input, httperrors.NewBadRequestError("ip addr %s is in use", input.IpAddr) } } else { input.IpAddr = self.IpAddr } - if input.MacAddr != "" { + input.MacAddr = strings.ToLower(input.MacAddr) + if input.MacAddr != "" && input.MacAddr != self.MacAddr { if !utils.IsMatchMacAddr(input.MacAddr) { return input, errors.Errorf("mac address %s is not valid", input.MacAddr) } - input.MacAddr = strings.ToLower(input.MacAddr) if macInUse, err := NetworkIpMacManager.NetworkMacAddrInUse(self.NetworkId, input.MacAddr); err != nil { return input, errors.Wrap(err, "check mac addr in use") } else if macInUse { - return input, errors.Errorf("mac addr %s is in use", input.MacAddr) + return input, httperrors.NewBadRequestError("mac addr %s is in use", input.MacAddr) } } else { input.MacAddr = self.MacAddr @@ -221,6 +236,27 @@ func (manager *SNetworkIpMacManager) validateIpMac(ip, mac string, network *SNet return nil } +func (self *SNetworkIpMac) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + iNetwork, _ := NetworkManager.FetchByIdOrName(userCred, self.NetworkId) + note := fmt.Sprintf("create ip %s mac %s bind", self.IpAddr, self.MacAddr) + db.OpsLog.LogEvent(iNetwork, db.ACT_IP_MAC_BIND, note, userCred) + logclient.AddActionLogWithContext(ctx, iNetwork, logclient.ACT_IP_MAC_BIND, note, userCred, true) +} + +func (self *SNetworkIpMac) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query, data jsonutils.JSONObject) { + iNetwork, _ := NetworkManager.FetchByIdOrName(userCred, self.NetworkId) + note := fmt.Sprintf("update ip %s mac %s bind", self.IpAddr, self.MacAddr) + db.OpsLog.LogEvent(iNetwork, db.ACT_IP_MAC_BIND, note, userCred) + logclient.AddActionLogWithContext(ctx, iNetwork, logclient.ACT_IP_MAC_BIND, note, userCred, true) +} + +func (self *SNetworkIpMac) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) { + iNetwork, _ := NetworkManager.FetchByIdOrName(userCred, self.NetworkId) + note := fmt.Sprintf("delete ip %s mac %s bind", self.IpAddr, self.MacAddr) + db.OpsLog.LogEvent(iNetwork, db.ACT_IP_MAC_BIND, note, userCred) + logclient.AddActionLogWithContext(ctx, iNetwork, logclient.ACT_IP_MAC_BIND, note, userCred, true) +} + func (manager *SNetworkIpMacManager) PerformBatchCreate( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkIpMacBatchCreateInput, ) (jsonutils.JSONObject, error) { @@ -235,6 +271,7 @@ func (manager *SNetworkIpMacManager) PerformBatchCreate( input.NetworkId = network.Id var errs = []error{} + var insertedIpMacs = map[string]string{} for ip, mac := range input.IpMac { if err := manager.validateIpMac(ip, mac, network); err != nil { errs = append(errs, err) @@ -249,7 +286,12 @@ func (manager *SNetworkIpMacManager) PerformBatchCreate( errs = append(errs, err) continue } + insertedIpMacs[ip] = mac } + note := fmt.Sprintf("create ip macs bind %v", insertedIpMacs) + db.OpsLog.LogEvent(iNetwork, db.ACT_IP_MAC_BIND, note, userCred) + logclient.AddActionLogWithContext(ctx, iNetwork, logclient.ACT_IP_MAC_BIND, note, userCred, true) + if len(errs) == 0 { return nil, nil } diff --git a/pkg/util/logclient/consts.go b/pkg/util/logclient/consts.go index bc56d74f65..8ce4c8e948 100644 --- a/pkg/util/logclient/consts.go +++ b/pkg/util/logclient/consts.go @@ -238,4 +238,6 @@ const ( ACT_SET_USER_PASSWORD = "set_user_password" ACT_PANIC = "panic" + + ACT_IP_MAC_BIND = "ip_mac_bind" )