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

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


The following commit(s) were added to refs/heads/master by this push:
     new e4f52eb  Create pdbTrait that adds PodDisruptionBudget for every 
integration
e4f52eb is described below

commit e4f52eb45ce9374dd2067bf5f628b4a40f7b3e87
Author: mmelko <mme...@redhat.com>
AuthorDate: Thu Oct 22 13:49:16 2020 +0200

    Create pdbTrait that adds PodDisruptionBudget for every integration
---
 deploy/operator-role-kubernetes.yaml |  11 ++++
 deploy/operator-role-olm.yaml        |  11 ++++
 deploy/operator-role-openshift.yaml  |  11 ++++
 deploy/resources.go                  |  12 ++--
 pkg/trait/pdb.go                     | 109 +++++++++++++++++++++++++++++++
 pkg/trait/pdb_test.go                | 122 +++++++++++++++++++++++++++++++++++
 pkg/trait/trait_register.go          |   1 +
 7 files changed, 271 insertions(+), 6 deletions(-)

diff --git a/deploy/operator-role-kubernetes.yaml 
b/deploy/operator-role-kubernetes.yaml
index 26c4c48..f194602 100644
--- a/deploy/operator-role-kubernetes.yaml
+++ b/deploy/operator-role-kubernetes.yaml
@@ -48,6 +48,17 @@ rules:
   - update
   - watch
 - apiGroups:
+  - policy
+  resources:
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - delete
+  - get
+  - update
+  - list
+  - patch
+- apiGroups:
   - rbac.authorization.k8s.io
   resources:
   - roles
diff --git a/deploy/operator-role-olm.yaml b/deploy/operator-role-olm.yaml
index 53fa59f..d488dd1 100644
--- a/deploy/operator-role-olm.yaml
+++ b/deploy/operator-role-olm.yaml
@@ -48,6 +48,17 @@ rules:
   - update
   - watch
 - apiGroups:
+  - policy
+  resources:
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - delete
+  - get
+  - update
+  - patch
+  - list
+- apiGroups:
   - rbac.authorization.k8s.io
   resources:
   - roles
diff --git a/deploy/operator-role-openshift.yaml 
b/deploy/operator-role-openshift.yaml
index 31696bc..8b20303 100644
--- a/deploy/operator-role-openshift.yaml
+++ b/deploy/operator-role-openshift.yaml
@@ -48,6 +48,17 @@ rules:
   - update
   - watch
 - apiGroups:
+  - policy
+  resources:
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - delete
+  - get
+  - update
+  - list
+  - patch
+- apiGroups:
   - rbac.authorization.k8s.io
   resources:
   - roles
diff --git a/deploy/resources.go b/deploy/resources.go
index a47f1d4..f432da1 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -231,9 +231,9 @@ var assets = func() http.FileSystem {
                "/operator-role-kubernetes.yaml": &vfsgen۰CompressedFileInfo{
                        name:             "operator-role-kubernetes.yaml",
                        modTime:          time.Time{},
-                       uncompressedSize: 2244,
+                       uncompressedSize: 2375,
 
-                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x54\xc1\x6e\x1b\x37\x10\xbd\xf3\x2b\x1e\xb4\x97\xa4\xb0\xe4\xb6\xa7\x42\x3d\xa9\x8e\xdd\x0a\x0d\x24\xc0\xab\x34\xc8\x91\xe2\x8e\x56\x53\x73\x39\x2c\xc9\x95\xec\x7e\x7d\x41\xee\x2a\x91\xa3\x04\xe8\x21\x88\xf7\xa2\x21\x77\xf6\xcd\x9b\xf7\x46\x53\x61\xfa\xed\x1e\x55\xe1\x2d\x1b\x72\x91\x1a\x24\x41\xda\x13\x16\x5e\x9b\x3d\xa1\x96\x5d\x3a\xea\x40\xb8\x93\xde\x35\x3a\xb1\x38\xbc\x5a\xd4\x77\xaf\xd1\xbb\x86\x02\xc4\x11\x
 [...]
+                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x54\xc1\x72\xdb\x36\x10\xbd\xf3\x2b\xde\x88\x97\xa4\x63\xc9\x6d\x4f\x1d\xf5\xa4\x26\x76\xab\x69\x46\x9a\x31\x95\x66\x72\x04\xc1\x15\xb5\x35\x88\x45\x01\x50\xb2\xfa\xf5\x1d\x40\x54\x22\x9b\xce\x8c\x0f\x9e\x86\x17\x2d\xc0\xe5\xdb\xb7\xfb\x9e\xb6\xc4\xf4\xf5\x9e\xa2\xc4\x07\xd6\x64\x03\x35\x88\x82\xb8\x23\x2c\x9c\xd2\x3b\x42\x25\xdb\x78\x50\x9e\x70\x2b\xbd\x6d\x54\x64\xb1\x78\xb3\xa8\x6e\xdf\xa2\xb7\x0d\x79\x88\x25\x
 [...]
                },
                "/operator-role-olm-cluster.yaml": &vfsgen۰CompressedFileInfo{
                        name:             "operator-role-olm-cluster.yaml",
@@ -245,16 +245,16 @@ var assets = func() http.FileSystem {
                "/operator-role-olm.yaml": &vfsgen۰CompressedFileInfo{
                        name:             "operator-role-olm.yaml",
                        modTime:          time.Time{},
-                       uncompressedSize: 3958,
+                       uncompressedSize: 4089,
 
-                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x56\x41\x8f\xdb\x36\x13\xbd\xeb\x57\x0c\xec\x4b\xf2\x61\x2d\x7f\xed\xa9\x70\x4f\x6e\xb2\xdb\x1a\x0d\xbc\xc0\x7a\xd3\x20\xc7\x31\x35\x96\xa6\x26\x39\x2c\x49\xd9\x71\x7e\x7d\x41\x4a\x4e\xe4\x68\xb7\x49\x81\x00\xae\x2f\xa6\x86\xa3\x99\x37\xef\x0d\x47\x9c\xc2\xec\xfb\xfd\x8a\x29\xbc\x61\x45\x36\x50\x05\x51\x20\x36\x04\x4b\x87\xaa\x21\xd8\xc8\x2e\x1e\xd1\x13\xdc\x49\x6b\x2b\x8c\x2c\x16\x5e\x2c\x37\x77\x2f\xa1\xb5\x15\x
 [...]
+                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x56\x51\x8f\xdb\x36\x0c\x7e\xf7\xaf\x20\x92\x97\x76\xb8\x38\xdb\x9e\x86\xec\x29\x6b\xef\xb6\x60\x45\x0e\xb8\x5c\x57\xf4\x91\x96\x19\x9b\x8b\x2c\x6a\x92\x9c\x34\xfd\xf5\x83\x64\xa7\xe7\xd4\x77\xeb\x15\x38\x2c\x79\x89\x4c\xd1\xe4\x47\x7e\x9f\x68\x4d\x61\xf6\x72\xbf\x6c\x0a\xef\x58\x91\xf1\x54\x42\x10\x08\x35\xc1\xd2\xa2\xaa\x09\x36\xb2\x0d\x07\x74\x04\x37\xd2\x9a\x12\x03\x8b\x81\x57\xcb\xcd\xcd\x6b\x68\x4d\x49\x0e\x
 [...]
                },
                "/operator-role-openshift.yaml": &vfsgen۰CompressedFileInfo{
                        name:             "operator-role-openshift.yaml",
                        modTime:          time.Time{},
-                       uncompressedSize: 3022,
+                       uncompressedSize: 3153,
 
-                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x54\x41\x8f\xdb\x46\x0f\xbd\xeb\x57\x10\xd2\x25\xf9\xb0\x96\xbf\xf6\x54\xb8\x27\x37\xd9\x6d\x8d\x06\x36\xb0\x72\x1a\xe4\x48\x8d\x68\x89\xdd\xd1\x70\x3a\x33\xb2\xe2\xfe\xfa\x42\x23\x39\xb1\xa3\x5d\xa4\x05\x02\xd8\x17\x53\x1c\xea\xf1\xf1\x3d\x6a\x32\x58\x7c\xbf\x5f\x92\xc1\x3b\x56\x64\x3c\x55\x10\x04\x42\x43\xb0\xb6\xa8\x1a\x82\x42\x0e\xa1\x47\x47\xf0\x20\x9d\xa9\x30\xb0\x18\x78\xb5\x2e\x1e\x5e\x43\x67\x2a\x72\x20\x
 [...]
+                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x54\xc1\x8e\xdb\x36\x10\xbd\xeb\x2b\x06\xd2\x25\x29\xd6\x76\xdb\x53\xe1\x9e\xdc\x64\xb7\x35\x1a\xd8\xc0\xda\x69\x90\xe3\x88\x1a\x4b\xd3\xa5\x38\x2c\x49\xd9\x71\xbf\xbe\x20\x25\x27\xf2\x6a\x17\x49\x81\x00\xeb\x8b\x47\xc3\xd1\x9b\x37\xf3\x9e\x58\xc0\xec\xfb\xfd\xb2\x02\xde\xb1\x22\xe3\xa9\x82\x20\x10\x1a\x82\x95\x45\xd5\x10\xec\xe4\x10\x4e\xe8\x08\xee\xa4\x33\x15\x06\x16\x03\xaf\x56\xbb\xbb\xd7\xd0\x99\x8a\x1c\x88\x
 [...]
                },
                "/operator-role-servicemonitors.yaml": 
&vfsgen۰CompressedFileInfo{
                        name:             "operator-role-servicemonitors.yaml",
diff --git a/pkg/trait/pdb.go b/pkg/trait/pdb.go
new file mode 100644
index 0000000..7b273ce
--- /dev/null
+++ b/pkg/trait/pdb.go
@@ -0,0 +1,109 @@
+/*
+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 (
+       "fmt"
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "k8s.io/api/policy/v1beta1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
+)
+
+// The Pdb trait allows to configure the PodDisruptionBudget resource.
+//
+// +camel-k:trait=pdb
+type pdbTrait struct {
+       BaseTrait      `property:",squash"`
+       MaxUnavailable string `property:"max-unavailable" 
json:"maxUnavailable,omitempty"`
+       MinAvailable   string `property:"min-available" 
json:"minAvailable,omitempty"`
+}
+
+func newPdbTrait() Trait {
+       return &pdbTrait{
+               BaseTrait: NewBaseTrait("pdb", 900),
+       }
+}
+
+func (t *pdbTrait) Configure(e *Environment) (bool, error) {
+       if t.Enabled == nil || !*t.Enabled {
+               return false, nil
+       }
+
+       strategy, err := e.DetermineControllerStrategy()
+       if err != nil {
+               return false, fmt.Errorf("unable to determine the controller 
stratedy")
+       }
+
+       if strategy == ControllerStrategyCronJob {
+               return false, fmt.Errorf("poddisruptionbudget isn't supported 
with cron-job controller strategy")
+       }
+
+       if t.MaxUnavailable != "" && t.MinAvailable != "" {
+               return false, fmt.Errorf("both minAvailable and maxUnavailable 
can't be set simultaneously")
+       }
+
+       return e.IntegrationInPhase(
+               v1.IntegrationPhaseDeploying,
+               v1.IntegrationPhaseRunning,
+       ), nil
+}
+
+func (t *pdbTrait) Apply(e *Environment) error {
+       if pdb, err := t.generatePodDisruptionBudget(e); err == nil {
+               e.Resources.Add(pdb)
+       } else {
+               return err
+       }
+       return nil
+}
+
+func (t *pdbTrait) generatePodDisruptionBudget(e *Environment) 
(*v1beta1.PodDisruptionBudget, error) {
+       if t.MaxUnavailable == "" && t.MinAvailable == "" {
+               t.MaxUnavailable = "1"
+       }
+
+       integration := e.Integration
+       spec := v1beta1.PodDisruptionBudgetSpec{
+               Selector: &metav1.LabelSelector{
+                       MatchLabels: map[string]string{
+                               v1.IntegrationLabel: integration.Name,
+                       },
+               },
+       }
+
+       var min, max intstr.IntOrString
+
+       if t.MaxUnavailable != "" {
+               max = intstr.Parse(t.MaxUnavailable)
+               spec.MaxUnavailable = &max
+
+       } else {
+               min = intstr.Parse(t.MinAvailable)
+               spec.MinAvailable = &min
+       }
+
+       return &v1beta1.PodDisruptionBudget{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      integration.Name,
+                       Namespace: integration.Namespace,
+                       Labels:    integration.Labels,
+               },
+               Spec: spec,
+       }, nil
+}
diff --git a/pkg/trait/pdb_test.go b/pkg/trait/pdb_test.go
new file mode 100644
index 0000000..d2e09aa
--- /dev/null
+++ b/pkg/trait/pdb_test.go
@@ -0,0 +1,122 @@
+/*
+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 (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+
+       appsv1 "k8s.io/api/apps/v1"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/api/policy/v1beta1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+)
+
+func TestConfigurePdbTraitDoesSucceed(t *testing.T) {
+       pdbTrait, environment, _ := createPdbTest()
+       configured, err := pdbTrait.Configure(environment)
+
+       assert.True(t, configured)
+       assert.Nil(t, err)
+}
+
+func TestConfigurePdbTraitDoesNotSucceed(t *testing.T) {
+       pdbTrait, environment, _ := createPdbTest()
+
+       pdbTrait.MinAvailable = "1"
+       pdbTrait.MaxUnavailable = "2"
+       configured, err := pdbTrait.Configure(environment)
+       assert.NotNil(t, err)
+       assert.False(t, configured)
+}
+func TestPdbIsCreatedWithoutParametersEnabled(t *testing.T) {
+       pdbTrait, environment, _ := createPdbTest()
+
+       pdb := pdbCreatedCheck(pdbTrait, environment, t)
+       assert.Equal(t, int32(1), pdb.Spec.MaxUnavailable.IntVal)
+}
+
+func TestPdbIsCreatedWithMaxUnavailable(t *testing.T) {
+       pdbTrait, environment, _ := createPdbTest()
+       pdbTrait.MaxUnavailable = "1"
+
+       pdb := pdbCreatedCheck(pdbTrait, environment, t)
+       assert.Equal(t, int32(1), pdb.Spec.MaxUnavailable.IntVal)
+}
+
+func TestPdbIsCreatedWithMinAvailable(t *testing.T) {
+       pdbTrait, environment, _ := createPdbTest()
+       pdbTrait.MinAvailable = "2"
+
+       pdb := pdbCreatedCheck(pdbTrait, environment, t)
+       assert.Equal(t, int32(2), pdb.Spec.MinAvailable.IntVal)
+}
+
+func pdbCreatedCheck(pdbTrait *pdbTrait, environment *Environment, t 
*testing.T) *v1beta1.PodDisruptionBudget {
+       err := pdbTrait.Apply(environment)
+       assert.Nil(t, err)
+       pdb := findPdb(environment.Resources)
+
+       assert.NotNil(t, pdb)
+       assert.Equal(t, environment.Integration.Name, pdb.Name)
+       assert.Equal(t, environment.Integration.Namespace, pdb.Namespace)
+       assert.Equal(t, environment.Integration.Labels, pdb.Labels)
+       return pdb
+}
+
+func findPdb(resources *kubernetes.Collection) *v1beta1.PodDisruptionBudget {
+       for _, a := range resources.Items() {
+               if _, ok := a.(*v1beta1.PodDisruptionBudget); ok {
+                       return a.(*v1beta1.PodDisruptionBudget)
+               }
+       }
+       return nil
+}
+
+func createPdbTest() (*pdbTrait, *Environment, *appsv1.Deployment) {
+       trait := newPdbTrait().(*pdbTrait)
+       enabled := true
+       trait.Enabled = &enabled
+
+       deployment := &appsv1.Deployment{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name: "integration-name",
+               },
+               Spec: appsv1.DeploymentSpec{
+                       Template: corev1.PodTemplateSpec{},
+               },
+       }
+
+       environment := &Environment{
+               Integration: &v1.Integration{
+                       ObjectMeta: metav1.ObjectMeta{
+                               Name: "integration-name",
+                       },
+                       Status: v1.IntegrationStatus{
+                               Phase: v1.IntegrationPhaseDeploying,
+                       },
+               },
+               Resources: kubernetes.NewCollection(deployment),
+       }
+
+       return trait, environment, deployment
+}
diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go
index 30c4356..ef171c7 100644
--- a/pkg/trait/trait_register.go
+++ b/pkg/trait/trait_register.go
@@ -46,4 +46,5 @@ func init() {
        AddToTraits(newIstioTrait)
        AddToTraits(newIngressTrait)
        AddToTraits(newOwnerTrait)
+       AddToTraits(newPdbTrait)
 }

Reply via email to