You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2020/11/12 13:34:45 UTC
[camel-k] branch master updated: Create pdbTrait that adds
PodDisruptionBudget for every integration
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 <mm...@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)
}