chore: remove unused configs code
This commit is contained in:
parent
f87f3c6599
commit
655725f6ad
|
@ -12,7 +12,7 @@
|
||||||
# must in major config file
|
# must in major config file
|
||||||
path.configs: "config"
|
path.configs: "config"
|
||||||
configs:
|
configs:
|
||||||
managed: true
|
managed: false
|
||||||
auto_reload: true
|
auto_reload: true
|
||||||
manager:
|
manager:
|
||||||
local_configs_repo_path: ./config_repo/
|
local_configs_repo_path: ./config_repo/
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/plugin/managed/common"
|
"infini.sh/framework/modules/configs/common"
|
||||||
"infini.sh/framework/core/elastic"
|
"infini.sh/framework/core/elastic"
|
||||||
"infini.sh/framework/core/global"
|
"infini.sh/framework/core/global"
|
||||||
"infini.sh/framework/core/kv"
|
"infini.sh/framework/core/kv"
|
||||||
|
|
|
@ -7,7 +7,7 @@ package common
|
||||||
import (
|
import (
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/modules/agent/model"
|
"infini.sh/console/modules/agent/model"
|
||||||
"infini.sh/console/plugin/managed/common"
|
"infini.sh/framework/modules/configs/common"
|
||||||
"infini.sh/framework/core/env"
|
"infini.sh/framework/core/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,261 +0,0 @@
|
||||||
/* Copyright © INFINI LTD. All rights reserved.
|
|
||||||
* Web: https://infinilabs.com
|
|
||||||
* Email: hello#infini.ltd */
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
log "github.com/cihub/seelog"
|
|
||||||
"infini.sh/console/plugin/managed/common"
|
|
||||||
"infini.sh/console/plugin/managed/config"
|
|
||||||
"infini.sh/framework/core/api"
|
|
||||||
"infini.sh/framework/core/errors"
|
|
||||||
"infini.sh/framework/core/global"
|
|
||||||
"infini.sh/framework/core/keystore"
|
|
||||||
"infini.sh/framework/core/kv"
|
|
||||||
"infini.sh/framework/core/model"
|
|
||||||
"infini.sh/framework/core/task"
|
|
||||||
"infini.sh/framework/core/util"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const bucketName = "instance_registered"
|
|
||||||
const configRegisterEnvKey = "CONFIG_MANAGED_SUCCESS"
|
|
||||||
|
|
||||||
func ConnectToManager() error {
|
|
||||||
|
|
||||||
if !global.Env().SystemConfig.Configs.Managed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if exists, err := kv.ExistsKey(bucketName, []byte(global.Env().SystemConfig.NodeConfig.ID)); exists && err == nil {
|
|
||||||
//already registered skip further process
|
|
||||||
log.Info("already registered to config manager")
|
|
||||||
global.Register(configRegisterEnvKey, true)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("register new instance to config manager")
|
|
||||||
|
|
||||||
//register to config manager
|
|
||||||
if global.Env().SystemConfig.Configs.Servers == nil || len(global.Env().SystemConfig.Configs.Servers) == 0 {
|
|
||||||
return errors.Errorf("no config manager was found")
|
|
||||||
}
|
|
||||||
|
|
||||||
info := model.GetInstanceInfo()
|
|
||||||
|
|
||||||
req := util.Request{Method: util.Verb_POST}
|
|
||||||
req.ContentType = "application/json"
|
|
||||||
req.Path = common.REGISTER_API
|
|
||||||
req.Body = util.MustToJSONBytes(info)
|
|
||||||
|
|
||||||
server, res, err := submitRequestToManager(&req)
|
|
||||||
if err == nil && server != "" {
|
|
||||||
if res.StatusCode == 200 || util.ContainStr(string(res.Body), "exists") {
|
|
||||||
log.Infof("success register to config manager: %v", string(server))
|
|
||||||
err := kv.AddValue(bucketName, []byte(global.Env().SystemConfig.NodeConfig.ID), []byte(util.GetLowPrecisionCurrentTime().String()))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
global.Register(configRegisterEnvKey, true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Error("failed to register to config manager,", err, ",", server)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func submitRequestToManager(req *util.Request) (string, *util.Result, error) {
|
|
||||||
var err error
|
|
||||||
var res *util.Result
|
|
||||||
for _, server := range global.Env().SystemConfig.Configs.Servers {
|
|
||||||
req.Url, err = url.JoinPath(server, req.Path)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res, err = util.ExecuteRequestWithCatchFlag(mTLSClient, req, true)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return server, res, nil
|
|
||||||
}
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientInitLock = sync.Once{}
|
|
||||||
var mTLSClient *http.Client
|
|
||||||
|
|
||||||
func ListenConfigChanges() error {
|
|
||||||
clientInitLock.Do(func() {
|
|
||||||
if global.Env().SystemConfig.Configs.Managed {
|
|
||||||
//init client
|
|
||||||
cfg := global.Env().GetClientConfigByEndpoint("configs", "")
|
|
||||||
if cfg != nil {
|
|
||||||
hClient, err := api.NewHTTPClient(cfg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
mTLSClient = hClient
|
|
||||||
}
|
|
||||||
|
|
||||||
//init config sync listening
|
|
||||||
req := common.ConfigSyncRequest{}
|
|
||||||
req.Client = model.GetInstanceInfo()
|
|
||||||
|
|
||||||
var syncFunc = func() {
|
|
||||||
if global.Env().IsDebug {
|
|
||||||
log.Trace("fetch configs from manger")
|
|
||||||
}
|
|
||||||
|
|
||||||
cfgs := config.GetConfigs(false, false)
|
|
||||||
req.Configs = cfgs
|
|
||||||
req.Hash = util.MD5digestString(util.MustToJSONBytes(cfgs))
|
|
||||||
|
|
||||||
//fetch configs from manager
|
|
||||||
request := util.Request{Method: util.Verb_POST}
|
|
||||||
request.ContentType = "application/json"
|
|
||||||
request.Path = common.SYNC_API
|
|
||||||
request.Body = util.MustToJSONBytes(req)
|
|
||||||
|
|
||||||
if global.Env().IsDebug {
|
|
||||||
log.Debug("config sync request: ", string(util.MustToJSONBytes(req)))
|
|
||||||
}
|
|
||||||
|
|
||||||
_, res, err := submitRequestToManager(&request)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to submit request to config manager,", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res != nil {
|
|
||||||
obj := common.ConfigSyncResponse{}
|
|
||||||
err := util.FromJSONBytes(res.Body, &obj)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if global.Env().IsDebug {
|
|
||||||
log.Debug("config sync response: ", string(res.Body))
|
|
||||||
}
|
|
||||||
|
|
||||||
if obj.Changed {
|
|
||||||
|
|
||||||
//update secrets //TODO client send salt to manager first, manager encrypt secrets with salt and send back
|
|
||||||
if obj.Secrets != nil {
|
|
||||||
for k, v := range obj.Secrets.Keystore {
|
|
||||||
if v.Type == "plaintext" {
|
|
||||||
err := saveKeystore(k, v.Value)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("error on save keystore:", k, ",", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO maybe we have other secrets
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range obj.Configs.DeletedConfigs {
|
|
||||||
if v.Managed {
|
|
||||||
err := config.DeleteConfig(v.Name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Error("config [", v.Name, "] is not managed by config manager, skip deleting")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range obj.Configs.CreatedConfigs {
|
|
||||||
err := config.SaveConfig(v.Name, v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range obj.Configs.UpdatedConfigs {
|
|
||||||
err := config.SaveConfig(v.Name, v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyValuePairs = []util.KeyValue{}
|
|
||||||
//checking backup files, remove old configs, only keep max num of files
|
|
||||||
filepath.Walk(global.Env().SystemConfig.PathConfig.Config, func(file string, f os.FileInfo, err error) error {
|
|
||||||
|
|
||||||
//only allow to delete backup files
|
|
||||||
if !util.SuffixStr(file, ".bak") {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
keyValuePairs = append(keyValuePairs, util.KeyValue{Key: file, Value: f.ModTime().Unix()})
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if len(keyValuePairs) > 0 {
|
|
||||||
keyValuePairs = util.SortKeyValueArray(keyValuePairs, true)
|
|
||||||
|
|
||||||
if len(keyValuePairs) > global.Env().SystemConfig.Configs.MaxBackupFiles {
|
|
||||||
tobeDeleted := keyValuePairs[global.Env().SystemConfig.Configs.MaxBackupFiles:]
|
|
||||||
for _, v := range tobeDeleted {
|
|
||||||
log.Debug("delete config file: ", v.Key)
|
|
||||||
err := util.FileDelete(v.Key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
syncFunc()
|
|
||||||
|
|
||||||
if !global.Env().SystemConfig.Configs.ScheduledTask {
|
|
||||||
log.Debug("register background task for checking configs changes")
|
|
||||||
global.RegisterBackgroundCallback(&global.BackgroundTask{
|
|
||||||
Tag: "checking configs changes",
|
|
||||||
Interval: util.GetDurationOrDefault(global.Env().SystemConfig.Configs.Interval, time.Duration(30)*time.Second),
|
|
||||||
Func: syncFunc,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
log.Debug("register schedule task for checking configs changes")
|
|
||||||
task.RegisterScheduleTask(task.ScheduleTask{
|
|
||||||
Description: fmt.Sprintf("sync configs from manager"),
|
|
||||||
Type: "interval",
|
|
||||||
Interval: global.Env().SystemConfig.Configs.Interval,
|
|
||||||
Task: func(ctx context.Context) {
|
|
||||||
syncFunc()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveKeystore(k string, v string) error {
|
|
||||||
|
|
||||||
log.Debug("save keystore:", k)
|
|
||||||
|
|
||||||
ks, err := keystore.GetWriteableKeystore()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ks.Store(k, util.UnsafeStringToBytes(v))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ks.Save()
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/* Copyright © INFINI LTD. All rights reserved.
|
|
||||||
* Web: https://infinilabs.com
|
|
||||||
* Email: hello#infini.ltd */
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
log "github.com/cihub/seelog"
|
|
||||||
"infini.sh/framework/core/global"
|
|
||||||
"infini.sh/framework/core/util"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetOrInitDefaultCaCerts()(string, string, error){
|
|
||||||
dataDir := global.Env().GetDataDir()
|
|
||||||
caFile := path.Join(dataDir, "certs/ca.crt")
|
|
||||||
caKey := path.Join(dataDir, "certs/ca.key")
|
|
||||||
if !(util.FileExists(caFile) && util.FileExists(caKey) ) {
|
|
||||||
err := os.MkdirAll(path.Join(dataDir, "certs"), 0775)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
log.Info("auto generating cert files")
|
|
||||||
_, rootKey, rootCertPEM := util.GetRootCert()
|
|
||||||
|
|
||||||
caKeyPEM := pem.EncodeToMemory(&pem.Block{
|
|
||||||
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootKey),
|
|
||||||
})
|
|
||||||
_, err = util.FilePutContentWithByte(caKey, caKeyPEM)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
_, err = util.FilePutContentWithByte(caFile, rootCertPEM)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return caFile, caKey, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
/* Copyright © INFINI LTD. All rights reserved.
|
|
||||||
* Web: https://infinilabs.com
|
|
||||||
* Email: hello#infini.ltd */
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import "infini.sh/framework/core/model"
|
|
||||||
|
|
||||||
const REGISTER_API = "/instance/_register"
|
|
||||||
const SYNC_API = "/configs/_sync"
|
|
||||||
const GET_INSTALL_SCRIPT_API = "/instance/_get_install_script"
|
|
||||||
|
|
||||||
type ConfigFile struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Location string `json:"location,omitempty"`
|
|
||||||
Content string `json:"content,omitempty"`
|
|
||||||
Updated int64 `json:"updated,omitempty"`
|
|
||||||
Version int64 `json:"version,omitempty"`
|
|
||||||
Size int64 `json:"size,omitempty"`
|
|
||||||
Readonly bool `json:"readonly,omitempty"`
|
|
||||||
Managed bool `json:"managed"`
|
|
||||||
Hash string `json:"hash,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigList struct {
|
|
||||||
Main ConfigFile `json:"main,omitempty"`
|
|
||||||
Configs map[string]ConfigFile `json:"configs,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigDeleteRequest struct {
|
|
||||||
Configs []string `json:"configs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigUpdateRequest struct {
|
|
||||||
Configs map[string]string `json:"configs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigSyncRequest struct {
|
|
||||||
ForceSync bool `json:"force_sync"` //ignore hash check in server
|
|
||||||
Hash string `json:"hash"`
|
|
||||||
Client model.Instance `json:"client"`
|
|
||||||
Configs ConfigList `json:"configs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigSyncResponse struct {
|
|
||||||
Changed bool `json:"changed"`
|
|
||||||
Configs struct {
|
|
||||||
CreatedConfigs map[string]ConfigFile `json:"created,omitempty"`
|
|
||||||
DeletedConfigs map[string]ConfigFile `json:"deleted,omitempty"`
|
|
||||||
UpdatedConfigs map[string]ConfigFile `json:"updated,omitempty"`
|
|
||||||
} `json:"configs,omitempty"`
|
|
||||||
|
|
||||||
Secrets *Secrets `json:"secrets,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourceGroup struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
List []string `json:"list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigGroup struct {
|
|
||||||
Files []string `config:"files"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstanceGroup struct {
|
|
||||||
ConfigGroups []string `config:"configs"`
|
|
||||||
Instances []string `config:"instances"`
|
|
||||||
Secrets []string `config:"secrets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Secrets struct {
|
|
||||||
Keystore map[string]KeystoreValue `json:"keystore,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeystoreValue struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigRepo struct {
|
|
||||||
ConfigGroups map[string]ConfigGroup `config:"configs"`
|
|
||||||
InstanceGroups map[string]InstanceGroup `config:"instances"`
|
|
||||||
SecretGroups map[string]Secrets `config:"secrets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstanceSettings struct {
|
|
||||||
ConfigFiles []string `config:"configs"`
|
|
||||||
Secrets []string `config:"secrets"`
|
|
||||||
}
|
|
|
@ -1,339 +0,0 @@
|
||||||
/* ©INFINI, All Rights Reserved.
|
|
||||||
* mail: contact#infini.ltd */
|
|
||||||
|
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
log "github.com/cihub/seelog"
|
|
||||||
"infini.sh/console/core"
|
|
||||||
"infini.sh/console/plugin/managed/common"
|
|
||||||
"infini.sh/framework/core/api"
|
|
||||||
httprouter "infini.sh/framework/core/api/router"
|
|
||||||
"infini.sh/framework/core/env"
|
|
||||||
"infini.sh/framework/core/errors"
|
|
||||||
"infini.sh/framework/core/global"
|
|
||||||
"infini.sh/framework/core/util"
|
|
||||||
"infini.sh/framework/core/util/file"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
api.HandleAPIMethod(api.GET, "/config/", h.listConfigAction)
|
|
||||||
api.HandleAPIMethod(api.PUT, "/config/", h.saveConfigAction)
|
|
||||||
api.HandleAPIMethod(api.DELETE, "/config/", h.deleteConfigAction)
|
|
||||||
api.HandleAPIMethod(api.POST, "/config/_reload", h.reloadConfigAction)
|
|
||||||
api.HandleAPIMethod(api.GET, "/config/runtime", h.getConfigAction)
|
|
||||||
api.HandleAPIMethod(api.GET, "/environments", h.getEnvAction)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var h = DefaultHandler{}
|
|
||||||
|
|
||||||
type DefaultHandler struct {
|
|
||||||
core.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) getEnvAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
|
||||||
handler.WriteJSONHeader(w)
|
|
||||||
handler.WriteJSON(w, os.Environ(), 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) getConfigAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
|
||||||
json := env.GetConfigAsJSON()
|
|
||||||
handler.WriteJSONHeader(w)
|
|
||||||
handler.Write(w, []byte(json))
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateFile(cfgDir, name string) error {
|
|
||||||
|
|
||||||
cfgDir, _ = filepath.Abs(cfgDir)
|
|
||||||
name, _ = filepath.Abs(name)
|
|
||||||
|
|
||||||
//filter out the hidden files and go files
|
|
||||||
if strings.HasPrefix(filepath.Base(name), ".") || strings.HasSuffix(filepath.Base(name), ".go") {
|
|
||||||
return errors.Errorf("invalid config filename")
|
|
||||||
}
|
|
||||||
|
|
||||||
//filetype checking
|
|
||||||
ext := filepath.Ext(name)
|
|
||||||
if len(global.Env().SystemConfig.Configs.ValidConfigsExtensions) > 0 && !util.ContainsAnyInArray(ext, global.Env().SystemConfig.Configs.ValidConfigsExtensions) {
|
|
||||||
return errors.Errorf("invalid config file: %s, only support: %v", name, global.Env().SystemConfig.Configs.ValidConfigsExtensions)
|
|
||||||
}
|
|
||||||
|
|
||||||
//permission checking
|
|
||||||
if !util.IsFileWithinFolder(name, cfgDir) {
|
|
||||||
return errors.Errorf("invalid config file: %s, outside of path: %v", name, cfgDir)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteConfig(name string) error {
|
|
||||||
|
|
||||||
cfgDir, err := filepath.Abs(global.Env().GetConfigDir())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fileToDelete := path.Join(cfgDir, name)
|
|
||||||
|
|
||||||
log.Info("delete config file: ", fileToDelete)
|
|
||||||
|
|
||||||
//file checking
|
|
||||||
if err := validateFile(cfgDir, fileToDelete); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if util.FileExists(fileToDelete) {
|
|
||||||
if global.Env().SystemConfig.Configs.SoftDelete {
|
|
||||||
err := util.Rename(fileToDelete, fmt.Sprintf("%v.%v.bak", fileToDelete, time.Now().UnixMilli()))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := util.FileDelete(fileToDelete)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.Errorf("file not exists: %s", fileToDelete)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveConfig(name string, cfg common.ConfigFile) error {
|
|
||||||
|
|
||||||
//update version
|
|
||||||
if cfg.Managed {
|
|
||||||
cfg.Content = updateConfigVersion(cfg.Content, cfg.Version)
|
|
||||||
cfg.Content = updateConfigManaged(cfg.Content, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return SaveConfigStr(name, cfg.Content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveConfigStr(name, content string) error {
|
|
||||||
|
|
||||||
cfgDir, err := filepath.Abs(global.Env().GetConfigDir())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fileToSave := path.Join(cfgDir, name)
|
|
||||||
|
|
||||||
log.Info("write config file: ", fileToSave)
|
|
||||||
log.Trace("file content: ", content)
|
|
||||||
|
|
||||||
if err := validateFile(cfgDir, fileToSave); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if util.FileExists(fileToSave) {
|
|
||||||
if global.Env().SystemConfig.Configs.SoftDelete {
|
|
||||||
err := util.Rename(fileToSave, fmt.Sprintf("%v.%v.bak", fileToSave, time.Now().UnixMilli()))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = util.FilePutContent(fileToSave, content)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) deleteConfigAction(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
|
||||||
reqBody := common.ConfigDeleteRequest{}
|
|
||||||
err := handler.DecodeJSON(req, &reqBody)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range reqBody.Configs {
|
|
||||||
err := DeleteConfig(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handler.WriteAckOKJSON(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionRegexp = regexp.MustCompile(`#MANAGED_CONFIG_VERSION:\s*(?P<version>\d+)`)
|
|
||||||
var managedRegexp = regexp.MustCompile(`#MANAGED:\s*(?P<managed>\w+)`)
|
|
||||||
|
|
||||||
func parseConfigVersion(input string) int64 {
|
|
||||||
matches := versionRegexp.FindStringSubmatch(util.TrimSpaces(input))
|
|
||||||
if len(matches) > 0 {
|
|
||||||
ver := versionRegexp.SubexpIndex("version")
|
|
||||||
if ver >= 0 {
|
|
||||||
str := (matches[ver])
|
|
||||||
v, err := util.ToInt64(util.TrimSpaces(str))
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseConfigManaged(input string, defaultManaged bool) bool {
|
|
||||||
matches := managedRegexp.FindStringSubmatch(util.TrimSpaces(input))
|
|
||||||
if len(matches) > 0 {
|
|
||||||
v := managedRegexp.SubexpIndex("managed")
|
|
||||||
if v >= 0 {
|
|
||||||
str := util.TrimSpaces(strings.ToLower(matches[v]))
|
|
||||||
if str == "true" {
|
|
||||||
return true
|
|
||||||
} else if str == "false" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultManaged
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateConfigManaged(input string, managed bool) string {
|
|
||||||
if managedRegexp.MatchString(input) {
|
|
||||||
return managedRegexp.ReplaceAllString(input, fmt.Sprintf("#MANAGED: %v", managed))
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("%v\n#MANAGED: %v", input, managed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateConfigVersion(input string, newVersion int64) string {
|
|
||||||
if versionRegexp.MatchString(input) {
|
|
||||||
return versionRegexp.ReplaceAllString(input, fmt.Sprintf("#MANAGED_CONFIG_VERSION: %d", newVersion))
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("%v\n#MANAGED_CONFIG_VERSION: %d", input, newVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) listConfigAction(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
|
||||||
configs := GetConfigs(true, false)
|
|
||||||
handler.WriteJSON(w, configs, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfigs(returnContent, managedOnly bool) common.ConfigList {
|
|
||||||
|
|
||||||
cfgDir, err := filepath.Abs(global.Env().GetConfigDir())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
configs := common.ConfigList{}
|
|
||||||
configs.Configs = make(map[string]common.ConfigFile)
|
|
||||||
|
|
||||||
mainConfig, _ := filepath.Abs(global.Env().GetConfigFile())
|
|
||||||
|
|
||||||
info, err := file.Stat(mainConfig)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
c, err := util.FileGetContent(mainConfig)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
configs.Main = common.ConfigFile{
|
|
||||||
Name: util.TrimLeftStr(filepath.Base(mainConfig), cfgDir),
|
|
||||||
Location: mainConfig,
|
|
||||||
Readonly: true,
|
|
||||||
Managed: false,
|
|
||||||
Updated: info.ModTime().Unix(),
|
|
||||||
Size: info.Size(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if returnContent {
|
|
||||||
configs.Main.Content = string(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
//get files within folder
|
|
||||||
filepath.Walk(cfgDir, func(file string, f os.FileInfo, err error) error {
|
|
||||||
|
|
||||||
cfg, err := GetConfigFromFile(cfgDir, file)
|
|
||||||
if cfg != nil {
|
|
||||||
|
|
||||||
if !cfg.Managed && managedOnly {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !returnContent {
|
|
||||||
cfg.Content = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
configs.Configs[cfg.Name] = *cfg
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return configs
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfigFromFile(cfgDir, filename string) (*common.ConfigFile, error) {
|
|
||||||
|
|
||||||
//file checking
|
|
||||||
if err := validateFile(cfgDir, filename); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := util.FileGetContent(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := file.Stat(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
content := string(c)
|
|
||||||
cfg := common.ConfigFile{
|
|
||||||
Name: util.TrimLeftStr(filepath.Base(filename), cfgDir),
|
|
||||||
Location: filename,
|
|
||||||
Version: parseConfigVersion(content),
|
|
||||||
Updated: f.ModTime().Unix(),
|
|
||||||
Size: f.Size(),
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Content = content
|
|
||||||
cfg.Managed = parseConfigManaged(content, cfg.Version > 0 || global.Env().SystemConfig.Configs.ConfigFileManagedByDefault)
|
|
||||||
|
|
||||||
return &cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) saveConfigAction(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
|
||||||
reqBody := common.ConfigUpdateRequest{}
|
|
||||||
err := handler.DecodeJSON(req, &reqBody)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, content := range reqBody.Configs {
|
|
||||||
err := SaveConfigStr(name, content)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handler.WriteAckOKJSON(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler DefaultHandler) reloadConfigAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
|
||||||
log.Infof("refresh config")
|
|
||||||
err := global.Env().RefreshConfig()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
handler.WriteAckOKJSON(w)
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/* Copyright © INFINI LTD. All rights reserved.
|
|
||||||
* Web: https://infinilabs.com
|
|
||||||
* Email: hello#infini.ltd */
|
|
||||||
|
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/magiconair/properties/assert"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUpdateVersion(t *testing.T) {
|
|
||||||
input := `PEFFIX DON"T CHANGE,,, #MANAGED_CONFIG_VERSION: 1234, keep this as well`
|
|
||||||
output := updateConfigVersion(input, 1235)
|
|
||||||
fmt.Println(output)
|
|
||||||
assert.Equal(t, output, `PEFFIX DON"T CHANGE,,, #MANAGED_CONFIG_VERSION: 1235, keep this as well`)
|
|
||||||
|
|
||||||
|
|
||||||
input = `PEFFIX DON"T CHANGE, this is my config`
|
|
||||||
output = updateConfigVersion(input, 1235)
|
|
||||||
fmt.Println("new config:")
|
|
||||||
fmt.Println(output)
|
|
||||||
|
|
||||||
assert.Equal(t, output, "PEFFIX DON\"T CHANGE, this is my config\n#MANAGED_CONFIG_VERSION: 1235")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVersion(t *testing.T) {
|
|
||||||
ver:=parseConfigVersion("#MANAGED_CONFIG_VERSION: 1234")
|
|
||||||
assert.Equal(t, ver, int64(1234))
|
|
||||||
|
|
||||||
ver=parseConfigVersion("#MANAGED_CONFIG_VERSION:1234")
|
|
||||||
assert.Equal(t, ver, int64(1234))
|
|
||||||
|
|
||||||
ver=parseConfigVersion("#MANAGED_CONFIG_VERSION:1234 ")
|
|
||||||
assert.Equal(t, ver, int64(1234))
|
|
||||||
|
|
||||||
ver=parseConfigVersion("##MANAGED_CONFIG_VERSION: 1234")
|
|
||||||
assert.Equal(t, ver, int64(1234))
|
|
||||||
|
|
||||||
ver=parseConfigVersion("what's the version, i think is 1234")
|
|
||||||
assert.Equal(t, ver, int64(-1))
|
|
||||||
}
|
|
|
@ -6,8 +6,8 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/plugin/managed/common"
|
"infini.sh/framework/modules/configs/common"
|
||||||
"infini.sh/console/plugin/managed/config"
|
"infini.sh/framework/modules/configs/config"
|
||||||
httprouter "infini.sh/framework/core/api/router"
|
httprouter "infini.sh/framework/core/api/router"
|
||||||
config3 "infini.sh/framework/core/config"
|
config3 "infini.sh/framework/core/config"
|
||||||
"infini.sh/framework/core/global"
|
"infini.sh/framework/core/global"
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/core/security/enum"
|
"infini.sh/console/core/security/enum"
|
||||||
"infini.sh/console/plugin/managed/common"
|
"infini.sh/framework/modules/configs/common"
|
||||||
"infini.sh/framework/core/api"
|
"infini.sh/framework/core/api"
|
||||||
httprouter "infini.sh/framework/core/api/router"
|
httprouter "infini.sh/framework/core/api/router"
|
||||||
elastic2 "infini.sh/framework/core/elastic"
|
elastic2 "infini.sh/framework/core/elastic"
|
||||||
|
@ -33,7 +33,7 @@ func init() {
|
||||||
api.HandleAPIMethod(api.POST, common.REGISTER_API, handler.registerInstance) //client register self to config servers
|
api.HandleAPIMethod(api.POST, common.REGISTER_API, handler.registerInstance) //client register self to config servers
|
||||||
|
|
||||||
//for public usage, get install script
|
//for public usage, get install script
|
||||||
api.HandleAPIMethod(api.GET, common.GET_INSTALL_SCRIPT_API, handler.getInstallScript)
|
api.HandleAPIMethod(api.GET, GET_INSTALL_SCRIPT_API, handler.getInstallScript)
|
||||||
|
|
||||||
api.HandleAPIMethod(api.POST, "/instance/_generate_install_script", handler.RequireLogin(handler.generateInstallCommand))
|
api.HandleAPIMethod(api.POST, "/instance/_generate_install_script", handler.RequireLogin(handler.generateInstallCommand))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/core"
|
"infini.sh/console/core"
|
||||||
"infini.sh/console/plugin/managed/common"
|
"infini.sh/framework/modules/configs/common"
|
||||||
"infini.sh/framework/core/api"
|
"infini.sh/framework/core/api"
|
||||||
"infini.sh/framework/core/errors"
|
"infini.sh/framework/core/errors"
|
||||||
"infini.sh/framework/core/global"
|
"infini.sh/framework/core/global"
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/valyala/fasttemplate"
|
"github.com/valyala/fasttemplate"
|
||||||
"infini.sh/console/core/security"
|
"infini.sh/console/core/security"
|
||||||
"infini.sh/console/modules/agent/common"
|
"infini.sh/console/modules/agent/common"
|
||||||
common2 "infini.sh/console/plugin/managed/common"
|
|
||||||
httprouter "infini.sh/framework/core/api/router"
|
httprouter "infini.sh/framework/core/api/router"
|
||||||
"infini.sh/framework/core/global"
|
"infini.sh/framework/core/global"
|
||||||
"infini.sh/framework/core/util"
|
"infini.sh/framework/core/util"
|
||||||
|
@ -29,6 +28,7 @@ type Token struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpiredIn = time.Millisecond * 1000 * 60 * 60
|
const ExpiredIn = time.Millisecond * 1000 * 60 * 60
|
||||||
|
const GET_INSTALL_SCRIPT_API = "/instance/_get_install_script"
|
||||||
|
|
||||||
var expiredTokenCache = util.NewCacheWithExpireOnAdd(ExpiredIn, 100)
|
var expiredTokenCache = util.NewCacheWithExpireOnAdd(ExpiredIn, 100)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (h *APIHandler) generateInstallCommand(w http.ResponseWriter, req *http.Req
|
||||||
consoleEndpoint = getDefaultEndpoint(req)
|
consoleEndpoint = getDefaultEndpoint(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint, err := url.JoinPath(consoleEndpoint, common2.GET_INSTALL_SCRIPT_API)
|
endpoint, err := url.JoinPath(consoleEndpoint, GET_INSTALL_SCRIPT_API)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue