diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index 34f581c1b2..524363bfa4 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -116,7 +116,7 @@ func (self *SBaremetalGuestDriver) GetRandomNetworkTypes() []string { return []string{models.NETWORK_TYPE_BAREMETAL, models.NETWORK_TYPE_GUEST} } -func (self *SBaremetalGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *models.SNetworkConfig, pendingUsage quotas.IQuota) error { +func (self *SBaremetalGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *models.SNetworkConfig, pendingUsage quotas.IQuota) (*models.SGuestnetwork, error) { netifs := host.GetNetInterfaces() netsAvaiable := make([]models.SNetwork, 0) netifIndexs := make(map[string]*models.SNetInterface, 0) @@ -152,14 +152,14 @@ func (self *SBaremetalGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ct } } if len(netsAvaiable) == 0 { - return fmt.Errorf("No appropriate host virtual network...") + return nil, fmt.Errorf("No appropriate host virtual network...") } net := models.ChooseCandidateNetworks(netsAvaiable, netConfig.Exit, netTypes) if net != nil { netif := netifIndexs[net.Id] return guest.Attach2Network(ctx, userCred, net, pendingUsage, "", netif.Mac, netConfig.Driver, netConfig.BwLimit, netConfig.Vip, netif.Index, false, models.IPAllocationStepup, false, "") } - return fmt.Errorf("No appropriate host virtual network...") + return nil, fmt.Errorf("No appropriate host virtual network...") } func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 9215b36ce2..2cacfe3c20 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -41,7 +41,7 @@ func (self *SVirtualizedGuestDriver) GetRandomNetworkTypes() []string { return []string{models.NETWORK_TYPE_GUEST} } -func (self *SVirtualizedGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *models.SNetworkConfig, pendingUsage quotas.IQuota) error { +func (self *SVirtualizedGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *models.SNetworkConfig, pendingUsage quotas.IQuota) (*models.SGuestnetwork, error) { var wirePattern *regexp.Regexp if len(netConfig.Wire) > 0 { wirePattern = regexp.MustCompile(netConfig.Wire) @@ -61,8 +61,6 @@ func (self *SVirtualizedGuestDriver) Attach2RandomNetwork(guest *models.SGuest, continue } - log.Debugf("Wire %#v", wire) - // !! if wirePattern != nil && !wirePattern.MatchString(wire.Id) && !wirePattern.MatchString(wire.Name) { continue @@ -79,14 +77,14 @@ func (self *SVirtualizedGuestDriver) Attach2RandomNetwork(guest *models.SGuest, } } if len(netsAvaiable) == 0 { - return fmt.Errorf("No appropriate host virtual network...") + return nil, fmt.Errorf("No appropriate host virtual network...") } selNet := models.ChooseCandidateNetworks(netsAvaiable, netConfig.Exit, netTypes) if selNet == nil { - return fmt.Errorf("Not enough address in virtual network") + return nil, fmt.Errorf("Not enough address in virtual network") } - err := guest.Attach2Network(ctx, userCred, selNet, pendingUsage, netConfig.Address, netConfig.Mac, netConfig.Driver, netConfig.BwLimit, netConfig.Vip, -1, netConfig.Reserved, models.IPAllocationDefault, false, netConfig.Ifname) - return err + gn, err := guest.Attach2Network(ctx, userCred, selNet, pendingUsage, netConfig.Address, netConfig.Mac, netConfig.Driver, netConfig.BwLimit, netConfig.Vip, -1, netConfig.Reserved, models.IPAllocationDefault, false, netConfig.Ifname) + return gn, err } func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 196aa77a02..588060a2b4 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -774,3 +774,13 @@ func (manager *SCloudproviderManager) ListItemFilter(ctx context.Context, q *sql return q, nil } + +func (self *SCloudprovider) IsAvailable() bool { + if !self.Enabled { + return false + } + if !utils.IsInStringArray(self.Status, CLOUD_PROVIDER_VALID_STATUS) { + return false + } + return true +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index b1cae7d671..e15a3da332 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1380,7 +1380,7 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T } host := self.GetHost() - _, err = func() (jsonutils.JSONObject, error) { + ngn, err := func() (*SGuestnetwork, error) { lockman.LockRawObject(ctx, GuestnetworkManager.KeywordPlural(), "") defer lockman.ReleaseRawObject(ctx, GuestnetworkManager.KeywordPlural(), "") @@ -1408,18 +1408,28 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T return nil, err } conf.Ifname = gn.Ifname - err = self.attach2NetworkDesc(ctx, userCred, host, conf, nil) + ngn, err := self.attach2NetworkDesc(ctx, userCred, host, conf, nil) if err != nil { return nil, httperrors.NewBadRequestError(err.Error()) } - return nil, nil + return ngn, nil }() if err != nil { + logclient.AddActionLogWithContext(ctx, self, logclient.ACT_VM_CHANGE_NIC, err, userCred, false) return nil, err } + notes := jsonutils.NewDict() + if gn != nil { + notes.Add(jsonutils.NewString(gn.IpAddr), "prev_ip") + } + if ngn != nil { + notes.Add(jsonutils.NewString(ngn.IpAddr), "ip") + } + logclient.AddActionLogWithContext(ctx, self, logclient.ACT_VM_CHANGE_NIC, notes, userCred, true) + err = self.StartSyncTask(ctx, userCred, true, "") return nil, err } @@ -1516,7 +1526,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient. return nil, httperrors.NewOutOfQuotaError(err.Error()) } host := self.GetHost() - err = self.attach2NetworkDesc(ctx, userCred, host, conf, pendingUsage) + _, err = self.attach2NetworkDesc(ctx, userCred, host, conf, pendingUsage) if err != nil { QuotaManager.CancelPendingUsage(ctx, userCred, projectId, nil, pendingUsage) return nil, httperrors.NewBadRequestError(err.Error()) @@ -2720,7 +2730,7 @@ func (self *SGuest) importNics(ctx context.Context, userCred mcclient.TokenCrede if err != nil { return httperrors.NewNotFoundError("Not found network by ip %s", nic.Ip) } - err = self.attach2NetworkDesc(ctx, userCred, self.GetHost(), nic.ToNetConfig(net), nil) + _, err = self.attach2NetworkDesc(ctx, userCred, self.GetHost(), nic.ToNetConfig(net), nil) if err != nil { return err } diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 3999161bdb..fd2be736ef 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -39,7 +39,7 @@ type IGuestDriver interface { GetNamedNetworkConfiguration(guest *SGuest, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig) (*SNetwork, string, int8, IPAddlocationDirection) - Attach2RandomNetwork(guest *SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) error + Attach2RandomNetwork(guest *SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) (*SGuestnetwork, error) GetRandomNetworkTypes() []string ChooseHostStorage(host *SHost, backend string) *SStorage diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 5f857654ec..b031fd12f3 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2087,12 +2087,12 @@ func (self *SGuest) getOSProfile() osprofile.SOSProfile { func (self *SGuest) Attach2Network(ctx context.Context, userCred mcclient.TokenCredential, network *SNetwork, pendingUsage quotas.IQuota, address string, mac string, driver string, bwLimit int, virtual bool, index int8, - reserved bool, allocDir IPAddlocationDirection, requireDesignatedIP bool, ifName string) error { + reserved bool, allocDir IPAddlocationDirection, requireDesignatedIP bool, ifName string) (*SGuestnetwork, error) { /* allow a guest attach to a network 2 times */ if self.getAttach2NetworkCount(network) > MAX_GUESTNIC_TO_SAME_NETWORK { - return fmt.Errorf("Guest has been attached to network %s", network.Name) + return nil, fmt.Errorf("Guest has been attached to network %s", network.Name) } if index < 0 { index = self.getMaxNicIndex() @@ -2108,7 +2108,7 @@ func (self *SGuest) Attach2Network(ctx context.Context, userCred mcclient.TokenC index, address, mac, driver, bwLimit, virtual, reserved, allocDir, requireDesignatedIP, ifName) if err != nil { - return err + return nil, err } network.updateDnsRecord(guestnic, true) network.updateGuestNetmap(guestnic) @@ -2124,7 +2124,7 @@ func (self *SGuest) Attach2Network(ctx context.Context, userCred mcclient.TokenC } err = QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, pendingUsage, &cancelUsage) if err != nil { - return err + log.Warningf("QuotaManager.CancelPendingUsage fail %s", err) } } notes := jsonutils.NewDict() @@ -2133,7 +2133,7 @@ func (self *SGuest) Attach2Network(ctx context.Context, userCred mcclient.TokenC } notes.Add(jsonutils.NewString(address), "ip_addr") db.OpsLog.LogAttachEvent(ctx, self, network, userCred, notes) - return nil + return guestnic, nil } type sRemoveGuestnic struct { @@ -2252,7 +2252,7 @@ func (self *SGuest) SyncVMNics(ctx context.Context, userCred mcclient.TokenCrede continue } } - err = self.Attach2Network(ctx, userCred, add.net, nil, add.nic.GetIP(), + _, err = self.Attach2Network(ctx, userCred, add.net, nil, add.nic.GetIP(), add.nic.GetMAC(), add.nic.GetDriver(), 0, false, -1, add.reserve, IPAllocationDefault, true, "") if err != nil { result.AddError(err) @@ -2512,14 +2512,15 @@ func (self *SGuest) CreateNetworksOnHost(ctx context.Context, userCred mcclient. }*/ if len(netJsonArray) == 0 { netConfig := self.getDefaultNetworkConfig() - return self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage) + _, err := self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage) + return err } for idx := 0; idx < len(netJsonArray); idx += 1 { netConfig, err := parseNetworkInfo(userCred, netJsonArray[idx]) if err != nil { return err } - err = self.attach2NetworkDesc(ctx, userCred, host, netConfig, pendingUsage) + _, err = self.attach2NetworkDesc(ctx, userCred, host, netConfig, pendingUsage) if err != nil { return err } @@ -2527,41 +2528,42 @@ func (self *SGuest) CreateNetworksOnHost(ctx context.Context, userCred mcclient. return nil } -func (self *SGuest) attach2NetworkDesc(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) error { +func (self *SGuest) attach2NetworkDesc(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) (*SGuestnetwork, error) { + var gn *SGuestnetwork var err1, err2 error if len(netConfig.Network) > 0 { - err1 = self.attach2NamedNetworkDesc(ctx, userCred, host, netConfig, pendingUsage) + gn, err1 = self.attach2NamedNetworkDesc(ctx, userCred, host, netConfig, pendingUsage) if err1 == nil { - return nil + return gn, nil } } - err2 = self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage) + gn, err2 = self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage) if err2 == nil { - return nil + return gn, nil } if err1 != nil { - return fmt.Errorf("%s/%s", err1, err2) + return nil, fmt.Errorf("%s/%s", err1, err2) } else { - return err2 + return nil, err2 } } -func (self *SGuest) attach2NamedNetworkDesc(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) error { +func (self *SGuest) attach2NamedNetworkDesc(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) (*SGuestnetwork, error) { driver := self.GetDriver() net, mac, idx, allocDir := driver.GetNamedNetworkConfiguration(self, userCred, host, netConfig) if net != nil { - err := self.Attach2Network(ctx, userCred, net, pendingUsage, netConfig.Address, mac, netConfig.Driver, netConfig.BwLimit, netConfig.Vip, idx, netConfig.Reserved, allocDir, false, netConfig.Ifname) + gn, err := self.Attach2Network(ctx, userCred, net, pendingUsage, netConfig.Address, mac, netConfig.Driver, netConfig.BwLimit, netConfig.Vip, idx, netConfig.Reserved, allocDir, false, netConfig.Ifname) if err != nil { - return err + return nil, err } else { - return nil + return gn, nil } } else { - return fmt.Errorf("Network %s not available", netConfig.Network) + return nil, fmt.Errorf("Network %s not available", netConfig.Network) } } -func (self *SGuest) attach2RandomNetwork(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) error { +func (self *SGuest) attach2RandomNetwork(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *SNetworkConfig, pendingUsage quotas.IQuota) (*SGuestnetwork, error) { driver := self.GetDriver() return driver.Attach2RandomNetwork(self, ctx, userCred, host, netConfig, pendingUsage) } diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index de4a3774f9..96c664e20c 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -825,6 +825,17 @@ func (self *SHost) GetSpec(statusCheck bool) *jsonutils.JSONDict { if self.ResourceType == HostResourceTypePrepaidRecycle && self.GetGuestCount() > 0 { return nil } + + if len(self.ManagerId) > 0 { + providerObj, _ := CloudproviderManager.FetchById(self.ManagerId) + if providerObj == nil { + return nil + } + provider := providerObj.(*SCloudprovider) + if !provider.IsAvailable() { + return nil + } + } } spec := self.GetHardwareSpecification() spec.Remove("storage_info") diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 0887f1c07c..cb39c98599 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -77,6 +77,8 @@ const ( ACT_RECYCLE_PREPAID = "池化预付费主机" ACT_UNDO_RECYCLE_PREPAID = "取消池化预付费主机" + + ACT_VM_CHANGE_NIC = "更改网卡配置" ) // golang 不支持 const 的string array, http://t.cn/EzAvbw8