github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/plugin/plugins.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 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 implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plugin 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 "plugin" 23 "strings" 24 25 "github.com/alibaba/sealer/utils/platform" 26 27 "github.com/alibaba/sealer/common" 28 v1 "github.com/alibaba/sealer/types/api/v1" 29 v2 "github.com/alibaba/sealer/types/api/v2" 30 "github.com/alibaba/sealer/utils" 31 ) 32 33 type InvalidPluginTypeError struct { 34 Name string 35 } 36 37 func (err InvalidPluginTypeError) Error() string { 38 return fmt.Sprintf("plugin type not registered: %s", err.Name) 39 } 40 41 type Plugins interface { 42 Load() error 43 Run(host []string, phase Phase) error 44 } 45 46 // PluginsProcessor : process two list: plugin config list and embed pluginFactories that contains plugin interface. 47 type PluginsProcessor struct { 48 // plugin config list 49 Plugins []v1.Plugin 50 Cluster *v2.Cluster 51 } 52 53 //plugins form Clusterfile 54 func NewPlugins(cluster *v2.Cluster, plugins []v1.Plugin) Plugins { 55 return &PluginsProcessor{ 56 Cluster: cluster, 57 Plugins: plugins, 58 } 59 } 60 61 // Load plugin configs and shared object(.so) file from $mountRootfs/plugins dir. 62 func (c *PluginsProcessor) Load() error { 63 path := filepath.Join(platform.DefaultMountCloudImageDir(c.Cluster.Name), "plugins") 64 _, err := os.Stat(path) 65 if os.IsNotExist(err) { 66 return nil 67 } 68 69 files, err := ioutil.ReadDir(path) 70 if err != nil { 71 return fmt.Errorf("failed to load plugin dir %v", err) 72 } 73 for _, f := range files { 74 // load shared object(.so) file 75 if filepath.Ext(f.Name()) == ".so" { 76 soFile := filepath.Join(common.DefaultTheClusterRootfsPluginDir(c.Cluster.Name), f.Name()) 77 p, pt, err := c.loadOutOfTree(soFile) 78 if err != nil { 79 return err 80 } 81 Register(pt, p) 82 } 83 if utils.YamlMatcher(f.Name()) { 84 plugins, err := utils.DecodePlugins(filepath.Join(path, f.Name())) 85 if err != nil { 86 return fmt.Errorf("failed to load plugin %v", err) 87 } 88 c.Plugins = append(c.Plugins, plugins...) 89 } 90 } 91 return nil 92 } 93 94 // Run execute each in-tree or out-of-tree plugin by traversing the plugin list. 95 func (c *PluginsProcessor) Run(host []string, phase Phase) error { 96 for _, plugin := range c.Plugins { 97 if utils.NotIn(string(phase), strings.Split(plugin.Spec.Action, "|")) { 98 continue 99 } 100 p, ok := pluginFactories[plugin.Spec.Type] 101 // if we use cluster file dump plugin config,some plugin load after mount rootfs, 102 // we still need to return those not find error. 103 // apply module to judged whether to show errors. 104 if !ok { 105 return InvalidPluginTypeError{plugin.Spec.Type} 106 } 107 // #nosec 108 err := p.Run(Context{Cluster: c.Cluster, Host: host, Plugin: &plugin}, phase) 109 if err != nil { 110 return fmt.Errorf("failed to run plugin %s: %v", plugin.Name, err) 111 } 112 } 113 return nil 114 } 115 116 func (c *PluginsProcessor) loadOutOfTree(soFile string) (Interface, string, error) { 117 plug, err := plugin.Open(soFile) 118 if err != nil { 119 return nil, "", err 120 } 121 //look up the exposed variable named `Plugin` 122 symbol, err := plug.Lookup(Plugin) 123 if err != nil { 124 return nil, "", err 125 } 126 127 p, ok := symbol.(Interface) 128 if !ok { 129 return nil, "", fmt.Errorf("failed to find Plugin symbol") 130 } 131 132 //look up the exposed variable named `PluginType` 133 pts, err := plug.Lookup(PluginType) 134 if err != nil { 135 return nil, "", err 136 } 137 138 pt, ok := pts.(*string) 139 if !ok { 140 return nil, "", fmt.Errorf("failed to find PluginType symbol") 141 } 142 return p, *pt, nil 143 }