This is an automated email from the ASF dual-hosted git repository.

nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 7e4d6619da416c1e8c20e476055c33d2b14b1725
Author: Nicola Ferraro <[email protected]>
AuthorDate: Tue Jun 23 11:19:01 2020 +0200

    kamelets: initial structure
---
 .../csv-config.yaml => crd-kamelet.yaml}           |  38 +++--
 ...el-k.v1.1.0-snapshot.clusterserviceversion.yaml |   5 +
 .../kamelets.camel.apache.org.crd.yaml}            |  38 +++--
 deploy/olm-catalog/csv-config.yaml                 |   1 +
 .../camel-k/crds/crd-kamelet.yaml                  |  38 +++--
 pkg/apis/addtoscheme_camel_v1alpha1.go             |  27 +++
 pkg/apis/camel/v1alpha1/kamelet_types.go           | 105 ++++++++++++
 pkg/apis/camel/v1alpha1/kamelet_types_support.go   |  46 +++++
 pkg/apis/camel/v1alpha1/register.go                |  55 ++++++
 pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go   | 102 +++++++++++
 pkg/controller/kamelet/action.go                   |  54 ++++++
 pkg/controller/kamelet/initialize.go               |  46 +++++
 pkg/controller/kamelet/kamelet_controller.go       | 187 +++++++++++++++++++++
 pkg/controller/kamelet/log.go                      |  23 +++
 pkg/event/manager.go                               |  37 ++++
 pkg/install/cluster.go                             |  39 +++--
 pkg/util/log/log.go                                |  11 ++
 17 files changed, 808 insertions(+), 44 deletions(-)

diff --git a/deploy/olm-catalog/csv-config.yaml b/deploy/crd-kamelet.yaml
similarity index 62%
copy from deploy/olm-catalog/csv-config.yaml
copy to deploy/crd-kamelet.yaml
index 3075a7a..7d36aab 100644
--- a/deploy/olm-catalog/csv-config.yaml
+++ b/deploy/crd-kamelet.yaml
@@ -15,13 +15,31 @@
 # limitations under the License.
 # ---------------------------------------------------------------------------
 
-operator-path: deploy/operator-deployment.yaml
-crd-cr-paths:
-  - deploy/crd-build.yaml
-  - deploy/crd-camel-catalog.yaml
-  - deploy/crd-integration.yaml
-  - deploy/crd-integration-kit.yaml
-  - deploy/crd-integration-platform.yaml
-role-paths:
-  - deploy/operator-role-olm.yaml
-  - deploy/operator-role-olm-cluster.yaml
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: kamelets.camel.apache.org
+  labels:
+    app: "camel-k"
+spec:
+  group: camel.apache.org
+  scope: Namespaced
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+  subresources:
+    status: {}
+  names:
+    kind: Kamelet
+    listKind: KameletList
+    plural: kamelets
+    singular: kamelet
+    shortNames:
+    - kl
+  additionalPrinterColumns:
+  - name: Phase
+    type: string
+    description: The Kamelet phase
+    JSONPath: .status.phase
diff --git 
a/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/camel-k.v1.1.0-snapshot.clusterserviceversion.yaml
 
b/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/camel-k.v1.1.0-snapshot.clusterserviceversion.yaml
index d761fee..4cc2a53 100644
--- 
a/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/camel-k.v1.1.0-snapshot.clusterserviceversion.yaml
+++ 
b/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/camel-k.v1.1.0-snapshot.clusterserviceversion.yaml
@@ -122,6 +122,11 @@ spec:
       kind: IntegrationPlatform
       name: integrationplatforms.camel.apache.org
       version: v1
+    - description: A Camel K Kamelet resource
+      displayName: Kamelet
+      kind: Kamelet
+      name: kamelets.camel.apache.org
+      version: v1alpha1
   description: |
     Apache Camel K
     ==============
diff --git a/deploy/olm-catalog/csv-config.yaml 
b/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/kamelets.camel.apache.org.crd.yaml
similarity index 62%
copy from deploy/olm-catalog/csv-config.yaml
copy to 
deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/kamelets.camel.apache.org.crd.yaml
index 3075a7a..7d36aab 100644
--- a/deploy/olm-catalog/csv-config.yaml
+++ 
b/deploy/olm-catalog/camel-k-dev/1.1.0-snapshot/kamelets.camel.apache.org.crd.yaml
@@ -15,13 +15,31 @@
 # limitations under the License.
 # ---------------------------------------------------------------------------
 
-operator-path: deploy/operator-deployment.yaml
-crd-cr-paths:
-  - deploy/crd-build.yaml
-  - deploy/crd-camel-catalog.yaml
-  - deploy/crd-integration.yaml
-  - deploy/crd-integration-kit.yaml
-  - deploy/crd-integration-platform.yaml
-role-paths:
-  - deploy/operator-role-olm.yaml
-  - deploy/operator-role-olm-cluster.yaml
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: kamelets.camel.apache.org
+  labels:
+    app: "camel-k"
+spec:
+  group: camel.apache.org
+  scope: Namespaced
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+  subresources:
+    status: {}
+  names:
+    kind: Kamelet
+    listKind: KameletList
+    plural: kamelets
+    singular: kamelet
+    shortNames:
+    - kl
+  additionalPrinterColumns:
+  - name: Phase
+    type: string
+    description: The Kamelet phase
+    JSONPath: .status.phase
diff --git a/deploy/olm-catalog/csv-config.yaml 
b/deploy/olm-catalog/csv-config.yaml
index 3075a7a..a5e2dd2 100644
--- a/deploy/olm-catalog/csv-config.yaml
+++ b/deploy/olm-catalog/csv-config.yaml
@@ -22,6 +22,7 @@ crd-cr-paths:
   - deploy/crd-integration.yaml
   - deploy/crd-integration-kit.yaml
   - deploy/crd-integration-platform.yaml
+  - deploy/crd-kamelet.yaml
 role-paths:
   - deploy/operator-role-olm.yaml
   - deploy/operator-role-olm-cluster.yaml
diff --git a/deploy/olm-catalog/csv-config.yaml 
b/helm/camel-k/crds/crd-kamelet.yaml
similarity index 62%
copy from deploy/olm-catalog/csv-config.yaml
copy to helm/camel-k/crds/crd-kamelet.yaml
index 3075a7a..7d36aab 100644
--- a/deploy/olm-catalog/csv-config.yaml
+++ b/helm/camel-k/crds/crd-kamelet.yaml
@@ -15,13 +15,31 @@
 # limitations under the License.
 # ---------------------------------------------------------------------------
 
-operator-path: deploy/operator-deployment.yaml
-crd-cr-paths:
-  - deploy/crd-build.yaml
-  - deploy/crd-camel-catalog.yaml
-  - deploy/crd-integration.yaml
-  - deploy/crd-integration-kit.yaml
-  - deploy/crd-integration-platform.yaml
-role-paths:
-  - deploy/operator-role-olm.yaml
-  - deploy/operator-role-olm-cluster.yaml
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: kamelets.camel.apache.org
+  labels:
+    app: "camel-k"
+spec:
+  group: camel.apache.org
+  scope: Namespaced
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+  subresources:
+    status: {}
+  names:
+    kind: Kamelet
+    listKind: KameletList
+    plural: kamelets
+    singular: kamelet
+    shortNames:
+    - kl
+  additionalPrinterColumns:
+  - name: Phase
+    type: string
+    description: The Kamelet phase
+    JSONPath: .status.phase
diff --git a/pkg/apis/addtoscheme_camel_v1alpha1.go 
b/pkg/apis/addtoscheme_camel_v1alpha1.go
new file mode 100644
index 0000000..001d778
--- /dev/null
+++ b/pkg/apis/addtoscheme_camel_v1alpha1.go
@@ -0,0 +1,27 @@
+/*
+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 apis
+
+import (
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+)
+
+func init() {
+       // Register the types with the Scheme so the components can map objects 
to GroupVersionKinds and back
+       AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
+}
diff --git a/pkg/apis/camel/v1alpha1/kamelet_types.go 
b/pkg/apis/camel/v1alpha1/kamelet_types.go
new file mode 100644
index 0000000..ed99b66
--- /dev/null
+++ b/pkg/apis/camel/v1alpha1/kamelet_types.go
@@ -0,0 +1,105 @@
+package v1alpha1
+
+import (
+       camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       openapi "github.com/go-openapi/spec"
+       corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// KameletSpec defines the desired state of Kamelet
+type KameletSpec struct {
+       Info          KameletInfo         `json:"info,omitempty"`
+       Parameters    []KameletParameter  `json:"parameters,omitempty"`
+       Authorization AuthorizationSpec   `json:"authorization,omitempty"`
+       Sources       *camelv1.SourceSpec `json:"sources,omitempty"`
+       Flow          *camelv1.Flow       `json:"flow,omitempty"`
+       Dependencies  []string            `json:"dependencies,omitempty"`
+}
+
+type KameletInfo struct {
+       DisplayName string      `json:"displayName,omitempty"`
+       Description string      `json:"description,omitempty"`
+       Group       string      `json:"group,omitempty"`
+       Icon        KameletIcon `json:"icon,omitempty"`
+}
+
+type KameletIcon struct {
+       Data      string `json:"data,omitempty"`
+       MediaType string `json:"mediaType,omitempty"`
+}
+
+type KameletParameter struct {
+       Name        string            `json:"name,omitempty"`
+       Required    bool              `json:"required,omitempty"`
+       Description string            `json:"description,omitempty"`
+       Annotations map[string]string `json:"annotations,omitempty"`
+       Schema      *openapi.Schema   `json:"schema,omitempty"`
+}
+
+// AuthorizationSpec is TODO (oauth information)
+type AuthorizationSpec struct {
+}
+
+// KameletStatus defines the observed state of Kamelet
+type KameletStatus struct {
+       Phase      KameletPhase       `json:"phase,omitempty"`
+       Conditions []KameletCondition `json:"conditions,omitempty"`
+}
+
+// KameletCondition describes the state of a resource at a certain point.
+type KameletCondition struct {
+       // Type of kamelet condition.
+       Type KameletConditionType `json:"type"`
+       // Status of the condition, one of True, False, Unknown.
+       Status corev1.ConditionStatus `json:"status"`
+       // The last time this condition was updated.
+       LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
+       // Last time the condition transitioned from one status to another.
+       LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+       // The reason for the condition's last transition.
+       Reason string `json:"reason,omitempty"`
+       // A human readable message indicating details about the transition.
+       Message string `json:"message,omitempty"`
+}
+
+type KameletConditionType string
+
+const (
+       // KameletConditionReady --
+       KameletConditionReady KameletConditionType = "Ready"
+)
+
+type KameletPhase string
+
+const (
+       // KameletKind --
+       KameletKind string = "Kamelet"
+
+       // KameletPhaseNone --
+       KameletPhaseNone KameletPhase = ""
+       // KameletPhaseReady --
+       KameletPhaseReady KameletPhase = "Ready"
+)
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// Kamelet is the Schema for the kamelets API
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:path=kamelets,scope=Namespaced
+type Kamelet struct {
+       metav1.TypeMeta   `json:",inline"`
+       metav1.ObjectMeta `json:"metadata,omitempty"`
+
+       Spec   KameletSpec   `json:"spec,omitempty"`
+       Status KameletStatus `json:"status,omitempty"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// KameletList contains a list of Kamelet
+type KameletList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata,omitempty"`
+       Items           []Kamelet `json:"items"`
+}
diff --git a/pkg/apis/camel/v1alpha1/kamelet_types_support.go 
b/pkg/apis/camel/v1alpha1/kamelet_types_support.go
new file mode 100644
index 0000000..eb18093
--- /dev/null
+++ b/pkg/apis/camel/v1alpha1/kamelet_types_support.go
@@ -0,0 +1,46 @@
+package v1alpha1
+
+import (
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// GetConditions --
+func (in *KameletStatus) GetConditions() []v1.ResourceCondition {
+       res := make([]v1.ResourceCondition, 0, len(in.Conditions))
+       for _, c := range in.Conditions {
+               res = append(res, c)
+       }
+       return res
+}
+
+// GetType --
+func (c KameletCondition) GetType() string {
+       return string(c.Type)
+}
+
+// GetStatus --
+func (c KameletCondition) GetStatus() corev1.ConditionStatus {
+       return c.Status
+}
+
+// GetLastUpdateTime --
+func (c KameletCondition) GetLastUpdateTime() metav1.Time {
+       return c.LastUpdateTime
+}
+
+// GetLastTransitionTime --
+func (c KameletCondition) GetLastTransitionTime() metav1.Time {
+       return c.LastTransitionTime
+}
+
+// GetReason --
+func (c KameletCondition) GetReason() string {
+       return c.Reason
+}
+
+// GetMessage --
+func (c KameletCondition) GetMessage() string {
+       return c.Message
+}
diff --git a/pkg/apis/camel/v1alpha1/register.go 
b/pkg/apis/camel/v1alpha1/register.go
new file mode 100644
index 0000000..5bafade
--- /dev/null
+++ b/pkg/apis/camel/v1alpha1/register.go
@@ -0,0 +1,55 @@
+/*
+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.
+*/
+
+// NOTE: Boilerplate only.  Ignore this file.
+
+// Package v1alpha1 contains Camel unstable API Schema definitions
+// +k8s:deepcopy-gen=package,register
+// +groupName=camel.apache.org
+package v1alpha1
+
+import (
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var (
+       // SchemeGroupVersion is group version used to register these objects
+       SchemeGroupVersion = schema.GroupVersion{Group: "camel.apache.org", 
Version: "v1alpha1"}
+
+       // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+       SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+
+       // AddToScheme is a shortcut to SchemeBuilder.AddToScheme
+       AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// Resource takes an unqualified resource and returns a Group qualified 
GroupResource
+func Resource(resource string) schema.GroupResource {
+       return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+// Adds the list of known types to Scheme.
+func addKnownTypes(scheme *runtime.Scheme) error {
+       scheme.AddKnownTypes(SchemeGroupVersion,
+               &Kamelet{},
+               &KameletList{},
+       )
+       metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
+       return nil
+}
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 0000000..8c7d0d7
--- /dev/null
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,102 @@
+// +build !ignore_autogenerated
+
+// Code generated by operator-sdk. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+       runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *Kamelet) DeepCopyInto(out *Kamelet) {
+       *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 Kamelet.
+func (in *Kamelet) DeepCopy() *Kamelet {
+       if in == nil {
+               return nil
+       }
+       out := new(Kamelet)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *Kamelet) 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 *KameletList) DeepCopyInto(out *KameletList) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ListMeta.DeepCopyInto(&out.ListMeta)
+       if in.Items != nil {
+               in, out := &in.Items, &out.Items
+               *out = make([]Kamelet, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new KameletList.
+func (in *KameletList) DeepCopy() *KameletList {
+       if in == nil {
+               return nil
+       }
+       out := new(KameletList)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, 
creating a new runtime.Object.
+func (in *KameletList) 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 *KameletSpec) DeepCopyInto(out *KameletSpec) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new KameletSpec.
+func (in *KameletSpec) DeepCopy() *KameletSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(KameletSpec)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *KameletStatus) DeepCopyInto(out *KameletStatus) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new KameletStatus.
+func (in *KameletStatus) DeepCopy() *KameletStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(KameletStatus)
+       in.DeepCopyInto(out)
+       return out
+}
diff --git a/pkg/controller/kamelet/action.go b/pkg/controller/kamelet/action.go
new file mode 100644
index 0000000..7f07717
--- /dev/null
+++ b/pkg/controller/kamelet/action.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 kamelet
+
+import (
+       "context"
+
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/client"
+       "github.com/apache/camel-k/pkg/util/log"
+)
+
+// Action --
+type Action interface {
+       client.Injectable
+       log.Injectable
+
+       // a user friendly name for the action
+       Name() string
+
+       // returns true if the action can handle the kamelet
+       CanHandle(kamelet *v1alpha1.Kamelet) bool
+
+       // executes the handling function
+       Handle(ctx context.Context, kamelet *v1alpha1.Kamelet) 
(*v1alpha1.Kamelet, error)
+}
+
+type baseAction struct {
+       client client.Client
+       L      log.Logger
+}
+
+func (action *baseAction) InjectClient(client client.Client) {
+       action.client = client
+}
+
+func (action *baseAction) InjectLogger(log log.Logger) {
+       action.L = log
+}
diff --git a/pkg/controller/kamelet/initialize.go 
b/pkg/controller/kamelet/initialize.go
new file mode 100644
index 0000000..e1f4360
--- /dev/null
+++ b/pkg/controller/kamelet/initialize.go
@@ -0,0 +1,46 @@
+/*
+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 kamelet
+
+import (
+       "context"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+)
+
+// NewInitializeAction returns a action that initializes the kamelet 
configuration when not provided by the user
+func NewInitializeAction() Action {
+       return &initializeAction{}
+}
+
+type initializeAction struct {
+       baseAction
+}
+
+func (action *initializeAction) Name() string {
+       return "initialize"
+}
+
+func (action *initializeAction) CanHandle(kamelet *v1alpha1.Kamelet) bool {
+       return kamelet.Status.Phase == v1alpha1.KameletPhaseNone
+}
+
+func (action *initializeAction) Handle(ctx context.Context, kamelet 
*v1alpha1.Kamelet) (*v1alpha1.Kamelet, error) {
+       target := kamelet.DeepCopy()
+       target.Status.Phase = v1alpha1.KameletPhaseReady
+       return target, nil
+}
diff --git a/pkg/controller/kamelet/kamelet_controller.go 
b/pkg/controller/kamelet/kamelet_controller.go
new file mode 100644
index 0000000..048cf22
--- /dev/null
+++ b/pkg/controller/kamelet/kamelet_controller.go
@@ -0,0 +1,187 @@
+/*
+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 kamelet
+
+import (
+       "context"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "time"
+
+       camelevent "github.com/apache/camel-k/pkg/event"
+       "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/client-go/tools/record"
+
+       k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/controller"
+       "sigs.k8s.io/controller-runtime/pkg/event"
+       "sigs.k8s.io/controller-runtime/pkg/handler"
+       "sigs.k8s.io/controller-runtime/pkg/manager"
+       "sigs.k8s.io/controller-runtime/pkg/predicate"
+       "sigs.k8s.io/controller-runtime/pkg/reconcile"
+       "sigs.k8s.io/controller-runtime/pkg/source"
+
+       "github.com/apache/camel-k/pkg/client"
+)
+
+// Add creates a new Kamelet Controller and adds it to the Manager. The 
Manager will set fields on the Controller
+// and Start it when the Manager is Started.
+func Add(mgr manager.Manager) error {
+       c, err := client.FromManager(mgr)
+       if err != nil {
+               return err
+       }
+       return add(mgr, newReconciler(mgr, c))
+}
+
+// newReconciler returns a new reconcile.Reconciler
+func newReconciler(mgr manager.Manager, c client.Client) reconcile.Reconciler {
+       return &ReconcileKamelet{
+               client:   c,
+               scheme:   mgr.GetScheme(),
+               recorder: mgr.GetEventRecorderFor("camel-k-kamelet-controller"),
+       }
+}
+
+// add adds a new Controller to mgr with r as the reconcile.Reconciler
+func add(mgr manager.Manager, r reconcile.Reconciler) error {
+       // Create a new controller
+       c, err := controller.New("kamelet-controller", mgr, 
controller.Options{Reconciler: r})
+       if err != nil {
+               return err
+       }
+
+       // Watch for changes to primary resource Kamelet
+       err = c.Watch(&source.Kind{Type: &v1alpha1.Kamelet{}}, 
&handler.EnqueueRequestForObject{}, predicate.Funcs{
+               UpdateFunc: func(e event.UpdateEvent) bool {
+                       oldKamelet := e.ObjectOld.(*v1alpha1.Kamelet)
+                       newKamelet := e.ObjectNew.(*v1alpha1.Kamelet)
+                       // Ignore updates to the kamelet status in which case 
metadata.Generation
+                       // does not change, or except when the kamelet phase 
changes as it's used
+                       // to transition from one phase to another
+                       return oldKamelet.Generation != newKamelet.Generation ||
+                               oldKamelet.Status.Phase != 
newKamelet.Status.Phase
+               },
+               DeleteFunc: func(e event.DeleteEvent) bool {
+                       // Evaluates to false if the object has been confirmed 
deleted
+                       return !e.DeleteStateUnknown
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+var _ reconcile.Reconciler = &ReconcileKamelet{}
+
+// ReconcileKamelet reconciles a Kamelet object
+type ReconcileKamelet struct {
+       // This client, initialized using mgr.Client() above, is a split client
+       // that reads objects from the cache and writes to the apiserver
+       client   client.Client
+       scheme   *runtime.Scheme
+       recorder record.EventRecorder
+}
+
+// Reconcile reads that state of the cluster for a Kamelet object and makes 
changes based
+// on the state read and what is in the Kamelet.Spec
+// Note:
+// The Controller will requeue the Request to be processed again if the 
returned error is non-nil or
+// Result.Requeue is true, otherwise upon completion it will remove the work 
from the queue.
+func (r *ReconcileKamelet) Reconcile(request reconcile.Request) 
(reconcile.Result, error) {
+       rlog := Log.WithValues("request-namespace", request.Namespace, 
"request-name", request.Name)
+       rlog.Info("Reconciling Kamelet")
+
+       ctx := context.TODO()
+
+       // Fetch the Kamelet instance
+       var instance v1alpha1.Kamelet
+
+       if err := r.client.Get(ctx, request.NamespacedName, &instance); err != 
nil {
+               if errors.IsNotFound(err) {
+                       // Request object not found, could have been deleted 
after reconcile request.
+                       // Owned objects are automatically garbage collected. 
For additional cleanup
+                       // logic use finalizers.
+
+                       // Return and don't requeue
+                       return reconcile.Result{}, nil
+               }
+               // Error reading the object - requeue the request.
+               return reconcile.Result{}, err
+       }
+
+       actions := []Action{
+               NewInitializeAction(),
+       }
+
+       var targetPhase v1alpha1.KameletPhase
+       var err error
+
+       target := instance.DeepCopy()
+       targetLog := rlog.ForKamelet(target)
+
+       for _, a := range actions {
+               a.InjectClient(r.client)
+               a.InjectLogger(targetLog)
+
+               if a.CanHandle(target) {
+                       targetLog.Infof("Invoking action %s", a.Name())
+
+                       phaseFrom := target.Status.Phase
+
+                       target, err = a.Handle(ctx, target)
+                       if err != nil {
+                               camelevent.NotifyKameletError(ctx, r.client, 
r.recorder, &instance, target, err)
+                               return reconcile.Result{}, err
+                       }
+
+                       if target != nil {
+                               if err := r.client.Status().Patch(ctx, target, 
k8sclient.MergeFrom(&instance)); err != nil {
+                                       camelevent.NotifyKameletError(ctx, 
r.client, r.recorder, &instance, target, err)
+                                       return reconcile.Result{}, err
+                               }
+
+                               targetPhase = target.Status.Phase
+
+                               if targetPhase != phaseFrom {
+                                       targetLog.Info(
+                                               "state transition",
+                                               "phase-from", phaseFrom,
+                                               "phase-to", target.Status.Phase,
+                                       )
+                               }
+                       }
+
+                       // handle one action at time so the resource
+                       // is always at its latest state
+                       camelevent.NotifyKameletUpdated(ctx, r.client, 
r.recorder, &instance, target)
+                       break
+               }
+       }
+
+       if targetPhase == v1alpha1.KameletPhaseReady {
+               return reconcile.Result{}, nil
+       }
+
+       // Requeue
+       return reconcile.Result{
+               RequeueAfter: 5 * time.Second,
+       }, nil
+}
diff --git a/pkg/controller/kamelet/log.go b/pkg/controller/kamelet/log.go
new file mode 100644
index 0000000..2df12a4
--- /dev/null
+++ b/pkg/controller/kamelet/log.go
@@ -0,0 +1,23 @@
+/*
+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 kamelet
+
+import "github.com/apache/camel-k/pkg/util/log"
+
+// Log --
+var Log = log.Log.WithName("controller").WithName("kamelet")
diff --git a/pkg/event/manager.go b/pkg/event/manager.go
index 43d1051..93e27f9 100644
--- a/pkg/event/manager.go
+++ b/pkg/event/manager.go
@@ -20,6 +20,7 @@ package event
 import (
        "context"
        "fmt"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
        "github.com/apache/camel-k/pkg/client"
@@ -60,6 +61,13 @@ const (
        // ReasonBuildError --
        ReasonBuildError = "BuildError"
 
+       // ReasonKameletError --
+       ReasonKameletError = "KameletError"
+       // ReasonKameletConditionChanged --
+       ReasonKameletConditionChanged = "KameletConditionChanged"
+       // ReasonKameletPhaseUpdated --
+       ReasonKameletPhaseUpdated = "KameletPhaseUpdated"
+
        // ReasonRelatedObjectChanged --
        ReasonRelatedObjectChanged = "ReasonRelatedObjectChanged"
 )
@@ -151,6 +159,35 @@ func NotifyIntegrationPlatformError(ctx context.Context, c 
client.Client, record
        recorder.Eventf(p, corev1.EventTypeWarning, 
ReasonIntegrationPlatformError, "Cannot reconcile Integration Platform %s: %v", 
p.Name, err)
 }
 
+// NotifyKameletUpdated automatically generates events when a Kamelet changes
+func NotifyKameletUpdated(ctx context.Context, c client.Client, recorder 
record.EventRecorder, old, new *v1alpha1.Kamelet) {
+       if new == nil {
+               return
+       }
+       oldPhase := ""
+       var oldConditions []v1.ResourceCondition
+       if old != nil {
+               oldPhase = string(old.Status.Phase)
+               oldConditions = old.Status.GetConditions()
+       }
+       if new.Status.Phase != v1alpha1.KameletPhaseNone {
+               notifyIfConditionUpdated(recorder, new, oldConditions, 
new.Status.GetConditions(), "Kamelet", new.Name, ReasonKameletConditionChanged)
+       }
+       notifyIfPhaseUpdated(ctx, c, recorder, new, oldPhase, 
string(new.Status.Phase), "Kamelet", new.Name, ReasonKameletPhaseUpdated, "")
+}
+
+// NotifyKameletError automatically generates error events when the kamelet 
reconcile cycle phase has an error
+func NotifyKameletError(ctx context.Context, c client.Client, recorder 
record.EventRecorder, old, new *v1alpha1.Kamelet, err error) {
+       k := old
+       if new != nil {
+               k = new
+       }
+       if k == nil {
+               return
+       }
+       recorder.Eventf(k, corev1.EventTypeWarning, ReasonKameletError, "Cannot 
reconcile Kamelet %s: %v", k.Name, err)
+}
+
 // NotifyBuildUpdated automatically generates events when a build changes
 func NotifyBuildUpdated(ctx context.Context, c client.Client, recorder 
record.EventRecorder, old, new *v1.Build) {
        if new == nil {
diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go
index 9b67062..ae55328 100644
--- a/pkg/install/cluster.go
+++ b/pkg/install/cluster.go
@@ -20,6 +20,7 @@ package install
 import (
        "context"
        "errors"
+       "fmt"
        "strconv"
        "time"
 
@@ -45,27 +46,32 @@ func SetupClusterWideResourcesOrCollect(ctx 
context.Context, clientProvider clie
        }
 
        // Install CRD for Integration Platform (if needed)
-       if err := installCRD(ctx, c, "IntegrationPlatform", 
"crd-integration-platform.yaml", collection); err != nil {
+       if err := installCRD(ctx, c, "IntegrationPlatform", "v1", 
"crd-integration-platform.yaml", collection); err != nil {
                return err
        }
 
        // Install CRD for Integration Kit (if needed)
-       if err := installCRD(ctx, c, "IntegrationKit", 
"crd-integration-kit.yaml", collection); err != nil {
+       if err := installCRD(ctx, c, "IntegrationKit", "v1", 
"crd-integration-kit.yaml", collection); err != nil {
                return err
        }
 
        // Install CRD for Integration (if needed)
-       if err := installCRD(ctx, c, "Integration", "crd-integration.yaml", 
collection); err != nil {
+       if err := installCRD(ctx, c, "Integration", "v1", 
"crd-integration.yaml", collection); err != nil {
                return err
        }
 
        // Install CRD for Camel Catalog (if needed)
-       if err := installCRD(ctx, c, "CamelCatalog", "crd-camel-catalog.yaml", 
collection); err != nil {
+       if err := installCRD(ctx, c, "CamelCatalog", "v1", 
"crd-camel-catalog.yaml", collection); err != nil {
                return err
        }
 
        // Install CRD for Build (if needed)
-       if err := installCRD(ctx, c, "Build", "crd-build.yaml", collection); 
err != nil {
+       if err := installCRD(ctx, c, "Build", "v1", "crd-build.yaml", 
collection); err != nil {
+               return err
+       }
+
+       // Install CRD for Kamelet (if needed)
+       if err := installCRD(ctx, c, "Kamelet", "v1alpha1", "crd-kamelet.yaml", 
collection); err != nil {
                return err
        }
 
@@ -120,32 +126,37 @@ func WaitForAllCRDInstallation(ctx context.Context, 
clientProvider client.Provid
 
 // AreAllCRDInstalled check if all the required CRDs are installed
 func AreAllCRDInstalled(ctx context.Context, c client.Client) (bool, error) {
-       if ok, err := IsCRDInstalled(ctx, c, "IntegrationPlatform"); err != nil 
{
+       if ok, err := IsCRDInstalled(ctx, c, "IntegrationPlatform", "v1"); err 
!= nil {
+               return ok, err
+       } else if !ok {
+               return false, nil
+       }
+       if ok, err := IsCRDInstalled(ctx, c, "IntegrationKit", "v1"); err != 
nil {
                return ok, err
        } else if !ok {
                return false, nil
        }
-       if ok, err := IsCRDInstalled(ctx, c, "IntegrationKit"); err != nil {
+       if ok, err := IsCRDInstalled(ctx, c, "Integration", "v1"); err != nil {
                return ok, err
        } else if !ok {
                return false, nil
        }
-       if ok, err := IsCRDInstalled(ctx, c, "Integration"); err != nil {
+       if ok, err := IsCRDInstalled(ctx, c, "CamelCatalog", "v1"); err != nil {
                return ok, err
        } else if !ok {
                return false, nil
        }
-       if ok, err := IsCRDInstalled(ctx, c, "CamelCatalog"); err != nil {
+       if ok, err := IsCRDInstalled(ctx, c, "Build", "v1"); err != nil {
                return ok, err
        } else if !ok {
                return false, nil
        }
-       return IsCRDInstalled(ctx, c, "Build")
+       return IsCRDInstalled(ctx, c, "Kamelet", "v1alpha1")
 }
 
 // IsCRDInstalled check if the given CRD kind is installed
-func IsCRDInstalled(ctx context.Context, c client.Client, kind string) (bool, 
error) {
-       lst, err := 
c.Discovery().ServerResourcesForGroupVersion("camel.apache.org/v1")
+func IsCRDInstalled(ctx context.Context, c client.Client, kind string, version 
string) (bool, error) {
+       lst, err := 
c.Discovery().ServerResourcesForGroupVersion(fmt.Sprintf("camel.apache.org/%s", 
version))
        if err != nil && k8serrors.IsNotFound(err) {
                return false, nil
        } else if err != nil {
@@ -159,7 +170,7 @@ func IsCRDInstalled(ctx context.Context, c client.Client, 
kind string) (bool, er
        return false, nil
 }
 
-func installCRD(ctx context.Context, c client.Client, kind string, 
resourceName string, collection *kubernetes.Collection) error {
+func installCRD(ctx context.Context, c client.Client, kind string, version 
string, resourceName string, collection *kubernetes.Collection) error {
        crd := deploy.Resource(resourceName)
        if collection != nil {
                unstr, err := kubernetes.LoadRawResourceFromYaml(string(crd))
@@ -171,7 +182,7 @@ func installCRD(ctx context.Context, c client.Client, kind 
string, resourceName
        }
 
        // Installing Integration CRD
-       installed, err := IsCRDInstalled(ctx, c, kind)
+       installed, err := IsCRDInstalled(ctx, c, kind, version)
        if err != nil {
                return err
        }
diff --git a/pkg/util/log/log.go b/pkg/util/log/log.go
index 8287561..7ac3573 100644
--- a/pkg/util/log/log.go
+++ b/pkg/util/log/log.go
@@ -19,6 +19,7 @@ package log
 
 import (
        "fmt"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
        "github.com/go-logr/logr"
@@ -128,6 +129,16 @@ func (l Logger) ForIntegrationPlatform(target 
*v1.IntegrationPlatform) Logger {
        )
 }
 
+// ForIntegrationPlatform --
+func (l Logger) ForKamelet(target *v1alpha1.Kamelet) Logger {
+       return l.WithValues(
+               "api-version", target.APIVersion,
+               "kind", target.Kind,
+               "ns", target.Namespace,
+               "name", target.Name,
+       )
+}
+
 // ***********************************
 //
 // Helpers

Reply via email to