From 1ceb1e9532dd613756639624ea1f77b7da0edabb Mon Sep 17 00:00:00 2001 From: Rudy Zhang Date: Wed, 24 Oct 2018 18:28:14 +0800 Subject: [PATCH] refactor: refact the pouch hook plugin Refact the pouch hook plugin, add plugins code into binary when building, instead of hook_plugin.so. Add the Cri plugin. More detail you can see: `docs/features/pouch_with_plugin.md` Signed-off-by: Rudy Zhang --- .gitignore | 1 + Makefile | 15 +- apis/plugins/VolumePlugin.go | 12 - apis/server/server.go | 4 +- cri/criservice.go | 9 +- cri/v1alpha2/cri.go | 28 ++- cri/v1alpha2/cri_types.go | 3 + cri/v1alpha2/cri_utils.go | 9 +- cri/v1alpha2/cri_utils_test.go | 160 ------------- daemon/config/config.go | 3 - daemon/daemon.go | 64 ++--- daemon/mgr/container.go | 12 +- docs/features/pouch_with_plugin.md | 219 +++++++++--------- hack/module | 44 +++- .../ContainerPlugin.go | 21 +- hookplugins/CriPlugin.go | 24 ++ {apis/plugins => hookplugins}/DaemonPlugin.go | 16 +- hookplugins/VolumePlugin.go | 24 ++ hookplugins/containerplugin/create_hook.go | 19 ++ hookplugins/containerplugin/start_hook.go | 16 ++ hookplugins/containerplugin/update_hook.go | 19 ++ hookplugins/criplugin/cri_hook.go | 19 ++ hookplugins/daemonplugin/daemon_hook.go | 22 ++ hookplugins/volumeplugin/volume_hook.go | 19 ++ internal/generator.go | 4 +- main.go | 1 - {plugins => storage/plugins}/client.go | 0 {plugins => storage/plugins}/client_test.go | 0 {plugins => storage/plugins}/error.go | 0 {plugins => storage/plugins}/manager.go | 0 {plugins => storage/plugins}/manager_test.go | 0 {plugins => storage/plugins}/plugin.go | 0 {plugins => storage/plugins}/plugins.go | 0 storage/volume/driver/driver.go | 2 +- storage/volume/driver/proxy.go | 2 +- storage/volume/driver/proxy_test.go | 2 +- storage/volume/driver/remote.go | 2 +- 37 files changed, 426 insertions(+), 369 deletions(-) delete mode 100644 apis/plugins/VolumePlugin.go rename {apis/plugins => hookplugins}/ContainerPlugin.go (68%) create mode 100644 hookplugins/CriPlugin.go rename {apis/plugins => hookplugins}/DaemonPlugin.go (56%) create mode 100644 hookplugins/VolumePlugin.go create mode 100644 hookplugins/containerplugin/create_hook.go create mode 100644 hookplugins/containerplugin/start_hook.go create mode 100644 hookplugins/containerplugin/update_hook.go create mode 100644 hookplugins/criplugin/cri_hook.go create mode 100644 hookplugins/daemonplugin/daemon_hook.go create mode 100644 hookplugins/volumeplugin/volume_hook.go rename {plugins => storage/plugins}/client.go (100%) rename {plugins => storage/plugins}/client_test.go (100%) rename {plugins => storage/plugins}/error.go (100%) rename {plugins => storage/plugins}/manager.go (100%) rename {plugins => storage/plugins}/manager_test.go (100%) rename {plugins => storage/plugins}/plugin.go (100%) rename {plugins => storage/plugins}/plugins.go (100%) diff --git a/.gitignore b/.gitignore index 0f75f93fa..418caf8e0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ pouchd pouch *.patch volume_build.go +hook_plugins_build.go coverage.txt .*.swp .*.swo diff --git a/Makefile b/Makefile index 19f270835..8273b42ad 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ COVERAGE_PACKAGES_LIST=$(shell echo $(COVERAGE_PACKAGES) | tr " " ",") build: build-daemon build-cli ## build PouchContainer both daemon and cli binaries -build-daemon: modules ## build PouchContainer daemon binary +build-daemon: modules plugin ## build PouchContainer daemon binary @echo "$@: bin/${DAEMON_BINARY_NAME}" @mkdir -p bin @GOOS=linux go build -ldflags ${DEFAULT_LDFLAGS} -o bin/${DAEMON_BINARY_NAME} -tags 'selinux' @@ -81,14 +81,14 @@ build-cli: ## build PouchContainer cli binary @mkdir -p bin @go build -o bin/${CLI_BINARY_NAME} github.com/alibaba/pouch/cli -build-daemon-integration: modules ## build PouchContainer daemon integration testing binary +build-daemon-integration: modules plugin ## build PouchContainer daemon integration testing binary @echo $@ @mkdir -p bin go test -c ${TEST_FLAGS} \ -cover -covermode=atomic -coverpkg ${COVERAGE_PACKAGES_LIST} \ -o bin/${DAEMON_INTEGRATION_BINARY_NAME} -build-integration-test: modules ## build PouchContainer integration test-case binary +build-integration-test: modules plugin ## build PouchContainer integration test-case binary @echo $@ @mkdir -p bin go test -c \ @@ -151,7 +151,7 @@ gometalinter: ## run gometalinter for go source code .PHONY: unit-test -unit-test: modules ## run go unit-test +unit-test: modules plugin ## run go unit-test @echo $@ @mkdir -p coverage @( for pkg in ${COVERAGE_PACKAGES}; do \ @@ -193,6 +193,13 @@ coverage: ## combine coverage after test @echo $@ @gocovmerge coverage/* > coverage.txt +.PHONY: plugin +plugin: ## build hook plugin + @echo "build $@" + @./hack/module --add-plugin=github.com/alibaba/pouch/hookplugins/containerplugin + @./hack/module --add-plugin=github.com/alibaba/pouch/hookplugins/daemonplugin + @./hack/module --add-plugin=github.com/alibaba/pouch/hookplugins/criplugin + @./hack/module --add-plugin=github.com/alibaba/pouch/hookplugins/volumeplugin .PHONY: help help: ## this help diff --git a/apis/plugins/VolumePlugin.go b/apis/plugins/VolumePlugin.go deleted file mode 100644 index 421d18438..000000000 --- a/apis/plugins/VolumePlugin.go +++ /dev/null @@ -1,12 +0,0 @@ -package plugins - -import ( - "github.com/alibaba/pouch/apis/types" -) - -// VolumePlugin defines places where a plugin will be triggered in volume lifecycle -type VolumePlugin interface { - // PreCreate defines plugin point where receives an volume create request, in this plugin point user - // could change the volume create body passed-in by http request body - PreVolumeCreate(*types.VolumeCreateConfig) error -} diff --git a/apis/server/server.go b/apis/server/server.go index 0f302cbcf..e7d638d97 100644 --- a/apis/server/server.go +++ b/apis/server/server.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/alibaba/pouch/apis/plugins" "github.com/alibaba/pouch/cri/stream" "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/hookplugins" "github.com/alibaba/pouch/pkg/httputils" "github.com/alibaba/pouch/pkg/netutils" @@ -29,7 +29,7 @@ type Server struct { NetworkMgr mgr.NetworkMgr StreamRouter stream.Router listeners []net.Listener - ContainerPlugin plugins.ContainerPlugin + ContainerPlugin hookplugins.ContainerPlugin ManagerWhiteList map[string]struct{} lock sync.RWMutex } diff --git a/cri/criservice.go b/cri/criservice.go index 08d6ca542..3a9146431 100644 --- a/cri/criservice.go +++ b/cri/criservice.go @@ -10,12 +10,13 @@ import ( servicev1alpha2 "github.com/alibaba/pouch/cri/v1alpha2/service" "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/hookplugins" "github.com/sirupsen/logrus" ) // RunCriService start cri service if pouchd is specified with --enable-cri. -func RunCriService(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, imageMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr, streamRouterCh chan stream.Router, stopCh chan error, readyCh chan bool) { +func RunCriService(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, imageMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr, criPlugin hookplugins.CriPlugin, streamRouterCh chan stream.Router, stopCh chan error, readyCh chan bool) { var err error defer func() { @@ -32,7 +33,7 @@ func RunCriService(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, i case "v1alpha1": err = runv1alpha1(daemonconfig, containerMgr, imageMgr, streamRouterCh, readyCh) case "v1alpha2": - err = runv1alpha2(daemonconfig, containerMgr, imageMgr, volumeMgr, streamRouterCh, readyCh) + err = runv1alpha2(daemonconfig, containerMgr, imageMgr, volumeMgr, criPlugin, streamRouterCh, readyCh) default: streamRouterCh <- nil readyCh <- false @@ -92,9 +93,9 @@ func runv1alpha1(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, ima } // Start CRI service with CRI version: v1alpha2 -func runv1alpha2(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, imageMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr, streamRouterCh chan stream.Router, readyCh chan bool) error { +func runv1alpha2(daemonconfig *config.Config, containerMgr mgr.ContainerMgr, imageMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr, criPlugin hookplugins.CriPlugin, streamRouterCh chan stream.Router, readyCh chan bool) error { logrus.Infof("Start CRI service with CRI version: v1alpha2") - criMgr, err := criv1alpha2.NewCriManager(daemonconfig, containerMgr, imageMgr, volumeMgr) + criMgr, err := criv1alpha2.NewCriManager(daemonconfig, containerMgr, imageMgr, volumeMgr, criPlugin) if err != nil { streamRouterCh <- nil readyCh <- false diff --git a/cri/v1alpha2/cri.go b/cri/v1alpha2/cri.go index 2b51129c6..cd4bfea3d 100644 --- a/cri/v1alpha2/cri.go +++ b/cri/v1alpha2/cri.go @@ -23,6 +23,7 @@ import ( criutils "github.com/alibaba/pouch/cri/utils" "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/hookplugins" "github.com/alibaba/pouch/pkg/errtypes" "github.com/alibaba/pouch/pkg/meta" "github.com/alibaba/pouch/pkg/reference" @@ -104,6 +105,7 @@ type CriManager struct { ImageMgr mgr.ImageMgr VolumeMgr mgr.VolumeMgr CniMgr cni.CniMgr + CriPlugin hookplugins.CriPlugin // StreamServer is the stream server of CRI serves container streaming request. StreamServer Server @@ -125,7 +127,7 @@ type CriManager struct { } // NewCriManager creates a brand new cri manager. -func NewCriManager(config *config.Config, ctrMgr mgr.ContainerMgr, imgMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr) (CriMgr, error) { +func NewCriManager(config *config.Config, ctrMgr mgr.ContainerMgr, imgMgr mgr.ImageMgr, volumeMgr mgr.VolumeMgr, criPlugin hookplugins.CriPlugin) (CriMgr, error) { var streamServerAddress string streamServerPort := config.CriConfig.StreamServerPort // If stream server reuse the pouchd's port, extract the ip and port from pouchd's listening addresses. @@ -147,6 +149,7 @@ func NewCriManager(config *config.Config, ctrMgr mgr.ContainerMgr, imgMgr mgr.Im ContainerMgr: ctrMgr, ImageMgr: imgMgr, VolumeMgr: volumeMgr, + CriPlugin: criPlugin, StreamServer: streamServer, SandboxBaseDir: path.Join(config.HomeDir, "sandboxes"), SandboxImage: config.CriConfig.SandboxImage, @@ -683,6 +686,19 @@ func (c *CriManager) CreateContainer(ctx context.Context, r *runtime.CreateConta sandboxConfig := r.GetSandboxConfig() podSandboxID := r.GetPodSandboxId() + // get sandbox + sandbox, err := c.ContainerMgr.Get(ctx, podSandboxID) + if err != nil { + return nil, fmt.Errorf("failed to get sandbox %q: %v", podSandboxID, err) + } + + res, err := c.SandboxStore.Get(podSandboxID) + if err != nil { + return nil, fmt.Errorf("failed to get metadata of %q from SandboxStore: %v", podSandboxID, err) + } + sandboxMeta := res.(*SandboxMeta) + sandboxMeta.NetNS = containerNetns(sandbox) + labels := makeLabels(config.GetLabels(), config.GetAnnotations()) // Apply the container type lable. labels[containerTypeLabelKey] = containerTypeLabelContainer @@ -723,7 +739,8 @@ func (c *CriManager) CreateContainer(ctx context.Context, r *runtime.CreateConta }, NetworkingConfig: &apitypes.NetworkingConfig{}, } - err := c.updateCreateConfig(createConfig, config, sandboxConfig, podSandboxID) + + err = c.updateCreateConfig(createConfig, config, sandboxConfig, sandboxMeta) if err != nil { return nil, err } @@ -744,6 +761,13 @@ func (c *CriManager) CreateContainer(ctx context.Context, r *runtime.CreateConta containerName := makeContainerName(sandboxConfig, config) + // call cri plugin to update create config + if c.CriPlugin != nil { + if err := c.CriPlugin.PreCreateContainer(createConfig, sandboxMeta); err != nil { + return nil, err + } + } + createResp, err := c.ContainerMgr.Create(ctx, containerName, createConfig) if err != nil { return nil, fmt.Errorf("failed to create container for sandbox %q: %v", podSandboxID, err) diff --git a/cri/v1alpha2/cri_types.go b/cri/v1alpha2/cri_types.go index fd4107a5e..7096dbd0f 100644 --- a/cri/v1alpha2/cri_types.go +++ b/cri/v1alpha2/cri_types.go @@ -20,6 +20,9 @@ type SandboxMeta struct { // Runtime whether to enable lxcfs for a container LxcfsEnabled bool + + // Netns is the sandbox's network namespace + NetNS string } // Key returns sandbox's id. diff --git a/cri/v1alpha2/cri_utils.go b/cri/v1alpha2/cri_utils.go index b1b6323ed..39cc6f074 100644 --- a/cri/v1alpha2/cri_utils.go +++ b/cri/v1alpha2/cri_utils.go @@ -730,13 +730,8 @@ func applyContainerSecurityContext(lc *runtime.LinuxContainerConfig, podSandboxI } // Apply Linux-specific options if applicable. -func (c *CriManager) updateCreateConfig(createConfig *apitypes.ContainerCreateConfig, config *runtime.ContainerConfig, sandboxConfig *runtime.PodSandboxConfig, podSandboxID string) error { +func (c *CriManager) updateCreateConfig(createConfig *apitypes.ContainerCreateConfig, config *runtime.ContainerConfig, sandboxConfig *runtime.PodSandboxConfig, sandboxMeta *SandboxMeta) error { // Apply runtime options. - res, err := c.SandboxStore.Get(podSandboxID) - if err != nil { - return fmt.Errorf("failed to get metadata of %q from SandboxStore: %v", podSandboxID, err) - } - sandboxMeta := res.(*SandboxMeta) if sandboxMeta.Runtime != "" { createConfig.HostConfig.Runtime = sandboxMeta.Runtime } @@ -755,7 +750,7 @@ func (c *CriManager) updateCreateConfig(createConfig *apitypes.ContainerCreateCo } // Apply security context. - if err := applyContainerSecurityContext(lc, podSandboxID, &createConfig.ContainerConfig, createConfig.HostConfig); err != nil { + if err := applyContainerSecurityContext(lc, sandboxMeta.ID, &createConfig.ContainerConfig, createConfig.HostConfig); err != nil { return fmt.Errorf("failed to apply container security context for container %q: %v", config.Metadata.Name, err) } } diff --git a/cri/v1alpha2/cri_utils_test.go b/cri/v1alpha2/cri_utils_test.go index 959a2a5ff..1ca7a66fc 100644 --- a/cri/v1alpha2/cri_utils_test.go +++ b/cri/v1alpha2/cri_utils_test.go @@ -1,7 +1,6 @@ package v1alpha2 import ( - "context" "fmt" "reflect" "strconv" @@ -380,33 +379,6 @@ func Test_parseSandboxName(t *testing.T) { } } -func Test_makeSandboxPouchConfig(t *testing.T) { - type args struct { - config *runtime.PodSandboxConfig - image string - } - tests := []struct { - name string - args args - want *apitypes.ContainerCreateConfig - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := makeSandboxPouchConfig(tt.args.config, tt.args.image) - if (err != nil) != tt.wantErr { - t.Errorf("makeSandboxPouchConfig() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("makeSandboxPouchConfig() = %v, want %v", got, tt.want) - } - }) - } -} - func Test_toCriSandboxState(t *testing.T) { type args struct { status apitypes.Status @@ -441,32 +413,6 @@ func Test_toCriSandboxState(t *testing.T) { } } -func Test_toCriSandbox(t *testing.T) { - type args struct { - c *mgr.Container - } - tests := []struct { - name string - args args - want *runtime.PodSandbox - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := toCriSandbox(tt.args.c) - if (err != nil) != tt.wantErr { - t.Errorf("toCriSandbox() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("toCriSandbox() = %v, want %v", got, tt.want) - } - }) - } -} - func Test_filterCRISandboxes(t *testing.T) { testSandboxes := []*runtime.PodSandbox{ { @@ -683,27 +629,6 @@ func Test_filterCRIContainers(t *testing.T) { } } -func Test_makeContainerName(t *testing.T) { - type args struct { - s *runtime.PodSandboxConfig - c *runtime.ContainerConfig - } - tests := []struct { - name string - args args - want string - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := makeContainerName(tt.args.s, tt.args.c); got != tt.want { - t.Errorf("makeContainerName() = %v, want %v", got, tt.want) - } - }) - } -} - func Test_modifyContainerNamespaceOptions(t *testing.T) { type args struct { nsOpts *runtime.NamespaceOption @@ -1029,61 +954,6 @@ func Test_modifyContainerConfig(t *testing.T) { } } -func Test_applyContainerSecurityContext(t *testing.T) { - type args struct { - lc *runtime.LinuxContainerConfig - podSandboxID string - config *apitypes.ContainerConfig - hc *apitypes.HostConfig - } - tests := []struct { - name string - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := applyContainerSecurityContext(tt.args.lc, tt.args.podSandboxID, tt.args.config, tt.args.hc); (err != nil) != tt.wantErr { - t.Errorf("applyContainerSecurityContext() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestCriManager_updateCreateConfig(t *testing.T) { - type fields struct { - ContainerMgr mgr.ContainerMgr - ImageMgr mgr.ImageMgr - } - type args struct { - createConfig *apitypes.ContainerCreateConfig - config *runtime.ContainerConfig - sandboxConfig *runtime.PodSandboxConfig - podSandboxID string - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := &CriManager{ - ContainerMgr: tt.fields.ContainerMgr, - ImageMgr: tt.fields.ImageMgr, - } - if err := c.updateCreateConfig(tt.args.createConfig, tt.args.config, tt.args.sandboxConfig, tt.args.podSandboxID); (err != nil) != tt.wantErr { - t.Errorf("CriManager.updateCreateConfig() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - func Test_toCriContainer(t *testing.T) { _, timeParseErr := time.Parse(utils.TimeLayout, "foo") type args struct { @@ -1333,36 +1203,6 @@ func Test_imageToCriImage(t *testing.T) { } } -func TestCriManager_ensureSandboxImageExists(t *testing.T) { - type fields struct { - ContainerMgr mgr.ContainerMgr - ImageMgr mgr.ImageMgr - } - type args struct { - ctx context.Context - image string - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := &CriManager{ - ContainerMgr: tt.fields.ContainerMgr, - ImageMgr: tt.fields.ImageMgr, - } - if err := c.ensureSandboxImageExists(tt.args.ctx, tt.args.image); (err != nil) != tt.wantErr { - t.Errorf("CriManager.ensureSandboxImageExists() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - func Test_getUserFromImageUser(t *testing.T) { imageUserInt := "1" uid, _ := strconv.ParseInt(imageUserInt, 10, 64) diff --git a/daemon/config/config.go b/daemon/config/config.go index 79d7f11f8..b1012ff1f 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -94,9 +94,6 @@ type Config struct { // CgroupParent is to set parent cgroup for all containers CgroupParent string `json:"cgroup-parent,omitempty"` - // PluginPath is set the path where plugin so file put - PluginPath string `json:"plugin,omitempty"` - // Labels is the metadata of daemon Labels []string `json:"label,omitempty"` diff --git a/daemon/daemon.go b/daemon/daemon.go index b39523be8..6f29704bb 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -8,7 +8,6 @@ import ( "plugin" "reflect" - "github.com/alibaba/pouch/apis/plugins" "github.com/alibaba/pouch/apis/server" criservice "github.com/alibaba/pouch/cri" "github.com/alibaba/pouch/cri/stream" @@ -17,6 +16,7 @@ import ( "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/events" "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/hookplugins" "github.com/alibaba/pouch/internal" "github.com/alibaba/pouch/network/mode" "github.com/alibaba/pouch/pkg/meta" @@ -45,9 +45,10 @@ type Daemon struct { volumeMgr mgr.VolumeMgr networkMgr mgr.NetworkMgr server server.Server - containerPlugin plugins.ContainerPlugin - daemonPlugin plugins.DaemonPlugin - volumePlugin plugins.VolumePlugin + containerPlugin hookplugins.ContainerPlugin + daemonPlugin hookplugins.DaemonPlugin + volumePlugin hookplugins.VolumePlugin + criPlugin hookplugins.CriPlugin eventsService *events.Events } @@ -125,47 +126,26 @@ func loadSymbolByName(p *plugin.Plugin, name string) (plugin.Symbol, error) { } func (d *Daemon) loadPlugin() error { - var s plugin.Symbol var err error - if d.config.PluginPath != "" { - p, err := plugin.Open(d.config.PluginPath) - if err != nil { - return errors.Wrapf(err, "load plugin at %s error", d.config.PluginPath) - } + // load daemon plugin if exist + if daemonPlugin := hookplugins.GetDaemonPlugin(); daemonPlugin != nil { + d.daemonPlugin = daemonPlugin + } - //load daemon plugin if exist - if s, err = loadSymbolByName(p, "DaemonPlugin"); err != nil { - return err - } - if daemonPlugin, ok := s.(plugins.DaemonPlugin); ok { - logrus.Infof("setup daemon plugin from %s", d.config.PluginPath) - d.daemonPlugin = daemonPlugin - } else if s != nil { - return fmt.Errorf("not a daemon plugin at %s %q", d.config.PluginPath, s) - } + // load container plugin if exist + if containerPlugin := hookplugins.GetContainerPlugin(); containerPlugin != nil { + d.containerPlugin = containerPlugin + } - //load container plugin if exist - if s, err = loadSymbolByName(p, "ContainerPlugin"); err != nil { - return err - } - if containerPlugin, ok := s.(plugins.ContainerPlugin); ok { - logrus.Infof("setup container plugin from %s", d.config.PluginPath) - d.containerPlugin = containerPlugin - } else if s != nil { - return fmt.Errorf("not a container plugin at %s %q", d.config.PluginPath, s) - } + // load volume plugin if exist + if volumePlugin := hookplugins.GetVolumePlugin(); volumePlugin != nil { + d.volumePlugin = volumePlugin + } - // load volume plugin if exist - if s, err = loadSymbolByName(p, "VolumePlugin"); err != nil { - return err - } - if volumePlugin, ok := s.(plugins.VolumePlugin); ok { - logrus.Infof("setup volume plugin from %s", d.config.PluginPath) - d.volumePlugin = volumePlugin - } else if s != nil { - return fmt.Errorf("not a volume plugin at %s %q", d.config.PluginPath, s) - } + // load cri plugin if exist + if criPlugin := hookplugins.GetCriPlugin(); criPlugin != nil { + d.criPlugin = criPlugin } if d.daemonPlugin != nil { @@ -246,7 +226,7 @@ func (d *Daemon) Run() error { criReadyCh := make(chan bool) criStopCh := make(chan error) - go criservice.RunCriService(d.config, d.containerMgr, d.imageMgr, d.volumeMgr, criStreamRouterCh, criStopCh, criReadyCh) + go criservice.RunCriService(d.config, d.containerMgr, d.imageMgr, d.volumeMgr, d.criPlugin, criStreamRouterCh, criStopCh, criReadyCh) streamRouter := <-criStreamRouterCh @@ -356,7 +336,7 @@ func (d *Daemon) networkInit(ctx context.Context) error { } // ContainerPlugin returns the container plugin fetched from shared file -func (d *Daemon) ContainerPlugin() plugins.ContainerPlugin { +func (d *Daemon) ContainerPlugin() hookplugins.ContainerPlugin { return d.containerPlugin } diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index 3ea14938f..30ab0800d 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -14,13 +14,13 @@ import ( "time" "github.com/alibaba/pouch/apis/opts" - "github.com/alibaba/pouch/apis/plugins" "github.com/alibaba/pouch/apis/types" "github.com/alibaba/pouch/ctrd" "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/containerio" "github.com/alibaba/pouch/daemon/events" "github.com/alibaba/pouch/daemon/logger" + "github.com/alibaba/pouch/hookplugins" "github.com/alibaba/pouch/lxcfs" networktypes "github.com/alibaba/pouch/network/types" "github.com/alibaba/pouch/pkg/collect" @@ -186,14 +186,14 @@ type ContainerManager struct { // monitor is used to handle container's event, eg: exit, stop and so on. monitor *ContainerMonitor - containerPlugin plugins.ContainerPlugin + containerPlugin hookplugins.ContainerPlugin // eventsService is used to publish events generated by pouchd eventsService *events.Events } // NewContainerManager creates a brand new container manager. -func NewContainerManager(ctx context.Context, store *meta.Store, cli ctrd.APIClient, imgMgr ImageMgr, volMgr VolumeMgr, cfg *config.Config, contPlugin plugins.ContainerPlugin, eventsService *events.Events) (*ContainerManager, error) { +func NewContainerManager(ctx context.Context, store *meta.Store, cli ctrd.APIClient, imgMgr ImageMgr, volMgr VolumeMgr, cfg *config.Config, contPlugin hookplugins.ContainerPlugin, eventsService *events.Events) (*ContainerManager, error) { mgr := &ContainerManager{ Store: store, NameToID: collect.NewSafeMap(), @@ -1816,7 +1816,11 @@ func (mgr *ContainerManager) buildContainerEndpoint(c *Container, name string) * } if mgr.containerPlugin != nil { - ep.Priority, ep.DisableResolver, ep.GenericParams = mgr.containerPlugin.PreCreateEndpoint(c.ID, c.Config.Env) + // just ignore return err + err := mgr.containerPlugin.PreCreateEndpoint(c.ID, c.Config.Env, ep) + if err != nil { + logrus.Warnf("failed to call PreCreateEndpoint plugin, err(%v)", err) + } } return ep diff --git a/docs/features/pouch_with_plugin.md b/docs/features/pouch_with_plugin.md index 08657c063..ff4d366d4 100644 --- a/docs/features/pouch_with_plugin.md +++ b/docs/features/pouch_with_plugin.md @@ -1,148 +1,157 @@ # PouchContainer with plugin -In order to run custom code provided by users which will be triggered at some point, we support a plugin framework which introduced from golang 1.8. At this time in this plugin framework we enable users to add custom code at file points: +## Why provide plugin -* pre-start daemon point -* pre-stop daemon point -* pre-create container point -* pre-start container point -* pre-create-endpoint container point +There are many scenes to use the container,the different container engine users, in addition to the general process of using the container operation, perhaps they will have their own customized operation scenarios, pouch-container provides users with a situation that does not affect the general scene. A plug-in mechanism for customizable operations to handle container operations for business privatization. -Above four points are organized by two Plugin interfaces, which are DaemonPlugin and ContainerPlugin, defined as follow: +## Plugin function -``` -// DaemonPlugin defines in which place does pouchd support plugin -type DaemonPlugin interface { - // PreStartHook is invoked by pouchd before real start, in this hook user could start dfget proxy or other - // standalone process plugins - PreStartHook() error +The pouch-container plugin provides developers or users with a way to call their own plugin logic, calling plugin logic before or after certain operations to satisfy the specific logic of the plugin implementation. - // PreStopHook is invoked by pouchd before daemon process exit, not a promise if daemon is killed, in this - // hook user could stop the process or plugin started by PreStartHook - PreStopHook() error -} +## Which plugins + +Currently pouch-container provides four plugins,they are: `container plugin`,`daemon plugin`,`volume plugin`,`cri plugin` + +### container plugin +In order to run custom code provided by users which will be triggered at some point, we support a plugin framework. + +* pre-create container point, at this point you can change the input stream by some rules, in some companies they have some stale orchestration system who use env to pass-in some limit which is an attribute in PouchContainer, then you can use this point to convert value in env to attribute in ContainerConfig or HostConfig of PouchContainer create api. +* pre-start container point, at this point you can set more pre-start hooks to oci spec, where you can do some special thing before container entrypoint start, priority decide the order of executing of the hook. libnetwork hook has priority 0, so if the hook is expected to run before network in container setup you should set priority to a value big then 0, and vice versa. +* pre-create-endpoint container point, at this point you can return the priority of this endpoint and if this endpoint need enable resolver and the generic params of this endpoint. +* pre-update container point, at this point you can change the input stream to your wanted format or rules. +* post-update container point, at this point you can change the update config into the container's env. + +Above five points are organized by container plugins, defined as follow: + +``` // ContainerPlugin defines places where a plugin will be triggered in container lifecycle type ContainerPlugin interface { - // PreCreate defines plugin point where receives an container create request, in this plugin point user - // could change the container create body passed-in by http request body - PreCreate(io.ReadCloser) (io.ReadCloser, error) - - // PreStart returns an array of priority and args which will pass to runc, the every priority - // used to sort the pre start array that pass to runc, network plugin hook always has priority value 0. - PreStart(interface{}) ([]int, [][]string, error) - - //NetworkGenericParams accepts the container id and env of this container and returns the priority of this endpoint - // and if this endpoint should enable resolver and a map which will be used as generic params to create endpoints of - // this container - PreCreateEndpoint(string, []string) (priority int, disableResolver bool, genericParam map[string]interface{}) -} + // PreCreate defines plugin point where receives a container create request, in this plugin point user + // could change the container create body passed-in by http request body + PreCreate(*types.ContainerCreateConfig) error + + // PreStart returns an array of priority and args which will pass to runc, the every priority + // used to sort the pre start array that pass to runc, network plugin hook always has priority value 0. + PreStart(interface{}) ([]int, [][]string, error) + // PreCreateEndpoint accepts the container id and env of this container, to update the config of container's endpoint. + PreCreateEndpoint(string, []string, *networktypes.Endpoint) error + + // PreUpdate defines plugin point where receives a container update request, in this plugin point user + // could change the container update body passed-in by http request body + PreUpdate(io.ReadCloser) (io.ReadCloser, error) + + // PostUpdate called after update method successful, + // the method accepts the rootfs path and envs of container + PostUpdate(string, []string) error +} ``` -These two Plugin symbols will be fetch by name `DaemonPlugin` and `ContainerPlugin` from shared object file like this: +### daemon plugin + +* pre-start daemon point, at this point you can start assistant processes like network plugins and dfget proxy which need by pouchd and whose life cycle is the same as pouchd. +* pre-stop daemon point, at this point you can stop the assistant processes gracefully, but the trigger of this point is not a promise, because pouchd may be killed by SIGKILL. + +Defined as follow: ``` -p, _ := plugin.Open("path_to_shared_object_file") -daemonPlugin, _ := p.Lookup("DaemonPlugin") -containerPlugin, _ := p.Lookup("ContainerPlugin") +// DaemonPlugin defines places where a plugin will be triggered in pouchd lifecycle +type DaemonPlugin interface { + // PreStartHook is invoked by pouch daemon before real start, in this hook user could start dfget proxy or other + // standalone process plugins + PreStartHook() error + + // PreStopHook is invoked by pouch daemon before daemon process exit, not a promise if daemon is killed, in this + // hook user could stop the process or plugin started by PreStartHook + PreStopHook() error +} ``` -## example +### volume plugin + +* pre-volume-create volume point, at this point you can change the volume's create config as you want, add your default volume's options. -define two plugin symbols which only print some logs at correspond point: +Defined as follow: ``` -package main +// VolumePlugin defines places where a plugin will be triggered in volume lifecycle +type VolumePlugin interface { + // PreVolumeCreate defines plugin point where receives an volume create request, in this plugin point user + // could change the volume create body passed-in by http request body + PreVolumeCreate(*types.VolumeCreateConfig) error +} +``` -import ( - "fmt" - "io" -) +### cri plugin -var ContainerPlugin ContPlugin +* pre-create-container cri point, at this point you can update the container config what it will be created, such as update the container's envs or labels. -type ContPlugin int +Defined as follow: -var DaemonPlugin DPlugin +``` +// CriPlugin defines places where a plugin will be triggered in CRI api lifecycle +type CriPlugin interface { + // PreCreateContainer defines plugin point where receives a container create request, in this plugin point user + // could update the container's config in cri interface. + PreCreateContainer(*types.ContainerCreateConfig, interface{}) error +} +``` -type DPlugin int +## Example -func (d DPlugin) PreStartHook() error { - fmt.Println("pre-start hook in daemon is called") - return nil -} +### How to write -func (d DPlugin) PreStopHook() error { - fmt.Println("pre-stop hook in daemon is called") - return nil -} +Introduce how to write a daemon plugin. -func (c ContPlugin) PreCreate(in io.ReadCloser) (io.ReadCloser, error) { - fmt.Println("pre create method called") - return in, nil -} +#### 1. Make your plugin package -func (c ContPlugin) PreStart(interface{}) ([]int, [][]string, error) { - fmt.Println("pre start method called") - // make this pre-start hook run after network in container setup - return []int{-4}, [][]string{{"/usr/bin/touch", "touch", "/tmp/pre_start_hook"}}, nil -} +You can make your package in directory `hookplugins/daemonplugin` and add a go file `daemon_hook.go`. -func (c ContPlugin) PreCreateEndpoint(string, []string) (priority int, disableResolver bool, genericParam map[string]interface{}) { - fmt.Println("pre create endpoint") - return -} +#### 2. Define a struct for your plugin -func main() { - fmt.Println(ContainerPlugin, DaemonPlugin) -} -``` +In `daemon_hook.go` define your plugin object, struct is `type daemonPlugin struct{}`. -then build it with command line like: +#### 3. Register your plugin -``` -go build -buildmode=plugin -ldflags "-pluginpath=plugins_$(date +%s)" -o hook_plugin.so -``` +In `init` function to register your plugin, now we provide 4 plugin to register: + + * `RegisterContainerPlugin` + * `RegisterDaemonPlugin` + * `RegisterCriPlugin` + * `RegisterVolumePlugin` -to use the shared object file generated, start pouchd which flag `--plugin=path_to_hook_plugin.so`, then when you start stop daemon and create container, in the log there will be some logs like: +In my plugin, we use `RegisterDaemonPlugin` to register a daemon plugin into pouch daemon. ``` -pre-start hook in daemon is called -pre create method called -pre-stop hook in daemon is called +func init() { + hookplugins.RegisterDaemonPlugin(&daemonPlugin{}) +} ``` -when you start a container, the config.json file (whose place is $home_dir/containerd/state/io.containerd.runtime.v1.linux/default/$container_id/config.json) will contains the pre-start hook specified in above code, eg: +#### 4. Implement the plugin's interface function + +We implement the daemon plugin's interface function, we just print some logs. ``` - "hooks": { - "prestart": [ - { - "args": [ - "libnetwork-setkey", - "f67df14e96fa4b94a6e386d0795bdd2703ca7b01713d48c9567203a37b05ae3d", - "8e3d8db7f72a66edee99d4db6ab911f8d618af057485731e9acf24b3668e25b6" - ], - "path": "/usr/local/bin/pouchd" - }, - { - "args": [ - "touch", - "/tmp/pre_start_hook" - ], - "path": "/usr/bin/touch" - } - ] - } +// DaemonPlugin defines places where a plugin will be triggered in pouchd lifecycle +type DaemonPlugin interface { + // PreStartHook is invoked by pouch daemon before real start, in this hook user could start http proxy or other + // standalone process plugins + PreStartHook() error + + // PreStopHook is invoked by pouch daemon before daemon process exit, not a promise if daemon is killed, in this + // hook user could stop the process or plugin started by PreStartHook + PreStopHook() error +} ``` -and if you use the exact code above, every time you start a container the file at /tmp/pre_start_hook will be touched. +### How to build + +Use this method to build my daemon plugin: -## usage +``` +# hack/module --add-plugin=github.com/alibaba/pouch/hookplugins/daemonplugin +``` -* at pre-start daemon point you can start assist processes like network plugins and dfget proxy which need by pouchd and whose life cycle is the same as pouchd. -* at pre-stop daemon point you can stop the assist processes gracefully, but the trigger of this point is not a promise, because pouchd may be killed by SIGKILL. -* at pre-create container point you can change the input stream by some rules, in some company they have some stale orchestration system who use env to pass-in some limit which is an attribute in PouchContainer, then you can use this point to convert value in env to attribute in ContainerConfig or HostConfig of PouchContainer create api. -* at pre-start container point you can set more pre-start hooks to oci spec, where you can do some special thing before container entrypoint start, priority decide the order of executing of the hook. libnetwork hook has priority 0, so if the hook is expected to run before network in container setup you should set priority to a value big then 0, and vice versa. -* at pre-create-endpoint container point you can return the priority of this endpoint and if this endpoint need enable resolver and the generic params of this endpoint. +And then `Makefile` will build your plugin into daemon binary, and it will be called when daemon is starting or stopping. diff --git a/hack/module b/hack/module index 423d78039..b6f8f97ad 100755 --- a/hack/module +++ b/hack/module @@ -1,9 +1,9 @@ #!/bin/bash -volume_module() { +function volume_module() { # generate "volume_build.go" file - if [ ! -f $volume_build ]; then - cat << END > $volume_build + if [[ ! -f ${volume_build} ]]; then + cat << END > ${volume_build} // +build linux // The file is automatically generated, DON'T EDIT. @@ -13,10 +13,29 @@ package main END fi - grep -q $1 $volume_build - if [ $? -ne "0" ] + grep -q $1 ${volume_build} + if [[ $? -ne "0" ]] then - echo "import _ \"$1\"" >> $volume_build + echo "import _ \"$1\"" >> ${volume_build} + fi +} + +function hook_plugins_module() { + # generate "hook_plugins_build.go" file + if [[ ! -f ${hook_plugins_build} ]]; then + cat << END > ${hook_plugins_build} +// +build linux + +// The file is automatically generated, DON'T EDIT. + +package main + +END + fi + + grep -q $1 ${hook_plugins_build} + if [[ $? -ne "0" ]]; then + echo "import _ \"$1\"" >> ${hook_plugins_build} fi } @@ -24,6 +43,7 @@ help= clean= gcflags= volume_build=volume_build.go +hook_plugins_build=hook_plugins_build.go opt= for option @@ -44,7 +64,9 @@ do --add-volume=*) volume_module $value ;; - + --add-plugin=*) + hook_plugins_module $value + ;; *) echo "$0: error: invalid option \"$option\"" exit 1 @@ -52,18 +74,20 @@ do esac done -if [ "$clean" = "yes" ]; then - rm -f $volume_build +if [[ "${clean}" == "yes" ]]; then + rm -f ${volume_build} + rm -f ${hook_plugins_build} exit 0 fi -if [ "$help" = "yes" ]; then +if [[ "${help}" == "yes" ]]; then echo "usage:" echo " module [options]" echo "" echo "options:" echo " --help, -h Print help information" echo " --add-volume= Add a volume driver module to compile" + echo " --add-plugin= Add a hook plugin to compile" echo " --clean Remove temporary codes, the 'build.go'" echo "" echo " ./module To comiple directly on current codes, include added modules" diff --git a/apis/plugins/ContainerPlugin.go b/hookplugins/ContainerPlugin.go similarity index 68% rename from apis/plugins/ContainerPlugin.go rename to hookplugins/ContainerPlugin.go index 728a41da0..2bc9393f7 100644 --- a/apis/plugins/ContainerPlugin.go +++ b/hookplugins/ContainerPlugin.go @@ -1,9 +1,10 @@ -package plugins +package hookplugins import ( "io" "github.com/alibaba/pouch/apis/types" + networktypes "github.com/alibaba/pouch/network/types" ) // ContainerPlugin defines places where a plugin will be triggered in container lifecycle @@ -16,10 +17,8 @@ type ContainerPlugin interface { // used to sort the pre start array that pass to runc, network plugin hook always has priority value 0. PreStart(interface{}) ([]int, [][]string, error) - // PreCreateEndpoint accepts the container id and env of this container and returns the priority of this endpoint - // and if this endpoint should enable resolver and a map which will be used as generic params to create endpoints of - // this container - PreCreateEndpoint(string, []string) (priority int, disableResolver bool, genericParam map[string]interface{}) + // PreCreateEndpoint accepts the container id and env of this container, to update the config of container's endpoint. + PreCreateEndpoint(string, []string, *networktypes.Endpoint) error // PreUpdate defines plugin point where receives a container update request, in this plugin point user // could change the container update body passed-in by http request body @@ -29,3 +28,15 @@ type ContainerPlugin interface { // the method accepts the rootfs path and envs of container PostUpdate(string, []string) error } + +var containerPlugin ContainerPlugin + +// RegisterContainerPlugin is used to register container plugin. +func RegisterContainerPlugin(cp ContainerPlugin) { + containerPlugin = cp +} + +// GetContainerPlugin returns the container plugin. +func GetContainerPlugin() ContainerPlugin { + return containerPlugin +} diff --git a/hookplugins/CriPlugin.go b/hookplugins/CriPlugin.go new file mode 100644 index 000000000..31df960fe --- /dev/null +++ b/hookplugins/CriPlugin.go @@ -0,0 +1,24 @@ +package hookplugins + +import ( + "github.com/alibaba/pouch/apis/types" +) + +// CriPlugin defines places where a plugin will be triggered in CRI api lifecycle +type CriPlugin interface { + // PreCreateContainer defines plugin point where receives a container create request, in this plugin point user + // could update the container's config in cri interface. + PreCreateContainer(*types.ContainerCreateConfig, interface{}) error +} + +var criPlugin CriPlugin + +// RegisterCriPlugin is used to register the cri plugin. +func RegisterCriPlugin(crip CriPlugin) { + criPlugin = crip +} + +// GetCriPlugin returns the cri plugin. +func GetCriPlugin() CriPlugin { + return criPlugin +} diff --git a/apis/plugins/DaemonPlugin.go b/hookplugins/DaemonPlugin.go similarity index 56% rename from apis/plugins/DaemonPlugin.go rename to hookplugins/DaemonPlugin.go index 2101a899e..4ed1e3182 100644 --- a/apis/plugins/DaemonPlugin.go +++ b/hookplugins/DaemonPlugin.go @@ -1,8 +1,8 @@ -package plugins +package hookplugins // DaemonPlugin defines places where a plugin will be triggered in pouchd lifecycle type DaemonPlugin interface { - // PreStartHook is invoked by pouch daemon before real start, in this hook user could start dfget proxy or other + // PreStartHook is invoked by pouch daemon before real start, in this hook user could start http proxy or other // standalone process plugins PreStartHook() error @@ -10,3 +10,15 @@ type DaemonPlugin interface { // hook user could stop the process or plugin started by PreStartHook PreStopHook() error } + +var daemonPlugin DaemonPlugin + +// RegisterDaemonPlugin is used to register daemon plugin. +func RegisterDaemonPlugin(dp DaemonPlugin) { + daemonPlugin = dp +} + +// GetDaemonPlugin returns the daemon plugin. +func GetDaemonPlugin() DaemonPlugin { + return daemonPlugin +} diff --git a/hookplugins/VolumePlugin.go b/hookplugins/VolumePlugin.go new file mode 100644 index 000000000..32be8e7d3 --- /dev/null +++ b/hookplugins/VolumePlugin.go @@ -0,0 +1,24 @@ +package hookplugins + +import ( + "github.com/alibaba/pouch/apis/types" +) + +// VolumePlugin defines places where a plugin will be triggered in volume lifecycle +type VolumePlugin interface { + // PreVolumeCreate defines plugin point where receives an volume create request, in this plugin point user + // could change the volume create body passed-in by http request body + PreVolumeCreate(*types.VolumeCreateConfig) error +} + +var volumePlugin VolumePlugin + +// RegisterVolumePlugin is used to register the volume plugin. +func RegisterVolumePlugin(vp VolumePlugin) { + volumePlugin = vp +} + +// GetVolumePlugin returns the volume plugin. +func GetVolumePlugin() VolumePlugin { + return volumePlugin +} diff --git a/hookplugins/containerplugin/create_hook.go b/hookplugins/containerplugin/create_hook.go new file mode 100644 index 000000000..ef7edf233 --- /dev/null +++ b/hookplugins/containerplugin/create_hook.go @@ -0,0 +1,19 @@ +package containerplugin + +import ( + "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/hookplugins" +) + +type contPlugin struct{} + +func init() { + hookplugins.RegisterContainerPlugin(&contPlugin{}) +} + +// PreCreate defines plugin point where receives a container create request, in this plugin point user +// could change the container create body passed-in by http request body +func (c *contPlugin) PreCreate(createConfig *types.ContainerCreateConfig) error { + // TODO: Implemented by the developer + return nil +} diff --git a/hookplugins/containerplugin/start_hook.go b/hookplugins/containerplugin/start_hook.go new file mode 100644 index 000000000..16fedeff4 --- /dev/null +++ b/hookplugins/containerplugin/start_hook.go @@ -0,0 +1,16 @@ +package containerplugin + +import networktypes "github.com/alibaba/pouch/network/types" + +// PreStart returns an array of priority and args which will pass to runc, the every priority +// used to sort the pre start array that pass to runc, network plugin hook always has priority value 0. +func (c *contPlugin) PreStart(interface{}) ([]int, [][]string, error) { + // TODO: Implemented by the developer + return nil, nil, nil +} + +// PreCreateEndpoint accepts the container id and env of this container, to update the config of container's endpoint. +func (c *contPlugin) PreCreateEndpoint(cid string, env []string, endpoint *networktypes.Endpoint) error { + // TODO: Implemented by the developer + return nil +} diff --git a/hookplugins/containerplugin/update_hook.go b/hookplugins/containerplugin/update_hook.go new file mode 100644 index 000000000..7b90de8d4 --- /dev/null +++ b/hookplugins/containerplugin/update_hook.go @@ -0,0 +1,19 @@ +package containerplugin + +import ( + "io" +) + +// PreUpdate defines plugin point where receives a container update request, in this plugin point user +// could change the container update body passed-in by http request body. +func (c *contPlugin) PreUpdate(in io.ReadCloser) (io.ReadCloser, error) { + // TODO: Implemented by the developer + return in, nil +} + +// PostUpdate called after update method successful, +// the method accepts the rootfs path and envs of container. +func (c *contPlugin) PostUpdate(rootfs string, env []string) error { + // TODO: Implemented by the developer + return nil +} diff --git a/hookplugins/criplugin/cri_hook.go b/hookplugins/criplugin/cri_hook.go new file mode 100644 index 000000000..be3d74040 --- /dev/null +++ b/hookplugins/criplugin/cri_hook.go @@ -0,0 +1,19 @@ +package criplugin + +import ( + "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/hookplugins" +) + +type criPlugin struct{} + +func init() { + hookplugins.RegisterCriPlugin(&criPlugin{}) +} + +// PreCreateContainer defines plugin point where receives a container create request, in this plugin point user +// could the container's config in cri interface. +func (c *criPlugin) PreCreateContainer(createConfig *types.ContainerCreateConfig, res interface{}) error { + // TODO: Implemented by the developer + return nil +} diff --git a/hookplugins/daemonplugin/daemon_hook.go b/hookplugins/daemonplugin/daemon_hook.go new file mode 100644 index 000000000..2f43f46de --- /dev/null +++ b/hookplugins/daemonplugin/daemon_hook.go @@ -0,0 +1,22 @@ +package daemonplugin + +import "github.com/alibaba/pouch/hookplugins" + +type daemonPlugin struct{} + +func init() { + hookplugins.RegisterDaemonPlugin(&daemonPlugin{}) +} + +// PreStartHook is invoked by pouch daemon before real start, in this hook user could start http proxy or other +// standalone process plugins +func (d *daemonPlugin) PreStartHook() error { + // TODO: Implemented by the developer + return nil +} + +// PreStopHook stops plugin processes than start ed by PreStartHook. +func (d *daemonPlugin) PreStopHook() error { + // TODO: Implemented by the developer + return nil +} diff --git a/hookplugins/volumeplugin/volume_hook.go b/hookplugins/volumeplugin/volume_hook.go new file mode 100644 index 000000000..4dda9df78 --- /dev/null +++ b/hookplugins/volumeplugin/volume_hook.go @@ -0,0 +1,19 @@ +package volumeplugin + +import ( + "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/hookplugins" +) + +type volumePlugin struct{} + +func init() { + hookplugins.RegisterVolumePlugin(&volumePlugin{}) +} + +// PreVolumeCreate defines plugin point where receives an volume create request, in this plugin point user +// could change the volume create body passed-in by http request body +func (v *volumePlugin) PreVolumeCreate(config *types.VolumeCreateConfig) error { + // TODO: Implemented by the developer + return nil +} diff --git a/internal/generator.go b/internal/generator.go index 4d72a53e1..6e420bd91 100644 --- a/internal/generator.go +++ b/internal/generator.go @@ -4,11 +4,11 @@ import ( "context" "path" - "github.com/alibaba/pouch/apis/plugins" "github.com/alibaba/pouch/ctrd" "github.com/alibaba/pouch/daemon/config" "github.com/alibaba/pouch/daemon/events" "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/hookplugins" "github.com/alibaba/pouch/pkg/meta" ) @@ -21,7 +21,7 @@ type DaemonProvider interface { VolMgr() mgr.VolumeMgr NetMgr() mgr.NetworkMgr MetaStore() *meta.Store - ContainerPlugin() plugins.ContainerPlugin + ContainerPlugin() hookplugins.ContainerPlugin EventsService() *events.Events } diff --git a/main.go b/main.go index 6727bee77..f04f1ef6f 100644 --- a/main.go +++ b/main.go @@ -120,7 +120,6 @@ func setupFlags(cmd *cobra.Command) { // cgroup-path flag is to set parent cgroup for all containers, default is "default" staying with containerd's configuration. flagSet.StringVar(&cfg.CgroupParent, "cgroup-parent", "default", "Set parent cgroup for all containers") - flagSet.StringVar(&cfg.PluginPath, "plugin", "", "Set the path where plugin shared library file put") flagSet.StringSliceVar(&cfg.Labels, "label", []string{}, "Set metadata for Pouch daemon") flagSet.BoolVar(&cfg.EnableProfiler, "enable-profiler", false, "Set if pouchd setup profiler") flagSet.StringVar(&cfg.Pidfile, "pidfile", "/var/run/pouch.pid", "Save daemon pid") diff --git a/plugins/client.go b/storage/plugins/client.go similarity index 100% rename from plugins/client.go rename to storage/plugins/client.go diff --git a/plugins/client_test.go b/storage/plugins/client_test.go similarity index 100% rename from plugins/client_test.go rename to storage/plugins/client_test.go diff --git a/plugins/error.go b/storage/plugins/error.go similarity index 100% rename from plugins/error.go rename to storage/plugins/error.go diff --git a/plugins/manager.go b/storage/plugins/manager.go similarity index 100% rename from plugins/manager.go rename to storage/plugins/manager.go diff --git a/plugins/manager_test.go b/storage/plugins/manager_test.go similarity index 100% rename from plugins/manager_test.go rename to storage/plugins/manager_test.go diff --git a/plugins/plugin.go b/storage/plugins/plugin.go similarity index 100% rename from plugins/plugin.go rename to storage/plugins/plugin.go diff --git a/plugins/plugins.go b/storage/plugins/plugins.go similarity index 100% rename from plugins/plugins.go rename to storage/plugins/plugins.go diff --git a/storage/volume/driver/driver.go b/storage/volume/driver/driver.go index d2db648c6..5ff18fe7c 100644 --- a/storage/volume/driver/driver.go +++ b/storage/volume/driver/driver.go @@ -6,7 +6,7 @@ import ( "sort" "sync" - "github.com/alibaba/pouch/plugins" + "github.com/alibaba/pouch/storage/plugins" "github.com/pkg/errors" ) diff --git a/storage/volume/driver/proxy.go b/storage/volume/driver/proxy.go index 28de52b10..8560437b4 100644 --- a/storage/volume/driver/proxy.go +++ b/storage/volume/driver/proxy.go @@ -3,7 +3,7 @@ package driver import ( "errors" - "github.com/alibaba/pouch/plugins" + "github.com/alibaba/pouch/storage/plugins" ) // the following const variables is the protocol of remote volume driver. diff --git a/storage/volume/driver/proxy_test.go b/storage/volume/driver/proxy_test.go index 807f42211..131863e6f 100644 --- a/storage/volume/driver/proxy_test.go +++ b/storage/volume/driver/proxy_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/alibaba/pouch/plugins" + "github.com/alibaba/pouch/storage/plugins" ) func TestRemoteDriverRequestError(t *testing.T) { diff --git a/storage/volume/driver/remote.go b/storage/volume/driver/remote.go index 8c4c969e1..012a79e17 100644 --- a/storage/volume/driver/remote.go +++ b/storage/volume/driver/remote.go @@ -1,7 +1,7 @@ package driver import ( - "github.com/alibaba/pouch/plugins" + "github.com/alibaba/pouch/storage/plugins" "github.com/alibaba/pouch/storage/volume/types" )