1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

integration/plugin/authz: inline CLI work-alike library

I strongly disagree with the design of this pull request.

Signed-off-by: David Sheets <dsheets@docker.com>
This commit is contained in:
David Sheets 2017-10-02 14:17:51 +01:00
parent 928b0631c9
commit 1574d91463
8 changed files with 163 additions and 400 deletions

View file

@ -15,7 +15,7 @@ source "$SCRIPTDIR/make/.go-autogen"
integration_api_dirs=${TEST_INTEGRATION_DIR:-"$(
find ./integration -type d |
grep -vE '^(./integration($|/util|/internal|/testdata|/plugin$))')"}
grep -vE '^(./integration($|/util|/testdata|/plugin$))')"}
run_test_integration() {
[[ "$TESTFLAGS" != *-check.f* ]] && run_test_integration_suites

View file

@ -1,128 +0,0 @@
package container
import (
"context"
"io"
"os"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
)
// CreateVMemLabel creates a container with the supplied parameters
func CreateVMemLabel(client client.APIClient, v []string, memoryMB int, labels map[string]string, img string, cmd []string) (string, error) {
ctx := context.Background()
config := container.Config{
Cmd: cmd,
Image: img,
Labels: labels,
}
hostConfig := container.HostConfig{
Binds: v,
Resources: container.Resources{
Memory: int64(memoryMB * 1024 * 1024),
},
}
networkingConfig := networktypes.NetworkingConfig{}
name := ""
response, err := client.ContainerCreate(ctx, &config, &hostConfig, &networkingConfig, name)
if err != nil {
return "", err
}
return response.ID, nil
}
// Run runs the command provided in the container image named
func Run(client client.APIClient, img string, cmd []string) (string, error) {
return RunV(client, []string{}, img, cmd)
}
// RunV runs the command provided in the container image named with
// the equivalent of -v bind mounts
func RunV(client client.APIClient, v []string, img string, cmd []string) (string, error) {
return RunVMem(client, v, 0, img, cmd)
}
// RunVMem runs the command provided in the container image named with
// the equivalent of -v bind mounts and a specified memory limit
func RunVMem(client client.APIClient, v []string, memoryMB int, img string, cmd []string) (string, error) {
return RunVMemLabel(client, v, memoryMB, map[string]string{}, img, cmd)
}
// RunVLabel runs the command provided in the container image named
// with the equivalent of -v bind mounts and the specified labels
func RunVLabel(client client.APIClient, v []string, labels map[string]string, img string, cmd []string) (string, error) {
return RunVMemLabel(client, v, 0, labels, img, cmd)
}
// RunVMemLabel runs the command provided in the container image named
// with the equivalent of -v bind mounts, a specified memory limit,
// and the specified labels
func RunVMemLabel(client client.APIClient, v []string, memoryMB int, labels map[string]string, img string, cmd []string) (string, error) {
containerID, err := CreateVMemLabel(client, v, memoryMB, labels, img, cmd)
if err != nil {
return "", err
}
ctx := context.Background()
if err := client.ContainerStart(ctx, containerID, types.ContainerStartOptions{}); err != nil {
return "", err
}
return containerID, nil
}
// Wait waits until the named container has exited
func Wait(client client.APIClient, container string) (int64, error) {
resultC, errC := client.ContainerWait(context.Background(), container, "")
select {
case result := <-resultC:
return result.StatusCode, nil
case err := <-errC:
return -1, err
}
}
// Stop stops the named container
func Stop(client client.APIClient, container string) error {
timeout := time.Duration(10) * time.Second
ctx := context.Background()
return client.ContainerStop(ctx, container, &timeout)
}
// Start starts the named container
func Start(client client.APIClient, container string) error {
ctx := context.Background()
return client.ContainerStart(ctx, container, types.ContainerStartOptions{})
}
// Kill kills the named container with SIGKILL
func Kill(client client.APIClient, container string) error {
ctx := context.Background()
return client.ContainerKill(ctx, container, "KILL")
}
// Export exports a container's file system as a tarball
func Export(client client.APIClient, path, name string) error {
ctx := context.Background()
responseReader, err := client.ContainerExport(ctx, name)
if err != nil {
return err
}
defer responseReader.Close()
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, responseReader)
return err
}

View file

@ -1,66 +0,0 @@
package image
import (
"context"
"io"
"os"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
// Save saves an image to a tarball names by path
func Save(client client.APIClient, path, image string) error {
ctx := context.Background()
responseReader, err := client.ImageSave(ctx, []string{image})
if err != nil {
return err
}
defer responseReader.Close()
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, responseReader)
return err
}
// Load loads an image from a tarball named by path
func Load(client client.APIClient, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
quiet := true
ctx := context.Background()
response, err := client.ImageLoad(ctx, file, quiet)
if err != nil {
return err
}
defer response.Body.Close()
return nil
}
// Import imports the contents of a tarball named by path
func Import(client client.APIClient, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
options := types.ImageImportOptions{}
ref := ""
source := types.ImageImportSource{
Source: file,
SourceName: "-",
}
ctx := context.Background()
responseReader, err := client.ImageImport(ctx, source, ref, options)
if err != nil {
return err
}
defer responseReader.Close()
return nil
}

View file

@ -1,59 +0,0 @@
package plugin
import (
"context"
"io/ioutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
// InstallGrantAllPermissions installs the plugin named and grants it
// all permissions it may require
func InstallGrantAllPermissions(client client.APIClient, name string) error {
ctx := context.Background()
options := types.PluginInstallOptions{
RemoteRef: name,
AcceptAllPermissions: true,
}
responseReader, err := client.PluginInstall(ctx, "", options)
if err != nil {
return err
}
defer responseReader.Close()
// we have to read the response out here because the client API
// actually starts a goroutine which we can only be sure has
// completed when we get EOF from reading responseBody
_, err = ioutil.ReadAll(responseReader)
return err
}
// Enable enables the named plugin
func Enable(client client.APIClient, name string) error {
ctx := context.Background()
options := types.PluginEnableOptions{}
return client.PluginEnable(ctx, name, options)
}
// Disable disables the named plugin
func Disable(client client.APIClient, name string) error {
ctx := context.Background()
options := types.PluginDisableOptions{}
return client.PluginDisable(ctx, name, options)
}
// Rm removes the named plugin
func Rm(client client.APIClient, name string) error {
return remove(client, name, false)
}
// RmF forces the removal of the named plugin
func RmF(client client.APIClient, name string) error {
return remove(client, name, true)
}
func remove(client client.APIClient, name string, force bool) error {
ctx := context.Background()
options := types.PluginRemoveOptions{Force: force}
return client.PluginRemove(ctx, name, options)
}

View file

@ -1,45 +0,0 @@
package system
import (
"context"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/client"
"github.com/docker/docker/internal/test/environment"
"github.com/stretchr/testify/require"
)
// Time provides the current time on the daemon host
func Time(t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
if testEnv.IsLocalDaemon() {
return time.Now()
}
ctx := context.Background()
info, err := client.Info(ctx)
require.Nil(t, err)
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
require.Nil(t, err, "invalid time format in GET /info response")
return dt
}
// Version provides the version of the daemon
func Version(client client.APIClient) (types.Version, error) {
ctx := context.Background()
return client.ServerVersion(ctx)
}
// EventsSince returns event and error streams since a provided time
func EventsSince(client client.APIClient, since string) (<-chan events.Message, <-chan error, func()) {
eventOptions := types.EventsOptions{
Since: since,
}
ctx, cancel := context.WithCancel(context.Background())
events, errs := client.Events(ctx, eventOptions)
return events, errs, cancel
}

View file

@ -1,61 +0,0 @@
package volume
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
volumetypes "github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
)
// Create creates a volume using the named driver with the specified options
func Create(client client.APIClient, driver string, opts map[string]string) (string, error) {
volReq := volumetypes.VolumesCreateBody{
Driver: driver,
DriverOpts: opts,
Name: "",
}
ctx := context.Background()
vol, err := client.VolumeCreate(ctx, volReq)
if err != nil {
return "", err
}
return vol.Name, nil
}
// Rm removes the volume named
func Rm(client client.APIClient, name string) error {
ctx := context.Background()
return client.VolumeRemove(ctx, name, false)
}
// Ls lists the volumes available
func Ls(client client.APIClient) ([]string, error) {
ctx := context.Background()
volumes, err := client.VolumeList(ctx, filters.Args{})
if err != nil {
return []string{}, err
}
names := []string{}
for _, volume := range volumes.Volumes {
names = append(names, volume.Name)
}
return names, nil
}
// Prune removes all volumes not used by at least one container
func Prune(client client.APIClient) (types.VolumesPruneReport, error) {
ctx := context.Background()
return client.VolumesPrune(ctx, filters.Args{})
}
// Inspect retrieves detailed information about the named volume
func Inspect(client client.APIClient, name string) (types.Volume, error) {
ctx := context.Background()
return client.VolumeInspect(ctx, name)
}

View file

@ -18,11 +18,13 @@ import (
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
eventtypes "github.com/docker/docker/api/types/events"
"github.com/docker/docker/integration/internal/api/container"
"github.com/docker/docker/integration/internal/api/image"
"github.com/docker/docker/integration/internal/api/system"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/util/request"
"github.com/docker/docker/internal/test/environment"
"github.com/docker/docker/pkg/authorization"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/require"
@ -90,13 +92,16 @@ func TestAuthZPluginAllowRequest(t *testing.T) {
require.Nil(t, err)
// Ensure command successful
id, err := container.Run(client, "busybox", []string{"top"})
createResponse, err := client.ContainerCreate(context.Background(), &container.Config{Cmd: []string{"top"}, Image: "busybox"}, &container.HostConfig{}, &networktypes.NetworkingConfig{}, "")
require.Nil(t, err)
err = client.ContainerStart(context.Background(), createResponse.ID, types.ContainerStartOptions{})
require.Nil(t, err)
assertURIRecorded(t, ctrl.requestsURIs, "/containers/create")
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", id))
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", createResponse.ID))
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.Nil(t, err)
require.Equal(t, 1, ctrl.versionReqCount)
require.Equal(t, 1, ctrl.versionResCount)
@ -127,7 +132,7 @@ func TestAuthZPluginTLS(t *testing.T) {
client, err := request.NewTLSAPIClient(t, testDaemonHTTPSAddr, cacertPath, clientCertPath, clientKeyPath)
require.Nil(t, err)
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.Nil(t, err)
require.Equal(t, "client", ctrl.reqUser)
@ -144,7 +149,7 @@ func TestAuthZPluginDenyRequest(t *testing.T) {
require.Nil(t, err)
// Ensure command is blocked
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.NotNil(t, err)
require.Equal(t, 1, ctrl.versionReqCount)
require.Equal(t, 0, ctrl.versionResCount)
@ -186,7 +191,7 @@ func TestAuthZPluginDenyResponse(t *testing.T) {
require.Nil(t, err)
// Ensure command is blocked
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.NotNil(t, err)
require.Equal(t, 1, ctrl.versionReqCount)
require.Equal(t, 1, ctrl.versionResCount)
@ -208,15 +213,19 @@ func TestAuthZPluginAllowEventStream(t *testing.T) {
client, err := d.NewClient()
require.Nil(t, err)
startTime := strconv.FormatInt(system.Time(t, client, testEnv).Unix(), 10)
events, errs, cancel := system.EventsSince(client, startTime)
startTime := strconv.FormatInt(systemTime(t, client, testEnv).Unix(), 10)
events, errs, cancel := systemEventsSince(client, startTime)
defer cancel()
// Create a container and wait for the creation events
id, err := container.Run(client, "busybox", []string{"top"})
createResponse, err := client.ContainerCreate(context.Background(), &container.Config{Cmd: []string{"top"}, Image: "busybox"}, &container.HostConfig{}, &networktypes.NetworkingConfig{}, "")
require.Nil(t, err)
err = client.ContainerStart(context.Background(), createResponse.ID, types.ContainerStartOptions{})
require.Nil(t, err)
for i := 0; i < 100; i++ {
c, err := client.ContainerInspect(context.Background(), id)
c, err := client.ContainerInspect(context.Background(), createResponse.ID)
require.Nil(t, err)
if c.State.Running {
break
@ -232,7 +241,7 @@ func TestAuthZPluginAllowEventStream(t *testing.T) {
for !created && !started {
select {
case event := <-events:
if event.Type == eventtypes.ContainerEventType && event.Actor.ID == id {
if event.Type == eventtypes.ContainerEventType && event.Actor.ID == createResponse.ID {
if event.Action == "create" {
created = true
}
@ -255,7 +264,31 @@ func TestAuthZPluginAllowEventStream(t *testing.T) {
// authorization plugin
assertURIRecorded(t, ctrl.requestsURIs, "/events")
assertURIRecorded(t, ctrl.requestsURIs, "/containers/create")
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", id))
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", createResponse.ID))
}
func systemTime(t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
if testEnv.IsLocalDaemon() {
return time.Now()
}
ctx := context.Background()
info, err := client.Info(ctx)
require.Nil(t, err)
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
require.Nil(t, err, "invalid time format in GET /info response")
return dt
}
func systemEventsSince(client client.APIClient, since string) (<-chan eventtypes.Message, <-chan error, func()) {
eventOptions := types.EventsOptions{
Since: since,
}
ctx, cancel := context.WithCancel(context.Background())
events, errs := client.Events(ctx, eventOptions)
return events, errs, cancel
}
func TestAuthZPluginErrorResponse(t *testing.T) {
@ -268,7 +301,7 @@ func TestAuthZPluginErrorResponse(t *testing.T) {
require.Nil(t, err)
// Ensure command is blocked
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.NotNil(t, err)
require.Equal(t, fmt.Sprintf("Error response from daemon: plugin %s failed with error: %s: %s", testAuthZPlugin, authorization.AuthZApiResponse, errorMessage), err.Error())
}
@ -282,7 +315,7 @@ func TestAuthZPluginErrorRequest(t *testing.T) {
require.Nil(t, err)
// Ensure command is blocked
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.NotNil(t, err)
require.Equal(t, fmt.Sprintf("Error response from daemon: plugin %s failed with error: %s: %s", testAuthZPlugin, authorization.AuthZApiRequest, errorMessage), err.Error())
}
@ -297,7 +330,7 @@ func TestAuthZPluginEnsureNoDuplicatePluginRegistration(t *testing.T) {
client, err := d.NewClient()
require.Nil(t, err)
_, err = system.Version(client)
_, err = client.ServerVersion(context.Background())
require.Nil(t, err)
// assert plugin is only called once..
@ -320,19 +353,83 @@ func TestAuthZPluginEnsureLoadImportWorking(t *testing.T) {
savedImagePath := filepath.Join(tmp, "save.tar")
err = image.Save(client, savedImagePath, "busybox")
err = imageSave(client, savedImagePath, "busybox")
require.Nil(t, err)
err = image.Load(client, savedImagePath)
err = imageLoad(client, savedImagePath)
require.Nil(t, err)
exportedImagePath := filepath.Join(tmp, "export.tar")
id, err := container.Run(client, "busybox", []string{})
createResponse, err := client.ContainerCreate(context.Background(), &container.Config{Cmd: []string{}, Image: "busybox"}, &container.HostConfig{}, &networktypes.NetworkingConfig{}, "")
require.Nil(t, err)
err = container.Export(client, exportedImagePath, id)
err = client.ContainerStart(context.Background(), createResponse.ID, types.ContainerStartOptions{})
require.Nil(t, err)
err = image.Import(client, exportedImagePath)
responseReader, err := client.ContainerExport(context.Background(), createResponse.ID)
require.Nil(t, err)
defer responseReader.Close()
file, err := os.Create(exportedImagePath)
require.Nil(t, err)
defer file.Close()
_, err = io.Copy(file, responseReader)
require.Nil(t, err)
err = imageImport(client, exportedImagePath)
require.Nil(t, err)
}
func imageSave(client client.APIClient, path, image string) error {
ctx := context.Background()
responseReader, err := client.ImageSave(ctx, []string{image})
if err != nil {
return err
}
defer responseReader.Close()
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, responseReader)
return err
}
func imageLoad(client client.APIClient, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
quiet := true
ctx := context.Background()
response, err := client.ImageLoad(ctx, file, quiet)
if err != nil {
return err
}
defer response.Body.Close()
return nil
}
func imageImport(client client.APIClient, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
options := types.ImageImportOptions{}
ref := ""
source := types.ImageImportSource{
Source: file,
SourceName: "-",
}
ctx := context.Background()
responseReader, err := client.ImageImport(ctx, source, ref, options)
if err != nil {
return err
}
defer responseReader.Close()
return nil
}
func TestAuthZPluginHeader(t *testing.T) {

View file

@ -5,13 +5,17 @@ package authz
import (
"context"
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
"github.com/docker/docker/integration/internal/api/container"
"github.com/docker/docker/integration/internal/api/plugin"
"github.com/docker/docker/integration/internal/api/volume"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
networktypes "github.com/docker/docker/api/types/network"
volumetypes "github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/util/requirement"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/require"
@ -44,7 +48,7 @@ func TestAuthZPluginV2AllowNonVolumeRequest(t *testing.T) {
require.Nil(t, err)
// Install authz plugin
err = plugin.InstallGrantAllPermissions(client, authzPluginNameWithTag)
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
require.Nil(t, err)
// start the daemon with the plugin and load busybox, --net=none build fails otherwise
// because it needs to pull busybox
@ -52,10 +56,13 @@ func TestAuthZPluginV2AllowNonVolumeRequest(t *testing.T) {
d.LoadBusybox(t)
// Ensure docker run command and accompanying docker ps are successful
id, err := container.Run(client, "busybox", []string{"top"})
createResponse, err := client.ContainerCreate(context.Background(), &container.Config{Cmd: []string{"top"}, Image: "busybox"}, &container.HostConfig{}, &networktypes.NetworkingConfig{}, "")
require.Nil(t, err)
_, err = client.ContainerInspect(context.Background(), id)
err = client.ContainerStart(context.Background(), createResponse.ID, types.ContainerStartOptions{})
require.Nil(t, err)
_, err = client.ContainerInspect(context.Background(), createResponse.ID)
require.Nil(t, err)
}
@ -67,22 +74,22 @@ func TestAuthZPluginV2Disable(t *testing.T) {
require.Nil(t, err)
// Install authz plugin
err = plugin.InstallGrantAllPermissions(client, authzPluginNameWithTag)
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
require.Nil(t, err)
d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag)
d.LoadBusybox(t)
_, err = volume.Create(client, "local", map[string]string{})
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"})
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
// disable the plugin
err = plugin.Disable(client, authzPluginNameWithTag)
err = client.PluginDisable(context.Background(), authzPluginNameWithTag, types.PluginDisableOptions{})
require.Nil(t, err)
// now test to see if the docker api works.
_, err = volume.Create(client, "local", map[string]string{})
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"})
require.Nil(t, err)
}
@ -94,30 +101,30 @@ func TestAuthZPluginV2RejectVolumeRequests(t *testing.T) {
require.Nil(t, err)
// Install authz plugin
err = plugin.InstallGrantAllPermissions(client, authzPluginNameWithTag)
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
require.Nil(t, err)
// restart the daemon with the plugin
d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag)
_, err = volume.Create(client, "local", map[string]string{})
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"})
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
_, err = volume.Ls(client)
_, err = client.VolumeList(context.Background(), filters.Args{})
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
// The plugin will block the command before it can determine the volume does not exist
err = volume.Rm(client, "test")
err = client.VolumeRemove(context.Background(), "test", false)
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
_, err = volume.Inspect(client, "test")
_, err = client.VolumeInspect(context.Background(), "test")
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
_, err = volume.Prune(client)
_, err = client.VolumesPrune(context.Background(), filters.Args{})
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
}
@ -130,7 +137,7 @@ func TestAuthZPluginV2BadManifestFailsDaemonStart(t *testing.T) {
require.Nil(t, err)
// Install authz plugin with bad manifest
err = plugin.InstallGrantAllPermissions(client, authzPluginBadManifestName)
err = pluginInstallGrantAllPermissions(client, authzPluginBadManifestName)
require.Nil(t, err)
// start the daemon with the plugin, it will error
@ -151,3 +158,21 @@ func TestAuthZPluginV2NonexistentFailsDaemonStart(t *testing.T) {
// restarting the daemon without requiring the plugin will succeed
d.Start(t)
}
func pluginInstallGrantAllPermissions(client client.APIClient, name string) error {
ctx := context.Background()
options := types.PluginInstallOptions{
RemoteRef: name,
AcceptAllPermissions: true,
}
responseReader, err := client.PluginInstall(ctx, "", options)
if err != nil {
return err
}
defer responseReader.Close()
// we have to read the response out here because the client API
// actually starts a goroutine which we can only be sure has
// completed when we get EOF from reading responseBody
_, err = ioutil.ReadAll(responseReader)
return err
}