Skip to content

Commit 89a7d9d

Browse files
dak1n1jhoblitt
andauthored
Add divisor to resource_field_ref (#1063)
* Add divisor to resource_field_ref Add `divisor` field to resource_field_ref. Add acceptance tests for resource_field_ref. This is a cherry-pick of #538 * Update wait_for logic to wait until Deployment pods are Ready * Fix permissions error in Deployment acceptance test Co-authored-by: Joshua Hoblitt <[email protected]>
1 parent dc44bd4 commit 89a7d9d

File tree

5 files changed

+157
-57
lines changed

5 files changed

+157
-57
lines changed

kubernetes/resource_kubernetes_deployment.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ func waitForDeploymentReplicasFunc(ctx context.Context, conn *kubernetes.Clients
416416
return resource.NonRetryableError(err)
417417
}
418418

419-
var specReplicas int32 = 1 // default, acording to API docs
419+
var specReplicas int32 = 1 // default, according to API docs
420420
if dply.Spec.Replicas != nil {
421421
specReplicas = *dply.Spec.Replicas
422422
}
@@ -436,6 +436,10 @@ func waitForDeploymentReplicasFunc(ctx context.Context, conn *kubernetes.Clients
436436
return resource.RetryableError(fmt.Errorf("Waiting for rollout to finish: %d old replicas are pending termination...", dply.Status.Replicas-dply.Status.UpdatedReplicas))
437437
}
438438

439+
if dply.Status.Replicas > dply.Status.ReadyReplicas {
440+
return resource.RetryableError(fmt.Errorf("Waiting for rollout to finish: %d replicas wanted; %d replicas Ready", dply.Status.Replicas, dply.Status.ReadyReplicas))
441+
}
442+
439443
if dply.Status.AvailableReplicas < dply.Status.UpdatedReplicas {
440444
return resource.RetryableError(fmt.Errorf("Waiting for rollout to finish: %d of %d updated replicas are available...", dply.Status.AvailableReplicas, dply.Status.UpdatedReplicas))
441445
}

kubernetes/resource_kubernetes_deployment_test.go

Lines changed: 127 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ func TestAccKubernetesDeployment_basic(t *testing.T) {
3232
Config: testAccKubernetesDeploymentConfig_basic(name),
3333
Check: resource.ComposeAggregateTestCheckFunc(
3434
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf),
35-
testAccCheckKubernetesDeploymentRolledOut("kubernetes_deployment.test"),
3635
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.%", "2"),
3736
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationOne", "one"),
3837
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationTwo", "two"),
@@ -436,24 +435,15 @@ func TestAccKubernetesDeployment_with_container_security_context_run_as_group(t
436435
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf),
437436
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.#", "2"),
438437
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.security_context.#", "1"),
439-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.security_context.0.capabilities.#", "0"),
440438
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.security_context.0.privileged", "true"),
441439
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.security_context.0.se_linux_options.#", "1"),
442440
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.security_context.0.se_linux_options.0.level", "s0:c123,c456"),
443441
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.#", "1"),
444442
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.allow_privilege_escalation", "true"),
445-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.#", "1"),
446-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.add.#", "1"),
447-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.add.0", "NET_BIND_SERVICE"),
448-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.#", "1"),
449-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.0", "all"),
450-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.privileged", "true"),
451-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.read_only_root_filesystem", "true"),
443+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.privileged", "false"),
452444
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.run_as_group", "200"),
453-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.run_as_non_root", "true"),
445+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.run_as_non_root", "false"),
454446
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.run_as_user", "201"),
455-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.#", "1"),
456-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.0.level", "s0:c123,c789"),
457447
),
458448
},
459449
},
@@ -915,14 +905,14 @@ func TestAccKubernetesDeployment_regression(t *testing.T) {
915905
resource.Test(t, resource.TestCase{
916906
PreCheck: func() { testAccPreCheck(t) },
917907
IDRefreshName: "kubernetes_deployment.test",
908+
IDRefreshIgnore: []string{"metadata.0.resource_version"},
918909
ExternalProviders: testAccExternalProviders,
919910
CheckDestroy: testAccCheckKubernetesDeploymentDestroy,
920911
Steps: []resource.TestStep{
921912
{
922913
Config: requiredProviders() + testAccKubernetesDeploymentConfig_regression("kubernetes-released", name),
923914
Check: resource.ComposeAggregateTestCheckFunc(
924915
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf1),
925-
testAccCheckKubernetesDeploymentRolledOut("kubernetes_deployment.test"),
926916
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.%", "2"),
927917
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationOne", "one"),
928918
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationTwo", "two"),
@@ -938,7 +928,7 @@ func TestAccKubernetesDeployment_regression(t *testing.T) {
938928
resource.TestCheckResourceAttrSet("kubernetes_deployment.test", "metadata.0.self_link"),
939929
resource.TestCheckResourceAttrSet("kubernetes_deployment.test", "metadata.0.uid"),
940930
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.image", defaultNginxImage),
941-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.name", "tf-acc-test"),
931+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.name", "containername"),
942932
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.type", "RollingUpdate"),
943933
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.rolling_update.0.max_surge", "25%"),
944934
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.rolling_update.0.max_unavailable", "25%"),
@@ -949,7 +939,6 @@ func TestAccKubernetesDeployment_regression(t *testing.T) {
949939
Config: requiredProviders() + testAccKubernetesDeploymentConfig_regression("kubernetes-local", name),
950940
Check: resource.ComposeAggregateTestCheckFunc(
951941
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf2),
952-
testAccCheckKubernetesDeploymentRolledOut("kubernetes_deployment.test"),
953942
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.%", "2"),
954943
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationOne", "one"),
955944
resource.TestCheckResourceAttr("kubernetes_deployment.test", "metadata.0.annotations.TestAnnotationTwo", "two"),
@@ -965,7 +954,7 @@ func TestAccKubernetesDeployment_regression(t *testing.T) {
965954
resource.TestCheckResourceAttrSet("kubernetes_deployment.test", "metadata.0.self_link"),
966955
resource.TestCheckResourceAttrSet("kubernetes_deployment.test", "metadata.0.uid"),
967956
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.image", defaultNginxImage),
968-
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.name", "tf-acc-test"),
957+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.name", "containername"),
969958
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.type", "RollingUpdate"),
970959
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.rolling_update.0.max_surge", "25%"),
971960
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.strategy.0.rolling_update.0.max_unavailable", "25%"),
@@ -977,6 +966,57 @@ func TestAccKubernetesDeployment_regression(t *testing.T) {
977966
})
978967
}
979968

969+
func TestAccKubernetesDeployment_with_resource_field_selector(t *testing.T) {
970+
var conf appsv1.Deployment
971+
rcName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
972+
imageName := "nginx:1.7.9"
973+
974+
resource.Test(t, resource.TestCase{
975+
PreCheck: func() { testAccPreCheck(t) },
976+
ProviderFactories: testAccProviderFactories,
977+
CheckDestroy: testAccCheckKubernetesDeploymentDestroy,
978+
Steps: []resource.TestStep{
979+
{
980+
ExpectError: regexp.MustCompile("quantities must match the regular expression"),
981+
Config: testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, "limits.cpu", ""),
982+
},
983+
{
984+
ExpectError: regexp.MustCompile("only divisor's values 1m and 1 are supported with the cpu resource"),
985+
Config: testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, "limits.cpu", "2"),
986+
},
987+
{
988+
Config: testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, "limits.cpu", "1m"),
989+
Check: resource.ComposeAggregateTestCheckFunc(
990+
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf),
991+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.image", imageName),
992+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.resources.0.limits.0.memory", "512Mi"),
993+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.#", "1"),
994+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.name", "K8S_LIMITS_CPU"),
995+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.container_name", "containername"),
996+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.divisor", "1m"),
997+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.resource", "limits.cpu"),
998+
),
999+
},
1000+
{
1001+
Config: testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, "limits.memory", "1Mi"),
1002+
Check: resource.ComposeAggregateTestCheckFunc(
1003+
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf),
1004+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.divisor", "1Mi"),
1005+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.resource", "limits.memory"),
1006+
),
1007+
},
1008+
{
1009+
Config: testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, "requests.memory", "1Ki"),
1010+
Check: resource.ComposeAggregateTestCheckFunc(
1011+
testAccCheckKubernetesDeploymentExists("kubernetes_deployment.test", &conf),
1012+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.divisor", "1Ki"),
1013+
resource.TestCheckResourceAttr("kubernetes_deployment.test", "spec.0.template.0.spec.0.container.0.env.0.value_from.0.resource_field_ref.0.resource", "requests.memory"),
1014+
),
1015+
},
1016+
},
1017+
})
1018+
}
1019+
9801020
func testAccCheckKubernetesDeploymentForceNew(old, new *appsv1.Deployment, wantNew bool) resource.TestCheckFunc {
9811021
return func(s *terraform.State) error {
9821022
if wantNew {
@@ -1095,21 +1135,6 @@ func testAccCheckKubernetesDeploymentRollingOut(n string) resource.TestCheckFunc
10951135
}
10961136
}
10971137

1098-
func testAccCheckKubernetesDeploymentRolledOut(n string) resource.TestCheckFunc {
1099-
return func(s *terraform.State) error {
1100-
d, err := getDeploymentFromResourceName(s, n)
1101-
if err != nil {
1102-
return err
1103-
}
1104-
1105-
if d.Status.Replicas != d.Status.ReadyReplicas {
1106-
return fmt.Errorf("deployment is still rolling out")
1107-
}
1108-
1109-
return nil
1110-
}
1111-
}
1112-
11131138
func testAccKubernetesDeploymentConfig_basic(name string) string {
11141139
return fmt.Sprintf(`resource "kubernetes_deployment" "test" {
11151140
metadata {
@@ -1841,27 +1866,12 @@ func testAccKubernetesDeploymentConfigWithContainerSecurityContextRunAsGroup(dep
18411866
}
18421867
18431868
container {
1844-
image = "gcr.io/google_containers/liveness"
1845-
name = "containername2"
1846-
args = ["/server"]
1847-
1869+
name = "container2"
1870+
image = "busybox"
1871+
command = ["sh", "-c", "echo The app is running! && sleep 3600"]
18481872
security_context {
1849-
allow_privilege_escalation = true
1850-
1851-
capabilities {
1852-
drop = ["all"]
1853-
add = ["NET_BIND_SERVICE"]
1854-
}
1855-
1856-
privileged = true
1857-
read_only_root_filesystem = true
1858-
run_as_group = 200
1859-
run_as_non_root = true
1860-
run_as_user = 201
1861-
1862-
se_linux_options {
1863-
level = "s0:c123,c789"
1864-
}
1873+
run_as_group = 200
1874+
run_as_user = 201
18651875
}
18661876
}
18671877
}
@@ -2388,7 +2398,7 @@ func testAccKubernetesDeploymentConfig_regression(provider, name string) string
23882398
spec {
23892399
container {
23902400
image = %q
2391-
name = "tf-acc-test"
2401+
name = "containername"
23922402
23932403
port {
23942404
container_port = 80
@@ -2408,6 +2418,24 @@ func testAccKubernetesDeploymentConfig_regression(provider, name string) string
24082418
cpu = "50m"
24092419
}
24102420
}
2421+
env {
2422+
name = "LIMITS_CPU"
2423+
value_from {
2424+
resource_field_ref {
2425+
container_name = "containername"
2426+
resource = "requests.cpu"
2427+
}
2428+
}
2429+
}
2430+
env {
2431+
name = "LIMITS_MEM"
2432+
value_from {
2433+
resource_field_ref {
2434+
container_name = "containername"
2435+
resource = "requests.memory"
2436+
}
2437+
}
2438+
}
24112439
}
24122440
}
24132441
}
@@ -2474,3 +2502,50 @@ resource "kubernetes_deployment" "test" {
24742502
}
24752503
`, secretName, label, deploymentName, imageName)
24762504
}
2505+
2506+
func testAccKubernetesDeploymentConfigWithResourceFieldSelector(rcName, imageName, resourceName, divisor string) string {
2507+
return fmt.Sprintf(`resource "kubernetes_deployment" "test" {
2508+
metadata {
2509+
name = "%s"
2510+
labels = {
2511+
Test = "TfAcceptanceTest"
2512+
}
2513+
}
2514+
spec {
2515+
selector {
2516+
match_labels = {
2517+
Test = "TfAcceptanceTest"
2518+
}
2519+
}
2520+
template {
2521+
metadata {
2522+
labels = {
2523+
Test = "TfAcceptanceTest"
2524+
}
2525+
}
2526+
spec {
2527+
container {
2528+
image = "%s"
2529+
name = "containername"
2530+
resources {
2531+
limits {
2532+
memory = "512Mi"
2533+
}
2534+
}
2535+
env {
2536+
name = "K8S_LIMITS_CPU"
2537+
value_from {
2538+
resource_field_ref {
2539+
container_name = "containername"
2540+
resource = "%s"
2541+
divisor = "%s"
2542+
}
2543+
}
2544+
}
2545+
}
2546+
}
2547+
}
2548+
}
2549+
}
2550+
`, rcName, imageName, resourceName, divisor)
2551+
}

kubernetes/schema_container.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ func containerFields(isUpdatable, isInitContainer bool) map[string]*schema.Schem
274274
Type: schema.TypeString,
275275
Optional: true,
276276
},
277+
"divisor": {
278+
Type: schema.TypeString,
279+
Optional: true,
280+
Default: "1",
281+
ValidateFunc: validateResourceQuantity,
282+
DiffSuppressFunc: suppressEquivalentResourceQuantity,
283+
},
277284
"resource": {
278285
Type: schema.TypeString,
279286
Required: true,

kubernetes/schema_pod_spec.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,9 +547,12 @@ func volumeSchema(isUpdatable bool) *schema.Resource {
547547
Type: schema.TypeString,
548548
Required: true,
549549
},
550-
"quantity": {
551-
Type: schema.TypeString,
552-
Optional: true,
550+
"divisor": {
551+
Type: schema.TypeString,
552+
Optional: true,
553+
Default: "1",
554+
ValidateFunc: validateResourceQuantity,
555+
DiffSuppressFunc: suppressEquivalentResourceQuantity,
553556
},
554557
"resource": {
555558
Type: schema.TypeString,

kubernetes/structures_container.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package kubernetes
22

33
import (
4-
v1 "k8s.io/api/core/v1"
4+
"k8s.io/api/core/v1"
5+
"k8s.io/apimachinery/pkg/api/resource"
56
"k8s.io/apimachinery/pkg/util/intstr"
67
)
78

@@ -205,6 +206,9 @@ func flattenResourceFieldSelector(in *v1.ResourceFieldSelector) []interface{} {
205206
if in.Resource != "" {
206207
att["resource"] = in.Resource
207208
}
209+
if in.Divisor.String() != "" {
210+
att["divisor"] = in.Divisor.String()
211+
}
208212
return []interface{}{att}
209213
}
210214

@@ -861,6 +865,13 @@ func expandResourceFieldRef(r []interface{}) (*v1.ResourceFieldSelector, error)
861865
if v, ok := in["resource"].(string); ok {
862866
obj.Resource = v
863867
}
868+
if v, ok := in["divisor"].(string); ok {
869+
q, err := resource.ParseQuantity(v)
870+
if err != nil {
871+
return obj, err
872+
}
873+
obj.Divisor = q
874+
}
864875
return obj, nil
865876
}
866877

0 commit comments

Comments
 (0)