Skip to content

Commit 4e93e5e

Browse files
mbarrienalexsomesan
authored andcommitted
Add PodDisruptionBudget (closes #320) (#338)
* Add support for PodDisruptionBudget
1 parent aea0c9a commit 4e93e5e

9 files changed

+613
-34
lines changed

kubernetes/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func Provider() terraform.ResourceProvider {
158158
"kubernetes_persistent_volume": resourceKubernetesPersistentVolume(),
159159
"kubernetes_persistent_volume_claim": resourceKubernetesPersistentVolumeClaim(),
160160
"kubernetes_pod": resourceKubernetesPod(),
161+
"kubernetes_pod_disruption_budget": resourceKubernetesPodDisruptionBudget(),
161162
"kubernetes_priority_class": resourceKubernetesPriorityClass(),
162163
"kubernetes_replication_controller": resourceKubernetesReplicationController(),
163164
"kubernetes_role_binding": resourceKubernetesRoleBinding(),
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package kubernetes
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
8+
api "k8s.io/api/policy/v1beta1"
9+
"k8s.io/apimachinery/pkg/api/errors"
10+
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
pkgApi "k8s.io/apimachinery/pkg/types"
12+
)
13+
14+
// Use generated swagger docs from kubernetes' client-go to avoid copy/pasting them here
15+
var (
16+
podDisruptionBudgetSpecDoc = api.PodDisruptionBudget{}.SwaggerDoc()["spec"]
17+
podDisruptionBudgetSpecMaxUnavailableDoc = api.PodDisruptionBudget{}.SwaggerDoc()["maxUnavailable"]
18+
podDisruptionBudgetSpecMinAvailableDoc = api.PodDisruptionBudget{}.SwaggerDoc()["minAvailable"]
19+
podDisruptionBudgetSpecSelectorDoc = api.PodDisruptionBudget{}.SwaggerDoc()["selector"]
20+
)
21+
22+
func resourceKubernetesPodDisruptionBudget() *schema.Resource {
23+
return &schema.Resource{
24+
Create: resourceKubernetesPodDisruptionBudgetCreate,
25+
Read: resourceKubernetesPodDisruptionBudgetRead,
26+
Update: resourceKubernetesPodDisruptionBudgetUpdate,
27+
Delete: resourceKubernetesPodDisruptionBudgetDelete,
28+
Exists: resourceKubernetesPodDisruptionBudgetExists,
29+
Importer: &schema.ResourceImporter{
30+
State: schema.ImportStatePassthrough,
31+
},
32+
33+
Schema: map[string]*schema.Schema{
34+
"metadata": namespacedMetadataSchema("pod disruption budget", true),
35+
// Updates to spec not allowed until Kubernetes dependencies are updated to
36+
// 1.13; have to delete and recreate until then
37+
// https://github.com/kubernetes/kubernetes/issues/45398
38+
"spec": {
39+
Type: schema.TypeList,
40+
Description: podDisruptionBudgetSpecDoc,
41+
Required: true,
42+
ForceNew: true,
43+
MaxItems: 1,
44+
Elem: &schema.Resource{
45+
Schema: map[string]*schema.Schema{
46+
"max_unavailable": {
47+
Type: schema.TypeString,
48+
Description: podDisruptionBudgetSpecMaxUnavailableDoc,
49+
Optional: true,
50+
ForceNew: true,
51+
ValidateFunc: validateTypeStringNullableIntOrPercent,
52+
},
53+
"min_available": {
54+
Type: schema.TypeString,
55+
Description: podDisruptionBudgetSpecMinAvailableDoc,
56+
Optional: true,
57+
ForceNew: true,
58+
ValidateFunc: validateTypeStringNullableIntOrPercent,
59+
},
60+
"selector": {
61+
Type: schema.TypeList,
62+
Description: podDisruptionBudgetSpecSelectorDoc,
63+
Required: true,
64+
ForceNew: true,
65+
MaxItems: 1,
66+
Elem: &schema.Resource{
67+
Schema: labelSelectorFields(false),
68+
},
69+
},
70+
},
71+
},
72+
},
73+
},
74+
}
75+
}
76+
77+
func resourceKubernetesPodDisruptionBudgetUpdate(d *schema.ResourceData, meta interface{}) error {
78+
conn := meta.(*KubeClientsets).MainClientset
79+
80+
namespace, name, err := idParts(d.Id())
81+
if err != nil {
82+
return err
83+
}
84+
85+
ops := patchMetadata("metadata.0.", "/metadata/", d)
86+
data, err := ops.MarshalJSON()
87+
if err != nil {
88+
return fmt.Errorf("Failed to marshal update operations: %s", err)
89+
}
90+
91+
log.Printf("[INFO] Updating pod disruption budget %s: %s", d.Id(), ops)
92+
out, err := conn.PolicyV1beta1().PodDisruptionBudgets(namespace).Patch(name, pkgApi.JSONPatchType, data)
93+
if err != nil {
94+
return err
95+
}
96+
97+
log.Printf("[INFO] Submitted updated pod disruption budget: %#v", out)
98+
d.SetId(buildId(out.ObjectMeta))
99+
100+
return resourceKubernetesPodDisruptionBudgetRead(d, meta)
101+
}
102+
103+
func resourceKubernetesPodDisruptionBudgetCreate(d *schema.ResourceData, meta interface{}) error {
104+
conn := meta.(*KubeClientsets).MainClientset
105+
106+
metadata := expandMetadata(d.Get("metadata").([]interface{}))
107+
spec, err := expandPodDisruptionBudgetSpec(d.Get("spec").([]interface{}))
108+
if err != nil {
109+
return err
110+
}
111+
pdb := api.PodDisruptionBudget{
112+
ObjectMeta: metadata,
113+
Spec: *spec,
114+
}
115+
116+
log.Printf("[INFO] Creating new pod disruption budget: %#v", pdb)
117+
out, err := conn.PolicyV1beta1().PodDisruptionBudgets(metadata.Namespace).Create(&pdb)
118+
if err != nil {
119+
return err
120+
}
121+
122+
log.Printf("[INFO] Submitted new pod disruption budget: %#v", out)
123+
d.SetId(buildId(out.ObjectMeta))
124+
125+
return resourceKubernetesPodDisruptionBudgetRead(d, meta)
126+
}
127+
128+
func resourceKubernetesPodDisruptionBudgetRead(d *schema.ResourceData, meta interface{}) error {
129+
conn := meta.(*KubeClientsets).MainClientset
130+
131+
namespace, name, err := idParts(d.Id())
132+
if err != nil {
133+
return err
134+
}
135+
136+
log.Printf("[INFO] Reading pod disruption budget %s", name)
137+
pdb, err := conn.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(name, meta_v1.GetOptions{})
138+
if err != nil {
139+
log.Printf("[DEBUG] Received error: %#v", err)
140+
return err
141+
}
142+
143+
log.Printf("[INFO] Received pod disruption budget: %#v", pdb)
144+
err = d.Set("metadata", flattenMetadata(pdb.ObjectMeta, d))
145+
if err != nil {
146+
return err
147+
}
148+
149+
err = d.Set("spec", flattenPodDisruptionBudgetSpec(pdb.Spec))
150+
if err != nil {
151+
return err
152+
}
153+
154+
return nil
155+
}
156+
157+
func resourceKubernetesPodDisruptionBudgetDelete(d *schema.ResourceData, meta interface{}) error {
158+
conn := meta.(*KubeClientsets).MainClientset
159+
160+
namespace, name, err := idParts(d.Id())
161+
if err != nil {
162+
return err
163+
}
164+
165+
log.Printf("[INFO] Deleting pod disruption budget %#v", name)
166+
err = conn.PolicyV1beta1().PodDisruptionBudgets(namespace).Delete(name, &meta_v1.DeleteOptions{})
167+
if err != nil {
168+
log.Printf("[DEBUG] Received error: %#v", err)
169+
return err
170+
}
171+
172+
log.Printf("[INFO] Pod disruption budget %#v deleted", name)
173+
174+
d.SetId("")
175+
return nil
176+
}
177+
178+
func resourceKubernetesPodDisruptionBudgetExists(d *schema.ResourceData, meta interface{}) (bool, error) {
179+
conn := meta.(*KubeClientsets).MainClientset
180+
181+
namespace, name, err := idParts(d.Id())
182+
if err != nil {
183+
return false, err
184+
}
185+
186+
log.Printf("[INFO] Checking pod disruption budget %s", name)
187+
_, err = conn.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(name, meta_v1.GetOptions{})
188+
if err != nil {
189+
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
190+
return false, nil
191+
}
192+
log.Printf("[DEBUG] Received error: %#v", err)
193+
}
194+
return true, err
195+
}

0 commit comments

Comments
 (0)