zoukankan      html  css  js  c++  java
  • go-plugin hashicorp开源的golang插件框架

    go-plugin 已经存在很长时间了,同时hashicorp公司的好多产品都在使用vault,terrform,nomad,waypoint
    详细的介绍可以参考官方文档,以下只是一个简单的学习试用(demo来自官方)

    项目准备

    • go mod
     
    go mo init demo-plugin
    go get github.com/hashicorp/go-plugin
    go get github.com/hashicorp/go-hclog
    • 项目结构
    ├── Dockerfile
    ├── README.md
    ├── commons
    │   └── greeter_interface.go
    ├── go.mod
    ├── go.sum
    ├── main.go
    └── plugin
        └── greeter_impl.go

    代码说明

    go-plugin 的开发模式,是基于二进制文件按需运行的(plugin 为二进制应用,懒加载运行)

    • plugin
      基于net-rpc模式开发的
      commons/greeter_interface.go 主要定义了关于plugin 接口的实现
     
    package commons
    import (
        "net/rpc"
        "github.com/hashicorp/go-plugin"
    )
    // Greeter greeter
    type Greeter interface {
        Greet() string
    }
    // GreeterRPC  Here is an implementation that talks over RPC
    type GreeterRPC struct{ client *rpc.Client }
    // Greet greet
    func (g *GreeterRPC) Greet() string {
        var resp string
        //  how to identifi
        err := g.client.Call("Plugin.Greet", new(interface{}), &resp)
        if err != nil {
            // You usually want your interfaces to return errors. If they don't,
            // there isn't much other choice here.
            panic(err)
        }
        return resp
    }
    // GreeterRPCServer Here is the RPC server that GreeterRPC talks to, conforming to
    // the requirements of net/rpc
    type GreeterRPCServer struct {
        // This is the real implementation
        Impl Greeter
    }
    // Greet greet for service impl
    func (s *GreeterRPCServer) Greet(args interface{}, resp *string) error {
        *resp = s.Impl.Greet()
        return nil
    }
    // GreeterPlugin  This is the implementation of plugin.Plugin so we can serve/consume this
    //
    // This has two methods: Server must return an RPC server for this plugin
    // type. We construct a GreeterRPCServer for this.
    //
    // Client must return an implementation of our interface that communicates
    // over an RPC client. We return GreeterRPC for this.
    //
    // Ignore MuxBroker. That is used to create more multiplexed streams on our
    // plugin connection and is a more advanced use case.
    type GreeterPlugin struct {
        // Impl Injection
        Impl Greeter
    }
    // Server server
    func (p *GreeterPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
        return &GreeterRPCServer{Impl: p.Impl}, nil
    }
    // Client client
    func (GreeterPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
        return &GreeterRPC{client: c}, nil
    }

    plugin/greeter_impl.go plugin 二进制程序的入口以及服务暴露

    package main
    import (
        "demo-plugin/commons"
        "os"
        "github.com/hashicorp/go-hclog"
        "github.com/hashicorp/go-plugin"
    )
    // Here is a real implementation of Greeter
    type GreeterHello struct {
        logger hclog.Logger
    }
    func (g *GreeterHello) Greet() string {
        g.logger.Debug("message from GreeterHello.Greet")
        return "dalong demoapp!"
    }
    // handshakeConfigs are used to just do a basic handshake between
    // a plugin and host. If the handshake fails, a user friendly error is shown.
    // This prevents users from executing bad plugins or executing a plugin
    // directory. It is a UX feature, not a security feature.
    var handshakeConfig = plugin.HandshakeConfig{
        ProtocolVersion:  1,
        MagicCookieKey:   "BASIC_PLUGIN",
        MagicCookieValue: "hello",
    }
    func main() {
        logger := hclog.New(&hclog.LoggerOptions{
            Level:      hclog.Trace,
            Output:     os.Stderr,
            JSONFormat: true,
        })
        greeter := &GreeterHello{
            logger: logger,
        }
        // pluginMap is the map of plugins we can dispense.
        var pluginMap = map[string]plugin.Plugin{
            "greeter": &commons.GreeterPlugin{Impl: greeter},
        }
        logger.Debug("message from plugin", "foo", "bar")
        // 暴露plugin 的rpc 服务,懒运行机制
        plugin.Serve(&plugin.ServeConfig{
            HandshakeConfig: handshakeConfig,
            Plugins:         pluginMap,
        })
    }
    • client (插件调用)
      main.go
     
    package main
    import (
        "demo-plugin/commons"
        "fmt"
        "log"
        "os"
        "os/exec"
        "github.com/hashicorp/go-hclog"
        "github.com/hashicorp/go-plugin"
    )
    func main() {
        // Create an hclog.Logger
        logger := hclog.New(&hclog.LoggerOptions{
            Name:   "plugin",
            Output: os.Stdout,
            Level:  hclog.Info,
        })
        // We're a host! Start by launching the plugin process.
        client := plugin.NewClient(&plugin.ClientConfig{
            HandshakeConfig: handshakeConfig,
            Plugins:         pluginMap,
            Cmd:             exec.Command("./plugin/greeter"),
            Logger:          logger,
        })
        defer client.Kill()
        // Connect via RPC
        rpcClient, err := client.Client()
        if err != nil {
            log.Fatal(err)
        }
        // Request the plugin
        raw, err := rpcClient.Dispense("greeter")
        if err != nil {
            log.Fatal(err)
        }
        // We should have a Greeter now! This feels like a normal interface
        // implementation but is in fact over an RPC connection.
        greeter := raw.(commons.Greeter)
        fmt.Println("from plugin message:" + greeter.Greet())
    }
    // handshakeConfigs are used to just do a basic handshake between
    // a plugin and host. If the handshake fails, a user friendly error is shown.
    // This prevents users from executing bad plugins or executing a plugin
    // directory. It is a UX feature, not a security feature.
    var handshakeConfig = plugin.HandshakeConfig{
        ProtocolVersion:  1,
        MagicCookieKey:   "BASIC_PLUGIN",
        MagicCookieValue: "hello",
    }
    // pluginMap is the map of plugins we can dispense.
    var pluginMap = map[string]plugin.Plugin{
        "greeter": &commons.GreeterPlugin{},
    }
    • Dockerfile
      all-in-one的部署运行
     
    FROM golang:1.14-alpine AS build-env
    RUN /bin/sed -i 's,http://dl-cdn.alpinelinux.org,https://mirrors.aliyun.com,g' /etc/apk/repositories
    WORKDIR /go/src/app
    COPY . .
    ENV  GO111MODULE=on
    ENV  GOPROXY=https://goproxy.cn
    RUN apk update && apk add git 
        && go build -o ./plugin/greeter ./plugin/greeter_impl.go && go build -o basic .
    FROM alpine:latest
    RUN /bin/sed -i 's,http://dl-cdn.alpinelinux.org,https://mirrors.aliyun.com,g' /etc/apk/repositories
    RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
    COPY --from=build-env /go/src/app/basic .
    COPY --from=build-env /go/src/app/plugin/greeter ./plugin/
    ENTRYPOINT [ "./basic" ]

    运行

    • 构建
    go build -o ./plugin/greeter ./plugin/greeter_impl.go
    go build -o basic .
    • 运行
    ./basic
    • 效果

    参考资料

    https://github.com/hashicorp/go-plugin
    https://github.com/hashicorp/go-plugin/tree/master/examples/basic
    https://github.com/rongfengliang/go-plugin-learning

  • 相关阅读:
    事务
    触发器
    SQL 存储过程
    SQL 视图 索引
    SQL 函数
    SQL查询语句练习
    SQL约束
    SQL Server 数据的添加修改删除和查询
    The type ProxyGenerator is not accessible due to restriction on required library问题的解决
    ==与equals
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/13847822.html
Copyright © 2011-2022 走看看