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 5d004a81f682aa55ea59989e3b3636228b936548 Author: nferraro <[email protected]> AuthorDate: Thu Oct 4 18:13:52 2018 +0200 Added trait configuration --- pkg/stub/action/integration/deploy.go | 11 +--- pkg/trait/base.go | 10 ++-- pkg/trait/catalog.go | 59 ++++++++------------ pkg/trait/identity.go | 33 ----------- pkg/trait/owner.go | 6 +- pkg/trait/route.go | 8 +-- pkg/trait/service.go | 37 ++++++++----- pkg/trait/trait.go | 40 +++++++------- pkg/trait/types.go | 101 ++++++++++++++++++++++++++++++++++ 9 files changed, 181 insertions(+), 124 deletions(-) diff --git a/pkg/stub/action/integration/deploy.go b/pkg/stub/action/integration/deploy.go index 9790bf8..2c814bc 100644 --- a/pkg/stub/action/integration/deploy.go +++ b/pkg/stub/action/integration/deploy.go @@ -22,7 +22,6 @@ import ( "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" "github.com/sirupsen/logrus" ) @@ -43,18 +42,12 @@ func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool { } func (action *deployAction) Handle(integration *v1alpha1.Integration) error { - environment, err := trait.NewEnvironment(integration) + resources, err := trait.ComputeDeployment(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") - } // TODO we should look for objects that are no longer present in the collection and remove them - err = kubernetes.ReplaceResources(resources.Items()) + err = kubernetes.ReplaceResources(resources) if err != nil { return err } diff --git a/pkg/trait/base.go b/pkg/trait/base.go index 6ba4dfc..d5eea62 100644 --- a/pkg/trait/base.go +++ b/pkg/trait/base.go @@ -30,11 +30,11 @@ import ( type baseTrait struct { } -func (*baseTrait) ID() ID { - return ID("base") +func (*baseTrait) id() id { + return id("base") } -func (d *baseTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) { +func (d *baseTrait) customize(environment environment, resources *kubernetes.Collection) (bool, error) { resources.Add(d.getConfigMapFor(environment)) resources.Add(d.getDeploymentFor(environment)) return true, nil @@ -46,7 +46,7 @@ func (d *baseTrait) Customize(environment Environment, resources *kubernetes.Col // // ********************************** -func (*baseTrait) getConfigMapFor(e Environment) *corev1.ConfigMap { +func (*baseTrait) getConfigMapFor(e environment) *corev1.ConfigMap { // combine properties of integration with context, integration // properties have the priority properties := CombineConfigurationAsMap("property", e.Context, e.Integration) @@ -82,7 +82,7 @@ func (*baseTrait) getConfigMapFor(e Environment) *corev1.ConfigMap { // // ********************************** -func (*baseTrait) getDeploymentFor(e Environment) *appsv1.Deployment { +func (*baseTrait) getDeploymentFor(e environment) *appsv1.Deployment { sourceName := strings.TrimPrefix(e.Integration.Spec.Source.Name, "/") // combine environment of integration with context, integration diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go index a969012..a2ba3b5 100644 --- a/pkg/trait/catalog.go +++ b/pkg/trait/catalog.go @@ -23,14 +23,14 @@ import ( ) var ( - tBase = &baseTrait{} + tBase = &baseTrait{} tService = &serviceTrait{} - tRoute = &routeTrait{} - tOwner = &ownerTrait{} + tRoute = &routeTrait{} + tOwner = &ownerTrait{} ) -// CustomizersFor returns a Catalog for the given integration details -func CustomizersFor(environment Environment) Customizer { +// customizersFor returns a Catalog for the given integration details +func customizersFor(environment environment) customizer { switch environment.Platform.Spec.Cluster { case v1alpha1.IntegrationPlatformClusterOpenShift: return compose( @@ -50,46 +50,33 @@ func CustomizersFor(environment Environment) Customizer { return nil } -func compose(traits ...Customizer) Customizer { - if len(traits) == 0 { - return &identityTrait{} - } else if len(traits) == 1 { - return traits[0] +func compose(traits ...customizer) customizer { + return &chainedCustomizer{ + customizers: traits, } - var composite Customizer = &identityTrait{} - for _, t := range traits { - composite = &chainedCustomizer{ - t1: composite, - t2: t, - } - } - return composite } // ------------------------------------------- type chainedCustomizer struct { - t1 Customizer - t2 Customizer + customizers []customizer } -func (c *chainedCustomizer) ID() ID { - return ID("") +func (c *chainedCustomizer) id() id { + return id("") } -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.ID() != "" { - environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t1.ID()) - } - atLeastOnce = atLeastOnce || done - done2, err := c.t2.Customize(environment, resources) - if done2 && c.t2.ID() != "" { - environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, c.t2.ID()) +func (c *chainedCustomizer) customize(environment environment, resources *kubernetes.Collection) (bool, error) { + atLeastOne := false + for _, custom := range c.customizers { + if environment.isEnabled(custom.id()) { + if done, err := custom.customize(environment, resources); err != nil { + return false, err + } else if done && custom.id() != "" { + environment.ExecutedCustomizers = append(environment.ExecutedCustomizers, custom.id()) + atLeastOne = atLeastOne || done + } + } } - return atLeastOnce || done2, err + return atLeastOne, nil } diff --git a/pkg/trait/identity.go b/pkg/trait/identity.go deleted file mode 100644 index eda9d3a..0000000 --- a/pkg/trait/identity.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -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" -) - -type identityTrait struct { -} - -func (*identityTrait) ID() ID { - return ID("identity") -} - -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 index 905800b..6d77ff9 100644 --- a/pkg/trait/owner.go +++ b/pkg/trait/owner.go @@ -24,11 +24,11 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" type ownerTrait struct { } -func (*ownerTrait) ID() ID { - return ID("identity") +func (*ownerTrait) id() id { + return id("owner") } -func (*ownerTrait) Customize(e Environment, resources *kubernetes.Collection) (bool, error) { +func (*ownerTrait) customize(e environment, resources *kubernetes.Collection) (bool, error) { controller := true blockOwnerDeletion := true resources.VisitMetaObject(func(res metav1.Object) { diff --git a/pkg/trait/route.go b/pkg/trait/route.go index 1906442..ded0fe3 100644 --- a/pkg/trait/route.go +++ b/pkg/trait/route.go @@ -28,11 +28,11 @@ import ( type routeTrait struct { } -func (*routeTrait) ID() ID { - return ID("route") +func (*routeTrait) id() id { + return id("route") } -func (e *routeTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) { +func (e *routeTrait) customize(environment environment, resources *kubernetes.Collection) (bool, error) { var service *corev1.Service resources.VisitService(func(s *corev1.Service) { if s.ObjectMeta.Labels != nil { @@ -50,7 +50,7 @@ func (e *routeTrait) Customize(environment Environment, resources *kubernetes.Co return false, nil } -func (*routeTrait) getRouteFor(e Environment, service *corev1.Service) *routev1.Route { +func (*routeTrait) getRouteFor(e environment, service *corev1.Service) *routev1.Route { route := routev1.Route{ TypeMeta: metav1.TypeMeta{ Kind: "Route", diff --git a/pkg/trait/service.go b/pkg/trait/service.go index a6438d8..d7d116a 100644 --- a/pkg/trait/service.go +++ b/pkg/trait/service.go @@ -37,19 +37,32 @@ var webComponents = map[string]bool{ type serviceTrait struct { } -func (*serviceTrait) ID() ID { - return ID("service") +const ( + serviceTraitPortKey = "port" +) + +func (*serviceTrait) id() id { + return id("service") } -func (e *serviceTrait) Customize(environment Environment, resources *kubernetes.Collection) (bool, error) { +func (e *serviceTrait) customize(environment environment, resources *kubernetes.Collection) (bool, error) { if !e.requiresService(environment) { return false, nil } - resources.Add(e.getServiceFor(environment)) + svc, err := e.getServiceFor(environment) + if err != nil { + return false, err + } + resources.Add(svc) return true, nil } -func (*serviceTrait) getServiceFor(e Environment) *corev1.Service { +func (s *serviceTrait) getServiceFor(e environment) (*corev1.Service, error) { + port, err := e.getIntConfigOr(s.id(), serviceTraitPortKey, 8080) + if err != nil { + return nil, err + } + svc := corev1.Service{ TypeMeta: metav1.TypeMeta{ Kind: "Service", @@ -65,12 +78,10 @@ func (*serviceTrait) getServiceFor(e Environment) *corev1.Service { Spec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{ { - Name: "http", - Port: 80, - Protocol: corev1.ProtocolTCP, - // TODO discovering the real port is hard - maybe we should just set 8080 as conventional port in the doc - // or allow users to configure it in the trait configuration section - TargetPort: intstr.FromInt(8080), + Name: "http", + Port: 80, + Protocol: corev1.ProtocolTCP, + TargetPort: intstr.FromInt(port), }, }, Selector: map[string]string{ @@ -79,10 +90,10 @@ func (*serviceTrait) getServiceFor(e Environment) *corev1.Service { }, } - return &svc + return &svc, nil } -func (*serviceTrait) requiresService(environment Environment) bool { +func (*serviceTrait) requiresService(environment environment) bool { for _, dep := range environment.Integration.Spec.Dependencies { if decision, present := webComponents[dep]; present { return decision diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go index d9c372f..a2b83c6 100644 --- a/pkg/trait/trait.go +++ b/pkg/trait/trait.go @@ -21,18 +21,27 @@ import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/util/kubernetes" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/runtime" ) -// A Environment provides the context where the trait is executed -type Environment struct { - Platform *v1alpha1.IntegrationPlatform - Context *v1alpha1.IntegrationContext - Integration *v1alpha1.Integration - ExecutedCustomizers []ID +// ComputeDeployment generates all required resources for deploying the given integration +func ComputeDeployment(integration *v1alpha1.Integration) ([]runtime.Object, error) { + environment, err := newEnvironment(integration) + if err != nil { + return nil, err + } + resources := kubernetes.NewCollection() + customizers := customizersFor(*environment) + // invoke the trait framework to determine the needed resources + if _, err = customizers.customize(*environment, resources); err != nil { + return nil, errors.Wrap(err, "error during trait customization") + } + return resources.Items(), nil } -// NewEnvironment creates a Environment from the given data -func NewEnvironment(integration *v1alpha1.Integration) (*Environment, error) { +// 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 @@ -42,21 +51,10 @@ func NewEnvironment(integration *v1alpha1.Integration) (*Environment, error) { return nil, err } - return &Environment{ + return &environment{ Platform: pl, Context: ctx, Integration: integration, - ExecutedCustomizers: make([]ID, 0), + 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 - 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/trait/types.go b/pkg/trait/types.go new file mode 100644 index 0000000..dd8c269 --- /dev/null +++ b/pkg/trait/types.go @@ -0,0 +1,101 @@ +/* +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/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/kubernetes" + "github.com/pkg/errors" + "strconv" +) + +// ID uniquely identifies a trait +type id string + +// A Customizer performs customization of the deployed objects +type customizer interface { + // The Name of the customizer + 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) +} + +// A environment provides the context where the trait is executed +type environment struct { + Platform *v1alpha1.IntegrationPlatform + Context *v1alpha1.IntegrationContext + Integration *v1alpha1.Integration + ExecutedCustomizers []id +} + +func (e environment) getTraitSpec(traitID id) *v1alpha1.IntegrationTraitSpec { + if e.Integration.Spec.Traits == nil { + return nil + } + if conf, ok := e.Integration.Spec.Traits[string(traitID)]; ok { + return &conf + } + return nil +} + +func (e environment) isEnabled(traitID id) bool { + conf := e.getTraitSpec(traitID) + return conf == nil || conf.Enabled == nil || *conf.Enabled +} + +func (e environment) getConfig(traitID id, key string) *string { + conf := e.getTraitSpec(traitID) + if conf == nil || conf.Configuration == nil { + return nil + } + if v, ok := conf.Configuration[key]; ok { + return &v + } + return nil +} + +func (e environment) getConfigOr(traitID id, key string, defaultValue string) string { + val := e.getConfig(traitID, key) + if val != nil { + return *val + } + return defaultValue +} + +func (e environment) getIntConfig(traitID id, key string) (*int, error) { + val := e.getConfig(traitID, key) + if val == nil { + return nil, nil + } + intVal, err := strconv.Atoi(*val) + if err != nil { + return nil, errors.Wrap(err, "cannot extract a integer from property "+key+" with value "+*val) + } + return &intVal, nil +} + +func (e environment) getIntConfigOr(traitID id, key string, defaultValue int) (int, error) { + val, err := e.getIntConfig(traitID, key) + if err != nil { + return 0, err + } + if val != nil { + return *val, nil + } + return defaultValue, nil +}
