You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2018/10/08 14:19:42 UTC
[camel-k] 02/14: Moving logic to the trait area
This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 3bbfaad7fbb88453bcd2e5bae7af18ebd2419c7e
Author: nferraro <ni...@gmail.com>
AuthorDate: Thu Oct 4 12:12:56 2018 +0200
Moving logic to the trait area
---
pkg/stub/action/integration/deploy.go | 281 ++-------------------
pkg/stub/action/integration/util.go | 83 ------
.../action/integration/deploy.go => trait/base.go} | 158 +++---------
pkg/trait/{catalog => }/catalog.go | 64 +++--
pkg/trait/{catalog => }/expose.go | 9 +-
pkg/trait/{catalog => }/identity.go | 9 +-
pkg/trait/owner.go | 48 ++++
pkg/trait/trait.go | 35 ++-
pkg/{stub/action/integration => trait}/util.go | 50 +---
pkg/util/kubernetes/collection.go | 19 +-
10 files changed, 213 insertions(+), 543 deletions(-)
diff --git a/pkg/stub/action/integration/deploy.go b/pkg/stub/action/integration/deploy.go
index 8067b3c..c9c7f4e 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -18,17 +18,14 @@ limitations under the License.
package integration
import (
- "fmt"
- "github.com/sirupsen/logrus"
- "strings"
-
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+ "github.com/apache/camel-k/pkg/trait"
+ "github.com/apache/camel-k/pkg/util/kubernetes"
"github.com/operator-framework/operator-sdk/pkg/sdk"
"github.com/pkg/errors"
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
+ "github.com/sirupsen/logrus"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
)
// NewDeployAction create an action that handles integration deploy
@@ -48,15 +45,18 @@ func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
}
func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
- ctx, err := LookupContextForIntegration(integration)
+ environment, err := trait.NewEnvironment(integration)
if err != nil {
return err
}
- err = createOrUpdateConfigMap(ctx, integration)
- if err != nil {
- return err
+ resources := kubernetes.NewCollection()
+ customizers := trait.CustomizersFor(*environment)
+ // invoke the trait framework to determine the needed resources
+ if _, err = customizers.Customize(*environment, resources); err != nil {
+ return errors.Wrap(err, "error during trait customization")
}
- err = createOrUpdateDeployment(ctx, integration)
+ // TODO we should look for objects that are no longer present in the collection and remove them
+ err = action.createOrUpdateObjects(resources.Items(), integration)
if err != nil {
return err
}
@@ -68,254 +68,15 @@ func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
return sdk.Update(target)
}
-// **********************************
-//
-// ConfigMap
-//
-// **********************************
-
-func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*corev1.ConfigMap, error) {
- controller := true
- blockOwnerDeletion := true
-
- // combine properties of integration with context, integration
- // properties have the priority
- properties := CombineConfigurationAsMap("property", ctx, integration)
-
- cm := corev1.ConfigMap{
- TypeMeta: metav1.TypeMeta{
- Kind: "ConfigMap",
- APIVersion: "v1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: integration.Name,
- Namespace: integration.Namespace,
- Labels: integration.Labels,
- Annotations: map[string]string{
- "camel.apache.org/source.language": string(integration.Spec.Source.Language),
- "camel.apache.org/source.name": integration.Spec.Source.Name,
- },
- OwnerReferences: []metav1.OwnerReference{
- {
- APIVersion: integration.APIVersion,
- Kind: integration.Kind,
- Name: integration.Name,
- UID: integration.UID,
- Controller: &controller,
- BlockOwnerDeletion: &blockOwnerDeletion,
- },
- },
- },
- Data: map[string]string{
- "integration": integration.Spec.Source.Content,
- "properties": PropertiesString(properties),
- },
- }
-
- return &cm, nil
-}
-
-func createOrUpdateConfigMap(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
- cm, err := getConfigMapFor(ctx, integration)
- if err != nil {
- return err
- }
-
- err = sdk.Create(cm)
- if err != nil && k8serrors.IsAlreadyExists(err) {
- err = sdk.Update(cm)
- }
- if err != nil {
- return errors.Wrap(err, "could not create or replace configmap for integration "+integration.Name)
- }
-
- return err
-}
-
-// **********************************
-//
-// Deployment
-//
-// **********************************
-
-func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*appsv1.Deployment, error) {
- controller := true
- blockOwnerDeletion := true
- sourceName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
-
- // combine environment of integration with context, integration
- // environment has the priority
- environment := CombineConfigurationAsMap("env", ctx, integration)
-
- // set env vars needed by the runtime
- environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
-
- // camel-k runtime
- environment["CAMEL_K_ROUTES_URI"] = "file:/etc/camel/conf/" + sourceName
- environment["CAMEL_K_ROUTES_LANGUAGE"] = string(integration.Spec.Source.Language)
- environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
- environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
-
- // add a dummy env var to trigger deployment if everything but the code
- // has been changed
- environment["CAMEL_K_DIGEST"] = integration.Status.Digest
-
- // optimizations
- environment["AB_JOLOKIA_OFF"] = "true"
-
- labels := map[string]string{
- "camel.apache.org/integration": integration.Name,
- }
- deployment := appsv1.Deployment{
- TypeMeta: metav1.TypeMeta{
- Kind: "Deployment",
- APIVersion: appsv1.SchemeGroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: integration.Name,
- Namespace: integration.Namespace,
- Labels: integration.Labels,
- Annotations: integration.Annotations,
- OwnerReferences: []metav1.OwnerReference{
- {
- APIVersion: integration.APIVersion,
- Kind: integration.Kind,
- Name: integration.Name,
- Controller: &controller,
- BlockOwnerDeletion: &blockOwnerDeletion,
- UID: integration.UID,
- },
- },
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: integration.Spec.Replicas,
- Selector: &metav1.LabelSelector{
- MatchLabels: labels,
- },
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: labels,
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: integration.Name,
- Image: integration.Status.Image,
- Env: EnvironmentAsEnvVarSlice(environment),
- },
- },
- },
- },
- },
- }
-
- //
- // Volumes :: Setup
- //
-
- vols := make([]corev1.Volume, 0)
- mnts := make([]corev1.VolumeMount, 0)
- cnt := 0
-
- //
- // Volumes :: Defaults
- //
-
- vols = append(vols, corev1.Volume{
- Name: "integration",
- VolumeSource: corev1.VolumeSource{
- ConfigMap: &corev1.ConfigMapVolumeSource{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: integration.Name,
- },
- Items: []corev1.KeyToPath{
- {
- Key: "integration",
- Path: sourceName,
- }, {
- Key: "properties",
- Path: "application.properties",
- },
- },
- },
- },
- })
-
- mnts = append(mnts, corev1.VolumeMount{
- Name: "integration",
- MountPath: "/etc/camel/conf",
- })
-
- //
- // Volumes :: Additional ConfigMaps
- //
-
- cmList := CombineConfigurationAsSlice("configmap", ctx, integration)
- for _, cmName := range cmList {
- cnt++
-
- vols = append(vols, corev1.Volume{
- Name: "integration-cm-" + cmName,
- VolumeSource: corev1.VolumeSource{
- ConfigMap: &corev1.ConfigMapVolumeSource{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: cmName,
- },
- },
- },
- })
-
- mnts = append(mnts, corev1.VolumeMount{
- Name: "integration-cm-" + cmName,
- MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, cmName),
- })
- }
-
- //
- // Volumes :: Additional Secrets
- //
-
- secretList := CombineConfigurationAsSlice("secret", ctx, integration)
- for _, secretName := range secretList {
- cnt++
-
- vols = append(vols, corev1.Volume{
- Name: "integration-secret-" + secretName,
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: secretName,
- },
- },
- })
-
- mnts = append(mnts, corev1.VolumeMount{
- Name: "integration-secret-" + secretName,
- MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, secretName),
- })
- }
-
- //
- // Volumes
- //
-
- deployment.Spec.Template.Spec.Volumes = vols
- deployment.Spec.Template.Spec.Containers[0].VolumeMounts = mnts
-
- return &deployment, nil
-}
-
-func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
- deployment, err := getDeploymentFor(ctx, integration)
- if err != nil {
- return err
- }
-
- err = sdk.Create(deployment)
- if err != nil && k8serrors.IsAlreadyExists(err) {
- err = sdk.Update(deployment)
- }
- if err != nil {
- return errors.Wrap(err, "could not create or replace deployment for integration "+integration.Name)
+func (action *deployAction) createOrUpdateObjects(objects []runtime.Object, integration *v1alpha1.Integration) error {
+ for _, object := range objects {
+ err := sdk.Create(object)
+ if err != nil && k8serrors.IsAlreadyExists(err) {
+ err = sdk.Update(object)
+ }
+ if err != nil {
+ return errors.Wrap(err, "could not create or replace resource for integration "+integration.Name)
+ }
}
return nil
diff --git a/pkg/stub/action/integration/util.go b/pkg/stub/action/integration/util.go
index ab9cf79..27bfb29 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/stub/action/integration/util.go
@@ -18,15 +18,10 @@ limitations under the License.
package integration
import (
- "fmt"
- "strings"
-
"github.com/apache/camel-k/pkg/util"
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/operator-framework/operator-sdk/pkg/sdk"
- "k8s.io/api/core/v1"
-
"github.com/pkg/errors"
)
@@ -65,81 +60,3 @@ func LookupContextForIntegration(integration *v1alpha1.Integration) (*v1alpha1.I
return nil, nil
}
-
-// PropertiesString --
-func PropertiesString(m map[string]string) string {
- properties := ""
- for k, v := range m {
- properties += fmt.Sprintf("%s=%s\n", k, v)
- }
-
- return properties
-}
-
-// EnvironmentAsEnvVarSlice --
-func EnvironmentAsEnvVarSlice(m map[string]string) []v1.EnvVar {
- env := make([]v1.EnvVar, 0, len(m))
-
- for k, v := range m {
- env = append(env, v1.EnvVar{Name: k, Value: v})
- }
-
- return env
-}
-
-// CombineConfigurationAsMap --
-func CombineConfigurationAsMap(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) map[string]string {
- result := make(map[string]string)
- if context != nil {
- // Add context properties first so integrations can
- // override it
- for _, c := range context.Spec.Configuration {
- if c.Type == configurationType {
- pair := strings.Split(c.Value, "=")
- if len(pair) == 2 {
- result[pair[0]] = pair[1]
- }
- }
- }
- }
-
- if integration != nil {
- for _, c := range integration.Spec.Configuration {
- if c.Type == configurationType {
- pair := strings.Split(c.Value, "=")
- if len(pair) == 2 {
- result[pair[0]] = pair[1]
- }
- }
- }
- }
-
- return result
-}
-
-// CombineConfigurationAsSlice --
-func CombineConfigurationAsSlice(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) []string {
- result := make(map[string]bool, 0)
- if context != nil {
- // Add context properties first so integrations can
- // override it
- for _, c := range context.Spec.Configuration {
- if c.Type == configurationType {
- result[c.Value] = true
- }
- }
- }
-
- for _, c := range integration.Spec.Configuration {
- if c.Type == configurationType {
- result[c.Value] = true
- }
- }
-
- keys := make([]string, 0, len(result))
- for k := range result {
- keys = append(keys, k)
- }
-
- return keys
-}
diff --git a/pkg/stub/action/integration/deploy.go b/pkg/trait/base.go
similarity index 51%
copy from pkg/stub/action/integration/deploy.go
copy to pkg/trait/base.go
index 8067b3c..69a46b9 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/trait/base.go
@@ -15,57 +15,38 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package integration
+package trait
import (
"fmt"
- "github.com/sirupsen/logrus"
+ "github.com/apache/camel-k/pkg/util/kubernetes"
"strings"
- "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
- "github.com/operator-framework/operator-sdk/pkg/sdk"
- "github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-// NewDeployAction create an action that handles integration deploy
-func NewDeployAction() Action {
- return &deployAction{}
+type baseTrait struct {
}
-type deployAction struct {
+func (*baseTrait) ID() ID {
+ return ID("base")
}
-func (action *deployAction) Name() string {
- return "deploy"
-}
-
-func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
- return integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying
-}
-
-func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
- ctx, err := LookupContextForIntegration(integration)
- if err != nil {
- return err
+func (d *baseTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) {
+ var cm *corev1.ConfigMap
+ var err error
+ if cm, err = d.getConfigMapFor(environment); err != nil {
+ return false, err
}
- err = createOrUpdateConfigMap(ctx, integration)
- if err != nil {
- return err
+ resources.Add(cm)
+ var depl *appsv1.Deployment
+ if depl, err = d.getDeploymentFor(environment); err != nil {
+ return false, err
}
- err = createOrUpdateDeployment(ctx, integration)
- if err != nil {
- return err
- }
-
- target := integration.DeepCopy()
- logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseRunning)
- target.Status.Phase = v1alpha1.IntegrationPhaseRunning
-
- return sdk.Update(target)
+ resources.Add(depl)
+ return true, nil
}
// **********************************
@@ -74,13 +55,10 @@ func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
//
// **********************************
-func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*corev1.ConfigMap, error) {
- controller := true
- blockOwnerDeletion := true
-
+func (*baseTrait) getConfigMapFor(e Environment) (*corev1.ConfigMap, error) {
// combine properties of integration with context, integration
// properties have the priority
- properties := CombineConfigurationAsMap("property", ctx, integration)
+ properties := CombineConfigurationAsMap("property", e.Context, e.Integration)
cm := corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
@@ -88,26 +66,16 @@ func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Int
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
- Name: integration.Name,
- Namespace: integration.Namespace,
- Labels: integration.Labels,
+ Name: e.Integration.Name,
+ Namespace: e.Integration.Namespace,
+ Labels: e.Integration.Labels,
Annotations: map[string]string{
- "camel.apache.org/source.language": string(integration.Spec.Source.Language),
- "camel.apache.org/source.name": integration.Spec.Source.Name,
- },
- OwnerReferences: []metav1.OwnerReference{
- {
- APIVersion: integration.APIVersion,
- Kind: integration.Kind,
- Name: integration.Name,
- UID: integration.UID,
- Controller: &controller,
- BlockOwnerDeletion: &blockOwnerDeletion,
- },
+ "camel.apache.org/source.language": string(e.Integration.Spec.Source.Language),
+ "camel.apache.org/source.name": e.Integration.Spec.Source.Name,
},
},
Data: map[string]string{
- "integration": integration.Spec.Source.Content,
+ "integration": e.Integration.Spec.Source.Content,
"properties": PropertiesString(properties),
},
}
@@ -115,56 +83,37 @@ func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Int
return &cm, nil
}
-func createOrUpdateConfigMap(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
- cm, err := getConfigMapFor(ctx, integration)
- if err != nil {
- return err
- }
-
- err = sdk.Create(cm)
- if err != nil && k8serrors.IsAlreadyExists(err) {
- err = sdk.Update(cm)
- }
- if err != nil {
- return errors.Wrap(err, "could not create or replace configmap for integration "+integration.Name)
- }
-
- return err
-}
-
// **********************************
//
// Deployment
//
// **********************************
-func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*appsv1.Deployment, error) {
- controller := true
- blockOwnerDeletion := true
- sourceName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
+func (*baseTrait) getDeploymentFor(e Environment) (*appsv1.Deployment, error) {
+ sourceName := strings.TrimPrefix(e.Integration.Spec.Source.Name, "/")
// combine environment of integration with context, integration
// environment has the priority
- environment := CombineConfigurationAsMap("env", ctx, integration)
+ environment := CombineConfigurationAsMap("env", e.Context, e.Integration)
// set env vars needed by the runtime
environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
// camel-k runtime
environment["CAMEL_K_ROUTES_URI"] = "file:/etc/camel/conf/" + sourceName
- environment["CAMEL_K_ROUTES_LANGUAGE"] = string(integration.Spec.Source.Language)
+ environment["CAMEL_K_ROUTES_LANGUAGE"] = string(e.Integration.Spec.Source.Language)
environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
// add a dummy env var to trigger deployment if everything but the code
// has been changed
- environment["CAMEL_K_DIGEST"] = integration.Status.Digest
+ environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
// optimizations
environment["AB_JOLOKIA_OFF"] = "true"
labels := map[string]string{
- "camel.apache.org/integration": integration.Name,
+ "camel.apache.org/integration": e.Integration.Name,
}
deployment := appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
@@ -172,23 +121,13 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
APIVersion: appsv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
- Name: integration.Name,
- Namespace: integration.Namespace,
- Labels: integration.Labels,
- Annotations: integration.Annotations,
- OwnerReferences: []metav1.OwnerReference{
- {
- APIVersion: integration.APIVersion,
- Kind: integration.Kind,
- Name: integration.Name,
- Controller: &controller,
- BlockOwnerDeletion: &blockOwnerDeletion,
- UID: integration.UID,
- },
- },
+ Name: e.Integration.Name,
+ Namespace: e.Integration.Namespace,
+ Labels: e.Integration.Labels,
+ Annotations: e.Integration.Annotations,
},
Spec: appsv1.DeploymentSpec{
- Replicas: integration.Spec.Replicas,
+ Replicas: e.Integration.Spec.Replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
@@ -199,8 +138,8 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
- Name: integration.Name,
- Image: integration.Status.Image,
+ Name: e.Integration.Name,
+ Image: e.Integration.Status.Image,
Env: EnvironmentAsEnvVarSlice(environment),
},
},
@@ -226,7 +165,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
- Name: integration.Name,
+ Name: e.Integration.Name,
},
Items: []corev1.KeyToPath{
{
@@ -250,7 +189,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
// Volumes :: Additional ConfigMaps
//
- cmList := CombineConfigurationAsSlice("configmap", ctx, integration)
+ cmList := CombineConfigurationAsSlice("configmap", e.Context, e.Integration)
for _, cmName := range cmList {
cnt++
@@ -275,7 +214,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
// Volumes :: Additional Secrets
//
- secretList := CombineConfigurationAsSlice("secret", ctx, integration)
+ secretList := CombineConfigurationAsSlice("secret", e.Context, e.Integration)
for _, secretName := range secretList {
cnt++
@@ -303,20 +242,3 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.In
return &deployment, nil
}
-
-func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
- deployment, err := getDeploymentFor(ctx, integration)
- if err != nil {
- return err
- }
-
- err = sdk.Create(deployment)
- if err != nil && k8serrors.IsAlreadyExists(err) {
- err = sdk.Update(deployment)
- }
- if err != nil {
- return errors.Wrap(err, "could not create or replace deployment for integration "+integration.Name)
- }
-
- return nil
-}
diff --git a/pkg/trait/catalog/catalog.go b/pkg/trait/catalog.go
similarity index 58%
rename from pkg/trait/catalog/catalog.go
rename to pkg/trait/catalog.go
index 924ed37..3325860 100644
--- a/pkg/trait/catalog/catalog.go
+++ b/pkg/trait/catalog.go
@@ -15,39 +15,48 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package catalog
+package trait
import (
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
- "github.com/apache/camel-k/pkg/trait"
"github.com/apache/camel-k/pkg/util/kubernetes"
)
-// TraitID uniquely identifies a trait
-type TraitID string
-
-const (
- // Expose exposes a integration to the external world
- Expose TraitID = "expose"
+var (
+ tExpose = &exposeTrait{}
+ tBase = &baseTrait{}
+ tOwner = &ownerTrait{}
)
-// A Catalog is just a DeploymentCustomizer that applies multiple traits
-type Catalog trait.DeploymentCustomizer
-
-// For returns a Catalog for the given integration details
-func For(environment trait.Environment) Catalog {
-
+// CustomizersFor returns a Catalog for the given integration details
+func CustomizersFor(environment Environment) Customizer {
+ switch environment.Platform.Spec.Cluster {
+ case v1alpha1.IntegrationPlatformClusterOpenShift:
+ return compose(
+ tBase,
+ tExpose,
+ tOwner,
+ )
+ case v1alpha1.IntegrationPlatformClusterKubernetes:
+ return compose(
+ tBase,
+ tExpose,
+ tOwner,
+ )
+ // case Knative: ...
+ }
+ return nil
}
-func compose(traits ...trait.DeploymentCustomizer) trait.DeploymentCustomizer {
+func compose(traits ...Customizer) Customizer {
if len(traits) == 0 {
return &identityTrait{}
} else if len(traits) == 1 {
return traits[0]
}
- var composite trait.DeploymentCustomizer = &identityTrait{}
+ var composite Customizer = &identityTrait{}
for _, t := range traits {
- composite = &catalogCustomizer{
+ composite = &chainedCustomizer{
t1: composite,
t2: t,
}
@@ -57,29 +66,28 @@ func compose(traits ...trait.DeploymentCustomizer) trait.DeploymentCustomizer {
// -------------------------------------------
-type catalogCustomizer struct {
- t1 trait.DeploymentCustomizer
- t2 trait.DeploymentCustomizer
+type chainedCustomizer struct {
+ t1 Customizer
+ t2 Customizer
}
-func (c *catalogCustomizer) Name() string {
- return ""
+func (c *chainedCustomizer) ID() ID {
+ return ID("")
}
-func (c *catalogCustomizer) Customize(environment trait.Environment, resources *kubernetes.Collection) (bool, error) {
+func (c *chainedCustomizer) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) {
atLeastOnce := false
var done bool
var err error
if done, err = c.t1.Customize(environment, resources); err != nil {
return false, err
- } else if done && c.t1.Name() != "" {
- environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t1.Name())
+ } else if done && c.t1.ID() != "" {
+ environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t1.ID())
}
atLeastOnce = atLeastOnce || done
done2, err := c.t2.Customize(environment, resources)
- if done2 && c.t2.Name() != "" {
- environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t2.Name())
+ if done2 && c.t2.ID() != "" {
+ environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t2.ID())
}
- environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t1.Name())
return atLeastOnce || done2, err
}
diff --git a/pkg/trait/catalog/expose.go b/pkg/trait/expose.go
similarity index 80%
rename from pkg/trait/catalog/expose.go
rename to pkg/trait/expose.go
index 91890eb..2dac116 100644
--- a/pkg/trait/catalog/expose.go
+++ b/pkg/trait/expose.go
@@ -15,20 +15,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package catalog
+package trait
import (
- "github.com/apache/camel-k/pkg/trait"
"github.com/apache/camel-k/pkg/util/kubernetes"
)
type exposeTrait struct {
}
-func (*exposeTrait) Name() string {
- return "expose"
+func (*exposeTrait) ID() ID {
+ return ID("expose")
}
-func (*exposeTrait) Customize(environment trait.Environment, resources *kubernetes.Collection) (bool, error) {
+func (*exposeTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) {
return false, nil
}
diff --git a/pkg/trait/catalog/identity.go b/pkg/trait/identity.go
similarity index 79%
rename from pkg/trait/catalog/identity.go
rename to pkg/trait/identity.go
index cddd0f4..eda9d3a 100644
--- a/pkg/trait/catalog/identity.go
+++ b/pkg/trait/identity.go
@@ -15,20 +15,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package catalog
+package trait
import (
- "github.com/apache/camel-k/pkg/trait"
"github.com/apache/camel-k/pkg/util/kubernetes"
)
type identityTrait struct {
}
-func (*identityTrait) Name() string {
- return "identity"
+func (*identityTrait) ID() ID {
+ return ID("identity")
}
-func (*identityTrait) Customize(environment trait.Environment, resources *kubernetes.Collection) (bool, error) {
+func (*identityTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) {
return false, nil
}
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
new file mode 100644
index 0000000..905800b
--- /dev/null
+++ b/pkg/trait/owner.go
@@ -0,0 +1,48 @@
+/*
+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 trait
+
+import "github.com/apache/camel-k/pkg/util/kubernetes"
+import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+// ownerTrait ensures that all created resources belong to the integration being created
+type ownerTrait struct {
+}
+
+func (*ownerTrait) ID() ID {
+ return ID("identity")
+}
+
+func (*ownerTrait) Customize(e Environment, resources *kubernetes.Collection) (bool, error) {
+ controller := true
+ blockOwnerDeletion := true
+ resources.VisitMetaObject(func(res metav1.Object) {
+ references := []metav1.OwnerReference{
+ {
+ APIVersion: e.Integration.APIVersion,
+ Kind: e.Integration.Kind,
+ Name: e.Integration.Name,
+ UID: e.Integration.UID,
+ Controller: &controller,
+ BlockOwnerDeletion: &blockOwnerDeletion,
+ },
+ }
+ res.SetOwnerReferences(references)
+ })
+ return true, nil
+}
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index e0bb7ef..90e4d29 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -19,6 +19,8 @@ package trait
import (
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+ "github.com/apache/camel-k/pkg/discover"
+ "github.com/apache/camel-k/pkg/platform"
"github.com/apache/camel-k/pkg/util/kubernetes"
)
@@ -27,13 +29,38 @@ type Environment struct {
Platform *v1alpha1.IntegrationPlatform
Context *v1alpha1.IntegrationContext
Integration *v1alpha1.Integration
- ExecutedCustomizers []string
+ Dependencies []string
+ ExecutedCustomizers []ID
}
-// A DeploymentCustomizer performs customization of the deployed objects
-type DeploymentCustomizer interface {
+// NewEnvironment creates a Environment from the given data
+func NewEnvironment(integration *v1alpha1.Integration) (*Environment, error) {
+ pl, err := platform.GetCurrentPlatform(integration.Namespace)
+ if err != nil {
+ return nil, err
+ }
+ ctx, err := GetIntegrationContext(integration)
+ if err != nil {
+ return nil, err
+ }
+ dependencies := discover.Dependencies(integration.Spec.Source)
+
+ return &Environment{
+ Platform: pl,
+ Context: ctx,
+ Integration: integration,
+ Dependencies: dependencies,
+ ExecutedCustomizers: make([]ID, 0),
+ }, nil
+}
+
+// ID uniquely identifies a trait
+type ID string
+
+// A Customizer performs customization of the deployed objects
+type Customizer interface {
// The Name of the customizer
- Name() string
+ ID() ID
// Customize executes the trait customization on the resources and return true if the resources have been changed
Customize(environment Environment, resources *kubernetes.Collection) (bool, error)
}
diff --git a/pkg/stub/action/integration/util.go b/pkg/trait/util.go
similarity index 73%
copy from pkg/stub/action/integration/util.go
copy to pkg/trait/util.go
index ab9cf79..0e5da55 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/trait/util.go
@@ -15,55 +15,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package integration
+package trait
import (
"fmt"
- "strings"
-
- "github.com/apache/camel-k/pkg/util"
-
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/operator-framework/operator-sdk/pkg/sdk"
- "k8s.io/api/core/v1"
-
"github.com/pkg/errors"
+ "k8s.io/api/core/v1"
+ "strings"
)
-// LookupContextForIntegration --
-func LookupContextForIntegration(integration *v1alpha1.Integration) (*v1alpha1.IntegrationContext, error) {
- if integration.Spec.Context != "" {
- name := integration.Spec.Context
- ctx := v1alpha1.NewIntegrationContext(integration.Namespace, name)
-
- if err := sdk.Get(&ctx); err != nil {
- return nil, errors.Wrapf(err, "unable to find integration context %s, %s", ctx.Name, err)
- }
-
- return &ctx, nil
- }
-
- ctxList := v1alpha1.NewIntegrationContextList()
- if err := sdk.List(integration.Namespace, &ctxList); err != nil {
- return nil, err
- }
-
- for _, ctx := range ctxList.Items {
- if ctx.Labels["camel.apache.org/context.type"] == "platform" {
- ideps := len(integration.Spec.Dependencies)
- cdeps := len(ctx.Spec.Dependencies)
-
- if ideps != cdeps {
- continue
- }
-
- if util.StringSliceContains(ctx.Spec.Dependencies, integration.Spec.Dependencies) {
- return &ctx, nil
- }
- }
+// GetIntegrationContext retrieves the context set on the integration
+func GetIntegrationContext(integration *v1alpha1.Integration) (*v1alpha1.IntegrationContext, error) {
+ if integration.Spec.Context == "" {
+ return nil, errors.New("no context set on the integration")
}
- return nil, nil
+ name := integration.Spec.Context
+ ctx := v1alpha1.NewIntegrationContext(integration.Namespace, name)
+ err := sdk.Get(&ctx)
+ return &ctx, err
}
// PropertiesString --
diff --git a/pkg/util/kubernetes/collection.go b/pkg/util/kubernetes/collection.go
index a3ff2b7..91cb7ee 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -20,6 +20,7 @@ package kubernetes
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -28,6 +29,13 @@ type Collection struct {
items []runtime.Object
}
+// NewCollection creates a new empty collection
+func NewCollection() *Collection {
+ return &Collection{
+ items: make([]runtime.Object, 0),
+ }
+}
+
// Items returns all resources belonging to the collection
func (c *Collection) Items() []runtime.Object {
return c.items
@@ -48,7 +56,7 @@ func (c *Collection) VisitDeployment(visitor func(*appsv1.Deployment)) {
}
// VisitConfigMap executes the visitor function on all ConfigMap resources
-func (c *Collection) VisitConfigMap(visitor func(configMap *corev1.ConfigMap)) {
+func (c *Collection) VisitConfigMap(visitor func(*corev1.ConfigMap)) {
c.Visit(func(res runtime.Object) {
if conv, ok := res.(*corev1.ConfigMap); ok {
visitor(conv)
@@ -56,6 +64,15 @@ func (c *Collection) VisitConfigMap(visitor func(configMap *corev1.ConfigMap)) {
})
}
+// VisitMetaObject executes the visitor function on all meta.Object resources
+func (c *Collection) VisitMetaObject(visitor func(metav1.Object)) {
+ c.Visit(func(res runtime.Object) {
+ if conv, ok := res.(metav1.Object); ok {
+ visitor(conv)
+ }
+ })
+}
+
// Visit executes the visitor function on all resources
func (c *Collection) Visit(visitor func(runtime.Object)) {
for _, res := range c.items {