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

Add ready condition to the integration #1438

Merged
merged 6 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions e2e/common/cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"testing"

. "github.com/apache/camel-k/e2e/support"
camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
)
Expand All @@ -38,6 +39,7 @@ func TestRunCronExample(t *testing.T) {

Expect(Kamel("run", "-n", ns, "files/cron.groovy").Execute()).Should(BeNil())
Eventually(IntegrationCronJob(ns, "cron"), TestTimeoutMedium).ShouldNot(BeNil())
Eventually(IntegrationCondition(ns, "cron", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "cron"), TestTimeoutMedium).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -47,6 +49,7 @@ func TestRunCronExample(t *testing.T) {

Expect(Kamel("run", "-n", ns, "files/cron-timer.groovy").Execute()).Should(BeNil())
Eventually(IntegrationCronJob(ns, "cron-timer"), TestTimeoutMedium).ShouldNot(BeNil())
Eventually(IntegrationCondition(ns, "cron", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "cron-timer"), TestTimeoutMedium).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -56,6 +59,7 @@ func TestRunCronExample(t *testing.T) {

Expect(Kamel("run", "-n", ns, "files/cron-fallback.groovy").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "cron-fallback"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "cron", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "cron-fallback"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand Down
15 changes: 10 additions & 5 deletions e2e/common/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,15 @@ limitations under the License.
package common

import (
"os"
"testing"

. "github.com/apache/camel-k/e2e/support"
camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
)

func TestRunSimpleExamples(t *testing.T) {
if os.Getenv("KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY") == "Buildah" {
t.Skip("Apparently this test require too much CI resources to be run with Buildah, let's save some...")
return
}

WithNewTestNamespace(t, func(ns string) {
Expect(Kamel("install", "-n", ns).Execute()).Should(BeNil())
Expand All @@ -43,6 +39,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/Java.java").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "java", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -51,6 +48,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/Prop.java", "--property-file", "files/prop.properties").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "prop"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "prop", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "prop"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -59,6 +57,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/xml.xml").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "xml"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "xml", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "xml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -67,6 +66,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/groovy.groovy").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "groovy"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "groovy", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "groovy"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -75,6 +75,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/js.js").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "js"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "js", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "js"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -83,6 +84,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/kotlin.kts").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "kotlin"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "kotlin", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "kotlin"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -91,6 +93,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "files/yaml.yaml").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "yaml"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "yaml", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "yaml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
})
Expand All @@ -99,6 +102,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "--name", "yaml-quarkus", "files/yaml.yaml", "-t", "quarkus.enabled=true").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "yaml-quarkus"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "yaml-quarkus", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "yaml-quarkus"), TestTimeoutShort).Should(ContainSubstring("powered by Quarkus"))
Eventually(IntegrationLogs(ns, "yaml-quarkus"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
Expand All @@ -108,6 +112,7 @@ func TestRunSimpleExamples(t *testing.T) {
RegisterTestingT(t)
Expect(Kamel("run", "-n", ns, "--name", "polyglot", "files/js-polyglot.js", "files/yaml-polyglot.yaml").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "polyglot"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "polyglot", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "polyglot"), TestTimeoutShort).Should(ContainSubstring("Magicpolyglot-yaml"))
Eventually(IntegrationLogs(ns, "polyglot"), TestTimeoutShort).Should(ContainSubstring("Magicpolyglot-js"))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
Expand Down
4 changes: 4 additions & 0 deletions e2e/knative/knative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

. "github.com/apache/camel-k/e2e/support"
camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
)
Expand All @@ -36,10 +37,13 @@ func TestRunServiceCombo(t *testing.T) {
Expect(Kamel("install", "-n", ns, "--trait-profile", "knative").Execute()).Should(BeNil())
Expect(Kamel("run", "-n", ns, "files/knative2.groovy").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "knative2"), TestTimeoutLong).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "knative2", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Expect(Kamel("run", "-n", ns, "files/knative3.groovy").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "knative3"), TestTimeoutLong).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "knative3", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Expect(Kamel("run", "-n", ns, "files/knative1.groovy").Execute()).Should(BeNil())
Eventually(IntegrationPodPhase(ns, "knative1"), TestTimeoutLong).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "knative1", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
// Correct logs
Eventually(IntegrationLogs(ns, "knative1"), TestTimeoutMedium).Should(ContainSubstring("Received from 2: Hello from knative2"))
Eventually(IntegrationLogs(ns, "knative1"), TestTimeoutMedium).Should(ContainSubstring("Received from 3: Hello from knative3"))
Expand Down
14 changes: 14 additions & 0 deletions e2e/support/test_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,20 @@ func IntegrationPod(ns string, name string) func() *corev1.Pod {
}
}

func IntegrationCondition(ns string, name string, conditionType v1.IntegrationConditionType) func() corev1.ConditionStatus {
return func() corev1.ConditionStatus {
it := Integration(ns, name)()
if it == nil {
return "IntegrationMissing"
}
c := it.Status.GetCondition(conditionType)
if c == nil {
return "ConditionMissing"
}
return c.Status
}
}

func ConfigMap(ns string, name string) func() *corev1.ConfigMap {
return func() *corev1.ConfigMap {
cm := corev1.ConfigMap{}
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/camel/v1/integration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ const (
IntegrationConditionJolokiaAvailable IntegrationConditionType = "JolokiaAvailable"
// IntegrationConditionProbesAvailable --
IntegrationConditionProbesAvailable IntegrationConditionType = "ProbesAvailable"
// IntegrationConditionReady --
IntegrationConditionReady IntegrationConditionType = "Ready"

// IntegrationConditionKitAvailableReason --
IntegrationConditionKitAvailableReason string = "IntegrationKitAvailable"
Expand Down Expand Up @@ -231,6 +233,10 @@ const (
IntegrationConditionJolokiaAvailableReason string = "JolokiaAvailable"
// IntegrationConditionProbesAvailableReason --
IntegrationConditionProbesAvailableReason string = "ProbesAvailable"
// IntegrationConditionErrorReason --
IntegrationConditionErrorReason string = "Error"
// IntegrationConditionCronJobCreatedReason --
IntegrationConditionCronJobCreatedReason string = "CronJobCreatedReason"
)

// IntegrationCondition describes the state of a resource at a certain point.
Expand Down
32 changes: 32 additions & 0 deletions pkg/controller/integration/integration_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import (

camelevent "github.com/apache/camel-k/pkg/event"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/batch/v1beta1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"

k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
Expand Down Expand Up @@ -200,6 +203,35 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
return err
}

// Watch deployment to update the ready condition
err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
OwnerType: &v1.Integration{},
IsController: false,
})
if err != nil {
return err
}

// Watch Knative service to update the ready condition
err = c.Watch(&source.Kind{Type: &servingv1.Service{}}, &handler.EnqueueRequestForOwner{
OwnerType: &v1.Integration{},
IsController: false,
})
if _, ok := err.(*meta.NoKindMatchError); ok {
log.Info("No watch has been set on Knative services because the type is not known")
} else if err != nil {
log.Error(err, "Cannot set watch on Knative services")
}

// Watch cronjob to update the ready condition
err = c.Watch(&source.Kind{Type: &v1beta1.CronJob{}}, &handler.EnqueueRequestForOwner{
OwnerType: &v1.Integration{},
IsController: false,
})
if err != nil {
return err
}

astefanutti marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/trait/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ func (t *deployerTrait) Apply(e *Environment) error {
}
return nil
})

// Mirror ready condition from the sub resource to the integration
e.PostActions = append(e.PostActions, func(e *Environment) error {
kubernetes.MirrorReadyCondition(t.Ctx, t.Client, e.Integration)
return nil
})
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/trait/deployer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestApplyDeployerTraitDoesSucceed(t *testing.T) {
err := deployerTrait.Apply(environment)

assert.Nil(t, err)
assert.Len(t, environment.PostActions, 1)
assert.Len(t, environment.PostActions, 2)
}

func TestApplyDeployerTraitInInitializationPhaseDoesSucceed(t *testing.T) {
Expand Down
101 changes: 101 additions & 0 deletions pkg/util/kubernetes/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package kubernetes

import (
"context"
"fmt"

v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/client"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/apis"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
)

// nolint: gocritic
func MirrorReadyCondition(ctx context.Context, c client.Client, it *v1.Integration) {
if isConditionTrue(it, v1.IntegrationConditionDeploymentAvailable) {
mirrorReadyConditionFromDeployment(ctx, c, it)
} else if isConditionTrue(it, v1.IntegrationConditionKnativeServiceAvailable) {
mirrorReadyConditionFromKnativeService(ctx, c, it)
} else if isConditionTrue(it, v1.IntegrationConditionCronJobAvailable) {
mirrorReadyConditionFromCronJob(ctx, c, it)
} else {
it.Status.SetCondition(
v1.IntegrationConditionReady,
corev1.ConditionUnknown,
"",
"",
)
}
}

func mirrorReadyConditionFromDeployment(ctx context.Context, c client.Client, it *v1.Integration) {
deployment := appsv1.Deployment{}
if err := c.Get(ctx, runtimeclient.ObjectKey{Namespace: it.Namespace, Name: it.Name}, &deployment); err != nil {
setReadyConditionError(it, err)
} else {
for _, c := range deployment.Status.Conditions {
if c.Type == appsv1.DeploymentAvailable {
it.Status.SetCondition(
v1.IntegrationConditionReady,
c.Status,
c.Reason,
c.Message,
)
}
}
}
}

func mirrorReadyConditionFromKnativeService(ctx context.Context, c client.Client, it *v1.Integration) {
service := servingv1.Service{}
if err := c.Get(ctx, runtimeclient.ObjectKey{Namespace: it.Namespace, Name: it.Name}, &service); err != nil {
setReadyConditionError(it, err)
} else {
for _, c := range service.Status.Conditions {
if c.Type == apis.ConditionReady {
it.Status.SetCondition(
v1.IntegrationConditionReady,
c.Status,
c.Reason,
c.Message,
)
}
}
}
}

func mirrorReadyConditionFromCronJob(ctx context.Context, c client.Client, it *v1.Integration) {
cronJob := v1beta1.CronJob{}
if err := c.Get(ctx, runtimeclient.ObjectKey{Namespace: it.Namespace, Name: it.Name}, &cronJob); err != nil {
setReadyConditionError(it, err)
} else {
// CronJob status is not tracked by Kubernetes
it.Status.SetCondition(
v1.IntegrationConditionReady,
corev1.ConditionTrue,
v1.IntegrationConditionCronJobCreatedReason,
"",
)
}
}

func isConditionTrue(it *v1.Integration, conditionType v1.IntegrationConditionType) bool {
cond := it.Status.GetCondition(conditionType)
if cond == nil {
return false
}
return cond.Status == corev1.ConditionTrue
}

func setReadyConditionError(it *v1.Integration, err error) {
it.Status.SetCondition(
v1.IntegrationConditionReady,
corev1.ConditionUnknown,
v1.IntegrationConditionErrorReason,
fmt.Sprintf("%v", err),
)
}