Skip to content

Commit

Permalink
Fix PDB implementation (#425)
Browse files Browse the repository at this point in the history
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. Run unit tests and ensure that they are passing
2. If your change introduces any API changes, make sure to update the
e2e tests
3. Make sure documentation is updated for your PR!

-->

**What this PR does / why we need it**:
<!-- Explain here the context and why you're making the change. What is
the problem you're trying to solve. --->

1. Fix PDB apply by supplying `FieldManager: "application/apply-patch"`
kubernetes/client-go#1036 (comment)
2. Fix PDB config to always have % as suffix

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->

Fixes PDB implementation

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required. Enter your extended release note in
the block below.
If the PR requires additional action from users switching to the new
release, include the string "action required".

For more information about release notes, see kubernetes' guide here:
http://git.k8s.io/community/contributors/guide/release-notes.md
-->

```release-note
NONE
```

**Checklist**

- [x] Added unit test, integration, and/or e2e tests
- [x] Tested locally
- [ ] Updated documentation
- [ ] Update Swagger spec if the PR introduce API changes
- [ ] Regenerated Golang and Python client if the PR introduce API
changes
  • Loading branch information
ariefrahmansyah committed Jul 10, 2023
1 parent 48d8ca1 commit b2ed508
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 8 deletions.
7 changes: 3 additions & 4 deletions api/cluster/pdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ type PodDisruptionBudget struct {
Labels map[string]string
MaxUnavailablePercentage *int
MinAvailablePercentage *int
Selector *metav1.LabelSelector
}

func NewPodDisruptionBudget(modelService *models.Service, componentType string, pdbConfig config.PodDisruptionBudgetConfig) *PodDisruptionBudget {
Expand All @@ -47,10 +46,10 @@ func (cfg PodDisruptionBudget) BuildPDBSpec() (*policyv1cfg.PodDisruptionBudgetS
// Since we can specify only one of maxUnavailable and minAvailable, minAvailable takes precedence
// https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
if cfg.MinAvailablePercentage != nil {
minAvailable := intstr.FromInt(*cfg.MinAvailablePercentage)
minAvailable := intstr.FromString(fmt.Sprintf("%d%%", *cfg.MinAvailablePercentage))
pdbSpec.MinAvailable = &minAvailable
} else if cfg.MaxUnavailablePercentage != nil {
maxUnavailable := intstr.FromInt(*cfg.MaxUnavailablePercentage)
maxUnavailable := intstr.FromString(fmt.Sprintf("%d%%", *cfg.MaxUnavailablePercentage))
pdbSpec.MaxUnavailable = &maxUnavailable
}

Expand Down Expand Up @@ -90,7 +89,7 @@ func (c *controller) deployPodDisruptionBudget(ctx context.Context, pdb *PodDisr
pdbCfg.WithLabels(pdb.Labels)
pdbCfg.WithSpec(pdbSpec)

_, err = c.policyClient.PodDisruptionBudgets(pdb.Namespace).Apply(ctx, pdbCfg, metav1.ApplyOptions{})
_, err = c.policyClient.PodDisruptionBudgets(pdb.Namespace).Apply(ctx, pdbCfg, metav1.ApplyOptions{FieldManager: "application/apply-patch"})
if err != nil {
return err
}
Expand Down
100 changes: 100 additions & 0 deletions api/cluster/pdb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package cluster

import (
"reflect"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
metav1cfg "k8s.io/client-go/applyconfigurations/meta/v1"
policyv1cfg "k8s.io/client-go/applyconfigurations/policy/v1"
)

func TestPodDisruptionBudget_BuildPDBSpec(t *testing.T) {
defaultInt := 20
defaultIntOrString := intstr.FromString("20%")
defaultLabels := map[string]string{
"gojek.com/app": "sklearn-sample-s",
}

type fields struct {
Name string
Namespace string
Labels map[string]string
MaxUnavailablePercentage *int
MinAvailablePercentage *int
Selector *metav1.LabelSelector
}
tests := []struct {
name string
fields fields
want *policyv1cfg.PodDisruptionBudgetSpecApplyConfiguration
wantErr bool
}{
{
name: "valid: enabled with min_available",
fields: fields{
Name: "sklearn-sample-s-1-model-pdb",
Namespace: "pdb-test",
Labels: defaultLabels,
MaxUnavailablePercentage: nil,
MinAvailablePercentage: &defaultInt,
},
want: &policyv1cfg.PodDisruptionBudgetSpecApplyConfiguration{
MinAvailable: &defaultIntOrString,
Selector: &metav1cfg.LabelSelectorApplyConfiguration{
MatchLabels: defaultLabels,
},
},
wantErr: false,
},
{
name: "valid: enabled but both max_unavailable and min_available specified. will use min available",
fields: fields{
Name: "sklearn-sample-s-1-model-pdb",
Namespace: "pdb-test",
Labels: defaultLabels,
MaxUnavailablePercentage: &defaultInt,
MinAvailablePercentage: &defaultInt,
},
want: &policyv1cfg.PodDisruptionBudgetSpecApplyConfiguration{
MinAvailable: &defaultIntOrString,
Selector: &metav1cfg.LabelSelectorApplyConfiguration{
MatchLabels: defaultLabels,
},
},
wantErr: false,
},
{
name: "invalid: enabled but no max_unavailable and min_available",
fields: fields{
Name: "sklearn-sample-s-1-model-pdb",
Namespace: "pdb-test",
Labels: map[string]string{},
MaxUnavailablePercentage: nil,
MinAvailablePercentage: nil,
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := PodDisruptionBudget{
Name: tt.fields.Name,
Namespace: tt.fields.Namespace,
Labels: tt.fields.Labels,
MaxUnavailablePercentage: tt.fields.MaxUnavailablePercentage,
MinAvailablePercentage: tt.fields.MinAvailablePercentage,
}
got, err := cfg.BuildPDBSpec()
if (err != nil) != tt.wantErr {
t.Errorf("PodDisruptionBudget.BuildPDBSpec() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("PodDisruptionBudget.BuildPDBSpec() = %v, want %v", got, tt.want)
}
})
}
}
6 changes: 3 additions & 3 deletions api/config/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestUnmarshalTopologySpreadConstraints(t *testing.T) {
}

func TestPDBConfig(t *testing.T) {
defaultMaxUnavailablePercentage := 20
defaultMinAvailablePercentage := 20

testCases := []struct {
desc string
Expand All @@ -112,8 +112,8 @@ func TestPDBConfig(t *testing.T) {
desc: "Success: valid pdb config",
envConfigPath: "./testdata/valid-environment-1.yaml",
expectedPDBConfig: PodDisruptionBudgetConfig{
Enabled: true,
MaxUnavailablePercentage: &defaultMaxUnavailablePercentage,
Enabled: true,
MinAvailablePercentage: &defaultMinAvailablePercentage,
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion api/config/testdata/valid-environment-1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
max_memory: "8Gi"
pod_disruption_budget:
enabled: true
max_unavailable_percentage: 20
min_available_percentage: 20
queue_resource_percentage: "20"
default_prediction_job_config:
executor_replica: 3
Expand Down

0 comments on commit b2ed508

Please sign in to comment.