diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 12fa332b79..1140f3dbaa 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -33,6 +33,7 @@ import ( "yunion.io/x/pkg/util/fileutils" "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/util/sets" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -1735,6 +1736,11 @@ func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.Toke self.SyncShareState(ctx, userCred, provider.getAccountShareInfo()) } + if err := self.syncSchedtags(ctx, userCred, extHost); err != nil { + log.Errorf("syncSchedtags fail: %v", err) + return err + } + if err := HostManager.ClearSchedDescCache(self.Id); err != nil { log.Errorf("ClearSchedDescCache for host %s error %v", self.Name, err) } @@ -1766,6 +1772,102 @@ func (self *SHost) syncWithCloudPrepaidVM(extVM cloudprovider.ICloudVM, host *SH return err } +var ( + METADATA_EXT_SCHEDTAG_KEY = "ext:schedtag" + METADATA_EXT_SCHEDTAG_VALUE = "yes" +) + +func (s *SHost) syncSchedtags(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost) error { + stq := SchedtagManager.Query() + subq := HostschedtagManager.Query("schedtag_id").Equals("host_id", s.Id).SubQuery() + stq = stq.Join(subq, sqlchemy.Equals(stq.Field("id"), subq.Field("schedtag_id"))) + schedtags := make([]SSchedtag, 0) + err := db.FetchModelObjects(SchedtagManager, stq, &schedtags) + if err != nil { + return errors.Wrap(err, "db.FetchModelObjects") + } + extSchedtagStrs, err := extHost.GetSchedtags() + if err != nil { + return errors.Wrap(err, "extHost.GetSchedtags") + } + extStStrSet := sets.NewString(extSchedtagStrs...) + removed := make([]*SSchedtag, 0) + removedIds := make([]string, 0) + for i := range schedtags { + stag := &schedtags[i] + if v := stag.GetMetadata(METADATA_EXT_SCHEDTAG_KEY, userCred); v != METADATA_EXT_SCHEDTAG_VALUE { + continue + } + if !extStStrSet.Has(stag.GetName()) { + removed = append(removed, stag) + removedIds = append(removedIds, stag.GetId()) + } else { + extStStrSet.Delete(stag.GetName()) + } + } + added := extStStrSet.UnsortedList() + + for _, stStr := range added { + st := &SSchedtag{ + ResourceType: HostManager.KeywordPlural(), + } + st.DomainId = s.DomainId + st.Name = stStr + st.Description = "Sync from cloud" + err := SchedtagManager.TableSpec().Insert(ctx, st) + if err != nil { + return errors.Wrapf(err, "unable to create schedtag %q", stStr) + } + st.SetModelManager(SchedtagManager, st) + st.SetMetadata(ctx, METADATA_EXT_SCHEDTAG_KEY, METADATA_EXT_SCHEDTAG_VALUE, userCred) + // attach + hostschedtag := &SHostschedtag{ + HostId: s.GetId(), + } + hostschedtag.SchedtagId = st.GetId() + err = HostschedtagManager.TableSpec().Insert(ctx, hostschedtag) + if err != nil { + return errors.Wrapf(err, "unable to create hostschedtag for tag %q host %q", stStr, s.GetId()) + } + } + + if len(removedIds) == 0 { + return nil + } + + q := HostschedtagManager.Query().Equals("host_id", s.GetId()).In("schedtag_id", removedIds) + hostschedtags := make([]SHostschedtag, 0, len(removedIds)) + err = db.FetchModelObjects(HostschedtagManager, q, &hostschedtags) + if err != nil { + return errors.Wrap(err, "db.FetchModelObject") + } + for i := range hostschedtags { + err = hostschedtags[i].Detach(ctx, userCred) + if err != nil { + return errors.Wrapf(err, "unable to detach host %q and schedtag %q", hostschedtags[i].HostId, hostschedtags[i].SchedtagId) + } + } + + // try to clean + for _, tag := range removed { + cnt, err := tag.GetObjectCount() + if err != nil { + log.Errorf("unable to GetObjectCount for schedtag %q: %v", tag.GetName(), err) + continue + } + if cnt > 0 { + continue + } + err = tag.Delete(ctx, userCred) + if err != nil { + log.Errorf("unable to delete schedtag %q: %v", tag.GetName(), err) + continue + } + } + + return nil +} + func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost, provider *SCloudprovider, izone *SZone) (*SHost, error) { host := SHost{} host.SetModelManager(manager, &host) @@ -1844,6 +1946,11 @@ func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mccl SyncCloudDomain(userCred, &host, provider.GetOwnerId()) + if err := host.syncSchedtags(ctx, userCred, extHost); err != nil { + log.Errorf("newFromCloudHost fail in syncSchedtags %v", err) + return nil, err + } + if provider != nil { host.SyncShareState(ctx, userCred, provider.getAccountShareInfo()) }