This is an automated email from the ASF dual-hosted git repository. orpiske pushed a commit to branch camel-main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 5edd5df80768226ecd92f4ba9766012fe3966ae0 Author: Luca Burgazzoli <lburgazz...@gmail.com> AuthorDate: Fri Jun 4 14:55:14 2021 +0200 Make it possible to define the ocontainer image without IntegrationKit --- pkg/controller/integration/initialize.go | 42 ++++---- pkg/controller/integrationkit/monitor.go | 5 + pkg/resources/resources.go | 4 +- pkg/trait/container.go | 54 ++++++++-- pkg/trait/container_test.go | 179 +++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 33 deletions(-) diff --git a/pkg/controller/integration/initialize.go b/pkg/controller/integration/initialize.go index 04a95b4..7a55d80 100644 --- a/pkg/controller/integration/initialize.go +++ b/pkg/controller/integration/initialize.go @@ -55,30 +55,32 @@ func (action *initializeAction) Handle(ctx context.Context, integration *v1.Inte return nil, err } - if integration.Spec.IntegrationKit == nil && integration.Spec.Kit != "" { - // TODO: temporary fallback until deprecated field gets removed - integration.Spec.IntegrationKit = &corev1.ObjectReference{ - Name: integration.Spec.Kit, + if integration.Status.IntegrationKit == nil { + if integration.Spec.IntegrationKit == nil && integration.Spec.Kit != "" { + // TODO: temporary fallback until deprecated field gets removed + integration.Spec.IntegrationKit = &corev1.ObjectReference{ + Name: integration.Spec.Kit, + } } - } - if integration.Spec.IntegrationKit != nil && integration.Spec.IntegrationKit.Name != "" { - kitNamespace := integration.Spec.IntegrationKit.Namespace - kitName := integration.Spec.IntegrationKit.Name - - if kitNamespace == "" { - pl, err := platform.GetCurrent(ctx, action.client, integration.Namespace) - if err != nil && !k8serrors.IsNotFound(err) { - return nil, err - } - if pl != nil { - kitNamespace = pl.Namespace + if integration.Spec.IntegrationKit != nil && integration.Spec.IntegrationKit.Name != "" { + kitNamespace := integration.Spec.IntegrationKit.Namespace + kitName := integration.Spec.IntegrationKit.Name + + if kitNamespace == "" { + pl, err := platform.GetCurrent(ctx, action.client, integration.Namespace) + if err != nil && !k8serrors.IsNotFound(err) { + return nil, err + } + if pl != nil { + kitNamespace = pl.Namespace + } } + kit := v1.NewIntegrationKit(kitNamespace, kitName) + integration.SetIntegrationKit(&kit) + } else { + integration.Status.IntegrationKit = nil } - kit := v1.NewIntegrationKit(kitNamespace, kitName) - integration.SetIntegrationKit(&kit) - } else { - integration.Status.IntegrationKit = nil } integration.Status.Phase = v1.IntegrationPhaseBuildingKit diff --git a/pkg/controller/integrationkit/monitor.go b/pkg/controller/integrationkit/monitor.go index 84177b1..336a574 100644 --- a/pkg/controller/integrationkit/monitor.go +++ b/pkg/controller/integrationkit/monitor.go @@ -54,6 +54,11 @@ func (action *monitorAction) Handle(ctx context.Context, kit *v1.IntegrationKit) return kit, nil } + if kit.Spec.Image != "" && kit.Spec.Image != kit.Status.Image { + kit.Status.Phase = v1.IntegrationKitPhaseInitialization + + return kit, nil + } return nil, nil } diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index 0a7b203..46a12d1 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -474,9 +474,9 @@ var assets = func() http.FileSystem { "/traits.yaml": &vfsgen۰CompressedFileInfo{ name: "traits.yaml", modTime: time.Time{}, - uncompressedSize: 38748, + uncompressedSize: 38972, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x6d\x6f\x1c\x37\xd2\xe0\x77\xff\x0a\x42\xcf\x01\x7a\xc1\x4c\x4b\xce\x22\xbb\x39\xdd\xf9\x16\x8a\xed\xec\x2a\x89\x6d\x9d\xe5\xcd\xe2\xe0\x0b\x76\x38\xdd\x35\x33\xb4\xd8\x64\x2f\xc9\x96\x3c\x39\xdc\x7f\x3f\xb0\x8a\x6f\x3d\xd3\x92\x46\x4e\x14\x44\x87\x67\xf7\x43\x2c\xa9\xbb\x58\x2c\x16\xeb\xbd\xaa\x9d\xe1\xc2\xd9\xd3\x67\x53\xa6\x78\x0b\xa7\x8c\x2f\x16\x42\x09\xb7\x7e\xc6\x58\x27\xb9\x5b\x68\xd3\x9e\xb2\x05\x97\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x7b\x73\x1c\x37\xf2\xd8\xff\xfa\x14\x28\xfe\x52\xc5\x47\xed\x0e\x29\x5f\x7c\xe7\x30\x51\xae\x68\x49\xbe\xa3\x6d\x49\x8c\xa8\xf3\x55\x4a\x71\xdd\x62\x67\x7a\x77\x21\x62\x80\x39\x00\x43\x6a\x9d\xca\x77\x4f\xa1\x1b\xaf\xd9\x1d\x92\x4b\xd9\x74\x99\xa9\xdc\xfd\x61\x91\x9c\x69\x34\x1a\x8d\x7e\x77\x8f\x33\x5c\x38\x7b\xfa\x6c\xca\x14\x6f\xe1\x94\xf1\xc5\x42\x28\xe1\xd6\xcf\x18\xeb\x24\x77\x0b\x6d\xda\x53\xb6\xe0\xd2\x [...] }, } fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{ diff --git a/pkg/trait/container.go b/pkg/trait/container.go index 11dcb61..65781bb 100644 --- a/pkg/trait/container.go +++ b/pkg/trait/container.go @@ -76,6 +76,8 @@ type containerTrait struct { // The main container name. It's named `integration` by default. Name string `property:"name" json:"name,omitempty"` + // The main container image + Image string `property:"image" json:"image,omitempty"` // ProbesEnabled enable/disable probes on the container (default `false`) ProbesEnabled *bool `property:"probes-enabled" json:"probesEnabled,omitempty"` @@ -141,7 +143,7 @@ func (t *containerTrait) Configure(e *Environment) (bool, error) { func (t *containerTrait) Apply(e *Environment) error { if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) { - t.configureDependencies(e) + return t.configureDependencies(e) } if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) { @@ -156,21 +158,51 @@ func (t *containerTrait) IsPlatformTrait() bool { return true } -func (t *containerTrait) configureDependencies(e *Environment) { - if util.IsNilOrFalse(t.ProbesEnabled) { - return - } - +func (t *containerTrait) configureDependencies(e *Environment) error { if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) { - if capability, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityHealth]; ok { - for _, dependency := range capability.Dependencies { - util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID()) + if t.Image != "" { + if e.Integration.Spec.IntegrationKit != nil { + return fmt.Errorf( + "unsupported configuration: a container image has been set in conjunction with an IntegrationKit %v", + e.Integration.Spec.IntegrationKit) + } + if e.Integration.Spec.Kit != "" { + return fmt.Errorf( + "unsupported configuration: a container image has been set in conjunction with an IntegrationKit %s", + e.Integration.Spec.Kit) + } + + kitName := fmt.Sprintf("kit-%s", e.Integration.Name) + kit := v1.NewIntegrationKit(e.Integration.Namespace, kitName) + kit.Spec.Image = t.Image + + // Add some information for post-processing, this may need to be refactored + // to a proper data structure + kit.Labels = map[string]string{ + "camel.apache.org/kit.type": v1.IntegrationKitTypeExternal, + "camel.apache.org/created.by.kind": v1.IntegrationKind, + "camel.apache.org/created.by.name": e.Integration.Name, + "camel.apache.org/created.by.namespace": e.Integration.Namespace, + "camel.apache.org/created.by.version": e.Integration.ResourceVersion, } - // sort the dependencies to get always the same list if they don't change - sort.Strings(e.Integration.Status.Dependencies) + t.L.Infof("image %s", kit.Spec.Image) + e.Resources.Add(&kit) + e.Integration.SetIntegrationKit(&kit) + } + if util.IsTrue(t.ProbesEnabled) { + if capability, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityHealth]; ok { + for _, dependency := range capability.Dependencies { + util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID()) + } + + // sort the dependencies to get always the same list if they don't change + sort.Strings(e.Integration.Status.Dependencies) + } } } + + return nil } // nolint:gocyclo diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go index a4610ee..9952aa8 100644 --- a/pkg/trait/container_test.go +++ b/pkg/trait/container_test.go @@ -19,12 +19,15 @@ package trait import ( "context" + "github.com/google/uuid" + "k8s.io/apimachinery/pkg/types" "testing" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime/pkg/client" v1 "github.com/apache/camel-k/pkg/apis/camel/v1" "github.com/apache/camel-k/pkg/util/camel" @@ -148,3 +151,179 @@ func TestContainerWithCustomName(t *testing.T) { trait := test.TraitSpecToMap(t, environment.Integration.Spec.Traits["container"]) assert.Equal(t, trait["name"], d.Spec.Template.Spec.Containers[0].Name) } + +func TestContainerWithCustomImage(t *testing.T) { + catalog, err := camel.DefaultCatalog() + assert.Nil(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(context.TODO(), nil) + + environment := Environment{ + C: context.TODO(), + Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: ServiceTestName, + Namespace: "ns", + UID: types.UID(uuid.NewString()), + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseInitialization, + }, + Spec: v1.IntegrationSpec{ + Profile: v1.TraitProfileKubernetes, + Traits: map[string]v1.TraitSpec{ + "container": test.TraitSpecFromMap(t, map[string]interface{}{ + "image": "foo/bar:1.0.0", + }), + }, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterOpenShift, + Build: v1.IntegrationPlatformBuildSpec{ + PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, + Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, + }, + }, + }, + EnvVars: make([]corev1.EnvVar, 0), + ExecutedTraits: make([]Trait, 0), + Resources: kubernetes.NewCollection(), + } + environment.Platform.ResyncStatusFullConfig() + + err = traitCatalog.apply(&environment) + assert.Nil(t, err) + + for _, postAction := range environment.PostActions { + assert.Nil(t, postAction(&environment)) + } + + assert.NotEmpty(t, environment.ExecutedTraits) + assert.NotNil(t, environment.GetTrait("deployer")) + assert.NotNil(t, environment.GetTrait("container")) + assert.Equal(t, "kit-"+ServiceTestName, environment.Integration.Status.IntegrationKit.Name) + + ikt := v1.IntegrationKit{} + key := ctrl.ObjectKey{ + Namespace: "ns", + Name: "kit-" + ServiceTestName, + } + + err = client.Get(context.TODO(), key, &ikt) + assert.Nil(t, err) + assert.Equal(t, environment.Integration.ObjectMeta.UID, ikt.ObjectMeta.OwnerReferences[0].UID) + + trait := test.TraitSpecToMap(t, environment.Integration.Spec.Traits["container"]) + assert.Equal(t, trait["image"], ikt.Spec.Image) +} + +func TestContainerWithCustomImageAndIntegrationKit(t *testing.T) { + catalog, err := camel.DefaultCatalog() + assert.Nil(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(context.TODO(), nil) + + environment := Environment{ + C: context.TODO(), + Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: ServiceTestName, + Namespace: "ns", + UID: types.UID(uuid.NewString()), + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseInitialization, + }, + Spec: v1.IntegrationSpec{ + Profile: v1.TraitProfileKubernetes, + Traits: map[string]v1.TraitSpec{ + "container": test.TraitSpecFromMap(t, map[string]interface{}{ + "image": "foo/bar:1.0.0", + }), + }, + IntegrationKit: &corev1.ObjectReference{ + Name: "bad-" + ServiceTestName, + Namespace: "ns", + }, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterOpenShift, + Build: v1.IntegrationPlatformBuildSpec{ + PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, + Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, + }, + }, + }, + EnvVars: make([]corev1.EnvVar, 0), + ExecutedTraits: make([]Trait, 0), + Resources: kubernetes.NewCollection(), + } + environment.Platform.ResyncStatusFullConfig() + + err = traitCatalog.apply(&environment) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "unsupported configuration: a container image has been set in conjunction with an IntegrationKit") +} + +func TestContainerWithCustomImageAndDeprecatedIntegrationKit(t *testing.T) { + catalog, err := camel.DefaultCatalog() + assert.Nil(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(context.TODO(), nil) + + environment := Environment{ + C: context.TODO(), + Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: ServiceTestName, + Namespace: "ns", + UID: types.UID(uuid.NewString()), + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseInitialization, + }, + Spec: v1.IntegrationSpec{ + Profile: v1.TraitProfileKubernetes, + Traits: map[string]v1.TraitSpec{ + "container": test.TraitSpecFromMap(t, map[string]interface{}{ + "image": "foo/bar:1.0.0", + }), + }, + Kit: "bad-" + ServiceTestName, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterOpenShift, + Build: v1.IntegrationPlatformBuildSpec{ + PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, + Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, + }, + }, + }, + EnvVars: make([]corev1.EnvVar, 0), + ExecutedTraits: make([]Trait, 0), + Resources: kubernetes.NewCollection(), + } + environment.Platform.ResyncStatusFullConfig() + + err = traitCatalog.apply(&environment) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "unsupported configuration: a container image has been set in conjunction with an IntegrationKit") +}