Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm extension #1204

Merged
merged 10 commits into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ coverage.txt
.vscode/*
bfe
dist/*
conf/wasm_plugin

.DS_Store
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ strip: prepare compile-strip package
# make prepare, download dependencies
prepare: prepare-dep prepare-gen
prepare-dep:
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest)
prepare-gen:
cd "bfe_basic/condition/parser" && $(GOGEN)

Expand Down Expand Up @@ -117,7 +117,7 @@ package:
# make deps
deps:
$(call PIP_INSTALL_PKG, pre-commit)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest)
$(call INSTALL_PKG, staticcheck, honnef.co/go/tools/cmd/staticcheck)
$(call INSTALL_PKG, license-eye, github.com/apache/skywalking-eyes/cmd/license-eye@latest)

Expand Down
5 changes: 5 additions & 0 deletions bfe_config/bfe_conf/conf_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type ConfigBasic struct {
DebugBfeRoute bool // whether open bferoute debug log
DebugBal bool // whether open bal debug log
DebugHealthCheck bool // whether open health check debug log

// wasm plugin path
BfeWasmPath string //root path of wasm plugins
}

func (cfg *ConfigBasic) SetDefaultConf() {
Expand Down Expand Up @@ -99,6 +102,8 @@ func (cfg *ConfigBasic) SetDefaultConf() {
cfg.NameConf = "server_data_conf/name_conf.data"

cfg.MonitorInterval = 20

cfg.BfeWasmPath = "plugin"
}

func (cfg *ConfigBasic) Check(confRoot string) error {
Expand Down
4 changes: 4 additions & 0 deletions bfe_modules/bfe_modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/bfenetworks/bfe/bfe_modules/mod_trust_clientip"
"github.com/bfenetworks/bfe/bfe_modules/mod_userid"
"github.com/bfenetworks/bfe/bfe_modules/mod_waf"
"github.com/bfenetworks/bfe/bfe_modules/mod_wasmplug"
)

// list of all modules, the order is very important
Expand Down Expand Up @@ -131,6 +132,9 @@ var moduleList = []bfe_module.BfeModule{

// mod_access
mod_access.NewModuleAccess(),

// mod_wasm
mod_wasmplug.NewModuleWasm(),
}

// init modules list
Expand Down
291 changes: 291 additions & 0 deletions bfe_modules/mod_wasmplug/conf_mod_wasmplug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
// Copyright (c) 2019 The BFE Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mod_wasmplug
xuleiming marked this conversation as resolved.
Show resolved Hide resolved

import (
"fmt"
"os"
"path"
"sync"

"github.com/baidu/go-lib/log"
"github.com/bfenetworks/bfe/bfe_basic/condition"
"github.com/bfenetworks/bfe/bfe_util"
"github.com/bfenetworks/bfe/bfe_util/json"
"github.com/bfenetworks/bfe/bfe_wasmplug"
gcfg "gopkg.in/gcfg.v1"
)

type ConfModWasm struct {
Basic struct {
WasmPluginPath string // path of Wasm plugins
xuleiming marked this conversation as resolved.
Show resolved Hide resolved
xuleiming marked this conversation as resolved.
Show resolved Hide resolved
DataPath string // path of config data
}

Log struct {
OpenDebug bool
}
}

// ConfLoad loads config from config file
func ConfLoad(filePath string, confRoot string) (*ConfModWasm, error) {
var cfg ConfModWasm
var err error

// read config from file
err = gcfg.ReadFileInto(&cfg, filePath)
if err != nil {
return &cfg, err
}

// check conf of mod_redirect
err = cfg.Check(confRoot)
if err != nil {
return &cfg, err
}

return &cfg, nil
}

func (cfg *ConfModWasm) Check(confRoot string) error {
if cfg.Basic.WasmPluginPath == "" {
log.Logger.Warn("ModWasm.WasmPluginPath not set, use default value")
cfg.Basic.WasmPluginPath = "mod_wasm"
}
cfg.Basic.WasmPluginPath = bfe_util.ConfPathProc(cfg.Basic.WasmPluginPath, confRoot)

if cfg.Basic.DataPath == "" {
log.Logger.Warn("ModWasm.DataPath not set, use default value")
cfg.Basic.WasmPluginPath = "mod_wasm/wasm.data"
}
cfg.Basic.DataPath = bfe_util.ConfPathProc(cfg.Basic.DataPath, confRoot)

return nil
}

type PluginConfFile struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该切分为独立的文件

Version *string // version of the config
BeforeLocationRules *[]FilterRuleFile // rule list for BeforeLocation
ProductRules *map[string][]FilterRuleFile // product --> rule list
xuleiming marked this conversation as resolved.
Show resolved Hide resolved
PluginMap *map[string]PluginMeta
}

type FilterRuleFile struct {
Cond *string // condition for plugin
PluginList *[]string
}

type PluginMeta struct {
Name string
WasmVersion string
ConfVersion string
// Md5 string
InstanceNum int
Product string
}

type FilterRule struct {
Cond condition.Condition // condition for plugin
PluginList []bfe_wasmplug.WasmPlugin
}

type RuleList []FilterRule
type ProductRules map[string]RuleList // product => list of filter rules

func updatePluginConf(t *PluginTable, conf PluginConfFile, pluginPath string) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个函数需要拆分。有的作为函数放在对应的“数据类模块”,有的应该作为函数放在mod_wasmplug中

if conf.Version != nil && *conf.Version != t.GetVersion() {
pluginMapNew := make(map[string]bfe_wasmplug.WasmPlugin)
var beforeLocationRulesNew RuleList
productRulesNew := make(ProductRules)

// 1. check plugin map
unchanged := make(map[string]bool)

pm := t.GetPluginMap()
if conf.PluginMap != nil {
for pn, p := range *conf.PluginMap {
plugOld := pm[pn]
// check whether plugin version changed.
if plugOld != nil {
configOld := plugOld.GetConfig()
if configOld.WasmVersion == p.WasmVersion && configOld.ConfigVersion == p.ConfVersion {
// not change, just copy to new map
pluginMapNew[pn] = plugOld

// ensure instance num
actual := plugOld.EnsureInstanceNum(p.InstanceNum)
if actual != p.InstanceNum {
return fmt.Errorf("can not EnsureInstanceNum, plugin:%s, num:%d", pn, p.InstanceNum)
}

unchanged[pn] = true
continue
}
}
// if changed, construct a new plugin.
wasmconf := bfe_wasmplug.WasmPluginConfig {
PluginName: pn,
WasmVersion: p.WasmVersion,
ConfigVersion: p.ConfVersion,
InstanceNum: p.InstanceNum,
Path: path.Join(pluginPath, pn),
// Md5: p.Md5,
}
plug, err := bfe_wasmplug.NewWasmPlugin(wasmconf)
if err != nil {
// build plugin error
return err
}

// plug.OnPluginStart()

pluginMapNew[pn] = plug
}
}

// 2. construct product rules
if conf.BeforeLocationRules != nil {
for _, r := range *conf.BeforeLocationRules {
rule := FilterRule{}
cond, err := condition.Build(*r.Cond)
if err != nil {
return err
}
rule.Cond =cond
for _, pn := range *r.PluginList {
plug := pluginMapNew[pn]
if plug == nil {
return fmt.Errorf("unknown plugin: %s", pn)
}
rule.PluginList = append(rule.PluginList, plug)
}
beforeLocationRulesNew = append(beforeLocationRulesNew, rule)
}
}

if conf.ProductRules != nil {
for product, rules := range *conf.ProductRules {
var rulelist RuleList
for _, r := range rules {
rule := FilterRule{}
cond, err := condition.Build(*r.Cond)
if err != nil {
return err
}
rule.Cond =cond
for _, pn := range *r.PluginList {
plug := pluginMapNew[pn]
if plug == nil {
return fmt.Errorf("unknown plugin: %s", pn)
}
rule.PluginList = append(rule.PluginList, plug)
}
rulelist = append(rulelist, rule)
}
productRulesNew[product] = rulelist
}
}

// 3. update PluginTable
t.Update(*conf.Version, beforeLocationRulesNew, productRulesNew, pluginMapNew)

// 4. stop & clear old plugins
for pn, plug := range pm {
if _, ok := unchanged[pn]; !ok {
// stop plug
plug.OnPluginDestroy()
plug.Clear()
}
}
}
return nil
}

type PluginTable struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该切分为独立的文件

lock sync.RWMutex
version string
beforeLocationRules RuleList
productRules ProductRules
pluginMap map[string]bfe_wasmplug.WasmPlugin
}

func NewPluginTable() *PluginTable {
t := new(PluginTable)
t.productRules = make(ProductRules)
t.pluginMap = make(map[string]bfe_wasmplug.WasmPlugin)
return t
}

func (t *PluginTable) Update(version string, beforeLocationRules RuleList, productRules ProductRules, pluginMap map[string]bfe_wasmplug.WasmPlugin) {
t.lock.Lock()

t.version = version
t.beforeLocationRules = beforeLocationRules
t.productRules = productRules
t.pluginMap = pluginMap

t.lock.Unlock()
}

func (t *PluginTable) GetVersion() string {
defer t.lock.RUnlock()
t.lock.RLock()
return t.version
}

func (t *PluginTable) GetPluginMap() map[string]bfe_wasmplug.WasmPlugin {
defer t.lock.RUnlock()
t.lock.RLock()
return t.pluginMap
}

func (t *PluginTable) GetBeforeLocationRules() RuleList {
defer t.lock.RUnlock()
t.lock.RLock()
return t.beforeLocationRules
}

func (t *PluginTable) Search(product string) (RuleList, bool) {
t.lock.RLock()
productRules := t.productRules
t.lock.RUnlock()

rules, ok := productRules[product]
return rules, ok
}


func pluginConfLoad(filename string) (PluginConfFile, error) {
var conf PluginConfFile

/* open the file */
file, err := os.Open(filename)

if err != nil {
return conf, err
}

/* decode the file */
decoder := json.NewDecoder(file)

err = decoder.Decode(&conf)
file.Close()

if err != nil {
return conf, err
}

return conf, nil
}
Loading
Loading