Skip to content
This repository was archived by the owner on Aug 20, 2021. It is now read-only.

Commit 4aaf924

Browse files
authored
Merge pull request #41 from dweomer/build/image-sync
build: sync built images from k3c.io to k8s.io
2 parents 9f89dff + f99ecb6 commit 4aaf924

File tree

2 files changed

+112
-15
lines changed

2 files changed

+112
-15
lines changed

cmd/daemon/daemon_linux.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import (
77
"path/filepath"
88
"strings"
99

10-
"github.com/containerd/containerd/services/opt"
11-
1210
"github.com/containerd/containerd/cmd/containerd/command"
1311
"github.com/containerd/containerd/plugin"
12+
"github.com/containerd/containerd/services/opt"
1413
"github.com/containerd/cri"
1514
criconfig "github.com/containerd/cri/pkg/config"
1615
"github.com/rancher/k3c/pkg/daemon"

pkg/daemon/client.go

+111-13
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,32 @@ package daemon
22

33
import (
44
"context"
5+
"io"
56
"path/filepath"
67
"sync"
78

89
"github.com/containerd/containerd"
9-
"github.com/containerd/containerd/api/services/containers/v1"
10-
"github.com/containerd/containerd/api/services/diff/v1"
11-
"github.com/containerd/containerd/api/services/images/v1"
12-
"github.com/containerd/containerd/api/services/namespaces/v1"
13-
"github.com/containerd/containerd/api/services/tasks/v1"
10+
eventspb "github.com/containerd/containerd/api/events"
11+
containerspb "github.com/containerd/containerd/api/services/containers/v1"
12+
diffpb "github.com/containerd/containerd/api/services/diff/v1"
13+
imagespb "github.com/containerd/containerd/api/services/images/v1"
14+
namespacespb "github.com/containerd/containerd/api/services/namespaces/v1"
15+
taskspb "github.com/containerd/containerd/api/services/tasks/v1"
1416
"github.com/containerd/containerd/content"
1517
"github.com/containerd/containerd/errdefs"
18+
"github.com/containerd/containerd/events/exchange"
19+
"github.com/containerd/containerd/images"
1620
"github.com/containerd/containerd/leases"
1721
"github.com/containerd/containerd/log"
18-
cns "github.com/containerd/containerd/namespaces"
22+
"github.com/containerd/containerd/namespaces"
1923
"github.com/containerd/containerd/plugin"
2024
"github.com/containerd/containerd/services"
2125
"github.com/containerd/containerd/snapshots"
2226
criutil "github.com/containerd/cri/pkg/containerd/util"
2327
"github.com/containerd/cri/pkg/server"
28+
"github.com/containerd/typeurl"
29+
prototypes "github.com/gogo/protobuf/types"
30+
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2431
"github.com/pkg/errors"
2532
"github.com/rancher/k3c/pkg/client"
2633
"github.com/rancher/k3c/pkg/daemon/config"
@@ -58,7 +65,7 @@ func (c *Daemon) RemoveVolume(ctx context.Context, name string, force bool) erro
5865

5966
func (c *Daemon) start(ic *plugin.InitContext) error {
6067
var (
61-
ctx = criutil.WithUnlisted(cns.WithNamespace(ic.Context, defaults.PublicNamespace), defaults.PrivateNamespace)
68+
ctx = criutil.WithUnlisted(namespaces.WithNamespace(ic.Context, defaults.PublicNamespace), defaults.PrivateNamespace)
6269
)
6370
plugins, err := ic.GetByType(plugin.GRPCPlugin)
6471
if err != nil {
@@ -86,13 +93,14 @@ func (c *Daemon) start(ic *plugin.InitContext) error {
8693
}
8794

8895
go c.gc(ctx)
96+
go c.syncImages(namespaces.WithNamespace(ic.Context, defaults.PrivateNamespace), ic.Events)
8997

9098
return nil
9199
}
92100

93101
func (c *Daemon) bootstrap(ic *plugin.InitContext) error {
94102
var (
95-
ctx = cns.WithNamespace(ic.Context, k3c.PrivateNamespace)
103+
ctx = namespaces.WithNamespace(ic.Context, k3c.PrivateNamespace)
96104
cfg = ic.Config.(*config.K3Config)
97105
)
98106

@@ -147,6 +155,96 @@ func (c *Daemon) Close() error {
147155
return nil
148156
}
149157

158+
// syncImages listens for ImageCreate events in the private namespace and copies them to the public namespace
159+
// based on the assumption that ImageCreate events are from images built by buildkit
160+
func (c *Daemon) syncImages(ctx context.Context, ex *exchange.Exchange) {
161+
evtch, errch := ex.Subscribe(ctx, `topic~="/images/"`)
162+
for {
163+
select {
164+
case err, ok := <-errch:
165+
if !ok {
166+
return
167+
}
168+
log.G(ctx).WithError(err).Error("image sync listener")
169+
case evt, ok := <-evtch:
170+
if !ok {
171+
return
172+
}
173+
if evt.Namespace != defaults.PrivateNamespace {
174+
continue
175+
}
176+
if err := c.handleEvent(ctx, evt.Event); err != nil {
177+
log.G(ctx).WithError(err).Error("image sync handler")
178+
}
179+
case <-ctx.Done():
180+
log.G(ctx).WithError(ctx.Err()).Error("image sync handler")
181+
return
182+
}
183+
}
184+
}
185+
186+
func (c *Daemon) handleEvent(ctx context.Context, any *prototypes.Any) error {
187+
evt, err := typeurl.UnmarshalAny(any)
188+
if err != nil {
189+
return errors.Wrap(err, "failed to unmarshal any")
190+
}
191+
192+
switch e := evt.(type) {
193+
case *eventspb.ImageCreate:
194+
log.G(ctx).WithField("event", "image.create").Debug(e.Name)
195+
return c.handleImageCreate(ctx, e.Name)
196+
}
197+
198+
return nil
199+
}
200+
201+
func (c *Daemon) handleImageCreate(ctx context.Context, name string) error {
202+
imageStore := c.ctd.ImageService()
203+
img, err := imageStore.Get(ctx, name)
204+
if err != nil {
205+
return err
206+
}
207+
contentStore := c.ctd.ContentStore()
208+
otherContext := namespaces.WithNamespace(ctx, defaults.PublicNamespace)
209+
var copy images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
210+
log.G(ctx).WithField("media-type", desc.MediaType).Debug(desc.Digest)
211+
info, err := contentStore.Info(ctx, desc.Digest)
212+
if err != nil {
213+
return subdescs, err
214+
}
215+
if _, err = contentStore.Info(otherContext, desc.Digest); err != nil && !errdefs.IsNotFound(err) {
216+
return subdescs, err
217+
}
218+
ra, err := contentStore.ReaderAt(ctx, desc)
219+
if err != nil {
220+
return subdescs, err
221+
}
222+
defer ra.Close()
223+
r := content.NewReader(ra)
224+
w, err := contentStore.Writer(otherContext, content.WithRef(img.Name))
225+
if err != nil {
226+
return subdescs, err
227+
}
228+
defer w.Close()
229+
if _, err = io.Copy(w, r); err != nil {
230+
return subdescs, err
231+
}
232+
if err = w.Commit(otherContext, 0, w.Digest(), content.WithLabels(info.Labels)); err != nil && errdefs.IsAlreadyExists(err) {
233+
return subdescs, nil
234+
}
235+
return subdescs, err
236+
}
237+
err = images.Walk(ctx, images.Handlers(images.ChildrenHandler(contentStore), copy), img.Target)
238+
if err != nil {
239+
return err
240+
}
241+
_, err = imageStore.Create(otherContext, img)
242+
if errdefs.IsAlreadyExists(err) {
243+
return nil
244+
}
245+
return err
246+
}
247+
150248
func getServicesOpts(ic *plugin.InitContext) ([]containerd.ServicesOpt, error) {
151249
plugins, err := ic.GetByType(plugin.ServicePlugin)
152250
if err != nil {
@@ -162,22 +260,22 @@ func getServicesOpts(ic *plugin.InitContext) ([]containerd.ServicesOpt, error) {
162260
return containerd.WithContentStore(s.(content.Store))
163261
},
164262
services.ImagesService: func(s interface{}) containerd.ServicesOpt {
165-
return containerd.WithImageService(s.(images.ImagesClient))
263+
return containerd.WithImageService(s.(imagespb.ImagesClient))
166264
},
167265
services.SnapshotsService: func(s interface{}) containerd.ServicesOpt {
168266
return containerd.WithSnapshotters(s.(map[string]snapshots.Snapshotter))
169267
},
170268
services.ContainersService: func(s interface{}) containerd.ServicesOpt {
171-
return containerd.WithContainerService(s.(containers.ContainersClient))
269+
return containerd.WithContainerService(s.(containerspb.ContainersClient))
172270
},
173271
services.TasksService: func(s interface{}) containerd.ServicesOpt {
174-
return containerd.WithTaskService(s.(tasks.TasksClient))
272+
return containerd.WithTaskService(s.(taskspb.TasksClient))
175273
},
176274
services.DiffService: func(s interface{}) containerd.ServicesOpt {
177-
return containerd.WithDiffService(s.(diff.DiffClient))
275+
return containerd.WithDiffService(s.(diffpb.DiffClient))
178276
},
179277
services.NamespacesService: func(s interface{}) containerd.ServicesOpt {
180-
return containerd.WithNamespaceService(s.(namespaces.NamespacesClient))
278+
return containerd.WithNamespaceService(s.(namespacespb.NamespacesClient))
181279
},
182280
services.LeasesService: func(s interface{}) containerd.ServicesOpt {
183281
return containerd.WithLeasesService(s.(leases.Manager))

0 commit comments

Comments
 (0)