From b8d6d1c64a3087ab91cd8cbd85464e54e716bb0f Mon Sep 17 00:00:00 2001 From: adriantpaez Date: Wed, 11 Oct 2023 16:28:48 +0000 Subject: [PATCH 1/2] fix: pull plugin image if does not exist locally --- pkg/daemon/docker.go | 3 + pkg/daemon/egn_daemon.go | 18 ++++-- pkg/daemon/egn_daemon_test.go | 100 ++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/pkg/daemon/docker.go b/pkg/daemon/docker.go index 3e062681..1387ebae 100644 --- a/pkg/daemon/docker.go +++ b/pkg/daemon/docker.go @@ -28,4 +28,7 @@ type DockerManager interface { // ImageRemove removes the given image. ImageRemove(image string) error + + // ImageExists checks if the given image exists. + ImageExist(image string) (bool, error) } diff --git a/pkg/daemon/egn_daemon.go b/pkg/daemon/egn_daemon.go index 756ad8fb..aa78f6c0 100644 --- a/pkg/daemon/egn_daemon.go +++ b/pkg/daemon/egn_daemon.go @@ -962,11 +962,19 @@ func (d *EgnDaemon) RunPlugin(instanceId string, pluginArgs []string, options Ru } network = networks[0] } - // XXX: Pull is removed to support local images that are already pulled - // err = d.docker.Pull(instance.Plugin.Image) - // if err != nil { - // return err - // } + + // Pull image if it does not exist + ok, err := d.docker.ImageExist(instance.Plugin.Image) + if err != nil { + return err + } + if !ok { + err = d.docker.Pull(instance.Plugin.Image) + if err != nil { + return err + } + } + if !options.NoDestroyImage { defer func() { if err := d.docker.ImageRemove(instance.Plugin.Image); err != nil { diff --git a/pkg/daemon/egn_daemon_test.go b/pkg/daemon/egn_daemon_test.go index b34b3861..9acd5bbd 100644 --- a/pkg/daemon/egn_daemon_test.go +++ b/pkg/daemon/egn_daemon_test.go @@ -2891,6 +2891,7 @@ func TestRunPlugin(t *testing.T) { }, }, nil), d.dockerManager.EXPECT().ContainerNetworks("abc123").Return([]string{"network-el"}, nil), + d.dockerManager.EXPECT().ImageExist(common.PluginImage.FullImage()).Return(true, nil), d.dockerManager.EXPECT().Run(common.PluginImage.FullImage(), docker.RunOptions{ Network: "network-el", Args: []string{"arg1", "arg2"}, @@ -2911,6 +2912,104 @@ func TestRunPlugin(t *testing.T) { ) }, }, + { + name: `pull image if does not exist`, + instanceId: "mock-avs-default", + args: []string{"arg1", "arg2"}, + options: RunPluginOptions{ + Binds: map[string]string{ + "/tmp": "/tmp", + }, + Volumes: map[string]string{ + "volume1": "/tmp/volume1", + }, + }, + mocker: func(t *testing.T, d *mockerData) { + initInstanceDir(t, d.fs, d.dataDir.Path(), "mock-avs-default", `{ + "name": "mock-avs", + "tag": "default", + "version": "`+common.MockAvsPkg.Version()+`", + "profile": "option-returner", + "url": "`+common.MockAvsPkg.Repo()+`", + "plugin": { + "image": "`+common.PluginImage.FullImage()+`" + } + }`) + gomock.InOrder( + d.locker.EXPECT().New(filepath.Join(d.dataDir.Path(), "nodes", "mock-avs-default", ".lock")).Return(d.locker), + d.composeManager.EXPECT().PS(compose.DockerComposePsOptions{ + FilterRunning: true, + Path: filepath.Join(d.dataDir.Path(), "nodes", "mock-avs-default", "docker-compose.yml"), + Format: "json", + }).Return([]compose.ComposeService{ + { + Id: "abc123", + }, + }, nil), + d.dockerManager.EXPECT().ContainerNetworks("abc123").Return([]string{"network-el"}, nil), + d.dockerManager.EXPECT().ImageExist(common.PluginImage.FullImage()).Return(false, nil), + d.dockerManager.EXPECT().Pull(common.PluginImage.FullImage()).Return(nil), + d.dockerManager.EXPECT().Run(common.PluginImage.FullImage(), docker.RunOptions{ + Network: "network-el", + Args: []string{"arg1", "arg2"}, + Mounts: []docker.Mount{ + { + Type: docker.VolumeTypeBind, + Source: "/tmp", + Target: "/tmp", + }, + { + Type: docker.VolumeTypeVolume, + Source: "volume1", + Target: "/tmp/volume1", + }, + }, + }), + d.dockerManager.EXPECT().ImageRemove(common.PluginImage.FullImage()).Return(nil), + ) + }, + }, + { + name: `pull image error`, + instanceId: "mock-avs-default", + args: []string{"arg1", "arg2"}, + options: RunPluginOptions{ + Binds: map[string]string{ + "/tmp": "/tmp", + }, + Volumes: map[string]string{ + "volume1": "/tmp/volume1", + }, + }, + wantErr: true, + mocker: func(t *testing.T, d *mockerData) { + initInstanceDir(t, d.fs, d.dataDir.Path(), "mock-avs-default", `{ + "name": "mock-avs", + "tag": "default", + "version": "`+common.MockAvsPkg.Version()+`", + "profile": "option-returner", + "url": "`+common.MockAvsPkg.Repo()+`", + "plugin": { + "image": "`+common.PluginImage.FullImage()+`" + } + }`) + gomock.InOrder( + d.locker.EXPECT().New(filepath.Join(d.dataDir.Path(), "nodes", "mock-avs-default", ".lock")).Return(d.locker), + d.composeManager.EXPECT().PS(compose.DockerComposePsOptions{ + FilterRunning: true, + Path: filepath.Join(d.dataDir.Path(), "nodes", "mock-avs-default", "docker-compose.yml"), + Format: "json", + }).Return([]compose.ComposeService{ + { + Id: "abc123", + }, + }, nil), + d.dockerManager.EXPECT().ContainerNetworks("abc123").Return([]string{"network-el"}, nil), + d.dockerManager.EXPECT().ImageExist(common.PluginImage.FullImage()).Return(false, nil), + d.dockerManager.EXPECT().Pull(common.PluginImage.FullImage()).Return(assert.AnError), + ) + }, + }, { name: `run plugin from image and host network`, instanceId: "mock-avs-default", @@ -2937,6 +3036,7 @@ func TestRunPlugin(t *testing.T) { }`) gomock.InOrder( d.locker.EXPECT().New(filepath.Join(d.dataDir.Path(), "nodes", "mock-avs-default", ".lock")).Return(d.locker), + d.dockerManager.EXPECT().ImageExist(common.PluginImage.FullImage()).Return(true, nil), d.dockerManager.EXPECT().Run(common.PluginImage.FullImage(), docker.RunOptions{ Network: docker.NetworkHost, Args: []string{"arg1", "arg2"}, From 741f18c231e55c60d9d62119a56a1c8cec3830e9 Mon Sep 17 00:00:00 2001 From: adriantpaez Date: Wed, 11 Oct 2023 16:39:50 +0000 Subject: [PATCH 2/2] doc: update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9254fd8c..ca7a2b46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [Unreleased] +### Fixed + +- Pull plugin image if does not exist locally ([#101](https://github.com/NethermindEth/eigenlayer/pull/101)) + ## [v0.2.0] - 2023-10-10 + ### Added - Sort backup `ls` command results by date. ([#95](https://github.com/NethermindEth/eigenlayer/pull/95))