plugin

package
v0.0.0-...-092e436 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2021 License: Apache-2.0 Imports: 13 Imported by: 26

Documentation

Overview

Pakcage plugin provides means to create an Aker plugin. It exposes the ListenAndServeHTTP function, which is the main entry point for a plugin.

Following is an example plugin implementation that returns configured response body and status code.

package main

import (
	"net/http"

	"github.com/SAP/aker/plugin"
)

type MessageHandler struct {
	Message []byte
	Code    int
}

func (h *MessageHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	w.WriteHeader(h.Code)
	w.Write(h.Message)
}

func main() {
	plugin.ListenAndServeHTTP(func(data []byte) (http.Handler, error) {
		var handler = &MessageHandler{}
		if err := plugin.UnmarshalConfig(data, &handler); err != nil {
			return nil, err
		}
		return handler, nil
	})
}

Creating a plugin requires implementing a HandlerFactory object, which basically is just a function that accepts a byte array as input parameter and returns a http.Handler and an error. The byte array provided as input contains all configuration that was passed to the Aker process and is intended to configure the implemented plugin.

The factory should use UnmarshalConfig to get a Go struct representation of the data. The underlying notation is YAML, thus if you want to make use of Go's struct field tags, you should use 'yaml:<opts>' for configuring how the unmarshaller should handle the Go struct fields.

func myFactory(data []byte) (http.Handler, error) {
	var myConfig struct{
		a int
		b string
	} cfg

	if err := plugin.UnmarshalConfig(data, &cfg); err != nil {
		return nil, err
	}
	return newMyHandler(cfg), nil
}

The communication between Aker and each plugin, and between each pair of plugins, happens via HTTP, which is transported over unix domain sockets. The ListenAndServeHTTP method takes care of cleaning up the socket file, once the plugin receives signal to exit. Because of that, it is undesirable to call os.Exit from within a plugin, since this will leave the allocated socket file on the file system.

Plugin's Stdin and Stderr are captured by Aker, so writing to them is the way to send log messages to the central Aker log. They'll get decorated by appending the plugin name in front of each log line.

[plugin-name]: 2016/07/19 14:28:59 [INFO] Starting...

It is advisable to use the logger provided by the logging package.

Request tracking mechanism is provided by Aker. Each incoming HTTP request is decorated with the X-Aker-Request-Id header, as well as each response. If a plugin encounters problem with some request, it is advisable to dump the value of the X-Aker-Request-Id header for debugging purposes. The X-Aker-Request-Id header is also propagated to the end user, so when one complains, she is able to provide the header value for tracing.

If a plugin is part of a plugin chain, which means that each request gets processed by multiple plugins before it is returned to Aker and thus to the user, then the way of telling the requests not to continue further the plugin chain is to write something to the response by calling Write or WriteHeader of the http.Responsewriter. This will stop the request from going through sequential plugins and will return the response to the end user.

Index

Constants

This section is empty.

Variables

View Source
var DefaultOpener = &Opener{
	PluginStdout: os.Stdout,
	PluginStderr: os.Stderr,
}

DefaultOpener redirects the plugin's stdout and stderr to the calling process's stdout and stderr.

View Source
var DefaultServer = NewServer(os.Stdin, gologger.DefaultLogger, socketProxy{}, notifier{})

DefaultServer is a server with default configuration. One should not need to create a different server. If you're creating new server and reading this, you're doing something wrong.

It uses os.Stdin for reading configuration. It uses the gologger.DefaultLogger to log. It uses the socket package for HTTP over unix domain sockets. It uses the signal package from the standard library for signal handling.

Functions

func ListenAndServeHTTP

func ListenAndServeHTTP(factory HandlerFactory) error

ListenAndServeHTTP calls ListenAndServeHTTP of the DefaultServer.

func MarshalConfig

func MarshalConfig(v interface{}) ([]byte, error)

MarshalConfig returns the plugin configuration data encoding of v.

func UnmarshalConfig

func UnmarshalConfig(data []byte, v interface{}) error

UnmarshalConfig parses the plugin configuration data and stores the result in the value pointed by v.

Types

type ConfigDecodeError

type ConfigDecodeError struct {
	// contains filtered or unexported fields
}

func (*ConfigDecodeError) Error

func (e *ConfigDecodeError) Error() string

type HTTPServer

type HTTPServer interface {
	Start() error
	Stop() error
}

HTTPServer represents a HTTP server that could be started and then stopped.

type HandlerFactory

type HandlerFactory func(config []byte) (http.Handler, error)

type Notifier

type Notifier interface {
	// Notify relays incoming signals to c. If no
	// signals are provided, all incoming signals will be relayed to c.
	// Otherwise, just the provided signals will.
	Notify(c chan<- os.Signal, sig ...os.Signal)
}

Notifier notifies on OS signals.

type Opener

type Opener struct {
	// Stdout of the child process is redirected to PluginStdout.
	PluginStdout io.Writer
	// Stderr of the child process is redirected to PluginStderr.
	PluginStderr io.Writer
}

Opener opens a plugin as a subprocess.

func (*Opener) Open

func (o *Opener) Open(name string, config []byte, next *Plugin) (*Plugin, error)

type Plugin

type Plugin struct {
	http.Handler
	// contains filtered or unexported fields
}

Plugin represents an Aker plugin.

func Open

func Open(name string, config []byte, next *Plugin) (*Plugin, error)

Open opens the specified plugin using the DefaultOpener.

func (*Plugin) Close

func (p *Plugin) Close() error

Close releases all resources allocated by the plugin.

func (*Plugin) SocketPath

func (p *Plugin) SocketPath() string

SocketPath returns the path of the socket that the plugin is binded to.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server provides a functionality to run a Plugin.

func NewServer

func NewServer(config io.Reader, log gologger.Logger, socket Socket, signal Notifier) *Server

NewServer returns a brand new server.

func (*Server) ListenAndServeHTTP

func (s *Server) ListenAndServeHTTP(factory HandlerFactory) error

ListenAndServeHTTP starts the http.Handler returned by the factory as plugin.

type Socket

type Socket interface {
	// ProxyHTTP should return a Handler that proxies all request to the
	// provided unix domain socket path.
	ProxyHTTP(socketPath string) http.Handler
	// NewHTTPServer creates a HTTPServer on the provided unix socket path.
	// The server uses the passed handler for serving HTTP requests.
	// The server is not started. It is caller's responsibility to start it.
	NewHTTPServer(path string, h http.Handler) HTTPServer
}

Socket enables running HTTP using unix domain socket transport.

Directories

Path Synopsis
This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter
This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter
Used only for testing.
Used only for testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL