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
2 changes: 2 additions & 0 deletions controllers/workspace/devworkspace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"time"

Expand Down Expand Up @@ -182,6 +183,7 @@ func (r *DevWorkspaceReconciler) Reconcile(req ctrl.Request) (reconcileResult ct
Context: ctx,
K8sClient: r.Client,
InternalRegistry: &registry.InternalRegistryImpl{},
HttpClient: http.DefaultClient,
}
flattenedWorkspace, err := flatten.ResolveDevWorkspace(workspace.Spec.Template, flattenHelpers)
if err != nil {
Expand Down
69 changes: 46 additions & 23 deletions pkg/library/flatten/flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ package flatten
import (
"context"
"fmt"

"github.com/devfile/devworkspace-operator/pkg/library/flatten/web_terminal"

registry "github.com/devfile/devworkspace-operator/pkg/library/flatten/internal_registry"
"net/url"
"path"

devworkspace "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/api/v2/pkg/utils/overriding"
registry "github.com/devfile/devworkspace-operator/pkg/library/flatten/internal_registry"
"github.com/devfile/devworkspace-operator/pkg/library/flatten/network"
"github.com/devfile/devworkspace-operator/pkg/library/flatten/web_terminal"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -32,6 +33,7 @@ type ResolverTools struct {
Context context.Context
K8sClient client.Client
InternalRegistry registry.InternalRegistry
HttpClient network.HTTPGetter
}

// ResolveDevWorkspace takes a devworkspace and returns a "resolved" version of it -- i.e. one where all plugins and parents
Expand Down Expand Up @@ -74,12 +76,11 @@ func recursiveResolve(workspace devworkspace.DevWorkspaceTemplateSpec, tooling R
// No action necessary
resolvedContent.Components = append(resolvedContent.Components, component)
} else {
pluginComponent, pluginMeta, err := resolvePluginComponent(component.Name, component.Plugin, tooling)
pluginComponent, err := resolvePluginComponent(component.Name, component.Plugin, tooling)
if err != nil {
return nil, err
}
newCtx := resolveCtx.addPlugin(component.Name, component.Plugin)
newCtx.pluginMetadata = pluginMeta
if err := newCtx.hasCycle(); err != nil {
return nil, err
}
Expand All @@ -105,24 +106,24 @@ func recursiveResolve(workspace devworkspace.DevWorkspaceTemplateSpec, tooling R
func resolvePluginComponent(
name string,
plugin *devworkspace.PluginComponent,
tooling ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, pluginMeta map[string]string, err error) {
tooling ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, err error) {
switch {
// TODO: Add support for plugin ID and URI
case plugin.Kubernetes != nil:
// Search in devworkspace's namespace if namespace ref is unset
if plugin.Kubernetes.Namespace == "" {
plugin.Kubernetes.Namespace = tooling.InstanceNamespace
}
resolvedPlugin, pluginMeta, err = resolvePluginComponentByKubernetesReference(name, plugin, tooling)
resolvedPlugin, err = resolvePluginComponentByKubernetesReference(name, plugin, tooling)
case plugin.Uri != "":
err = fmt.Errorf("failed to resolve plugin %s: only plugins specified by kubernetes reference or id are supported", name)
resolvedPlugin, err = resolvePluginComponentByURI(name, plugin, tooling)
case plugin.Id != "":
resolvedPlugin, pluginMeta, err = resolvePluginComponentById(name, plugin, tooling)
resolvedPlugin, err = resolvePluginComponentById(name, plugin, tooling)
default:
err = fmt.Errorf("plugin %s does not define any resources", name)
}
if err != nil {
return nil, nil, err
return nil, err
}

if plugin.Components != nil || plugin.Commands != nil {
Expand All @@ -132,17 +133,17 @@ func resolvePluginComponent(
})

if err != nil {
return nil, nil, err
return nil, err
}
resolvedPlugin.DevWorkspaceTemplateSpecContent = *overrideSpec
}
return resolvedPlugin, pluginMeta, nil
return resolvedPlugin, nil
}

func resolvePluginComponentByKubernetesReference(
name string,
plugin *devworkspace.PluginComponent,
tooling ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, pluginLabels map[string]string, err error) {
tooling ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, err error) {

var dwTemplate devworkspace.DevWorkspaceTemplate
namespacedName := types.NamespacedName{
Expand All @@ -152,32 +153,54 @@ func resolvePluginComponentByKubernetesReference(
err = tooling.K8sClient.Get(tooling.Context, namespacedName, &dwTemplate)
if err != nil {
if errors.IsNotFound(err) {
return nil, nil, fmt.Errorf("plugin for component %s not found", name)
return nil, fmt.Errorf("plugin for component %s not found", name)
}
return nil, nil, fmt.Errorf("failed to retrieve plugin referenced by kubernetes name and namespace '%s': %w", name, err)
return nil, fmt.Errorf("failed to retrieve plugin referenced by kubernetes name and namespace '%s': %w", name, err)
}
return &dwTemplate.Spec, dwTemplate.Labels, nil
return &dwTemplate.Spec, nil
}

func resolvePluginComponentById(
name string,
plugin *devworkspace.PluginComponent,
tools ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, pluginLabels map[string]string, err error) {
tools ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, err error) {

// Check internal registry for plugins that do not specify a registry
if plugin.RegistryUrl == "" {
if tools.InternalRegistry == nil {
return nil, nil, fmt.Errorf("plugin %s does not specify a registryUrl and no internal registry is configured", name)
return nil, fmt.Errorf("plugin %s does not specify a registryUrl and no internal registry is configured", name)
}
if !tools.InternalRegistry.IsInInternalRegistry(plugin.Id) {
return nil, nil, fmt.Errorf("plugin for component %s does not specify a registry and is not present in the internal registry", name)
return nil, fmt.Errorf("plugin for component %s does not specify a registry and is not present in the internal registry", name)
}
pluginDWT, err := tools.InternalRegistry.ReadPluginFromInternalRegistry(plugin.Id)
if err != nil {
return nil, nil, fmt.Errorf("failed to read plugin for component %s from internal registry: %w", name, err)
return nil, fmt.Errorf("failed to read plugin for component %s from internal registry: %w", name, err)
}
return &pluginDWT.Spec, pluginDWT.Labels, nil
return &pluginDWT.Spec, nil
}

pluginURL, err := url.Parse(plugin.RegistryUrl)
if err != nil {
return nil, fmt.Errorf("failed to parse registry URL for plugin %s: %w", name, err)
}
pluginURL.Path = path.Join(pluginURL.Path, "plugins", plugin.Id)

return nil, nil, fmt.Errorf("non-internal plugins not supported")
dwt, err := network.FetchDevWorkspaceTemplate(pluginURL.String(), tools.HttpClient)
if err != nil {
return nil, fmt.Errorf("failed to resolve plugin %s from registry %s: %w", name, plugin.RegistryUrl, err)
}
return dwt, nil
}

func resolvePluginComponentByURI(
name string,
plugin *devworkspace.PluginComponent,
tools ResolverTools) (resolvedPlugin *devworkspace.DevWorkspaceTemplateSpec, err error) {

dwt, err := network.FetchDevWorkspaceTemplate(plugin.Uri, tools.HttpClient)
if err != nil {
return nil, fmt.Errorf("failed to resolve plugin %s by URI: %w", name, err)
}
return dwt, nil
}
Loading