diff --git a/e2e/test_support.go b/e2e/test_support.go index 6d27b6e350..4f5ada9dd2 100644 --- a/e2e/test_support.go +++ b/e2e/test_support.go @@ -23,6 +23,8 @@ package e2e import ( "context" + "errors" + "fmt" "time" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -35,6 +37,7 @@ import ( projectv1 "github.com/openshift/api/project/v1" "github.com/spf13/cobra" "io/ioutil" + appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -121,6 +124,16 @@ func integrationPodPhase(ns string, name string) func() v1.PodPhase { } } +func integrationPodImage(ns string, name string) func() string { + return func() string { + pod := integrationPod(ns, name)() + if pod == nil || len(pod.Spec.Containers) == 0 { + return "" + } + return pod.Spec.Containers[0].Image + } +} + func integrationPod(ns string, name string) func() *v1.Pod { return func() *v1.Pod { lst := v1.PodList{ @@ -145,6 +158,86 @@ func integrationPod(ns string, name string) func() *v1.Pod { } } +func integration(ns string, name string) func() *v1alpha1.Integration { + return func() *v1alpha1.Integration { + it := v1alpha1.NewIntegration(ns, name) + key := k8sclient.ObjectKey{ + Namespace: ns, + Name: name, + } + if err := testClient.Get(testContext, key, &it); err != nil && !k8serrors.IsNotFound(err) { + panic(err) + } else if err != nil && k8serrors.IsNotFound(err) { + return nil + } + return &it + } +} + +func integrationVersion(ns string, name string) func() string { + return func() string { + it := integration(ns, name)() + if it == nil { + return "" + } + return it.Status.Version + } +} + +func setIntegrationVersion(ns string, name string, version string) error { + it := integration(ns, name)() + if it == nil { + return fmt.Errorf("no integration named %s found", name) + } + it.Status.Version = version + return testClient.Status().Update(testContext, it) +} + +func setIntegrationPhase(ns string, name string, phase v1alpha1.IntegrationPhase) error { + it := integration(ns, name)() + if it == nil { + return fmt.Errorf("no integration named %s found", name) + } + it.Status.Phase = phase + return testClient.Status().Update(testContext, it) +} + +func kits(ns string) func() []v1alpha1.IntegrationKit { + return func() []v1alpha1.IntegrationKit { + lst := v1alpha1.NewIntegrationKitList() + opts := k8sclient.ListOptions{ + Namespace: ns, + } + if err := testClient.List(testContext, &opts, &lst); err != nil { + panic(err) + } + return lst.Items + } +} + +func kitsWithVersion(ns string, version string) func() int { + return func() int { + count := 0 + for _, k := range kits(ns)() { + if k.Status.Version == version { + count++ + } + } + return count + } +} + +func setAllKitsVersion(ns string, version string) error { + for _, k := range kits(ns)() { + kit := k + kit.Status.Version = version + if err := testClient.Status().Update(testContext, &kit); err != nil { + return err + } + } + return nil +} + func operatorImage(ns string) func() string { return func() string { pod := operatorPod(ns)() @@ -200,6 +293,44 @@ func build(ns string, name string) func() *v1alpha1.Build { } } +func platform(ns string) func() *v1alpha1.IntegrationPlatform { + return func() *v1alpha1.IntegrationPlatform { + lst := v1alpha1.NewIntegrationPlatformList() + opts := k8sclient.ListOptions{ + Namespace: ns, + } + if err := testClient.List(testContext, &opts, &lst); err != nil { + panic(err) + } + if len(lst.Items) == 0 { + return nil + } + if len(lst.Items) > 1 { + panic("multiple integration platforms found in namespace " + ns) + } + return &lst.Items[0] + } +} + +func setPlatformVersion(ns string, version string) error { + p := platform(ns)() + if p == nil { + return errors.New("no platform found") + } + p.Status.Version = version + return testClient.Status().Update(testContext, p) +} + +func platformVersion(ns string) func() string { + return func() string { + p := platform(ns)() + if p == nil { + return "" + } + return p.Status.Version + } +} + func operatorPod(ns string) func() *v1.Pod { return func() *v1.Pod { lst := v1.PodList{ @@ -224,6 +355,55 @@ func operatorPod(ns string) func() *v1.Pod { } } +func operatorTryPodForceKill(ns string) { + pod := operatorPod(ns)() + if pod != nil { + opts := func(options *k8sclient.DeleteOptions) { + zero := int64(0) + options.GracePeriodSeconds = &zero + } + if err := testClient.Delete(testContext, pod, opts); err != nil { + log.Error(err, "cannot forcefully kill the pod") + } + } +} + +func scaleOperator(ns string, replicas int32) error { + lst := appsv1.DeploymentList{ + TypeMeta: metav1.TypeMeta{ + Kind: "Deployment", + APIVersion: appsv1.SchemeGroupVersion.String(), + }, + } + opts := k8sclient.ListOptions{ + LabelSelector: labels.SelectorFromSet(labels.Set{ + "camel.apache.org/component": "operator", + }), + Namespace: ns, + } + if err := testClient.List(testContext, &opts, &lst); err != nil { + return err + } + if len(lst.Items) == 0 { + return errors.New("camel k operator not found") + } else if len(lst.Items) > 1 { + return errors.New("too many camel k operators") + } + + operatorDeployment := lst.Items[0] + operatorDeployment.Spec.Replicas = &replicas + err := testClient.Update(testContext, &operatorDeployment) + if err != nil { + return err + } + + if replicas == 0 { + // speedup scale down by killing the pod + operatorTryPodForceKill(ns) + } + return nil +} + /* Namespace testing functions */ diff --git a/e2e/upgrade_test.go b/e2e/upgrade_test.go new file mode 100644 index 0000000000..1469e98085 --- /dev/null +++ b/e2e/upgrade_test.go @@ -0,0 +1,93 @@ +// +build integration + +// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration" + +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "testing" + "time" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/defaults" + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" +) + +func TestPlatformUpgrade(t *testing.T) { + withNewTestNamespace(func(ns string) { + RegisterTestingT(t) + Expect(kamel("install", "-n", ns).Execute()).Should(BeNil()) + Eventually(platformVersion(ns)).Should(Equal(defaults.Version)) + + // Scale the operator down to zero + Expect(scaleOperator(ns, 0)).Should(BeNil()) + Eventually(operatorPod(ns)).Should(BeNil()) + + // Change the version to an older one + Expect(setPlatformVersion(ns, "an.older.one")).Should(BeNil()) + Eventually(platformVersion(ns)).Should(Equal("an.older.one")) + + // Scale the operator up + Expect(scaleOperator(ns, 1)).Should(BeNil()) + Eventually(operatorPod(ns)).ShouldNot(BeNil()) + + // Check the platform version change + Eventually(platformVersion(ns)).Should(Equal(defaults.Version)) + }) +} + +func TestIntegrationUpgrade(t *testing.T) { + withNewTestNamespace(func(ns string) { + RegisterTestingT(t) + Expect(kamel("install", "-n", ns).Execute()).Should(BeNil()) + Eventually(platformVersion(ns)).Should(Equal(defaults.Version)) + + // Run an integration + Expect(kamel("run", "-n", ns, "files/js.js").Execute()).Should(BeNil()) + Eventually(integrationPodPhase(ns, "js"), 5*time.Minute).Should(Equal(v1.PodRunning)) + initialImage := integrationPodImage(ns, "js")() + + // Scale the operator down to zero + Expect(scaleOperator(ns, 0)).Should(BeNil()) + Eventually(operatorPod(ns)).Should(BeNil()) + + // Change the version to an older one + Expect(setIntegrationVersion(ns, "js", "an.older.one")).Should(BeNil()) + Expect(setAllKitsVersion(ns, "an.older.one")).Should(BeNil()) + Eventually(integrationVersion(ns, "js")).Should(Equal("an.older.one")) + Eventually(kitsWithVersion(ns, "an.older.one")).Should(Equal(1)) + Eventually(kitsWithVersion(ns, defaults.Version)).Should(Equal(0)) + + // Scale the operator up + Expect(scaleOperator(ns, 1)).Should(BeNil()) + Eventually(operatorPod(ns)).ShouldNot(BeNil()) + + // Clear the integration phase + Expect(setIntegrationPhase(ns, "js", v1alpha1.IntegrationPhaseNone)).Should(BeNil()) + + // Check the integration version change + Eventually(integrationVersion(ns, "js")).Should(Equal(defaults.Version)) + Eventually(kitsWithVersion(ns, "an.older.one")).Should(Equal(1)) // old one is not recycled + Eventually(kitsWithVersion(ns, defaults.Version)).Should(Equal(1)) + Eventually(integrationPodImage(ns, "js")).ShouldNot(Equal(initialImage)) // rolling deployment triggered + Eventually(integrationPodPhase(ns, "js"), 5*time.Minute).Should(Equal(v1.PodRunning)) + }) +} diff --git a/go.mod b/go.mod index be5c294555..a919738e88 100644 --- a/go.mod +++ b/go.mod @@ -57,14 +57,16 @@ require ( go.uber.org/atomic v1.3.2 // indirect go.uber.org/multierr v1.1.0 go.uber.org/zap v1.9.1 // indirect + golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect + golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect google.golang.org/appengine v1.5.0 // indirect gopkg.in/yaml.v2 v2.2.2 k8s.io/api v0.0.0-20190222213804-5cb15d344471 k8s.io/apiextensions-apiserver v0.0.0-20190228180357-d002e88f6236 // indirect k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4 - k8s.io/klog v0.3.0 // indirect + k8s.io/klog v0.3.1 // indirect k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22 // indirect sigs.k8s.io/controller-runtime v0.1.10 sigs.k8s.io/testing_frameworks v0.1.1 // indirect diff --git a/go.sum b/go.sum index 7815291add..ff29b1a71b 100644 --- a/go.sum +++ b/go.sum @@ -272,6 +272,8 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -285,6 +287,8 @@ golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -302,6 +306,9 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= @@ -355,10 +362,11 @@ k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 h1:UYfHH+KEF88OTg+GojQUwF k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4 h1:aE8wOCKuoRs2aU0OP/Rz8SXiAB0FTTku3VtGhhrkSmc= k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68= +k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22 h1:f0BTap/vrgs21vVbJ1ySdsNtcivpA1x4ut6Wla9HKKw= k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22/go.mod h1:iU+ZGYsNlvU9XKUSso6SQfKTCCw7lFduMZy26Mgr2Fw= sigs.k8s.io/controller-runtime v0.1.10 h1:amLOmcekVdnsD1uIpmgRqfTbQWJ2qxvQkcdeFhcotn4= diff --git a/pkg/apis/camel/v1alpha1/integration_types.go b/pkg/apis/camel/v1alpha1/integration_types.go index a3b211f6fa..d2d9ee0f60 100644 --- a/pkg/apis/camel/v1alpha1/integration_types.go +++ b/pkg/apis/camel/v1alpha1/integration_types.go @@ -49,6 +49,7 @@ type IntegrationStatus struct { CamelVersion string `json:"camelVersion,omitempty"` RuntimeVersion string `json:"runtimeVersion,omitempty"` Configuration []ConfigurationSpec `json:"configuration,omitempty"` + Version string `json:"version,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/camel/v1alpha1/integrationkit_types.go b/pkg/apis/camel/v1alpha1/integrationkit_types.go index 3a9b77066e..f4c584fa6c 100644 --- a/pkg/apis/camel/v1alpha1/integrationkit_types.go +++ b/pkg/apis/camel/v1alpha1/integrationkit_types.go @@ -43,6 +43,7 @@ type IntegrationKitStatus struct { Failure *Failure `json:"failure,omitempty"` CamelVersion string `json:"camelVersion,omitempty"` RuntimeVersion string `json:"runtimeVersion,omitempty"` + Version string `json:"version,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/camel/v1alpha1/integrationplatform_types.go b/pkg/apis/camel/v1alpha1/integrationplatform_types.go index fa52d438fd..e997d2cd80 100644 --- a/pkg/apis/camel/v1alpha1/integrationplatform_types.go +++ b/pkg/apis/camel/v1alpha1/integrationplatform_types.go @@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + package v1alpha1 import ( @@ -39,7 +40,8 @@ type IntegrationPlatformResourcesSpec struct { // IntegrationPlatformStatus defines the observed state of IntegrationPlatform type IntegrationPlatformStatus struct { - Phase IntegrationPlatformPhase `json:"phase,omitempty"` + Phase IntegrationPlatformPhase `json:"phase,omitempty"` + Version string `json:"version,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/integration/build_kit.go b/pkg/controller/integration/build_kit.go index eda6aa1acb..0af3d82d7a 100644 --- a/pkg/controller/integration/build_kit.go +++ b/pkg/controller/integration/build_kit.go @@ -58,8 +58,12 @@ func (action *buildKitAction) Handle(ctx context.Context, integration *v1alpha1. // out of sync if the integration that has generated it, has been // amended to add/remove dependencies + versionMatch := kit.Status.Version == integration.Status.Version + //TODO: this is a very simple check, we may need to provide a deps comparison strategy - if !util.StringSliceContains(kit.Spec.Dependencies, integration.Status.Dependencies) { + dependenciesMatch := util.StringSliceContains(kit.Spec.Dependencies, integration.Status.Dependencies) + + if !dependenciesMatch || !versionMatch { // We need to re-generate a kit or search for a new one that // satisfies integrations needs so let's remove the association // with a kit diff --git a/pkg/controller/integration/initialize.go b/pkg/controller/integration/initialize.go index 53be34d68b..325e8e8466 100644 --- a/pkg/controller/integration/initialize.go +++ b/pkg/controller/integration/initialize.go @@ -22,6 +22,7 @@ import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/pkg/trait" + "github.com/apache/camel-k/pkg/util/defaults" ) // NewInitializeAction creates a new initialize action @@ -52,6 +53,7 @@ func (action *initializeAction) Handle(ctx context.Context, integration *v1alpha integration.Status.Phase = v1alpha1.IntegrationPhaseBuildingKit integration.Status.Kit = integration.Spec.Kit integration.Status.Image = "" + integration.Status.Version = defaults.Version return integration, nil } diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go index f4ff480703..1da8bf0898 100644 --- a/pkg/controller/integration/monitor.go +++ b/pkg/controller/integration/monitor.go @@ -21,6 +21,7 @@ import ( "context" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/defaults" "github.com/apache/camel-k/pkg/util/digest" ) @@ -52,6 +53,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1alpha1.I integration.Status.Digest = hash integration.Status.Phase = v1alpha1.IntegrationPhaseInitialization + integration.Status.Version = defaults.Version return integration, nil } diff --git a/pkg/controller/integration/util.go b/pkg/controller/integration/util.go index 3504259bab..7de88d242c 100644 --- a/pkg/controller/integration/util.go +++ b/pkg/controller/integration/util.go @@ -66,6 +66,9 @@ func LookupKitForIntegration(ctx context.Context, c k8sclient.Reader, integratio if ctx.Status.RuntimeVersion != integration.Status.RuntimeVersion { continue } + if ctx.Status.Version != integration.Status.Version { + continue + } if allowed, ok := allowedLookupLabels[ctx.Labels["camel.apache.org/kit.type"]]; ok && allowed { ideps := len(integration.Status.Dependencies) diff --git a/pkg/controller/integrationkit/initialize.go b/pkg/controller/integrationkit/initialize.go index cfdb138e78..404e149014 100644 --- a/pkg/controller/integrationkit/initialize.go +++ b/pkg/controller/integrationkit/initialize.go @@ -22,6 +22,7 @@ import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/pkg/trait" + "github.com/apache/camel-k/pkg/util/defaults" ) // NewInitializeAction creates a new initialization handling action for the kit @@ -58,6 +59,7 @@ func (action *initializeAction) Handle(ctx context.Context, kit *v1alpha1.Integr // and set the image to be used kit.Status.Image = kit.Spec.Image } + kit.Status.Version = defaults.Version return kit, nil } diff --git a/pkg/controller/integrationplatform/initialize.go b/pkg/controller/integrationplatform/initialize.go index 2c499496ac..e38794160f 100644 --- a/pkg/controller/integrationplatform/initialize.go +++ b/pkg/controller/integrationplatform/initialize.go @@ -148,6 +148,7 @@ func (action *initializeAction) Handle(ctx context.Context, platform *v1alpha1.I } else { platform.Status.Phase = v1alpha1.IntegrationPlatformPhaseCreating } + platform.Status.Version = defaults.Version return platform, nil } diff --git a/pkg/controller/integrationplatform/integrationplatform_controller.go b/pkg/controller/integrationplatform/integrationplatform_controller.go index 49f5bb4665..21acde22f4 100644 --- a/pkg/controller/integrationplatform/integrationplatform_controller.go +++ b/pkg/controller/integrationplatform/integrationplatform_controller.go @@ -129,6 +129,7 @@ func (r *ReconcileIntegrationPlatform) Reconcile(request reconcile.Request) (rec NewInitializeAction(), NewWarmAction(), NewCreateAction(), + NewMonitorAction(), } var targetPhase camelv1alpha1.IntegrationPlatformPhase diff --git a/pkg/controller/integrationplatform/monitor.go b/pkg/controller/integrationplatform/monitor.go new file mode 100644 index 0000000000..f8509e12e5 --- /dev/null +++ b/pkg/controller/integrationplatform/monitor.go @@ -0,0 +1,52 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integrationplatform + +import ( + "context" + "github.com/apache/camel-k/pkg/util/defaults" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" +) + +// NewMonitorAction returns an action that monitors the integration platform after it's fully initialized +func NewMonitorAction() Action { + return &monitorAction{} +} + +type monitorAction struct { + baseAction +} + +func (action *monitorAction) Name() string { + return "monitor" +} + +func (action *monitorAction) CanHandle(platform *v1alpha1.IntegrationPlatform) bool { + return platform.Status.Phase == v1alpha1.IntegrationPlatformPhaseReady +} + +func (action *monitorAction) Handle(ctx context.Context, platform *v1alpha1.IntegrationPlatform) (*v1alpha1.IntegrationPlatform, error) { + // Just track the version of the operator in the platform resource + if platform.Status.Version != defaults.Version { + platform.Status.Version = defaults.Version + action.L.Info("IntegrationPlatform version updated", "version", platform.Status.Version) + } + + return platform, nil +} diff --git a/testing b/testing new file mode 100755 index 0000000000..01cd65fa7e Binary files /dev/null and b/testing differ