cubefs
162 строки · 3.8 Кб
1// Copyright 2023 The CubeFS Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied. See the License for the specific language governing
13// permissions and limitations under the License.
14
15package reloadconf16
17import (18"bytes"19"crypto/md5"20"encoding/base64"21"fmt"22"os"23"sync"24"time"25
26"github.com/cubefs/cubefs/blobstore/util/errors"27"github.com/cubefs/cubefs/util/log"28)
29
30// ReloadConf loads remote configuration change dynamically
31type ReloadConf struct {32ConfName string33ReloadSec int34RequestRemote func() ([]byte, error)35
36md5sum []byte37mutex sync.Mutex38}
39
40func (self *ReloadConf) reload(reload func(data []byte) error) error {41self.mutex.Lock()42defer self.mutex.Unlock()43
44// remote load45if self.RequestRemote != nil {46errRemote := self.remoteReload(reload)47if errRemote != nil {48log.LogWarn("remoteReload failed", self.ConfName, errors.Detail(errRemote))49} else {50return nil51}52}53
54// local load55errLocal := self.localReload(reload)56if errLocal != nil {57err := errors.Info(errLocal, "localReload").Detail(errLocal)58return err59}60return nil61}
62
63func (self *ReloadConf) remoteReload(reload func(data []byte) error) (err error) {64data, md5sum, err := fetchRemote(self.RequestRemote)65if err != nil {66err = errors.Info(err, "fetchRemote").Detail(err)67return68}69
70// compare whether md5sum is changed71if bytes.Equal(md5sum, self.md5sum) {72log.LogDebug("remoteReload:", self.ConfName, "do nothing cause of md5sum is equal")73return nil74}75
76confName := fmt.Sprintf("%v_%v", self.ConfName, base64.URLEncoding.EncodeToString(md5sum))77err = os.WriteFile(confName, data, 0o666)78if err != nil {79err = errors.Info(err, "os.WriteFile")80return81}82log.LogInfof("remoteReload %v remote file is changed, oldmd5: %v, newmd5: %v", self.ConfName, self.md5sum, md5sum)83
84err = reload(data)85if err != nil {86os.Remove(confName)87err = errors.Info(err, "reload", confName).Detail(err)88return89}90
91err = os.Rename(confName, self.ConfName)92if err != nil {93os.Remove(confName)94err = errors.Info(err, "os.Rename")95return96}97self.md5sum = md5sum98
99return100}
101
102func (self *ReloadConf) localReload(reload func(data []byte) error) (err error) {103data, err := os.ReadFile(self.ConfName)104if err != nil {105err = errors.Info(err, "os.ReadFile").Detail(err)106return107}108md5sum := calcMD5Sum(data)109
110if bytes.Equal(md5sum, self.md5sum) {111log.LogDebug("localReload:", self.ConfName, "do nothing cause of md5sum is equal")112return nil113}114
115log.LogInfof("localReload: %v local file is changed, oldmd5: %v, newmd5: %v", self.ConfName, self.md5sum, md5sum)116err = reload(data)117if err != nil {118err = errors.Info(err, "reload").Detail(err)119return120}121self.md5sum = md5sum122return123}
124
125func fetchRemote(requestRemote func() ([]byte, error)) (data, md5sum []byte, err error) {126data, err = requestRemote()127if err != nil {128err = errors.Info(err, "io.ReadAll")129return130}131md5sum = calcMD5Sum(data)132
133return134}
135
136func StartReload(cfg *ReloadConf, reload func(data []byte) error) (err error) {137err = cfg.reload(reload)138if err != nil {139log.LogError("cfg.reload:", cfg.ConfName, errors.Detail(err))140return141}142
143if cfg.ReloadSec == 0 {144return145}146go func() {147dur := time.Duration(cfg.ReloadSec) * time.Second148for range time.Tick(dur) {149err := cfg.reload(reload)150if err != nil {151log.LogError("cfg.reload:", cfg.ConfName, errors.Detail(err))152}153}154}()155return156}
157
158func calcMD5Sum(b []byte) []byte {159h := md5.New()160h.Write(b)161return h.Sum(nil)162}
163