Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/registry-facade-api/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ source "$ROOT_DIR"/scripts/protoc-generator.sh

install_dependencies
go_protoc "$COMPONENTS_DIR"
update_license
86 changes: 37 additions & 49 deletions components/registry-facade-api/go/imagespec.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions components/registry-facade-api/imagespec.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ message ImageSpec {
string ide_ref = 2;
// content_layer describe the last few layers which provide the workspace's content
repeated ContentLayer content_layer = 3;
// desktop_ide_ref points to an image denotign the desktop IDE to use
string desktop_ide_ref = 4;
// was used for desktop_ide_ref points to an image denotign the desktop IDE to use
reserved 4;
// supervisor_ref points to an image denotign the supervisor to use
string supervisor_ref = 5;
// desktop_ide_plugin_ref points to an image denotign the desktop IDE plugin to use
string desktop_ide_plugin_ref = 6;
// was used for desktop_ide_plugin_ref points to an image denotign the desktop IDE plugin to use
reserved 6;
// ide_layer_ref contains all these layers needed by ide except `web-ide` and `supervisor`
repeated string ide_layer_ref = 7;
}

// ContentLayer is a layer that provides a workspace's content
Expand Down
93 changes: 63 additions & 30 deletions components/registry-facade/pkg/registry/layersource.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func (cs CompositeLayerSource) GetBlob(ctx context.Context, spec *api.ImageSpec,
}

// RefSource extracts an image reference from an image spec
type RefSource func(*api.ImageSpec) (ref string, err error)
type RefSource func(*api.ImageSpec) (ref []string, err error)

// NewSpecMappedImageSource creates a new spec mapped image source
func NewSpecMappedImageSource(resolver ResolverProvider, refSource RefSource) (*SpecMappedImagedSource, error) {
Expand All @@ -392,71 +392,104 @@ type SpecMappedImagedSource struct {

// Envs returns the list of env modifiers
func (src *SpecMappedImagedSource) Envs(ctx context.Context, spec *api.ImageSpec) ([]EnvModifier, error) {
lsrc, err := src.getDelegate(ctx, spec)
lsrcs, err := src.getDelegate(ctx, spec)
if err != nil {
return nil, err
}
if lsrc == nil {
return []EnvModifier{}, nil
var res []EnvModifier
for _, lsrc := range lsrcs {
if lsrc == nil {
continue
}
envs, err := lsrc.Envs(ctx, spec)
if err != nil {
return nil, err
}
res = append(res, envs...)
}
return lsrc.Envs(ctx, spec)
return res, nil
}

// GetLayer returns the list of all layers from this source
func (src *SpecMappedImagedSource) GetLayer(ctx context.Context, spec *api.ImageSpec) ([]AddonLayer, error) {
lsrc, err := src.getDelegate(ctx, spec)
lsrcs, err := src.getDelegate(ctx, spec)
if err != nil {
return nil, err
}
if lsrc == nil {
return []AddonLayer{}, nil
var res []AddonLayer
for _, lsrc := range lsrcs {
if lsrc == nil {
continue
}
ls, err := lsrc.GetLayer(ctx, spec)
if err != nil {
return nil, err
}
res = append(res, ls...)
}
return lsrc.GetLayer(ctx, spec)
return res, nil
}

// HasBlob checks if a digest can be served by this blob source
func (src *SpecMappedImagedSource) HasBlob(ctx context.Context, spec *api.ImageSpec, dgst digest.Digest) bool {
lsrc, err := src.getDelegate(ctx, spec)
lsrcs, err := src.getDelegate(ctx, spec)
if err != nil {
return false
}
if lsrc == nil {
return false
for _, lsrc := range lsrcs {
if lsrc == nil {
continue
}
if lsrc.HasBlob(ctx, spec, dgst) {
return true
}
}
return lsrc.HasBlob(ctx, spec, dgst)
return false
}

// GetBlob provides access to a blob. If a ReadCloser is returned the receiver is expected to
// call close on it eventually.
func (src *SpecMappedImagedSource) GetBlob(ctx context.Context, spec *api.ImageSpec, dgst digest.Digest) (dontCache bool, mediaType string, url string, data io.ReadCloser, err error) {
lsrc, err := src.getDelegate(ctx, spec)
lsrcs, err := src.getDelegate(ctx, spec)
if err != nil {
return
}
return lsrc.GetBlob(ctx, spec, dgst)
for _, lsrc := range lsrcs {
if lsrc == nil {
continue
}
if lsrc.HasBlob(ctx, spec, dgst) {
return lsrc.GetBlob(ctx, spec, dgst)
}
}
err = errdefs.ErrNotFound
return
}

// getDelegate returns the cached layer source delegate computed from the image spec
func (src *SpecMappedImagedSource) getDelegate(ctx context.Context, spec *api.ImageSpec) (LayerSource, error) {
ref, err := src.RefSource(spec)
func (src *SpecMappedImagedSource) getDelegate(ctx context.Context, spec *api.ImageSpec) ([]LayerSource, error) {
refs, err := src.RefSource(spec)
if err != nil {
return nil, err
}
if ref == "" {
return nil, nil
}

if s, ok := src.cache.Get(ref); ok {
return s.(LayerSource), nil
}
layers := make([]LayerSource, len(refs))

lsrc, err := NewStaticSourceFromImage(ctx, src.Resolver(), ref)
if err != nil {
return nil, err
for i, ref := range refs {
if ref == "" {
continue
}
if s, ok := src.cache.Get(ref); ok {
layers[i] = s.(LayerSource)
continue
}
lsrc, err := NewStaticSourceFromImage(ctx, src.Resolver(), ref)
if err != nil {
return nil, err
}
src.cache.Add(ref, lsrc)
layers[i] = lsrc
}
src.cache.Add(ref, lsrc)

return lsrc, nil
return layers, nil
}

// NewContentLayerSource creates a new layer source providing the content layer of an image spec
Expand Down
38 changes: 5 additions & 33 deletions components/registry-facade/pkg/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,46 +142,18 @@ func NewRegistry(cfg config.Config, newResolver ResolverProvider, reg prometheus
staticLayer.Update(l)
}

// IDE layer
ideRefSource := func(s *api.ImageSpec) (ref string, err error) {
return s.IdeRef, nil
// ide layer
ideRefSource := func(s *api.ImageSpec) (ref []string, err error) {
ref = append(ref, s.IdeRef, s.SupervisorRef)
ref = append(ref, s.IdeLayerRef...)
return ref, nil
}
ideLayerSource, err := NewSpecMappedImageSource(newResolver, ideRefSource)
if err != nil {
return nil, err
}
layerSources = append(layerSources, ideLayerSource)

// desktop IDE layer
desktopIdeRefSource := func(s *api.ImageSpec) (ref string, err error) {
return s.DesktopIdeRef, nil
}
desktopIdeLayerSource, err := NewSpecMappedImageSource(newResolver, desktopIdeRefSource)
if err != nil {
return nil, err
}
layerSources = append(layerSources, desktopIdeLayerSource)

// desktop IDE plugin layer
desktopIdePluginRefSource := func(s *api.ImageSpec) (ref string, err error) {
return s.GetDesktopIdePluginRef(), nil
}
desktopIdePluginLayerSource, err := NewSpecMappedImageSource(newResolver, desktopIdePluginRefSource)
if err != nil {
return nil, err
}
layerSources = append(layerSources, desktopIdePluginLayerSource)

// supervisor layer
supervisorRefSource := func(s *api.ImageSpec) (ref string, err error) {
return s.SupervisorRef, nil
}
supervisorLayerSource, err := NewSpecMappedImageSource(newResolver, supervisorRefSource)
if err != nil {
return nil, err
}
layerSources = append(layerSources, supervisorLayerSource)

// content layer
clsrc, err := NewContentLayerSource()
if err != nil {
Expand Down
15 changes: 13 additions & 2 deletions components/ws-manager-api/core.proto
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,11 @@ message WorkspaceStatus {
message IDEImage {
// web_ref is a reference to an OCI image used for serving the web-based IDE
string web_ref = 1;
// desktop_ref is an optional reference to an OCI image used for serving desktop IDEs
// DEPRECATED desktop_ref is an optional reference to an OCI image used for serving desktop IDEs
string desktop_ref = 2;
// supervisor_ref is a reference to an OCI image used as supervisor
string supervisor_ref = 3;
// desktop_plugin_ref is an optional reference to an OCI image used for serving desktop IDE plugin
// DEPRECATED desktop_plugin_ref is an optional reference to an OCI image used for serving desktop IDE plugin
string desktop_plugin_ref = 4;
}

Expand Down Expand Up @@ -351,6 +351,10 @@ message WorkspaceSpec {

// class names the class of this workspace
string class = 9;

// ide_image_layers are contains the images needed for the ide to run,
// including ide-desktop, desktop-plugin and so on
repeated string ide_image_layers = 10;
}

// PortSpec describes a networking port exposed on a workspace
Expand Down Expand Up @@ -567,6 +571,13 @@ message StartWorkspaceSpec {

// ssh_public_keys is user's uploaded ssh public keys
repeated string ssh_public_keys = 15;

// sys_envvars are system level environment variables which ought to be available in the workspace
repeated EnvironmentVariable sys_envvars = 16;

// ide_image_layers are contains the images needed for the ide to run,
// including ide-desktop, desktop-plugin and so on
repeated string ide_image_layers = 17;
}

// WorkspaceFeatureFlag enable non-standard behaviour in workspaces
Expand Down
Loading