github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/container/lxd/image_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lxd_test 5 6 import ( 7 "context" 8 "errors" 9 "time" 10 11 lxdclient "github.com/canonical/lxd/client" 12 lxdapi "github.com/canonical/lxd/shared/api" 13 jc "github.com/juju/testing/checkers" 14 "go.uber.org/mock/gomock" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/container/lxd" 18 "github.com/juju/juju/container/lxd/mocks" 19 lxdtesting "github.com/juju/juju/container/lxd/testing" 20 corebase "github.com/juju/juju/core/base" 21 ) 22 23 var _ = gc.Suite(&imageSuite{}) 24 25 type imageSuite struct { 26 lxdtesting.BaseSuite 27 } 28 29 func (s *imageSuite) patch(remotes map[string]lxdclient.ImageServer) { 30 lxd.PatchConnectRemote(s, remotes) 31 } 32 33 func (s *imageSuite) TestCopyImageUsesPassedCallback(c *gc.C) { 34 ctrl := gomock.NewController(c) 35 defer ctrl.Finish() 36 iSvr := s.NewMockServer(ctrl) 37 38 copyOp := lxdtesting.NewMockRemoteOperation(ctrl) 39 copyOp.EXPECT().Wait().Return(nil).AnyTimes() 40 copyOp.EXPECT().GetTarget().Return(&lxdapi.Operation{StatusCode: lxdapi.Success}, nil) 41 copyOp.EXPECT().AddHandler(gomock.Any()).Return(nil, nil) 42 43 image := lxdapi.Image{Filename: "this-is-our-image"} 44 aliases := []lxdapi.ImageAlias{{Name: "local/image/alias"}} 45 req := &lxdclient.ImageCopyArgs{Aliases: aliases} 46 iSvr.EXPECT().CopyImage(iSvr, image, req).Return(copyOp, nil) 47 48 jujuSvr, err := lxd.NewServer(iSvr) 49 c.Assert(err, jc.ErrorIsNil) 50 51 sourced := lxd.SourcedImage{ 52 Image: &image, 53 LXDServer: iSvr, 54 } 55 err = jujuSvr.CopyRemoteImage(context.Background(), sourced, []string{"local/image/alias"}, lxdtesting.NoOpCallback) 56 c.Assert(err, jc.ErrorIsNil) 57 } 58 59 func (s *imageSuite) TestCopyImageRetries(c *gc.C) { 60 ctrl := gomock.NewController(c) 61 defer ctrl.Finish() 62 63 clock := mocks.NewMockClock(ctrl) 64 after := make(chan time.Time, 2) 65 after <- time.Time{} 66 after <- time.Time{} 67 clock.EXPECT().After(gomock.Any()).Return(after).AnyTimes() 68 clock.EXPECT().Now().Return(time.Now()).AnyTimes() 69 70 iSvr := s.NewMockServer(ctrl) 71 image := lxdapi.Image{Filename: "this-is-our-image"} 72 aliases := []lxdapi.ImageAlias{{Name: "local/image/alias"}} 73 req := &lxdclient.ImageCopyArgs{Aliases: aliases} 74 75 copyOp := lxdtesting.NewMockRemoteOperation(ctrl) 76 copyOp.EXPECT().AddHandler(gomock.Any()).Return(nil, nil).AnyTimes() 77 copyOp.EXPECT().Wait().Return(nil).Return(errors.New("Failed remote image download: boom")) 78 copyOp.EXPECT().Wait().Return(nil).Return(errors.New("Failed remote image download: boom")) 79 copyOp.EXPECT().Wait().Return(nil).Return(nil) 80 copyOp.EXPECT().GetTarget().Return(&lxdapi.Operation{StatusCode: lxdapi.Success}, nil) 81 82 iSvr.EXPECT().CopyImage(iSvr, image, req).Return(copyOp, nil).Times(3) 83 84 jujuSvr, err := lxd.NewTestingServer(iSvr, clock) 85 c.Assert(err, jc.ErrorIsNil) 86 87 sourced := lxd.SourcedImage{ 88 Image: &image, 89 LXDServer: iSvr, 90 } 91 err = jujuSvr.CopyRemoteImage(context.Background(), sourced, []string{"local/image/alias"}, lxdtesting.NoOpCallback) 92 c.Assert(err, jc.ErrorIsNil) 93 } 94 95 func (s *imageSuite) TestFindImageLocalServer(c *gc.C) { 96 ctrl := gomock.NewController(c) 97 defer ctrl.Finish() 98 iSvr := s.NewMockServer(ctrl) 99 100 alias := &lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-target"}} 101 image := lxdapi.Image{Filename: "this-is-our-image"} 102 gomock.InOrder( 103 iSvr.EXPECT().GetImageAlias("juju/ubuntu@16.04/"+s.Arch()).Return(alias, lxdtesting.ETag, nil), 104 iSvr.EXPECT().GetImage("foo-target").Return(&image, lxdtesting.ETag, nil), 105 ) 106 107 jujuSvr, err := lxd.NewServer(iSvr) 108 c.Assert(err, jc.ErrorIsNil) 109 110 found, err := jujuSvr.FindImage(context.Background(), corebase.MakeDefaultBase("ubuntu", "16.04"), s.Arch(), lxdapi.InstanceTypeContainer, []lxd.ServerSpec{{}}, false, nil) 111 c.Assert(err, jc.ErrorIsNil) 112 c.Check(found.LXDServer, gc.Equals, iSvr) 113 c.Check(*found.Image, gc.DeepEquals, image) 114 } 115 116 func (s *imageSuite) TestFindImageLocalServerUnknownSeries(c *gc.C) { 117 ctrl := gomock.NewController(c) 118 defer ctrl.Finish() 119 iSvr := s.NewMockServer(ctrl) 120 iSvr.EXPECT().GetImageAlias("juju/pldlinux@18.04/"+s.Arch()).Return(nil, lxdtesting.ETag, errors.New("not found")) 121 122 jujuSvr, err := lxd.NewServer(iSvr) 123 c.Assert(err, jc.ErrorIsNil) 124 125 _, err = jujuSvr.FindImage(context.Background(), corebase.MakeDefaultBase("pldlinux", "18.04"), s.Arch(), lxdapi.InstanceTypeContainer, []lxd.ServerSpec{{}}, false, nil) 126 c.Check(err, gc.ErrorMatches, `base.*pldlinux.*`) 127 } 128 129 func (s *imageSuite) TestFindImageRemoteServers(c *gc.C) { 130 ctrl := gomock.NewController(c) 131 defer ctrl.Finish() 132 iSvr := s.NewMockServer(ctrl) 133 134 rSvr1 := lxdtesting.NewMockImageServer(ctrl) 135 rSvr2 := lxdtesting.NewMockImageServer(ctrl) 136 s.patch(map[string]lxdclient.ImageServer{ 137 "server-that-wont-work": rSvr1, 138 "server-that-has-image": rSvr2, 139 }) 140 141 const imageType = "container" 142 image := lxdapi.Image{Filename: "this-is-our-image"} 143 alias := lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-remote-target"}} 144 gomock.InOrder( 145 iSvr.EXPECT().GetImageAlias("juju/ubuntu@16.04/"+s.Arch()).Return(nil, lxdtesting.ETag, errors.New("not found")), 146 rSvr1.EXPECT().GetImageAliasType(imageType, "16.04/"+s.Arch()).Return(nil, lxdtesting.ETag, errors.New("not found")), 147 rSvr2.EXPECT().GetImageAliasType(imageType, "16.04/"+s.Arch()).Return(&alias, lxdtesting.ETag, nil), 148 rSvr2.EXPECT().GetImage("foo-remote-target").Return(&image, lxdtesting.ETag, nil), 149 ) 150 151 jujuSvr, err := lxd.NewServer(iSvr) 152 c.Assert(err, jc.ErrorIsNil) 153 154 remotes := []lxd.ServerSpec{ 155 {Name: "server-that-wont-work", Protocol: lxd.LXDProtocol}, 156 {Name: "server-that-has-image", Protocol: lxd.SimpleStreamsProtocol}, 157 {Name: "server-that-should-not-be-touched", Protocol: lxd.LXDProtocol}, 158 } 159 found, err := jujuSvr.FindImage(context.Background(), corebase.MakeDefaultBase("ubuntu", "16.04"), s.Arch(), lxdapi.InstanceTypeContainer, remotes, false, nil) 160 c.Assert(err, jc.ErrorIsNil) 161 c.Check(found.LXDServer, gc.Equals, rSvr2) 162 c.Check(*found.Image, gc.DeepEquals, image) 163 } 164 165 func (s *imageSuite) TestFindImageRemoteServersCopyLocalNoCallback(c *gc.C) { 166 ctrl := gomock.NewController(c) 167 defer ctrl.Finish() 168 iSvr := s.NewMockServer(ctrl) 169 170 rSvr := lxdtesting.NewMockImageServer(ctrl) 171 s.patch(map[string]lxdclient.ImageServer{ 172 "server-that-has-image": rSvr, 173 }) 174 175 copyOp := lxdtesting.NewMockRemoteOperation(ctrl) 176 copyOp.EXPECT().Wait().Return(nil).AnyTimes() 177 copyOp.EXPECT().GetTarget().Return(&lxdapi.Operation{StatusCode: lxdapi.Success}, nil) 178 179 localAlias := "juju/ubuntu@16.04/" + s.Arch() 180 image := lxdapi.Image{Filename: "this-is-our-image"} 181 alias := lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-remote-target"}} 182 copyReq := &lxdclient.ImageCopyArgs{Aliases: []lxdapi.ImageAlias{{Name: localAlias}}} 183 gomock.InOrder( 184 iSvr.EXPECT().GetImageAlias(localAlias).Return(nil, lxdtesting.ETag, nil), 185 rSvr.EXPECT().GetImageAliasType("container", "16.04/"+s.Arch()).Return(&alias, lxdtesting.ETag, nil), 186 rSvr.EXPECT().GetImage("foo-remote-target").Return(&image, lxdtesting.ETag, nil), 187 iSvr.EXPECT().CopyImage(rSvr, image, copyReq).Return(copyOp, nil), 188 ) 189 190 jujuSvr, err := lxd.NewServer(iSvr) 191 c.Assert(err, jc.ErrorIsNil) 192 193 remotes := []lxd.ServerSpec{ 194 {Name: "server-that-has-image", Protocol: lxd.SimpleStreamsProtocol}, 195 } 196 found, err := jujuSvr.FindImage(context.Background(), corebase.MakeDefaultBase("ubuntu", "16.04"), s.Arch(), lxdapi.InstanceTypeContainer, remotes, true, nil) 197 c.Assert(err, jc.ErrorIsNil) 198 c.Check(found.LXDServer, gc.Equals, iSvr) 199 c.Check(*found.Image, gc.DeepEquals, image) 200 } 201 202 func (s *imageSuite) TestFindImageRemoteServersNotFound(c *gc.C) { 203 ctrl := gomock.NewController(c) 204 defer ctrl.Finish() 205 iSvr := s.NewMockServer(ctrl) 206 207 rSvr := lxdtesting.NewMockImageServer(ctrl) 208 s.patch(map[string]lxdclient.ImageServer{ 209 "server-that-has-image": rSvr, 210 }) 211 212 alias := lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-remote-target"}} 213 gomock.InOrder( 214 iSvr.EXPECT().GetImageAlias("juju/ubuntu@18.04/"+s.Arch()).Return(nil, lxdtesting.ETag, errors.New("not found")), 215 rSvr.EXPECT().GetImageAliasType("container", "18.04/"+s.Arch()).Return(&alias, lxdtesting.ETag, nil), 216 rSvr.EXPECT().GetImage("foo-remote-target").Return( 217 nil, lxdtesting.ETag, errors.New("failed to retrieve image")), 218 ) 219 220 jujuSvr, err := lxd.NewServer(iSvr) 221 c.Assert(err, jc.ErrorIsNil) 222 223 remotes := []lxd.ServerSpec{{Name: "server-that-has-image", Protocol: lxd.SimpleStreamsProtocol}} 224 _, err = jujuSvr.FindImage(context.Background(), corebase.MakeDefaultBase("ubuntu", "18.04"), s.Arch(), lxdapi.InstanceTypeContainer, remotes, false, nil) 225 c.Assert(err, gc.ErrorMatches, ".*failed to retrieve image.*") 226 } 227 228 func (s *imageSuite) TestBaseRemoteAliasesNotSupported(c *gc.C) { 229 _, err := lxd.BaseRemoteAliases(corebase.MakeDefaultBase("centos", "7"), "arm64") 230 c.Assert(err, gc.ErrorMatches, `base "centos@7" not supported`) 231 232 _, err = lxd.BaseRemoteAliases(corebase.MakeDefaultBase("centos", "8"), "arm64") 233 c.Assert(err, gc.ErrorMatches, `base "centos@8" not supported`) 234 235 _, err = lxd.BaseRemoteAliases(corebase.MakeDefaultBase("opensuse", "opensuse42"), "s390x") 236 c.Assert(err, gc.ErrorMatches, `base "opensuse@opensuse42" not supported`) 237 }