github.com/GuanceCloud/cliutils@v1.1.21/pipeline/manager/scriptstore.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the MIT License.
     3  // This product includes software developed at Guance Cloud (https://www.guance.com/).
     4  // Copyright 2021-present Guance, Inc.
     5  
     6  package manager
     7  
     8  import (
     9  	"path/filepath"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/GuanceCloud/cliutils/logger"
    14  	"github.com/GuanceCloud/cliutils/pipeline/ptinput/plmap"
    15  	"github.com/GuanceCloud/cliutils/pipeline/stats"
    16  	"github.com/GuanceCloud/cliutils/point"
    17  )
    18  
    19  var log = logger.DefaultSLogger("pl-script")
    20  
    21  const (
    22  	NSDefault = "default" // 内置 pl script, 优先级最低
    23  	NSGitRepo = "gitrepo" // git 管理的 pl script
    24  	NSConfd   = "confd"   // confd 管理的 pl script
    25  	NSRemote  = "remote"  // remote pl script,优先级最高
    26  )
    27  
    28  var nsSearchOrder = [4]string{
    29  	NSRemote, // 优先级最高的 ns
    30  	NSConfd,
    31  	NSGitRepo,
    32  	NSDefault,
    33  }
    34  
    35  func InitLog() {
    36  	log = logger.SLogger("pl-script")
    37  }
    38  
    39  func InitStore(manager *Manager, installDir string, tags map[string]string) {
    40  	stats.InitLog()
    41  
    42  	plPath := filepath.Join(installDir, "pipeline")
    43  	manager.LoadScriptsFromWorkspace(NSDefault, plPath, tags)
    44  }
    45  
    46  func NSFindPriority(ns string) int {
    47  	switch ns {
    48  	case NSDefault:
    49  		return 0 // lowest priority
    50  	case NSGitRepo:
    51  		return 1
    52  	case NSConfd:
    53  		return 2
    54  	case NSRemote:
    55  		return 3
    56  	default:
    57  		return -1
    58  	}
    59  }
    60  
    61  type ScriptStore struct {
    62  	category point.Category
    63  
    64  	storage scriptStorage
    65  
    66  	defultScript string
    67  
    68  	index     map[string]*PlScript
    69  	indexLock sync.RWMutex
    70  
    71  	cfg ManagerCfg
    72  }
    73  
    74  type scriptStorage struct {
    75  	sync.RWMutex
    76  	scripts map[string](map[string]*PlScript)
    77  }
    78  
    79  func NewScriptStore(category point.Category, cfg ManagerCfg) *ScriptStore {
    80  	return &ScriptStore{
    81  		category: category,
    82  		storage: scriptStorage{
    83  			scripts: map[string]map[string]*PlScript{
    84  				NSRemote:  {},
    85  				NSConfd:   {},
    86  				NSGitRepo: {},
    87  				NSDefault: {},
    88  			},
    89  		},
    90  		index: map[string]*PlScript{},
    91  		cfg:   cfg,
    92  	}
    93  }
    94  
    95  func (store *ScriptStore) SetDefaultScript(name string) {
    96  	store.indexLock.Lock()
    97  	defer store.indexLock.Unlock()
    98  	store.defultScript = name
    99  }
   100  
   101  func (store *ScriptStore) GetDefaultScript() string {
   102  	store.indexLock.RLock()
   103  	defer store.indexLock.RUnlock()
   104  	return store.defultScript
   105  }
   106  
   107  func (store *ScriptStore) IndexGet(name string) (*PlScript, bool) {
   108  	store.indexLock.RLock()
   109  	defer store.indexLock.RUnlock()
   110  	if v, ok := store.index[name]; ok {
   111  		return v, ok
   112  	}
   113  	return nil, false
   114  }
   115  
   116  func (store *ScriptStore) IndexDefault() (*PlScript, bool) {
   117  	store.indexLock.RLock()
   118  	defer store.indexLock.RUnlock()
   119  
   120  	if v, ok := store.index[store.defultScript]; ok {
   121  		return v, ok
   122  	}
   123  	return nil, false
   124  }
   125  
   126  func (store *ScriptStore) Count() int {
   127  	store.storage.RLock()
   128  	defer store.storage.RUnlock()
   129  
   130  	return len(store.storage.scripts[NSRemote]) +
   131  		len(store.storage.scripts[NSConfd]) +
   132  		len(store.storage.scripts[NSGitRepo]) +
   133  		len(store.storage.scripts[NSDefault])
   134  }
   135  
   136  func (store *ScriptStore) GetWithNs(name, ns string) (*PlScript, bool) {
   137  	store.storage.RLock()
   138  	defer store.storage.RUnlock()
   139  	if s, ok := store.storage.scripts[ns][name]; ok {
   140  		return s, ok
   141  	}
   142  	return nil, false
   143  }
   144  
   145  func (store *ScriptStore) indexStore(script *PlScript) {
   146  	store.indexLock.Lock()
   147  	defer store.indexLock.Unlock()
   148  
   149  	if store.index == nil {
   150  		store.index = map[string]*PlScript{}
   151  	}
   152  	store.index[script.name] = script
   153  }
   154  
   155  func (store *ScriptStore) indexDelete(name string) {
   156  	store.indexLock.Lock()
   157  	defer store.indexLock.Unlock()
   158  
   159  	delete(store.index, name)
   160  }
   161  
   162  func (store *ScriptStore) indexUpdate(script *PlScript) {
   163  	if script == nil {
   164  		return
   165  	}
   166  
   167  	curScript, ok := store.IndexGet(script.name)
   168  
   169  	if !ok {
   170  		store.indexStore(script)
   171  
   172  		stats.WriteUpdateTime(script.tags)
   173  		stats.WriteEvent(&stats.ChangeEvent{
   174  			Name:     script.name,
   175  			Category: script.category,
   176  			NS:       script.ns,
   177  			Script:   script.script,
   178  			Op:       stats.EventOpIndex,
   179  			Time:     time.Now(),
   180  		}, script.tags)
   181  		return
   182  	}
   183  
   184  	nsCur := NSFindPriority(curScript.ns)
   185  	nsNew := NSFindPriority(script.ns)
   186  	if nsNew >= nsCur {
   187  		store.indexStore(script)
   188  		stats.WriteUpdateTime(curScript.tags)
   189  		stats.WriteUpdateTime(script.tags)
   190  		stats.WriteEvent(&stats.ChangeEvent{
   191  			Name:      script.name,
   192  			Category:  script.category,
   193  			NS:        script.ns,
   194  			NSOld:     curScript.ns,
   195  			Script:    script.script,
   196  			ScriptOld: curScript.script,
   197  			Op:        stats.EventOpIndexUpdate,
   198  			Time:      time.Now(),
   199  		}, script.tags)
   200  	}
   201  }
   202  
   203  func (store *ScriptStore) indexDeleteAndBack(name, ns string, scripts4back map[string](map[string]*PlScript)) {
   204  	curScript, ok := store.IndexGet(name)
   205  	if !ok {
   206  		return
   207  	}
   208  
   209  	nsCur := NSFindPriority(curScript.ns)
   210  	if NSFindPriority(ns) != nsCur {
   211  		return
   212  	}
   213  
   214  	if nsCur > len(nsSearchOrder) {
   215  		return
   216  	}
   217  
   218  	if nsCur == -1 {
   219  		store.indexDelete(name)
   220  
   221  		stats.WriteEvent(&stats.ChangeEvent{
   222  			Name:     name,
   223  			Category: curScript.category,
   224  			NS:       curScript.ns,
   225  			Script:   curScript.script,
   226  			Op:       stats.EventOpIndexDelete,
   227  			Time:     time.Now(),
   228  		}, curScript.tags)
   229  		return
   230  	}
   231  
   232  	for _, v := range nsSearchOrder[len(nsSearchOrder)-nsCur:] {
   233  		if v, ok := scripts4back[v]; ok {
   234  			if s, ok := v[name]; ok {
   235  				store.indexStore(s)
   236  				stats.WriteUpdateTime(s.tags)
   237  				stats.WriteEvent(&stats.ChangeEvent{
   238  					Name:      name,
   239  					Category:  s.category,
   240  					NS:        s.ns,
   241  					NSOld:     curScript.ns,
   242  					Script:    s.script,
   243  					ScriptOld: curScript.script,
   244  					Op:        stats.EventOpIndexDeleteAndBack,
   245  					Time:      time.Now(),
   246  				}, s.tags)
   247  				return
   248  			}
   249  		}
   250  	}
   251  
   252  	store.indexDelete(name)
   253  
   254  	stats.WriteEvent(&stats.ChangeEvent{
   255  		Name:     name,
   256  		Category: curScript.category,
   257  		NS:       curScript.ns,
   258  		Script:   curScript.script,
   259  		Op:       stats.EventOpIndexDelete,
   260  		Time:     time.Now(),
   261  	}, curScript.tags)
   262  }
   263  
   264  func (store *ScriptStore) UpdateScriptsWithNS(ns string,
   265  	namedScript, scriptTags map[string]string,
   266  ) map[string]error {
   267  	store.storage.Lock()
   268  	defer store.storage.Unlock()
   269  
   270  	if _, ok := store.storage.scripts[ns]; !ok {
   271  		store.storage.scripts[ns] = map[string]*PlScript{}
   272  	}
   273  
   274  	aggBuk := plmap.NewAggBuks(store.cfg.upFn, store.cfg.gTags)
   275  	retScripts, retErr := NewScripts(namedScript, scriptTags, ns, store.category,
   276  		aggBuk)
   277  
   278  	for name, err := range retErr {
   279  		var errStr string
   280  		if err != nil {
   281  			errStr = err.Error()
   282  		}
   283  		change := stats.ChangeEvent{
   284  			Name:         name,
   285  			Category:     store.category,
   286  			NS:           ns,
   287  			Script:       namedScript[name],
   288  			Op:           stats.EventOpCompileError,
   289  			Time:         time.Now(),
   290  			CompileError: errStr,
   291  		}
   292  
   293  		sTags := map[string]string{
   294  			"name":     name,
   295  			"ns":       ns,
   296  			"lang":     "platypus",
   297  			"category": store.category.String(),
   298  		}
   299  
   300  		for k, v := range scriptTags {
   301  			if _, ok := sTags[k]; !ok {
   302  				sTags[k] = v
   303  			}
   304  		}
   305  
   306  		stats.WriteUpdateTime(sTags)
   307  		store.indexDeleteAndBack(name, ns, store.storage.scripts)
   308  
   309  		if v, ok := store.storage.scripts[ns][name]; ok {
   310  			if v.plBuks != nil {
   311  				v.plBuks.StopAllBukScanner()
   312  			}
   313  			if v.cache != nil {
   314  				v.cache.Stop()
   315  			}
   316  			if v.ptWindow != nil {
   317  				v.ptWindow.Deprecated()
   318  			}
   319  			delete(store.storage.scripts[ns], name)
   320  		}
   321  		stats.WriteEvent(&change, sTags)
   322  	}
   323  
   324  	// 如果上一次的集合中的脚本不存在于当前结果,则删除
   325  	for name, curScript := range store.storage.scripts[ns] {
   326  		if newScript, ok := retScripts[name]; ok { // 有更新
   327  			store.storage.scripts[ns][name] = newScript
   328  			stats.WriteUpdateTime(newScript.tags)
   329  			store.indexUpdate(newScript)
   330  		} else { // 删除
   331  			stats.WriteUpdateTime(curScript.tags)
   332  			store.indexDeleteAndBack(name, ns, store.storage.scripts)
   333  			delete(store.storage.scripts[ns], name)
   334  		}
   335  
   336  		// 清理之前一个脚本的资源
   337  		if curScript.plBuks != nil {
   338  			curScript.plBuks.StopAllBukScanner()
   339  		}
   340  		if curScript.cache != nil {
   341  			curScript.cache.Stop()
   342  		}
   343  		if curScript.ptWindow != nil {
   344  			curScript.ptWindow.Deprecated()
   345  		}
   346  	}
   347  
   348  	// 执行新增操作
   349  	for name, newScript := range retScripts {
   350  		if _, ok := store.storage.scripts[ns][name]; !ok {
   351  			store.storage.scripts[ns][name] = newScript
   352  			stats.WriteUpdateTime(newScript.tags)
   353  			store.indexUpdate(newScript)
   354  		}
   355  	}
   356  
   357  	if len(retErr) > 0 {
   358  		return retErr
   359  	}
   360  	return nil
   361  }