Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using imageName as a selector #6768

Merged
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
159 changes: 159 additions & 0 deletions docs/website/docs/development/devfile.md
Original file line number Diff line number Diff line change
@@ -313,6 +313,165 @@ is invoked, that is, in this example, when the `run` or `deploy` commands are in

Because the `kubernetes` component `k8s-deploybydefault-false-and-not-referenced` has `deployByDefault` set to `false` and is not referenced by any `apply` commands, it will never be applied.

### How `odo` handles image names

When the Devfile contains an Image Component with a relative `imageName` field, `odo` treats this field as an image name selector;
it will scan the whole Devfile and automatically replace matching image names with a unique value that will be pushed to a user-defined registry.
This replacement is done in matching Container components and manifests referenced in Kubernetes/OpenShift components.

An image is said to match a relative image name if they both have the same name, regardless of their registry, tag, or digest.

At the moment, `odo` only performs replacement in the manifests of the following core Kubernetes resources:
- [CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/)
- [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)
- [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
- [Job](https://kubernetes.io/docs/concepts/workloads/controllers/job/)
- [Pod](https://kubernetes.io/docs/concepts/workloads/pods/)
- [ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/)
- [ReplicationController](https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/)
- [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)

Replacement is done only if the user has set the `ImageRegistry` preference, which can be done via the `odo preference set ImageRegistry` command.
See the [Configuration](../overview/configure.md#configuring-global-settings) page for more details.

<details>
<summary>Example</summary>

```shell
$ odo preference set ImageRegistry quay.io/$USER
✓ Value of 'imageregistry' preference was set to 'quay.io/user'
```

</details>

In this case, `odo` will automatically build relative Image components and push them to the specified registry path defined in the Preferences,
using a dynamic image tag, so that the images built and pushed can be unique across executions of `odo`.

As an example, given the following Devfile excerpt (simplified to use only Kubernetes components, but the same behavior applies to OpenShift ones),
and provided the `ImageRegistry` preference has been set (say to `quay.io/user`):

```yaml
schemaVersion: 2.2.0

metadata:
name: my-app
version: 1.0.0

components:
- image:
imageName: "my-relative-image"
name: relative-image

- image:
imageName: "ghcr.io/myorg/my-absolute-image"
name: absolute-image

- container:
# [some-registry/]my-relative-image[:tag][@digest] will all match
# 'my-relative-image' defined in the `relative-image' component.
image: "my-relative-image"
name: cont1

- name: k8s-uri
kubernetes:
# Resources referenced via URIs will be resolved and inlined at runtime,
# so that replacement logic can also be applied on those manifests.
uri: kubernetes/k8s.yaml

- name: k8s-inlined
kubernetes:
inlined: |
apiVersion: batch/v1
kind: Job
metadata:
name: my-job
spec:
template:
metadata:
name: my-job-app
spec:
containers:
# Matches the imageName field of the 'relative-image' Image Component
# => it will be replaced dynamically regardless of the registry, tag or digest.
- image: "quay.io/my-relative-image@sha256:26c68657ccce2cb0a3"
name: my-main-cont1
initContainers:
- image: "busybox"
name: my-init-cont1
```

Because the `relative-image` Image component uses a relative image name (`my-relative-image`), it will automatically be built and pushed
by `odo` to an image named as follows: `<ImageRegistry>/<DevfileName>-<ImageName>:<SomeUniqueId>`,
where `<SomeUniqueId>` is a dynamic tag different for each execution of `odo`.
So the resulting image in the example above could be for instance: `quay.io/user/my-app-my-relative-image:1234567`

This new value will then be replaced in the following matching components and manifests:
- `cont1` container component
- the image name of `my-main-cont1` in the Job definition of the `k8s-inlined` Kubernetes component
- any matching image names in the manifests referenced by URIs in the `k8s-uri` Kubernetes component

For reference, the resulting Devfile generated by `odo` for this example would look like this:

<details>
<summary>Example</summary>

```yaml
schemaVersion: 2.2.0

metadata:
name: my-app
version: 1.0.0

components:
- image:
# highlight-next-line
imageName: "quay.io/user/my-app-my-relative-image:3295110"
name: relative-image

- image:
# Left unchanged: Absolute image names are not used as selectors.
imageName: "ghcr.io/myorg/my-absolute-image"
name: absolute-image

- container:
# highlight-next-line
image: "quay.io/user/my-app-my-relative-image:3295110"
name: cont1

- name: k8s-uri
kubernetes:
inlined: |
# highlight-start
# Resources referenced via URIs will be resolved and inlined at runtime,
# so that replacement logic can also be applied on those manifests.
# ...
# highlight-end

- name: k8s-inlined
kubernetes:
inlined: |
apiVersion: batch/v1
kind: Job
metadata:
name: my-job
spec:
template:
metadata:
name: my-job-app
spec:
containers:
# highlight-next-line
- image: "quay.io/user/my-app-my-relative-image:3295110"
name: my-main-cont1
initContainers:
# highlight-next-line
# Not replaced because it does not match 'my-relative-image'.
- image: "busybox"
name: my-init-cont1
```

</details>

## File Reference

This file reference outlines the **major** components of the Devfile API Reference using *snippets* and *examples*.
19 changes: 10 additions & 9 deletions docs/website/docs/overview/configure.md
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ Preference parameters:
PARAMETER VALUE
ConsentTelemetry true
Ephemeral true
ImageRegistry quay.io/user
PushTimeout
RegistryCacheTime
Timeout
@@ -113,15 +114,15 @@ Unsetting a preference key sets it to an empty value in the preference file. `od

### Preference Key Table

| Preference | Description | Default |
| ------------------ |--------------------------------------------------------------------------| ----------- |
| UpdateNotification | Control whether a notification to update `odo` is shown | True |
| Timeout | Timeout for Kubernetes server connection check | 1 second |
| PushTimeout | Timeout for waiting for a component to start | 240 seconds |
| RegistryCacheTime | Duration for which `odo` will cache information from the Devfile registry | 4 Minutes |
| Ephemeral | Control whether `odo` should create a emptyDir volume to store source code | False |
| ConsentTelemetry | Control whether `odo` can collect telemetry for the user's `odo` usage | False |

| Preference | Description | Default |
|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
| UpdateNotification | Control whether a notification to update `odo` is shown | True |
| Timeout | Timeout for Kubernetes server connection check | 1 second |
| PushTimeout | Timeout for waiting for a component to start | 240 seconds |
| RegistryCacheTime | Duration for which `odo` will cache information from the Devfile registry | 4 Minutes |
| Ephemeral | Control whether `odo` should create a emptyDir volume to store source code | False |
| ConsentTelemetry | Control whether `odo` can collect telemetry for the user's `odo` usage | False |
| ImageRegistry | The container image registry where relative image names will be automatically pushed to. See [How `odo` handles image names](../development/devfile.md#how-odo-handles-image-names) for more details. | |

## Managing Devfile registries

5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.5
github.com/Xuanwo/go-locale v1.1.0
github.com/blang/semver v3.5.1+incompatible
github.com/devfile/api/v2 v2.2.0
github.com/devfile/library/v2 v2.2.1-0.20230330160000-c1b23d25e652
github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd
github.com/devfile/library/v2 v2.2.1-0.20230515084048-f041d798707c
github.com/devfile/registry-support/index/generator v0.0.0-20230322155332-33914affc83b
github.com/devfile/registry-support/registry-library v0.0.0-20221201200738-19293ac0b8ab
github.com/fatih/color v1.14.1
@@ -93,6 +93,7 @@ require (
github.com/creack/pty v1.1.17 // indirect
github.com/danieljoos/wincred v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 // indirect
github.com/docker/cli v20.10.13+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.24+incompatible // indirect
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -368,13 +368,14 @@ github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devfile/api/v2 v2.0.0-20211021164004-dabee4e633ed/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q=
github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q=
github.com/devfile/api/v2 v2.2.0 h1:3Mwl/dtT508oU4pNt/v4G8vqvjoZqi9LOInXCNwKMoc=
github.com/devfile/api/v2 v2.2.0/go.mod h1:dN7xFrOVG+iPqn4UKGibXLd5oVsdE8XyK9OEb5JL3aI=
github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd h1:HpGR728CfB6BB9ZuFtQb0UeTIYNFgpuGsuoMOJNMUTM=
github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd/go.mod h1:qp8jcw12y1JdCsxjK/7LJ7uWaJOxcY1s2LUk5PhbkbM=
github.com/devfile/library v1.2.1-0.20211104222135-49d635cb492f/go.mod h1:uFZZdTuRqA68FVe/JoJHP92CgINyQkyWnM2Qyiim+50=
github.com/devfile/library v1.2.1-0.20220308191614-f0f7e11b17de/go.mod h1:GSPfJaBg0+bBjBHbwBE5aerJLH6tWGQu2q2rHYd9czM=
github.com/devfile/library/v2 v2.0.1/go.mod h1:paJ0PARAVy0br13VpBEQ4fO3rZVDxWtooQ29+23PNBk=
github.com/devfile/library/v2 v2.2.1-0.20230330160000-c1b23d25e652 h1:Lrg3ypN1LyGJ2yZAjU5tKh19tUPmHSH9dClyaxh6vko=
github.com/devfile/library/v2 v2.2.1-0.20230330160000-c1b23d25e652/go.mod h1:NWmKLN9RWVX5f4sCimjFtGX1REuXiYoBYU/Jcd11XAA=
github.com/devfile/library/v2 v2.2.1-0.20230515084048-f041d798707c h1:WXsJ/mP865odQ6yxP9MKULBg6N6lPmoBzMZ/Ur2y/5I=
github.com/devfile/library/v2 v2.2.1-0.20230515084048-f041d798707c/go.mod h1:7oEhkC6GW6OKmAP8HbxbaQ+nFbnACQuU7anYhJroltQ=
github.com/devfile/registry-support/index/generator v0.0.0-20220222194908-7a90a4214f3e/go.mod h1:iRPBxs+ZjfLEduVXpCCIOzdD2588Zv9OCs/CcXMcCCY=
github.com/devfile/registry-support/index/generator v0.0.0-20220527155645-8328a8a883be/go.mod h1:1fyDJL+fPHtcrYA6yjSVWeLmXmjCNth0d5Rq1rvtryc=
github.com/devfile/registry-support/index/generator v0.0.0-20221018203505-df96d34d4273/go.mod h1:ZJnaSLjTKCvGJhWmYgQoQ1O3g78qBe4Va6ZugLmi4dE=
@@ -386,7 +387,6 @@ github.com/devfile/registry-support/registry-library v0.0.0-20221201200738-19293
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/distribution/distribution v2.7.1+incompatible h1:aGFx4EvJWKEh//lHPLwFhFgwFHKH06TzNVPamrMn04M=
github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 h1:DBZ2sN7CK6dgvHVpQsQj4sRMCbWTmd17l+5SUCjnQSY=
github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684/go.mod h1:UfCu3YXJJCI+IdnqGgYP82dk2+Joxmv+mUTVBES6wac=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
5 changes: 2 additions & 3 deletions pkg/component/component_test.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import (
"testing"

devfilepkg "github.com/devfile/api/v2/pkg/devfile"
"github.com/devfile/library/v2/pkg/devfile"
"github.com/devfile/library/v2/pkg/devfile/parser"
devfileCtx "github.com/devfile/library/v2/pkg/devfile/parser/context"
"github.com/devfile/library/v2/pkg/devfile/parser/data"
@@ -24,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

"github.com/redhat-developer/odo/pkg/devfile"
"github.com/redhat-developer/odo/pkg/kclient"
"github.com/redhat-developer/odo/pkg/labels"
"github.com/redhat-developer/odo/pkg/libdevfile"
@@ -492,8 +492,7 @@ func TestGatherName(t *testing.T) {
return nil, dir, err
}

var d parser.DevfileObj
d, _, err = devfile.ParseDevfileAndValidate(parser.ParserArgs{Path: dPath})
d, err := devfile.ParseAndValidateFromFile(dPath, "", false)
if err != nil {
return nil, dir, err
}
2 changes: 1 addition & 1 deletion pkg/deploy/deploy.go
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ func NewDeployClient(kubeClient kclient.ClientInterface, configAutomountClient c

func (o *DeployClient) Deploy(ctx context.Context) error {
var (
devfileObj = odocontext.GetDevfileObj(ctx)
devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
devfilePath = odocontext.GetDevfilePath(ctx)
path = filepath.Dir(devfilePath)
componentName = odocontext.GetComponentName(ctx)
2 changes: 1 addition & 1 deletion pkg/dev/kubedev/cleanup.go
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ import (
func (o *DevClient) CleanupResources(ctx context.Context, out io.Writer) error {
var (
componentName = odocontext.GetComponentName(ctx)
devfileObj = odocontext.GetDevfileObj(ctx)
devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
)
fmt.Fprintln(out, "Cleaning resources, please wait")
appname := odocontext.GetApplication(ctx)
2 changes: 1 addition & 1 deletion pkg/dev/kubedev/kubedev.go
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ func (o *DevClient) Start(
// RegenerateAdapterAndPush get the new devfile and pushes the files to remote pod
func (o *DevClient) regenerateAdapterAndPush(ctx context.Context, pushParams common.PushParameters, componentStatus *watch.ComponentStatus) error {

devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables)
devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables, o.prefClient.GetImageRegistry(), true)
if err != nil {
return fmt.Errorf("unable to read devfile: %w", err)
}
2 changes: 1 addition & 1 deletion pkg/dev/podmandev/pod_test.go
Original file line number Diff line number Diff line change
@@ -1408,7 +1408,7 @@ func Test_createPodFromComponent(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
devfileObj := tt.args.devfileObj()
ctx = odocontext.WithDevfileObj(ctx, &devfileObj)
ctx = odocontext.WithEffectiveDevfileObj(ctx, &devfileObj)
ctx = odocontext.WithApplication(ctx, tt.args.appName)
ctx = odocontext.WithComponentName(ctx, tt.args.componentName)
ctx = odocontext.WithWorkingDirectory(ctx, "/tmp/dir")
8 changes: 6 additions & 2 deletions pkg/dev/podmandev/podmandev.go
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import (
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/podman"
"github.com/redhat-developer/odo/pkg/portForward"
"github.com/redhat-developer/odo/pkg/preference"
"github.com/redhat-developer/odo/pkg/state"
"github.com/redhat-developer/odo/pkg/sync"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
@@ -36,6 +37,7 @@ type DevClient struct {
fs filesystem.Filesystem

podmanClient podman.Client
prefClient preference.Client
portForwardClient portForward.Client
syncClient sync.Client
execClient exec.Client
@@ -51,6 +53,7 @@ var _ dev.Client = (*DevClient)(nil)
func NewDevClient(
fs filesystem.Filesystem,
podmanClient podman.Client,
prefClient preference.Client,
portForwardClient portForward.Client,
syncClient sync.Client,
execClient exec.Client,
@@ -60,6 +63,7 @@ func NewDevClient(
return &DevClient{
fs: fs,
podmanClient: podmanClient,
prefClient: prefClient,
portForwardClient: portForwardClient,
syncClient: syncClient,
execClient: execClient,
@@ -95,7 +99,7 @@ func (o *DevClient) Start(
// syncFiles syncs the local source files in path into the pod's source volume
func (o *DevClient) syncFiles(ctx context.Context, options dev.StartOptions, pod *corev1.Pod, path string) (bool, error) {
var (
devfileObj = odocontext.GetDevfileObj(ctx)
devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
componentName = odocontext.GetComponentName(ctx)
)

@@ -161,7 +165,7 @@ func (o *DevClient) checkVolumesFree(pod *corev1.Pod) error {

func (o *DevClient) watchHandler(ctx context.Context, pushParams common.PushParameters, componentStatus *watch.ComponentStatus) error {

devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables)
devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables, o.prefClient.GetImageRegistry(), true)
if err != nil {
return fmt.Errorf("unable to read devfile: %w", err)
}
Loading