You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2019/07/20 06:59:45 UTC
[camel-k] branch master updated: fix build-pod strategy on
kubernetes
This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/master by this push:
new d33cc45 fix build-pod strategy on kubernetes
d33cc45 is described below
commit d33cc45d2e16d021bbeabe0522b916c5d197c508
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Fri Jul 19 18:13:44 2019 +0200
fix build-pod strategy on kubernetes
---
deploy/builder-role-kubernetes.yaml | 1 +
deploy/resources.go | 1 +
pkg/controller/build/build_controller.go | 3 +-
pkg/controller/build/initialize_pod.go | 89 ++++++++++++++++++++++
.../build/{initialize.go => initialize_routine.go} | 17 +++--
pkg/controller/build/monitor_pod.go | 26 +++----
pkg/controller/build/schedule_pod.go | 70 +++++------------
pkg/controller/build/util_pod.go | 73 ++++++++++++++++++
8 files changed, 204 insertions(+), 76 deletions(-)
diff --git a/deploy/builder-role-kubernetes.yaml b/deploy/builder-role-kubernetes.yaml
index e3ee33e..db17ffd 100644
--- a/deploy/builder-role-kubernetes.yaml
+++ b/deploy/builder-role-kubernetes.yaml
@@ -28,6 +28,7 @@ rules:
- ""
resources:
- events
+ - configmaps
verbs:
- get
- list
diff --git a/deploy/resources.go b/deploy/resources.go
index ad80ee6..f4b51a7 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -73,6 +73,7 @@ rules:
- ""
resources:
- events
+ - configmaps
verbs:
- get
- list
diff --git a/pkg/controller/build/build_controller.go b/pkg/controller/build/build_controller.go
index 1d6ca04..3a01128 100644
--- a/pkg/controller/build/build_controller.go
+++ b/pkg/controller/build/build_controller.go
@@ -190,7 +190,8 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result,
}
actions := []Action{
- NewInitializeAction(),
+ NewInitializeRoutineAction(),
+ NewInitializePodAction(),
NewScheduleRoutineAction(r.reader, r.builder, &r.routines),
NewSchedulePodAction(r.reader),
NewMonitorRoutineAction(&r.routines),
diff --git a/pkg/controller/build/initialize_pod.go b/pkg/controller/build/initialize_pod.go
new file mode 100644
index 0000000..4576872
--- /dev/null
+++ b/pkg/controller/build/initialize_pod.go
@@ -0,0 +1,89 @@
+/*
+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 build
+
+import (
+ "context"
+
+ "github.com/apache/camel-k/pkg/install"
+ "github.com/pkg/errors"
+ corev1 "k8s.io/api/core/v1"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+)
+
+// NewInitializePodAction creates a new initialize action
+func NewInitializePodAction() Action {
+ return &initializePodAction{}
+}
+
+type initializePodAction struct {
+ baseAction
+}
+
+// Name returns a common name of the action
+func (action *initializePodAction) Name() string {
+ return "initialize-pod"
+}
+
+// CanHandle tells whether this action can handle the build
+func (action *initializePodAction) CanHandle(build *v1alpha1.Build) bool {
+ return build.Status.Phase == v1alpha1.BuildPhaseInitialization &&
+ build.Spec.Platform.Build.BuildStrategy == v1alpha1.IntegrationPlatformBuildStrategyPod
+}
+
+// Handle handles the builds
+func (action *initializePodAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) {
+ // Ensure service account is present
+ // TODO: maybe this should be done by the platform trait ??
+ if err := action.ensureServiceAccount(ctx, build); err != nil {
+ return nil, errors.Wrap(err, "cannot ensure service account is present")
+ }
+
+ if err := deleteBuilderPod(ctx, action.client, build); err != nil {
+ return nil, errors.Wrap(err, "cannot delete build pod")
+ }
+
+ pod, err := getBuilderPod(ctx, action.client, build)
+ if err != nil || pod != nil {
+ // We return and wait for the pod to be deleted before de-queue the build pod.
+ return nil, err
+ }
+
+ build.Status.Phase = v1alpha1.BuildPhaseScheduling
+
+ return build, nil
+}
+
+func (action *initializePodAction) ensureServiceAccount(ctx context.Context, build *v1alpha1.Build) error {
+ sa := corev1.ServiceAccount{}
+ saKey := k8sclient.ObjectKey{
+ Name: "camel-k-builder",
+ Namespace: build.Namespace,
+ }
+
+ err := action.client.Get(ctx, saKey, &sa)
+ if err != nil && k8serrors.IsNotFound(err) {
+ // Create a proper service account
+ return install.BuilderServiceAccountRoles(ctx, action.client, build.Namespace)
+ }
+
+ return err
+}
diff --git a/pkg/controller/build/initialize.go b/pkg/controller/build/initialize_routine.go
similarity index 65%
rename from pkg/controller/build/initialize.go
rename to pkg/controller/build/initialize_routine.go
index a3c0674..0f37b03 100644
--- a/pkg/controller/build/initialize.go
+++ b/pkg/controller/build/initialize_routine.go
@@ -23,27 +23,28 @@ import (
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
)
-// NewInitializeAction creates a new initialize action
-func NewInitializeAction() Action {
- return &initializeAction{}
+// NewInitializeRoutineAction creates a new initialize action
+func NewInitializeRoutineAction() Action {
+ return &initializeRoutineAction{}
}
-type initializeAction struct {
+type initializeRoutineAction struct {
baseAction
}
// Name returns a common name of the action
-func (action *initializeAction) Name() string {
+func (action *initializeRoutineAction) Name() string {
return "initialize"
}
// CanHandle tells whether this action can handle the build
-func (action *initializeAction) CanHandle(build *v1alpha1.Build) bool {
- return build.Status.Phase == v1alpha1.BuildPhaseInitialization
+func (action *initializeRoutineAction) CanHandle(build *v1alpha1.Build) bool {
+ return build.Status.Phase == v1alpha1.BuildPhaseInitialization &&
+ build.Spec.Platform.Build.BuildStrategy == v1alpha1.IntegrationPlatformBuildStrategyRoutine
}
// Handle handles the builds
-func (action *initializeAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) {
+func (action *initializeRoutineAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) {
build.Status.Phase = v1alpha1.BuildPhaseScheduling
return build, nil
diff --git a/pkg/controller/build/monitor_pod.go b/pkg/controller/build/monitor_pod.go
index 7979e34..3b7a185 100644
--- a/pkg/controller/build/monitor_pod.go
+++ b/pkg/controller/build/monitor_pod.go
@@ -20,11 +20,8 @@ package build
import (
"context"
- corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/types"
-
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+ corev1 "k8s.io/api/core/v1"
)
// NewMonitorPodAction creates a new monitor action for scheduled pod
@@ -51,24 +48,21 @@ func (action *monitorPodAction) CanHandle(build *v1alpha1.Build) bool {
// Handle handles the builds
func (action *monitorPodAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) {
// Get the build pod
- pod := &corev1.Pod{}
- err := action.client.Get(ctx, types.NamespacedName{Namespace: build.Namespace, Name: buildPodName(build.Spec.Meta)}, pod)
+ pod, err := getBuilderPod(ctx, action.client, build)
if err != nil {
- if k8serrors.IsNotFound(err) {
- // Let's reschedule the build
- build.Status.Phase = v1alpha1.BuildPhaseScheduling
- } else {
- return nil, err
- }
+ return nil, err
}
-
var buildPhase v1alpha1.BuildPhase
- switch pod.Status.Phase {
- case corev1.PodSucceeded:
+ switch {
+ case pod == nil:
+ build.Status.Phase = v1alpha1.BuildPhaseScheduling
+ case pod.Status.Phase == corev1.PodSucceeded:
buildPhase = v1alpha1.BuildPhaseSucceeded
- case corev1.PodFailed:
+ case pod.Status.Phase == corev1.PodFailed:
buildPhase = v1alpha1.BuildPhaseFailed
+ default:
+ buildPhase = build.Status.Phase
}
if build.Status.Phase == buildPhase {
diff --git a/pkg/controller/build/schedule_pod.go b/pkg/controller/build/schedule_pod.go
index a5f38da..2b719b1 100644
--- a/pkg/controller/build/schedule_pod.go
+++ b/pkg/controller/build/schedule_pod.go
@@ -22,12 +22,10 @@ import (
"sync"
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
- "github.com/apache/camel-k/pkg/install"
"github.com/apache/camel-k/pkg/platform"
"github.com/apache/camel-k/pkg/util/defaults"
corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -77,48 +75,37 @@ func (action *schedulePodAction) Handle(ctx context.Context, build *v1alpha1.Bui
// Emulate a serialized working queue to only allow one build to run at a given time.
// This is currently necessary for the incremental build to work as expected.
- hasScheduledBuild := false
for _, b := range builds.Items {
if b.Status.Phase == v1alpha1.BuildPhasePending || b.Status.Phase == v1alpha1.BuildPhaseRunning {
- hasScheduledBuild = true
- break
+ // Let's requeue the build in case one is already running
+ return nil, nil
}
}
- if hasScheduledBuild {
- // Let's requeue the build in case one is already running
- return nil, nil
- }
-
- // Try to get operator image name before starting the build
- operatorImage, err := platform.GetCurrentOperatorImage(ctx, action.client)
+ pod, err := getBuilderPod(ctx, action.client, build)
if err != nil {
return nil, err
}
- // Otherwise, let's create the build pod
- // We may want to explicitly manage build priority as opposed to relying on
- // the reconcile loop to handle the queuing
- pod := newBuildPod(build, operatorImage)
-
- // Set the Build instance as the owner and controller
- if err := controllerutil.SetControllerReference(build, pod, action.client.GetScheme()); err != nil {
- return nil, err
- }
+ if pod == nil {
+ // Try to get operator image name before starting the build
+ operatorImage, err := platform.GetCurrentOperatorImage(ctx, action.client)
+ if err != nil {
+ return nil, err
+ }
- // Ensure service account is present
- if err := action.ensureServiceAccount(ctx, pod); err != nil {
- return nil, errors.Wrap(err, "cannot ensure service account is present")
- }
+ // We may want to explicitly manage build priority as opposed to relying on
+ // the reconcile loop to handle the queuing
+ pod = newBuildPod(build, operatorImage)
- err = action.client.Delete(ctx, pod)
- if err != nil && !k8serrors.IsNotFound(err) {
- return nil, errors.Wrap(err, "cannot delete build pod")
- }
+ // Set the Build instance as the owner and controller
+ if err := controllerutil.SetControllerReference(build, pod, action.client.GetScheme()); err != nil {
+ return nil, err
+ }
- err = action.client.Create(ctx, pod)
- if err != nil {
- return nil, errors.Wrap(err, "cannot create build pod")
+ if err := action.client.Create(ctx, pod); err != nil {
+ return nil, errors.Wrap(err, "cannot create build pod")
+ }
}
build.Status.Phase = v1alpha1.BuildPhasePending
@@ -126,21 +113,6 @@ func (action *schedulePodAction) Handle(ctx context.Context, build *v1alpha1.Bui
return build, nil
}
-func (action *schedulePodAction) ensureServiceAccount(ctx context.Context, buildPod *corev1.Pod) error {
- sa := corev1.ServiceAccount{}
- saKey := k8sclient.ObjectKey{
- Name: "camel-k-builder",
- Namespace: buildPod.Namespace,
- }
-
- err := action.client.Get(ctx, saKey, &sa)
- if err != nil && k8serrors.IsNotFound(err) {
- // Create a proper service account
- return install.BuilderServiceAccountRoles(ctx, action.client, buildPod.Namespace)
- }
- return err
-}
-
func newBuildPod(build *v1alpha1.Build, operatorImage string) *corev1.Pod {
builderImage := operatorImage
if builderImage == "" {
@@ -219,7 +191,3 @@ func newBuildPod(build *v1alpha1.Build, operatorImage string) *corev1.Pod {
return pod
}
-
-func buildPodName(object metav1.ObjectMeta) string {
- return "camel-k-" + object.Name + "-builder"
-}
diff --git a/pkg/controller/build/util_pod.go b/pkg/controller/build/util_pod.go
new file mode 100644
index 0000000..6189e38
--- /dev/null
+++ b/pkg/controller/build/util_pod.go
@@ -0,0 +1,73 @@
+/*
+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 build
+
+import (
+ "context"
+
+ corev1 "k8s.io/api/core/v1"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+)
+
+// deleteBuilderPod --
+func deleteBuilderPod(ctx context.Context, client k8sclient.Writer, build *v1alpha1.Build) error {
+ pod := corev1.Pod{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: corev1.SchemeGroupVersion.String(),
+ Kind: "Pod",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: build.Namespace,
+ Name: buildPodName(build.Spec.Meta),
+ Labels: map[string]string{
+ "camel.apache.org/build": build.Name,
+ },
+ },
+ }
+
+ err := client.Delete(ctx, &pod)
+ if err != nil && k8serrors.IsNotFound(err) {
+ return nil
+ }
+
+ return err
+}
+
+// getBuilderPod --
+func getBuilderPod(ctx context.Context, client k8sclient.Reader, build *v1alpha1.Build) (*corev1.Pod, error) {
+ key := k8sclient.ObjectKey{Namespace: build.Namespace, Name: buildPodName(build.ObjectMeta)}
+ pod := corev1.Pod{}
+
+ err := client.Get(ctx, key, &pod)
+ if err != nil && k8serrors.IsNotFound(err) {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return &pod, nil
+}
+
+func buildPodName(object metav1.ObjectMeta) string {
+ return "camel-k-" + object.Name + "-builder"
+}