| 14 | ) |
| 15 | |
| 16 | func (o *Options) findAndLoadPlugins() error { |
| 17 | found := make(map[string]string) |
| 18 | done := make(map[string][]string) |
| 19 | |
| 20 | for _, dir := range o.PluginDirs { |
| 21 | filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { |
| 22 | if err != nil { |
| 23 | // don't fail when default plugin dir is missing |
| 24 | if _, ok := err.(*os.PathError); ok && dir == DefaultPluginDir { |
| 25 | return err |
| 26 | } |
| 27 | |
| 28 | log.Fatalf("failed to search for plugins: %s", err) |
| 29 | } |
| 30 | if info.IsDir() { |
| 31 | return nil |
| 32 | } |
| 33 | if strings.HasSuffix(path, ".so") { |
| 34 | name := filepath.Base(path) |
| 35 | name = name[:len(name)-3] // strip suffix |
| 36 | found[name] = path |
| 37 | log.Printf("found plugin %s at %s", name, path) |
| 38 | } |
| 39 | return nil |
| 40 | }) |
| 41 | } |
| 42 | |
| 43 | if err := o.loadPlugins(found, done); err != nil { |
| 44 | return err |
| 45 | } |
| 46 | if err := o.loadFilterPlugins(found, done); err != nil { |
| 47 | return err |
| 48 | } |
| 49 | if err := o.loadPredicatePlugins(found, done); err != nil { |
| 50 | return err |
| 51 | } |
| 52 | if err := o.loadDataClientPlugins(found, done); err != nil { |
| 53 | return err |
| 54 | } |
| 55 | |
| 56 | for name, path := range found { |
| 57 | log.Printf("attempting to load plugin from %s", path) |
| 58 | mod, err := plugin.Open(path) |
| 59 | if err != nil { |
| 60 | return fmt.Errorf("open plugin %s from %s: %s", name, path, err) |
| 61 | } |
| 62 | |
| 63 | conf, err := readPluginConfig(path) |
| 64 | if err != nil { |
| 65 | return fmt.Errorf("failed to read config for %s: %s", path, err) |
| 66 | } |
| 67 | |
| 68 | if !pluginIsLoaded(done, name, "InitPlugin") { |
| 69 | if sym, err := mod.Lookup("InitPlugin"); err == nil { |
| 70 | fltrs, preds, dcs, err := initPlugin(sym, path, conf) |
| 71 | if err != nil { |
| 72 | return fmt.Errorf("filter plugin %s returned: %s", path, err) |
| 73 | } |