Repository: k3s-io/k3s
File: pkg/spegel/store.go (Go)

Code before:
}

func (ds *deferredStore) Descriptor(ctx context.Context, dgst digest.Digest) (ocispec.Descriptor, error) {
	if ds.store == nil {
		return ocispec.Descriptor{}, errStoreNotStarted
	}
	return ds.store.Descriptor(ctx, dgst)
}

func (ds *deferredStore) Open(ctx context.Context, dgst digest.Digest) (io.ReadSeekCloser, error) {
	if ds.store == nil {
		return nil, errStoreNotStarted
	}
	return ds.store.Open(ctx, dgst)
}

func (ds *deferredStore) Subscribe(ctx context.Context) (<-chan oci.OCIEvent, error) {
	if ds.store == nil {
		return nil, errStoreNotStarted
	}
	return ds.store.Subscribe(ctx)
}

// Close is not part of the Store interface, but probably should be. Containerd impliments it.
func (ds *deferredStore) Close() error {
	store := ds.store
	ds.store = nil
	if closer, ok := store.(io.Closer); ok {
		return closer.Close()
	}
	return nil
}

// Start is called to actuall make a connection to the store backend
func (ds *deferredStore) Start() error {
	var err error
	if ds.store == nil && ds.create != nil {
		ds.store, err = ds.create()
	}
	return err
}

// NewDeferredContainerd creates a deferred store that creates a new Containerd store when Start is called.
func NewDeferredContainerd(ctx context.Context, sock, namespace string, opts ...oci.ContainerdOption) (DeferredStore, error) {
	return &deferredStore{
		create: func() (oci.Store, error) {
			return oci.NewContainerd(ctx, sock, namespace, opts...)
		},
	}, nil
}


Review comment (bug):
fixes a weird crash when stopping K3s while the spegel connection to containerd is still being brought up:

```
goroutine 645 [running]:
github.com/spegel-org/spegel/pkg/oci.(*Containerd).Close(0xc5c3530?)
	/go/pkg/mod/github.com/k3s-io/spegel@v0.6.0-k3s1/pkg/oci/containerd.go:136 +0xe
github.com/k3s-io/k3s/pkg/spegel.(*deferredStore).Close(0xc000bf6a80?)
	/go/src/github.com/k3s-io/k3s/pkg/spegel/store.go:86 +0x66
panic({0x6672100?, 0xc5af990?})
	/usr/local/go/src/runtime/panic.go:783 +0x132

```

Code after:
}

func (ds *deferredStore) Descriptor(ctx context.Context, dgst digest.Digest) (ocispec.Descriptor, error) {
	if ds.store == nil {
		return ocispec.Descriptor{}, errStoreNotStarted
	}
	return ds.store.Descriptor(ctx, dgst)
}

func (ds *deferredStore) Open(ctx context.Context, dgst digest.Digest) (io.ReadSeekCloser, error) {
	if ds.store == nil {
		return nil, errStoreNotStarted
	}
	return ds.store.Open(ctx, dgst)
}

func (ds *deferredStore) Subscribe(ctx context.Context) (<-chan oci.OCIEvent, error) {
	if ds.store == nil {
		return nil, errStoreNotStarted
	}
	return ds.store.Subscribe(ctx)
}

// Close is not part of the Store interface, but probably should be. Containerd impliments it.
func (ds *deferredStore) Close() error {
	if ds.store != nil {
		store := ds.store
		ds.store = nil
		if closer, ok := store.(io.Closer); ok {
			return closer.Close()
		}
	}
	return nil
}

// Start is called to actuall make a connection to the store backend
func (ds *deferredStore) Start() error {
	var err error
	if ds.store == nil && ds.create != nil {
		ds.store, err = ds.create()
	}
	return err
}

// NewDeferredContainerd creates a deferred store that creates a new Containerd store when Start is called.
func NewDeferredContainerd(ctx context.Context, sock, namespace string, opts ...oci.ContainerdOption) (DeferredStore, error) {
	return &deferredStore{
		create: func() (oci.Store, error) {
			return oci.NewContainerd(ctx, sock, namespace, opts...)
		},
	}, nil