lburgazzoli closed pull request #126: Add IntegrationPlatform resource
URL: https://github.com/apache/camel-k/pull/126
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/cmd/camel-k-operator/camel_k_operator.go 
b/cmd/camel-k-operator/camel_k_operator.go
index 32ee754..79ae793 100644
--- a/cmd/camel-k-operator/camel_k_operator.go
+++ b/cmd/camel-k-operator/camel_k_operator.go
@@ -62,6 +62,7 @@ func main() {
 
        watch(resource, "Integration", namespace, resyncPeriod)
        watch(resource, "IntegrationContext", namespace, resyncPeriod)
+       watch(resource, "IntegrationPlatform", namespace, resyncPeriod)
 
        sdk.Handle(stub.NewHandler(ctx, namespace))
        sdk.Run(ctx)
diff --git a/deploy/crd-integration-platform.yaml 
b/deploy/crd-integration-platform.yaml
new file mode 100644
index 0000000..ccba19c
--- /dev/null
+++ b/deploy/crd-integration-platform.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: integrationplatforms.camel.apache.org
+  labels:
+    app: "camel-k"
+spec:
+  group: camel.apache.org
+  names:
+    kind: IntegrationPlatform
+    listKind: IntegrationPlatformList
+    plural: integrationplatforms
+    singular: integrationplatform
+    shortNames:
+    - ip
+  scope: Namespaced
+  version: v1alpha1
diff --git a/deploy/platform-cr.yaml b/deploy/platform-cr.yaml
new file mode 100644
index 0000000..cdf13ff
--- /dev/null
+++ b/deploy/platform-cr.yaml
@@ -0,0 +1,6 @@
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationPlatform
+metadata:
+  name: camel-k
+  labels:
+    app: "camel-k"
diff --git a/deploy/resources.go b/deploy/resources.go
index 7a9888f..7749be3 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -2122,6 +2122,27 @@ spec:
   scope: Namespaced
   version: v1alpha1
 
+`
+       Resources["crd-integration-platform.yaml"] =
+               `
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: integrationplatforms.camel.apache.org
+  labels:
+    app: "camel-k"
+spec:
+  group: camel.apache.org
+  names:
+    kind: IntegrationPlatform
+    listKind: IntegrationPlatformList
+    plural: integrationplatforms
+    singular: integrationplatform
+    shortNames:
+    - ip
+  scope: Namespaced
+  version: v1alpha1
+
 `
        Resources["crd-integration.yaml"] =
                `
@@ -2435,6 +2456,16 @@ spec:
 status:
   loadBalancer: {}
 
+`
+       Resources["platform-cr.yaml"] =
+               `
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationPlatform
+metadata:
+  name: camel-k
+  labels:
+    app: "camel-k"
+
 `
        Resources["platform-integration-context-core.yaml"] =
                `
diff --git a/docs/cluster-setup.adoc b/docs/cluster-setup.adoc
index 2564b78..7e52648 100644
--- a/docs/cluster-setup.adoc
+++ b/docs/cluster-setup.adoc
@@ -7,7 +7,7 @@ There are various options for creating a development cluster:
 [[minishift]]
 == Minishift
 
-You can run Camel K integrations on Openshift using the Minishift cluster 
creation tool.
+You can run Camel K integrations on OpenShift using the Minishift cluster 
creation tool.
 Follow the instructions in the 
https://github.com/minishift/minishift#getting-started[getting started guide] 
for the installation.
 
 After installing the `minishift` binary, you need to enable the `admin-user` 
addon:
@@ -16,6 +16,8 @@ After installing the `minishift` binary, you need to enable 
the `admin-user` add
 minishift addons enable admin-user
 ```
 
+NOTE: the admin user addon should be enabled before starting the cluster for 
the first time
+
 Then you can start the cluster with:
 
 ```
diff --git a/docs/developers.adoc b/docs/developers.adoc
index 983f15a..06bb10a 100644
--- a/docs/developers.adoc
+++ b/docs/developers.adoc
@@ -45,7 +45,7 @@ This is a high level overview of the project structure:
 | link:/docs[/docs]                    | Contains this documentation.
 | link:/pkg[/pkg]                      | This is where the code resides. The 
code is divided in multiple subpackages.
 | link:/runtime[/runtime]      | The Java runtime code that is used inside the 
integration Docker containers.
-| link:/test[/test]                    | Include integration tests to ensure 
that the software interacts correctly with Kubernetes and Openshift.
+| link:/test[/test]                    | Include integration tests to ensure 
that the software interacts correctly with Kubernetes and OpenShift.
 | link:/tmp[/tmp]                      | Scripts and Docker configuration 
files used by the operator-sdk.
 | /vendor                                      | Project dependencies (not 
staged in git).
 | link:/version[/version]      | Contains the global version of the project.
@@ -88,7 +88,7 @@ make images
 
 Unit tests are executed automatically as part of the build. They use the 
standard go testing framework.
 
-Integration tests (aimed at ensuring that the code integrates correctly with 
Kubernetes and Openshift), need special care.
+Integration tests (aimed at ensuring that the code integrates correctly with 
Kubernetes and OpenShift), need special care.
 
 The **convention** used in this repo is to name unit tests `xxx_test.go`, and 
name integration tests `yyy_integration_test.go`.
 Integration tests are all in the link:/test[/test] dir.
@@ -102,7 +102,7 @@ integration tests. A integration test should start with the 
following line:
 
 Look into the link:/test[/test] directory for examples of integration tests.
 
-Before running a integration test, you need to be connected to a 
Kubernetes/Openshift namespace.
+Before running a integration test, you need to be connected to a 
Kubernetes/OpenShift namespace.
 After you log in into your cluster, you can run the following command to 
execute **all** integration tests:
 
 ```
@@ -144,7 +144,7 @@ It should be straightforward: just execute the 
link:/cmd/kamel/kamel.go[/cmd/kam
 
 It is a bit more complex (but not so much).
 
-You are going to run the operator code **outside** Openshift in your IDE so, 
first of all, you need to **stop the operator running inside**:
+You are going to run the operator code **outside** OpenShift in your IDE so, 
first of all, you need to **stop the operator running inside**:
 
 ```
 // use kubectl in plain Kubernetes
diff --git a/pkg/apis/camel/v1alpha1/register.go 
b/pkg/apis/camel/v1alpha1/register.go
index 460dd4c..7ef6212 100644
--- a/pkg/apis/camel/v1alpha1/register.go
+++ b/pkg/apis/camel/v1alpha1/register.go
@@ -49,6 +49,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
                &IntegrationList{},
                &IntegrationContext{},
                &IntegrationContextList{},
+               &IntegrationPlatform{},
+               &IntegrationPlatformList{},
        )
        metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
        return nil
diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index 80ebe59..fa27617 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -150,3 +150,79 @@ const (
        // IntegrationContextPhaseError --
        IntegrationContextPhaseError IntegrationContextPhase = "Error"
 )
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// IntegrationPlatformList --
+type IntegrationPlatformList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata"`
+       Items           []IntegrationPlatform `json:"items"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// IntegrationPlatform --
+type IntegrationPlatform struct {
+       metav1.TypeMeta   `json:",inline"`
+       metav1.ObjectMeta `json:"metadata"`
+       Spec              IntegrationPlatformSpec   `json:"spec"`
+       Status            IntegrationPlatformStatus `json:"status,omitempty"`
+}
+
+// IntegrationPlatformSpec --
+type IntegrationPlatformSpec struct {
+       Cluster IntegrationPlatformCluster   `json:"cluster,omitempty"`
+       Build   IntegrationPlatformBuildSpec `json:"build,omitempty"`
+}
+
+// IntegrationPlatformCluster is the kind of orchestration cluster the 
platform is installed into
+type IntegrationPlatformCluster string
+
+const (
+       // IntegrationPlatformClusterOpenShift is used when targeting a 
OpenShift cluster
+       IntegrationPlatformClusterOpenShift = "OpenShift"
+       // IntegrationPlatformClusterKubernetes is used when targeting a 
Kubernetes cluster
+       IntegrationPlatformClusterKubernetes = "Kubernetes"
+)
+
+// IntegrationPlatformBuildSpec contains platform related build information
+type IntegrationPlatformBuildSpec struct {
+       PublishStrategy IntegrationPlatformBuildPublishStrategy 
`json:"publishStrategy,omitempty"`
+       Registry        string                                  
`json:"registry,omitempty"`
+}
+
+// IntegrationPlatformBuildPublishStrategy enumerates all implemented build 
strategies
+type IntegrationPlatformBuildPublishStrategy string
+
+const (
+       // IntegrationPlatformBuildPublishStrategyS2I performs a OpenShift 
binary S2I build
+       IntegrationPlatformBuildPublishStrategyS2I = "S2I"
+
+       // IntegrationPlatformBuildPublishStrategyKaniko performs
+       IntegrationPlatformBuildPublishStrategyKaniko = "Kaniko"
+)
+
+// IntegrationPlatformStatus --
+type IntegrationPlatformStatus struct {
+       Phase IntegrationPlatformPhase `json:"phase,omitempty"`
+}
+
+// IntegrationPlatformPhase --
+type IntegrationPlatformPhase string
+
+const (
+       // IntegrationPlatformKind --
+       IntegrationPlatformKind string = "IntegrationPlatform"
+
+       // IntegrationPlatformPhaseCreating --
+       IntegrationPlatformPhaseCreating IntegrationPlatformPhase = "Creating"
+       // IntegrationPlatformPhaseStarting --
+       IntegrationPlatformPhaseStarting IntegrationPlatformPhase = "Starting"
+       // IntegrationPlatformPhaseReady --
+       IntegrationPlatformPhaseReady IntegrationPlatformPhase = "Ready"
+       // IntegrationPlatformPhaseError --
+       IntegrationPlatformPhaseError IntegrationPlatformPhase = "Error"
+       // IntegrationPlatformPhaseDuplicate --
+       IntegrationPlatformPhaseDuplicate IntegrationPlatformPhase = "Duplicate"
+)
diff --git a/pkg/apis/camel/v1alpha1/types_support.go 
b/pkg/apis/camel/v1alpha1/types_support.go
index 39eb11d..fa4cceb 100644
--- a/pkg/apis/camel/v1alpha1/types_support.go
+++ b/pkg/apis/camel/v1alpha1/types_support.go
@@ -39,6 +39,16 @@ func (spec ConfigurationSpec) String() string {
 //
 // **********************************
 
+// NewIntegrationPlatformList --
+func NewIntegrationPlatformList() IntegrationPlatformList {
+       return IntegrationPlatformList{
+               TypeMeta: metav1.TypeMeta{
+                       APIVersion: SchemeGroupVersion.String(),
+                       Kind:       IntegrationPlatformKind,
+               },
+       }
+}
+
 // NewIntegrationList --
 func NewIntegrationList() IntegrationList {
        return IntegrationList{
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 0784edc..57ff452 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -210,6 +210,116 @@ func (in *IntegrationList) DeepCopyObject() 
runtime.Object {
        return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IntegrationPlatform) DeepCopyInto(out *IntegrationPlatform) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+       out.Spec = in.Spec
+       out.Status = in.Status
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IntegrationPlatform.
+func (in *IntegrationPlatform) DeepCopy() *IntegrationPlatform {
+       if in == nil {
+               return nil
+       }
+       out := new(IntegrationPlatform)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *IntegrationPlatform) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IntegrationPlatformBuildSpec) DeepCopyInto(out 
*IntegrationPlatformBuildSpec) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IntegrationPlatformBuildSpec.
+func (in *IntegrationPlatformBuildSpec) DeepCopy() 
*IntegrationPlatformBuildSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(IntegrationPlatformBuildSpec)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IntegrationPlatformList) DeepCopyInto(out *IntegrationPlatformList) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       out.ListMeta = in.ListMeta
+       if in.Items != nil {
+               in, out := &in.Items, &out.Items
+               *out = make([]IntegrationPlatform, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IntegrationPlatformList.
+func (in *IntegrationPlatformList) DeepCopy() *IntegrationPlatformList {
+       if in == nil {
+               return nil
+       }
+       out := new(IntegrationPlatformList)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *IntegrationPlatformList) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IntegrationPlatformSpec) DeepCopyInto(out *IntegrationPlatformSpec) {
+       *out = *in
+       out.Build = in.Build
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IntegrationPlatformSpec.
+func (in *IntegrationPlatformSpec) DeepCopy() *IntegrationPlatformSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(IntegrationPlatformSpec)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IntegrationPlatformStatus) DeepCopyInto(out 
*IntegrationPlatformStatus) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IntegrationPlatformStatus.
+func (in *IntegrationPlatformStatus) DeepCopy() *IntegrationPlatformStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(IntegrationPlatformStatus)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *IntegrationSpec) DeepCopyInto(out *IntegrationSpec) {
        *out = *in
diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
index 2ca05ba..0d20021 100644
--- a/pkg/client/cmd/install.go
+++ b/pkg/client/cmd/install.go
@@ -35,7 +35,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        cmd := cobra.Command{
                Use:   "install",
                Short: "Install Camel K on a Kubernetes cluster",
-               Long:  `Installs Camel K on a Kubernetes or Openshift cluster.`,
+               Long:  `Installs Camel K on a Kubernetes or OpenShift cluster.`,
                RunE:  options.install,
        }
 
@@ -69,7 +69,7 @@ func (o *installCmdOptions) install(cmd *cobra.Command, args 
[]string) error {
                        return err
                }
 
-               err = install.PlatformContexts(namespace)
+               err = install.Platform(namespace)
                if err != nil {
                        return err
                }
diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go
index 855d8f6..dea1dee 100644
--- a/pkg/install/cluster.go
+++ b/pkg/install/cluster.go
@@ -32,6 +32,11 @@ import (
 // SetupClusterwideResources --
 func SetupClusterwideResources() error {
 
+       // Install CRD for Integration Platform (if needed)
+       if err := installCRD("IntegrationPlatform", 
"crd-integration-platform.yaml"); err != nil {
+               return err
+       }
+
        // Install CRD for Integration Context (if needed)
        if err := installCRD("IntegrationContext", 
"crd-integration-context.yaml"); err != nil {
                return err
diff --git a/pkg/install/common.go b/pkg/install/common.go
new file mode 100644
index 0000000..bef7f6f
--- /dev/null
+++ b/pkg/install/common.go
@@ -0,0 +1,66 @@
+/*
+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 install
+
+import (
+       "github.com/apache/camel-k/deploy"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+       "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Resources installs named resources from the project resource directory
+func Resources(namespace string, names ...string) error {
+       for _, name := range names {
+               if err := Resource(namespace, name); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// Resource installs a single named resource from the project resource 
directory
+func Resource(namespace string, name string) error {
+       obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources[name])
+       if err != nil {
+               return err
+       }
+
+       if metaObject, ok := obj.(metav1.Object); ok {
+               metaObject.SetNamespace(namespace)
+       }
+
+       err = sdk.Create(obj)
+       if err != nil && errors.IsAlreadyExists(err) {
+               // Don't recreate Service object
+               if obj.GetObjectKind().GroupVersionKind().Kind == "Service" {
+                       return nil
+               }
+               // Don't recreate integration contexts or platforms
+               if obj.GetObjectKind().GroupVersionKind().Kind == 
v1alpha1.IntegrationContextKind {
+                       return nil
+               }
+               if obj.GetObjectKind().GroupVersionKind().Kind == 
v1alpha1.IntegrationPlatformKind {
+                       return nil
+               }
+               return sdk.Update(obj)
+       }
+       return err
+}
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 58aed65..0f6039c 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -17,18 +17,9 @@ limitations under the License.
 
 package install
 
-import (
-       "github.com/apache/camel-k/deploy"
-       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-       "github.com/apache/camel-k/pkg/util/kubernetes"
-       "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "k8s.io/apimachinery/pkg/api/errors"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
 // Operator --
 func Operator(namespace string) error {
-       return installResources(namespace,
+       return Resources(namespace,
                "operator-service-account.yaml",
                "operator-role-openshift.yaml", // TODO distinguish between 
Openshift and Kubernetes
                "operator-role-binding.yaml",
@@ -37,51 +28,14 @@ func Operator(namespace string) error {
        )
 }
 
-// PlatformContexts --
-func PlatformContexts(namespace string) error {
-       return installResources(namespace,
-               "platform-integration-context-core.yaml",
-               "platform-integration-context-groovy.yaml",
-       )
+// Platform installs the platform custom resource
+func Platform(namespace string) error {
+       return Resource(namespace,"platform-cr.yaml")
 }
 
 // Example --
 func Example(namespace string) error {
-       return installResources(namespace,
+       return Resources(namespace,
                "cr-example.yaml",
        )
 }
-
-func installResources(namespace string, names ...string) error {
-       for _, name := range names {
-               if err := installResource(namespace, name); err != nil {
-                       return err
-               }
-       }
-       return nil
-}
-
-func installResource(namespace string, name string) error {
-       obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources[name])
-       if err != nil {
-               return err
-       }
-
-       if metaObject, ok := obj.(metav1.Object); ok {
-               metaObject.SetNamespace(namespace)
-       }
-
-       err = sdk.Create(obj)
-       if err != nil && errors.IsAlreadyExists(err) {
-               // Don't recreate Service object
-               if obj.GetObjectKind().GroupVersionKind().Kind == "Service" {
-                       return nil
-               }
-               // Don't recreate integration contexts
-               if obj.GetObjectKind().GroupVersionKind().Kind == 
v1alpha1.IntegrationContextKind {
-                       return nil
-               }
-               return sdk.Update(obj)
-       }
-       return err
-}
diff --git a/pkg/platform/build.go b/pkg/platform/build.go
new file mode 100644
index 0000000..994ced6
--- /dev/null
+++ b/pkg/platform/build.go
@@ -0,0 +1,91 @@
+/*
+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 platform
+
+import (
+       "context"
+       "errors"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/build"
+       "github.com/apache/camel-k/pkg/build/assemble"
+       "github.com/apache/camel-k/pkg/build/publish"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// buildManager is the current build manager
+// Note: it cannot be changed at runtime, needs a operator restart
+var buildManager *build.Manager
+
+// GetPlatformBuildManager returns a suitable build manager for the current 
platform
+func GetPlatformBuildManager(ctx context.Context, namespace string) 
(*build.Manager, error) {
+       if buildManager != nil {
+               return buildManager, nil
+       }
+       pl, err := GetCurrentPlatform(namespace)
+       if err != nil {
+               return nil, err
+       }
+
+       assembler := assemble.NewMavenAssembler(ctx)
+       if pl.Spec.Build.PublishStrategy == 
v1alpha1.IntegrationPlatformBuildPublishStrategyS2I {
+               publisher := publish.NewS2IIncrementalPublisher(ctx, namespace, 
newContextLister(namespace))
+               buildManager = build.NewManager(ctx, assembler, publisher)
+       }
+
+       if buildManager == nil {
+               return nil, errors.New("unsupported platform configuration")
+       }
+       return buildManager, nil
+}
+
+// =================================================================
+
+type contextLister struct {
+       namespace string
+}
+
+func newContextLister(namespace string) contextLister {
+       return contextLister{
+               namespace: namespace,
+       }
+}
+
+func (l contextLister) ListPublishedImages() ([]publish.PublishedImage, error) 
{
+       list := v1alpha1.NewIntegrationContextList()
+
+       err := sdk.List(l.namespace, &list, 
sdk.WithListOptions(&metav1.ListOptions{}))
+       if err != nil {
+               return nil, err
+       }
+       images := make([]publish.PublishedImage, 0)
+       for _, ctx := range list.Items {
+               if ctx.Status.Phase != v1alpha1.IntegrationContextPhaseReady || 
ctx.Labels == nil {
+                       continue
+               }
+               if ctxType, present := 
ctx.Labels["camel.apache.org/context.type"]; !present || ctxType != "platform" {
+                       continue
+               }
+
+               images = append(images, publish.PublishedImage{
+                       Image:     ctx.Status.Image,
+                       Classpath: ctx.Status.Classpath,
+               })
+       }
+       return images, nil
+}
diff --git a/pkg/platform/doc.go b/pkg/platform/doc.go
new file mode 100644
index 0000000..74e5c18
--- /dev/null
+++ b/pkg/platform/doc.go
@@ -0,0 +1,19 @@
+/*
+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 platform allows to retrieve information about the current installed 
platform
+package platform
diff --git a/pkg/platform/get.go b/pkg/platform/get.go
new file mode 100644
index 0000000..0da7163
--- /dev/null
+++ b/pkg/platform/get.go
@@ -0,0 +1,53 @@
+/*
+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 platform
+
+import (
+       "errors"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+)
+
+// GetCurrentPlatform returns the currently installed platform
+func GetCurrentPlatform(namespace string) (*v1alpha1.IntegrationPlatform, 
error) {
+       lst, err := ListPlatforms(namespace)
+       if err != nil {
+               return nil, err
+       }
+
+       for _, platform := range lst.Items {
+               if IsActive(&platform) {
+                       return &platform, nil
+               }
+       }
+       return nil, errors.New("no active integration platforms found in the 
namespace")
+}
+
+// ListPlatforms returns all platforms installed in a given namespace (only 
one will be active)
+func ListPlatforms(namespace string) (*v1alpha1.IntegrationPlatformList, 
error) {
+       lst := v1alpha1.NewIntegrationPlatformList()
+       if err := sdk.List(namespace, &lst); err != nil {
+               return nil, err
+       }
+       return &lst, nil
+}
+
+// IsActive determines if the given platform is being used
+func IsActive(p *v1alpha1.IntegrationPlatform) bool {
+       return p.Status.Phase != "" && p.Status.Phase != 
v1alpha1.IntegrationPlatformPhaseDuplicate
+}
diff --git a/pkg/stub/action/context/action.go 
b/pkg/stub/action/context/action.go
index 23b0f10..97f35c4 100644
--- a/pkg/stub/action/context/action.go
+++ b/pkg/stub/action/context/action.go
@@ -15,14 +15,14 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package context
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 )
 
-// IntegrationContextAction --
-type IntegrationContextAction interface {
+// Action --
+type Action interface {
 
        // a user friendly name for the action
        Name() string
diff --git a/pkg/stub/action/context/build.go b/pkg/stub/action/context/build.go
index a0ab58f..875114b 100644
--- a/pkg/stub/action/context/build.go
+++ b/pkg/stub/action/context/build.go
@@ -15,12 +15,11 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package context
 
 import (
        "context"
-       "github.com/apache/camel-k/pkg/build/assemble"
-       "github.com/apache/camel-k/pkg/build/publish"
+       "github.com/apache/camel-k/pkg/platform"
 
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
@@ -31,49 +30,52 @@ import (
        "github.com/apache/camel-k/pkg/build"
 )
 
-// NewIntegrationContextBuildAction creates a new build handling action for 
the context
-func NewIntegrationContextBuildAction(ctx context.Context, namespace string) 
IntegrationContextAction {
-       assembler := assemble.NewMavenAssembler(ctx)
-       publisher := publish.NewS2IIncrementalPublisher(ctx, namespace, 
newContextLister(namespace))
-       manager := build.NewManager(ctx, assembler, publisher)
-
-       return &integrationContextBuildAction{
-               buildManager: manager,
+// NewBuildAction creates a new build handling action for the context
+func NewBuildAction(ctx context.Context) Action {
+       return &buildAction{
+               ctx,
        }
 }
 
-type integrationContextBuildAction struct {
-       buildManager *build.Manager
+type buildAction struct {
+       context.Context
 }
 
-func (action *integrationContextBuildAction) Name() string {
+func (action *buildAction) Name() string {
        return "build"
 }
 
-func (action *integrationContextBuildAction) CanHandle(context 
*v1alpha1.IntegrationContext) bool {
+func (action *buildAction) CanHandle(context *v1alpha1.IntegrationContext) 
bool {
        return context.Status.Phase == v1alpha1.IntegrationContextPhaseBuilding
 }
 
-func (action *integrationContextBuildAction) Handle(context 
*v1alpha1.IntegrationContext) error {
+func (action *buildAction) Handle(context *v1alpha1.IntegrationContext) error {
+       buildManager, err := platform.GetPlatformBuildManager(action.Context, 
context.Namespace)
+       if err != nil {
+               return err
+       }
+
        buildIdentifier := build.Identifier{
                Name:      "context-" + context.Name,
                Qualifier: context.ResourceVersion,
        }
 
-       buildResult := action.buildManager.Get(buildIdentifier)
+       buildResult := buildManager.Get(buildIdentifier)
        if buildResult.Status == build.StatusNotRequested {
-               action.buildManager.Start(build.Request{
+               buildManager.Start(build.Request{
                        Identifier:   buildIdentifier,
                        Dependencies: context.Spec.Dependencies,
                })
                logrus.Info("Build started")
        } else if buildResult.Status == build.StatusError {
                target := context.DeepCopy()
+               logrus.Info("Context ", target.Name, " transitioning to state 
", v1alpha1.IntegrationContextPhaseError)
                target.Status.Phase = v1alpha1.IntegrationContextPhaseError
                return sdk.Update(target)
        } else if buildResult.Status == build.StatusCompleted {
                target := context.DeepCopy()
                target.Status.Image = buildResult.Image
+               logrus.Info("Context ", target.Name, " transitioning to state 
", v1alpha1.IntegrationContextPhaseReady)
                target.Status.Phase = v1alpha1.IntegrationContextPhaseReady
 
                target.Status.Classpath = make([]string, 
len(buildResult.Classpath))
@@ -93,7 +95,7 @@ func (action *integrationContextBuildAction) Handle(context 
*v1alpha1.Integratio
 }
 
 // informIntegrations triggers the processing of all integrations waiting for 
this context to be built
-func (action *integrationContextBuildAction) informIntegrations(context 
*v1alpha1.IntegrationContext) error {
+func (action *buildAction) informIntegrations(context 
*v1alpha1.IntegrationContext) error {
        list := v1alpha1.NewIntegrationList()
        err := sdk.List(context.Namespace, &list, 
sdk.WithListOptions(&metav1.ListOptions{}))
        if err != nil {
@@ -116,37 +118,4 @@ func (action *integrationContextBuildAction) 
informIntegrations(context *v1alpha
        return nil
 }
 
-// =================================================================
-
-type contextLister struct {
-       namespace string
-}
-
-func newContextLister(namespace string) contextLister {
-       return contextLister{
-               namespace: namespace,
-       }
-}
-
-func (l contextLister) ListPublishedImages() ([]publish.PublishedImage, error) 
{
-       list := v1alpha1.NewIntegrationContextList()
-       err := sdk.List(l.namespace, &list, 
sdk.WithListOptions(&metav1.ListOptions{}))
-       if err != nil {
-               return nil, err
-       }
-       images := make([]publish.PublishedImage, 0)
-       for _, ctx := range list.Items {
-               if ctx.Status.Phase != v1alpha1.IntegrationContextPhaseReady || 
ctx.Labels == nil {
-                       continue
-               }
-               if ctxType, present := 
ctx.Labels["camel.apache.org/context.type"]; !present || ctxType != "platform" {
-                       continue
-               }
 
-               images = append(images, publish.PublishedImage{
-                       Image:     ctx.Status.Image,
-                       Classpath: ctx.Status.Classpath,
-               })
-       }
-       return images, nil
-}
diff --git a/pkg/stub/action/context/initialize.go 
b/pkg/stub/action/context/initialize.go
index 64d7647..6f7108e 100644
--- a/pkg/stub/action/context/initialize.go
+++ b/pkg/stub/action/context/initialize.go
@@ -15,34 +15,43 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package context
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/util/digest"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
+       "github.com/sirupsen/logrus"
 )
 
-// NewIntegrationContextInitializeAction creates a new initialization handling 
action for the context
-func NewIntegrationContextInitializeAction() IntegrationContextAction {
-       return &integrationContextInitializeAction{}
+// NewInitializeAction creates a new initialization handling action for the 
context
+func NewInitializeAction() Action {
+       return &initializeAction{}
 }
 
-type integrationContextInitializeAction struct {
+type initializeAction struct {
 }
 
-func (action *integrationContextInitializeAction) Name() string {
+func (action *initializeAction) Name() string {
        return "initialize"
 }
 
-func (action *integrationContextInitializeAction) CanHandle(context 
*v1alpha1.IntegrationContext) bool {
+func (action *initializeAction) CanHandle(context 
*v1alpha1.IntegrationContext) bool {
        return context.Status.Phase == ""
 }
 
-func (action *integrationContextInitializeAction) Handle(context 
*v1alpha1.IntegrationContext) error {
+func (action *initializeAction) Handle(context *v1alpha1.IntegrationContext) 
error {
+       // The integration platform needs to be initialized before starting to 
create contexts
+       if _, err := platform.GetCurrentPlatform(context.Namespace); err != nil 
{
+               logrus.Info("Waiting for a integration platform to be 
initialized")
+               return nil
+       }
+
        target := context.DeepCopy()
 
        // update the status
+       logrus.Info("Context ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationContextPhaseBuilding)
        target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding
        target.Status.Digest = digest.ComputeForIntegrationContext(context)
 
diff --git a/pkg/stub/action/context/monitor.go 
b/pkg/stub/action/context/monitor.go
index e30a1ea..f090ffb 100644
--- a/pkg/stub/action/context/monitor.go
+++ b/pkg/stub/action/context/monitor.go
@@ -15,7 +15,7 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package context
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -24,29 +24,30 @@ import (
        "github.com/sirupsen/logrus"
 )
 
-// NewIntegrationContextMonitorAction creates a new monitoring handling action 
for the context
-func NewIntegrationContextMonitorAction() IntegrationContextAction {
-       return &integrationContextMonitorAction{}
+// NewMonitorAction creates a new monitoring handling action for the context
+func NewMonitorAction() Action {
+       return &monitorAction{}
 }
 
-type integrationContextMonitorAction struct {
+type monitorAction struct {
 }
 
-func (action *integrationContextMonitorAction) Name() string {
+func (action *monitorAction) Name() string {
        return "monitor"
 }
 
-func (action *integrationContextMonitorAction) CanHandle(context 
*v1alpha1.IntegrationContext) bool {
+func (action *monitorAction) CanHandle(context *v1alpha1.IntegrationContext) 
bool {
        return context.Status.Phase == v1alpha1.IntegrationContextPhaseReady || 
context.Status.Phase == v1alpha1.IntegrationContextPhaseError
 }
 
-func (action *integrationContextMonitorAction) Handle(context 
*v1alpha1.IntegrationContext) error {
+func (action *monitorAction) Handle(context *v1alpha1.IntegrationContext) 
error {
        hash := digest.ComputeForIntegrationContext(context)
        if hash != context.Status.Digest {
                logrus.Info("IntegrationContext ", context.Name, " needs a 
rebuild")
 
                target := context.DeepCopy()
                target.Status.Digest = hash
+               logrus.Info("Context ", target.Name, " transitioning to state 
", v1alpha1.IntegrationContextPhaseBuilding)
                target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding
                return sdk.Update(target)
        }
diff --git a/pkg/stub/action/integration/action.go 
b/pkg/stub/action/integration/action.go
index 9e4a69c..729ec5c 100644
--- a/pkg/stub/action/integration/action.go
+++ b/pkg/stub/action/integration/action.go
@@ -15,14 +15,14 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package integration
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 )
 
-// IntegrationAction --
-type IntegrationAction interface {
+// Action --
+type Action interface {
 
        // a user friendly name for the action
        Name() string
diff --git a/pkg/stub/action/integration/build.go 
b/pkg/stub/action/integration/build.go
index 20cd506..e107642 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -15,10 +15,11 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package integration
 
 import (
        "fmt"
+       "github.com/sirupsen/logrus"
 
        "github.com/apache/camel-k/pkg/util"
        "github.com/apache/camel-k/pkg/util/digest"
@@ -30,7 +31,7 @@ import (
 )
 
 // NewBuildAction create an action that handles integration build
-func NewBuildAction(namespace string) IntegrationAction {
+func NewBuildAction(namespace string) Action {
        return &buildAction{
                namespace: namespace,
        }
@@ -76,6 +77,7 @@ func (action *buildAction) Handle(integration 
*v1alpha1.Integration) error {
                        target := integration.DeepCopy()
                        target.Status.Image = ctx.Status.Image
                        target.Spec.Context = ctx.Name
+                       logrus.Info("Integration ", target.Name, " 
transitioning to state ", v1alpha1.IntegrationPhaseDeploying)
                        target.Status.Phase = v1alpha1.IntegrationPhaseDeploying
                        target.Status.Digest = 
digest.ComputeForIntegration(target)
                        return sdk.Update(target)
diff --git a/pkg/stub/action/integration/deploy.go 
b/pkg/stub/action/integration/deploy.go
index a679bbd..8067b3c 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -15,10 +15,11 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package integration
 
 import (
        "fmt"
+       "github.com/sirupsen/logrus"
        "strings"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -31,7 +32,7 @@ import (
 )
 
 // NewDeployAction create an action that handles integration deploy
-func NewDeployAction() IntegrationAction {
+func NewDeployAction() Action {
        return &deployAction{}
 }
 
@@ -60,7 +61,11 @@ func (action *deployAction) Handle(integration 
*v1alpha1.Integration) error {
                return err
        }
 
-       return nil
+       target := integration.DeepCopy()
+       logrus.Info("Integration ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationPhaseRunning)
+       target.Status.Phase = v1alpha1.IntegrationPhaseRunning
+
+       return sdk.Update(target)
 }
 
 // **********************************
@@ -313,8 +318,5 @@ func createOrUpdateDeployment(ctx 
*v1alpha1.IntegrationContext, integration *v1a
                return errors.Wrap(err, "could not create or replace deployment 
for integration "+integration.Name)
        }
 
-       target := integration.DeepCopy()
-       target.Status.Phase = v1alpha1.IntegrationPhaseRunning
-
-       return sdk.Update(target)
+       return nil
 }
diff --git a/pkg/stub/action/integration/initialize.go 
b/pkg/stub/action/integration/initialize.go
index 44bac89..d9ab6c0 100644
--- a/pkg/stub/action/integration/initialize.go
+++ b/pkg/stub/action/integration/initialize.go
@@ -15,9 +15,11 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package integration
 
 import (
+       "github.com/apache/camel-k/pkg/platform"
+       "github.com/sirupsen/logrus"
        "sort"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -27,7 +29,7 @@ import (
 )
 
 // NewInitializeAction creates a new inititialize action
-func NewInitializeAction() IntegrationAction {
+func NewInitializeAction() Action {
        return &initializeAction{}
 }
 
@@ -46,6 +48,12 @@ func (action *initializeAction) CanHandle(integration 
*v1alpha1.Integration) boo
 
 // Handle handles the integratios
 func (action *initializeAction) Handle(integration *v1alpha1.Integration) 
error {
+       // The integration platform needs to be ready before starting to create 
integrations
+       if pl, err := platform.GetCurrentPlatform(integration.Namespace); err 
!= nil || pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady {
+               logrus.Info("Waiting for a integration platform to be ready")
+               return nil
+       }
+
        target := integration.DeepCopy()
        // set default values
        if target.Spec.Replicas == nil {
@@ -67,6 +75,7 @@ func (action *initializeAction) Handle(integration 
*v1alpha1.Integration) error
        // sort the dependencies to get always the same list if they don't 
change
        sort.Strings(target.Spec.Dependencies)
        // update the status
+       logrus.Info("Integration ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationPhaseBuilding)
        target.Status.Phase = v1alpha1.IntegrationPhaseBuilding
        target.Status.Digest = digest.ComputeForIntegration(integration)
        return sdk.Update(target)
diff --git a/pkg/stub/action/integration/monitor.go 
b/pkg/stub/action/integration/monitor.go
index 483212e..ebdb420 100644
--- a/pkg/stub/action/integration/monitor.go
+++ b/pkg/stub/action/integration/monitor.go
@@ -15,7 +15,7 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package action
+package integration
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -25,7 +25,7 @@ import (
 )
 
 // NewMonitorAction creates a new monitoring action for an integration
-func NewMonitorAction() IntegrationAction {
+func NewMonitorAction() Action {
        return &monitorAction{}
 }
 
@@ -49,6 +49,7 @@ func (action *monitorAction) Handle(integration 
*v1alpha1.Integration) error {
 
                target := integration.DeepCopy()
                target.Status.Digest = hash
+               logrus.Info("Integration ", target.Name, " transitioning to 
state ", v1alpha1.IntegrationPhaseBuilding)
                target.Status.Phase = v1alpha1.IntegrationPhaseBuilding
                return sdk.Update(target)
        }
diff --git a/pkg/stub/action/integration/util.go 
b/pkg/stub/action/integration/util.go
index 33c3787..ab9cf79 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/stub/action/integration/util.go
@@ -1,4 +1,21 @@
-package action
+/*
+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 integration
 
 import (
        "fmt"
diff --git a/pkg/stub/action/platform/action.go 
b/pkg/stub/action/platform/action.go
new file mode 100644
index 0000000..cb9ba4c
--- /dev/null
+++ b/pkg/stub/action/platform/action.go
@@ -0,0 +1,34 @@
+/*
+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 platform
+
+import (
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+)
+
+// Action --
+type Action interface {
+       // a user friendly name for the action
+       Name() string
+
+       // returns true if the action can handle the integration context
+       CanHandle(platform *v1alpha1.IntegrationPlatform) bool
+
+       // executes the handling function
+       Handle(platform *v1alpha1.IntegrationPlatform) error
+}
diff --git a/pkg/stub/action/platform/create.go 
b/pkg/stub/action/platform/create.go
new file mode 100644
index 0000000..c313ccf
--- /dev/null
+++ b/pkg/stub/action/platform/create.go
@@ -0,0 +1,54 @@
+/*
+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 platform
+
+import (
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/install"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+       "github.com/sirupsen/logrus"
+)
+
+// NewCreateAction returns a action that creates resources needed by the 
platform
+func NewCreateAction() Action {
+       return &createAction{}
+}
+
+type createAction struct {
+}
+
+func (action *createAction) Name() string {
+       return "create"
+}
+
+func (action *createAction) CanHandle(platform *v1alpha1.IntegrationPlatform) 
bool {
+       return platform.Status.Phase == 
v1alpha1.IntegrationPlatformPhaseCreating
+}
+
+func (action *createAction) Handle(platform *v1alpha1.IntegrationPlatform) 
error {
+       err := install.Resources(platform.Namespace, 
"platform-integration-context-core.yaml", 
"platform-integration-context-groovy.yaml")
+       if err != nil {
+               return err
+       }
+
+       target := platform.DeepCopy()
+       logrus.Info("Platform ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationPlatformPhaseStarting)
+       target.Status.Phase = v1alpha1.IntegrationPlatformPhaseStarting
+
+       return sdk.Update(target)
+}
diff --git a/pkg/stub/action/platform/initialize.go 
b/pkg/stub/action/platform/initialize.go
new file mode 100644
index 0000000..4215daa
--- /dev/null
+++ b/pkg/stub/action/platform/initialize.go
@@ -0,0 +1,112 @@
+/*
+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 platform
+
+import (
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       platformutils "github.com/apache/camel-k/pkg/platform"
+       "github.com/operator-framework/operator-sdk/pkg/k8sclient"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+       "github.com/sirupsen/logrus"
+       "k8s.io/apimachinery/pkg/api/errors"
+)
+
+// NewInitializeAction returns a action that initializes the platform 
configuration when not provided by the user
+func NewInitializeAction() Action {
+       return &initializeAction{}
+}
+
+type initializeAction struct {
+}
+
+func (action *initializeAction) Name() string {
+       return "initialize"
+}
+
+func (action *initializeAction) CanHandle(platform 
*v1alpha1.IntegrationPlatform) bool {
+       return platform.Status.Phase == "" || platform.Status.Phase == 
v1alpha1.IntegrationPlatformPhaseDuplicate
+}
+
+func (action *initializeAction) Handle(platform *v1alpha1.IntegrationPlatform) 
error {
+       target := platform.DeepCopy()
+
+       duplicate, err := action.isDuplicate(platform)
+       if err != nil {
+               return err
+       }
+       if duplicate {
+               // another platform already present in the namespace
+               if platform.Status.Phase != 
v1alpha1.IntegrationPlatformPhaseDuplicate {
+                       target := platform.DeepCopy()
+                       logrus.Info("Platform ", target.Name, " transitioning 
to state ", v1alpha1.IntegrationPlatformPhaseDuplicate)
+                       target.Status.Phase = 
v1alpha1.IntegrationPlatformPhaseDuplicate
+                       return sdk.Update(target)
+               }
+               return nil
+       }
+
+       // update missing fields in the resource
+       if target.Spec.Cluster == "" {
+               // determine the kind of cluster the platform in installed into
+               if openshift, err := action.isOpenshift(); err != nil {
+                       return err
+               } else if openshift {
+                       target.Spec.Cluster = 
v1alpha1.IntegrationPlatformClusterOpenShift
+               } else {
+                       target.Spec.Cluster = 
v1alpha1.IntegrationPlatformClusterKubernetes
+               }
+       }
+
+       if target.Spec.Build.PublishStrategy == "" {
+               if target.Spec.Cluster == 
v1alpha1.IntegrationPlatformClusterOpenShift {
+                       target.Spec.Build.PublishStrategy = 
v1alpha1.IntegrationPlatformBuildPublishStrategyS2I
+               } else {
+                       target.Spec.Build.PublishStrategy = 
v1alpha1.IntegrationPlatformBuildPublishStrategyKaniko
+                       // TODO discover registry location
+               }
+       }
+
+       // next status
+       logrus.Info("Platform ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationPlatformPhaseCreating)
+       target.Status.Phase = v1alpha1.IntegrationPlatformPhaseCreating
+       return sdk.Update(target)
+}
+
+func (action *initializeAction) isOpenshift() (bool, error) {
+       _, err := 
k8sclient.GetKubeClient().Discovery().ServerResourcesForGroupVersion("image.openshift.io/v1")
+       if err != nil && errors.IsNotFound(err) {
+               return false, nil
+       } else if err != nil {
+               return false, err
+       }
+       return true, nil
+}
+
+func (action *initializeAction) isDuplicate(thisPlatform 
*v1alpha1.IntegrationPlatform) (bool, error) {
+       platforms, err := platformutils.ListPlatforms(thisPlatform.Namespace)
+       if err != nil {
+               return false, err
+       }
+       for _, platform := range platforms.Items {
+               if platform.Name != thisPlatform.Name && 
platformutils.IsActive(&platform) {
+                       return true, nil
+               }
+       }
+
+       return false, nil
+}
diff --git a/pkg/stub/action/platform/start.go 
b/pkg/stub/action/platform/start.go
new file mode 100644
index 0000000..df205db
--- /dev/null
+++ b/pkg/stub/action/platform/start.go
@@ -0,0 +1,81 @@
+/*
+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 platform
+
+import (
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+       "github.com/sirupsen/logrus"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// NewStartAction returns a action that waits for all required platform 
resources to start
+func NewStartAction() Action {
+       return &startAction{}
+}
+
+type startAction struct {
+}
+
+func (action *startAction) Name() string {
+       return "start"
+}
+
+func (action *startAction) CanHandle(platform *v1alpha1.IntegrationPlatform) 
bool {
+       return platform.Status.Phase == 
v1alpha1.IntegrationPlatformPhaseStarting || platform.Status.Phase == 
v1alpha1.IntegrationPlatformPhaseError
+}
+
+func (action *startAction) Handle(platform *v1alpha1.IntegrationPlatform) 
error {
+       aggregatePhase, err := 
action.aggregatePlatformPhaseFromContexts(platform.Namespace)
+       if err != nil {
+               return err
+       }
+       if platform.Status.Phase != aggregatePhase {
+               target := platform.DeepCopy()
+               logrus.Info("Platform ", target.Name, " transitioning to state 
", aggregatePhase)
+               target.Status.Phase = aggregatePhase
+               return sdk.Update(target)
+       }
+       // wait
+       return nil
+}
+
+func (action *startAction) aggregatePlatformPhaseFromContexts(namespace 
string) (v1alpha1.IntegrationPlatformPhase, error) {
+       ctxs := v1alpha1.NewIntegrationContextList()
+       options := metav1.ListOptions{
+               LabelSelector: "camel.apache.org/context.type=platform",
+       }
+       if err := sdk.List(namespace, &ctxs, sdk.WithListOptions(&options)); 
err != nil {
+               return "", err
+       }
+
+       countReady := 0
+       for _, ctx := range ctxs.Items {
+               if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseError {
+                       return v1alpha1.IntegrationPlatformPhaseError, nil
+               } else if ctx.Status.Phase == 
v1alpha1.IntegrationContextPhaseReady {
+                       countReady++
+               }
+       }
+
+       if countReady < len(ctxs.Items) {
+               return v1alpha1.IntegrationPlatformPhaseStarting, nil
+       }
+
+       return v1alpha1.IntegrationPlatformPhaseReady, nil
+}
diff --git a/pkg/stub/handler.go b/pkg/stub/handler.go
index cb78d7b..18ae691 100644
--- a/pkg/stub/handler.go
+++ b/pkg/stub/handler.go
@@ -18,44 +18,50 @@ limitations under the License.
 package stub
 
 import (
-       "context"
-
+       ctx "context"
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/stub/action/platform"
 
-       caction "github.com/apache/camel-k/pkg/stub/action/context"
-       iaction "github.com/apache/camel-k/pkg/stub/action/integration"
+       "github.com/apache/camel-k/pkg/stub/action/context"
+       "github.com/apache/camel-k/pkg/stub/action/integration"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
        "github.com/sirupsen/logrus"
 )
 
 // NewHandler --
-func NewHandler(ctx context.Context, namespace string) sdk.Handler {
+func NewHandler(ctx ctx.Context, namespace string) sdk.Handler {
        return &handler{
-               integrationActionPool: []iaction.IntegrationAction{
-                       iaction.NewInitializeAction(),
-                       iaction.NewBuildAction(namespace),
-                       iaction.NewDeployAction(),
-                       iaction.NewMonitorAction(),
+               integrationActionPool: []integration.Action{
+                       integration.NewInitializeAction(),
+                       integration.NewBuildAction(namespace),
+                       integration.NewDeployAction(),
+                       integration.NewMonitorAction(),
+               },
+               integrationContextActionPool: []context.Action{
+                       context.NewInitializeAction(),
+                       context.NewBuildAction(ctx),
+                       context.NewMonitorAction(),
                },
-               integrationContextActionPool: 
[]caction.IntegrationContextAction{
-                       caction.NewIntegrationContextInitializeAction(),
-                       caction.NewIntegrationContextBuildAction(ctx, 
namespace),
-                       caction.NewIntegrationContextMonitorAction(),
+               integrationPlatformActionPool: []platform.Action{
+                       platform.NewInitializeAction(),
+                       platform.NewCreateAction(),
+                       platform.NewStartAction(),
                },
        }
 }
 
 type handler struct {
-       integrationActionPool        []iaction.IntegrationAction
-       integrationContextActionPool []caction.IntegrationContextAction
+       integrationActionPool         []integration.Action
+       integrationContextActionPool  []context.Action
+       integrationPlatformActionPool []platform.Action
 }
 
-func (h *handler) Handle(ctx context.Context, event sdk.Event) error {
+func (h *handler) Handle(ctx ctx.Context, event sdk.Event) error {
        switch o := event.Object.(type) {
        case *v1alpha1.Integration:
                for _, a := range h.integrationActionPool {
                        if a.CanHandle(o) {
-                               logrus.Info("Invoking action ", a.Name(), " on 
integration ", o.Name)
+                               logrus.Debug("Invoking action ", a.Name(), " on 
integration ", o.Name)
                                if err := a.Handle(o); err != nil {
                                        return err
                                }
@@ -64,7 +70,16 @@ func (h *handler) Handle(ctx context.Context, event 
sdk.Event) error {
        case *v1alpha1.IntegrationContext:
                for _, a := range h.integrationContextActionPool {
                        if a.CanHandle(o) {
-                               logrus.Info("Invoking action ", a.Name(), " on 
context ", o.Name)
+                               logrus.Debug("Invoking action ", a.Name(), " on 
context ", o.Name)
+                               if err := a.Handle(o); err != nil {
+                                       return err
+                               }
+                       }
+               }
+       case *v1alpha1.IntegrationPlatform:
+               for _, a := range h.integrationPlatformActionPool {
+                       if a.CanHandle(o) {
+                               logrus.Debug("Invoking action ", a.Name(), " on 
platform ", o.Name)
                                if err := a.Handle(o); err != nil {
                                        return err
                                }
diff --git a/pkg/util/openshift/register.go b/pkg/util/openshift/register.go
index 83b08aa..373e42e 100644
--- a/pkg/util/openshift/register.go
+++ b/pkg/util/openshift/register.go
@@ -29,7 +29,7 @@ import (
        "k8s.io/apimachinery/pkg/runtime"
 )
 
-// Register all Openshift types that we want to manage.
+// Register all OpenShift types that we want to manage.
 func init() {
        k8sutil.AddToSDKScheme(addKnownTypes)
 }
diff --git a/runtime/examples/routes-rest.js b/runtime/examples/routes-rest.js
index 47b9c24..e888019 100644
--- a/runtime/examples/routes-rest.js
+++ b/runtime/examples/routes-rest.js
@@ -1,7 +1,7 @@
 //
 // To run this integrations use:
 //
-//     kamel run --name=withrest --dependency=camel:undertow 
runtime/examples/routes-rest.js
+//     kamel run --name=withrest --dependency=camel-undertow 
runtime/examples/routes-rest.js
 //
 
 // ****************


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to