Skip to content

Commit 73e2558

Browse files
authored
Adding a Runtime class resource (#2080)
Added a runtime class resource to the provider.
1 parent c1408ac commit 73e2558

File tree

5 files changed

+415
-0
lines changed

5 files changed

+415
-0
lines changed

.changelog/2080.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
`resource/kubernetes_runtime_class_v1`: Add a new resource `kubernetes_runtime_class_v1`.
3+
```

kubernetes/provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ func Provider() *schema.Provider {
345345

346346
// authentication
347347
"kubernetes_token_request_v1": resourceKubernetesTokenRequestV1(),
348+
349+
//node
350+
"kubernetes_runtime_class_v1": resourceKubernetesRuntimeClassV1(),
348351
},
349352
}
350353

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package kubernetes
5+
6+
import (
7+
"context"
8+
"log"
9+
"regexp"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
12+
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
15+
nodev1 "k8s.io/api/node/v1"
16+
17+
"k8s.io/apimachinery/pkg/api/errors"
18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
pkgApi "k8s.io/apimachinery/pkg/types"
20+
)
21+
22+
func resourceKubernetesRuntimeClassV1() *schema.Resource {
23+
return &schema.Resource{
24+
CreateContext: resourceKubernetesRuntimeClassV1Create,
25+
ReadContext: resourceKubernetesRuntimeClassV1Read,
26+
UpdateContext: resourceKubernetesRuntimeClassV1Update,
27+
DeleteContext: resourceKubernetesRuntimeClassV1Delete,
28+
29+
Importer: &schema.ResourceImporter{
30+
StateContext: schema.ImportStatePassthroughContext,
31+
},
32+
33+
Schema: map[string]*schema.Schema{
34+
"metadata": metadataSchema("runtimeclass", true),
35+
36+
"handler": {
37+
Type: schema.TypeString,
38+
Description: "Specifies the underlying runtime and configuration that the CRI implementation will use to handle pods of this class",
39+
Required: true,
40+
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?`), ""),
41+
ForceNew: true,
42+
},
43+
},
44+
}
45+
46+
}
47+
48+
func resourceKubernetesRuntimeClassV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
49+
conn, err := meta.(KubeClientsets).MainClientset()
50+
if err != nil {
51+
return diag.FromErr(err)
52+
}
53+
54+
metadata := expandMetadata(d.Get("metadata").([]interface{}))
55+
56+
runtimeClass := nodev1.RuntimeClass{
57+
ObjectMeta: metadata,
58+
Handler: d.Get("handler").(string),
59+
}
60+
61+
out, err := conn.NodeV1().RuntimeClasses().Create(ctx, &runtimeClass, metav1.CreateOptions{})
62+
if err != nil {
63+
return diag.FromErr(err)
64+
}
65+
66+
log.Printf("[INFO] New runtime class created: %#v", out)
67+
d.SetId(out.Name)
68+
69+
return resourceKubernetesRuntimeClassV1Read(ctx, d, meta)
70+
}
71+
72+
func resourceKubernetesRuntimeClassV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
73+
exists, err := resourceKubernetesRuntimeClassV1Exists(ctx, d, meta)
74+
if err != nil {
75+
return diag.FromErr(err)
76+
}
77+
if !exists {
78+
d.SetId("")
79+
return diag.Diagnostics{}
80+
}
81+
82+
conn, err := meta.(KubeClientsets).MainClientset()
83+
if err != nil {
84+
return diag.FromErr(err)
85+
}
86+
87+
name := d.Id()
88+
89+
log.Printf("[INFO] Reading runtime class %s", name)
90+
rc, err := conn.NodeV1().RuntimeClasses().Get(ctx, name, metav1.GetOptions{})
91+
if err != nil {
92+
log.Printf("[DEBUG] Received error: %#v", err)
93+
return diag.FromErr(err)
94+
}
95+
96+
log.Printf("[INFO] Received runtime class: %#v", rc)
97+
err = d.Set("metadata", flattenMetadata(rc.ObjectMeta, d, meta))
98+
if err != nil {
99+
return diag.FromErr(err)
100+
}
101+
102+
err = d.Set("handler", rc.Handler)
103+
if err != nil {
104+
return diag.FromErr(err)
105+
}
106+
107+
return nil
108+
}
109+
110+
func resourceKubernetesRuntimeClassV1Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
111+
conn, err := meta.(KubeClientsets).MainClientset()
112+
if err != nil {
113+
return diag.FromErr(err)
114+
}
115+
116+
name := d.Id()
117+
118+
patch := patchMetadata("metadata.0.", "/metadata/", d)
119+
120+
data, err := patch.MarshalJSON()
121+
if err != nil {
122+
return diag.Errorf("Failed to marshal update operations: %s", err)
123+
}
124+
125+
log.Printf("[INFO] Updating runtime class %s: %#v", d.Id(), patch)
126+
127+
out, err := conn.NodeV1().RuntimeClasses().Patch(ctx, name, pkgApi.JSONPatchType, data, metav1.PatchOptions{})
128+
if err != nil {
129+
return diag.Errorf("Failed to update runtime class! API error: %s", err)
130+
}
131+
132+
log.Printf("[INFO] Submitted updated runtime class: %#v", out)
133+
d.SetId(out.Name)
134+
135+
return resourceKubernetesRuntimeClassV1Read(ctx, d, meta)
136+
}
137+
138+
func resourceKubernetesRuntimeClassV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
139+
conn, err := meta.(KubeClientsets).MainClientset()
140+
if err != nil {
141+
return diag.FromErr(err)
142+
}
143+
144+
name := d.Id()
145+
146+
log.Printf("[INFO] Deleting runtime class: %#v", name)
147+
err = conn.NodeV1().RuntimeClasses().Delete(ctx, name, metav1.DeleteOptions{})
148+
if err != nil {
149+
if statusErr, ok := err.(*errors.StatusError); ok && errors.IsNotFound(statusErr) {
150+
return nil
151+
}
152+
return diag.FromErr(err)
153+
}
154+
log.Printf("[INFO] runtime class %s deleted", name)
155+
156+
return nil
157+
}
158+
159+
func resourceKubernetesRuntimeClassV1Exists(ctx context.Context, d *schema.ResourceData, meta interface{}) (bool, error) {
160+
conn, err := meta.(KubeClientsets).MainClientset()
161+
if err != nil {
162+
return false, err
163+
}
164+
165+
name := d.Id()
166+
167+
log.Printf("[INFO] Checking runtime class %s", name)
168+
_, err = conn.NodeV1().RuntimeClasses().Get(ctx, name, metav1.GetOptions{})
169+
if err != nil {
170+
if statusErr, ok := err.(*errors.StatusError); ok && errors.IsNotFound(statusErr) {
171+
return false, nil
172+
}
173+
log.Printf("[DEBUG] Received error: %#v", err)
174+
}
175+
176+
return true, err
177+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package kubernetes
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"testing"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
14+
nodev1 "k8s.io/api/node/v1"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
)
17+
18+
func TestAccKubernetesruntime_class_v1_basic(t *testing.T) {
19+
var conf nodev1.RuntimeClass
20+
rcName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
21+
resourceName := "kubernetes_runtime_class_v1.test"
22+
23+
resource.Test(t, resource.TestCase{
24+
PreCheck: func() { testAccPreCheck(t) },
25+
IDRefreshName: resourceName,
26+
IDRefreshIgnore: []string{"metadata.0.resource_version"},
27+
ProviderFactories: testAccProviderFactories,
28+
CheckDestroy: testAccCheckKubernetesRuntimeClassV1Destroy,
29+
Steps: []resource.TestStep{
30+
{
31+
Config: testAccKubernetesruntime_class_v1_basic(rcName),
32+
Check: resource.ComposeAggregateTestCheckFunc(
33+
testAccCheckKubernetesruntime_class_v1Exists(resourceName, &conf),
34+
resource.TestCheckResourceAttr(resourceName, "metadata.0.name", rcName),
35+
resource.TestCheckResourceAttr(resourceName, "handler", "myclass"),
36+
),
37+
},
38+
{
39+
ResourceName: resourceName,
40+
ImportState: true,
41+
ImportStateVerify: true,
42+
ImportStateVerifyIgnore: []string{"metadata.0.resource_version"},
43+
},
44+
{
45+
Config: testAccKubernetesruntime_class_v1_addAnnotations(rcName),
46+
Check: resource.ComposeAggregateTestCheckFunc(
47+
testAccCheckKubernetesruntime_class_v1Exists(resourceName, &conf),
48+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.%", "2"),
49+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.TestAnnotationOne", "one"),
50+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.TestAnnotationTwo", "two"),
51+
resource.TestCheckResourceAttr(resourceName, "metadata.0.labels.%", "0"),
52+
resource.TestCheckResourceAttr(resourceName, "metadata.0.name", rcName),
53+
resource.TestCheckResourceAttr(resourceName, "handler", "newclass"),
54+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.generation"),
55+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.resource_version"),
56+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.uid"),
57+
),
58+
},
59+
{
60+
Config: testAccKubernetesruntime_class_v1_addLabels(rcName),
61+
Check: resource.ComposeAggregateTestCheckFunc(
62+
testAccCheckKubernetesruntime_class_v1Exists(resourceName, &conf),
63+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.%", "2"),
64+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.TestAnnotationOne", "one"),
65+
resource.TestCheckResourceAttr(resourceName, "metadata.0.annotations.TestAnnotationTwo", "two"),
66+
resource.TestCheckResourceAttr(resourceName, "metadata.0.labels.%", "2"),
67+
resource.TestCheckResourceAttr(resourceName, "metadata.0.labels.TestLabelOne", "one"),
68+
resource.TestCheckResourceAttr(resourceName, "metadata.0.labels.TestLabelTwo", "two"),
69+
resource.TestCheckResourceAttr(resourceName, "metadata.0.name", rcName),
70+
resource.TestCheckResourceAttr(resourceName, "handler", "my-class"),
71+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.generation"),
72+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.resource_version"),
73+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.uid"),
74+
),
75+
},
76+
},
77+
})
78+
}
79+
80+
func testAccKubernetesruntime_class_v1_basic(name string) string {
81+
return fmt.Sprintf(`resource "kubernetes_runtime_class_v1" "test" {
82+
metadata {
83+
name = %q
84+
}
85+
handler = "myclass"
86+
}
87+
`, name)
88+
}
89+
90+
func testAccKubernetesruntime_class_v1_addAnnotations(name string) string {
91+
return fmt.Sprintf(`resource "kubernetes_runtime_class_v1" "test" {
92+
metadata {
93+
annotations = {
94+
TestAnnotationOne = "one"
95+
TestAnnotationTwo = "two"
96+
}
97+
name = %q
98+
}
99+
handler = "newclass"
100+
}
101+
`, name)
102+
}
103+
104+
func testAccKubernetesruntime_class_v1_addLabels(name string) string {
105+
return fmt.Sprintf(`resource "kubernetes_runtime_class_v1" "test" {
106+
metadata {
107+
annotations = {
108+
TestAnnotationOne = "one"
109+
TestAnnotationTwo = "two"
110+
}
111+
112+
labels = {
113+
TestLabelOne = "one"
114+
TestLabelTwo = "two"
115+
}
116+
name = %q
117+
}
118+
handler = "my-class"
119+
}
120+
`, name)
121+
}
122+
123+
func testAccCheckKubernetesRuntimeClassV1Destroy(s *terraform.State) error {
124+
conn, err := testAccProvider.Meta().(KubeClientsets).MainClientset()
125+
126+
if err != nil {
127+
return err
128+
}
129+
ctx := context.TODO()
130+
131+
for _, rs := range s.RootModule().Resources {
132+
if rs.Type != "kubernetes_runtime_class_v1" {
133+
continue
134+
}
135+
136+
resp, err := conn.NodeV1().RuntimeClasses().Get(ctx, rs.Primary.ID, metav1.GetOptions{})
137+
if err == nil {
138+
if resp.Name == rs.Primary.ID {
139+
return fmt.Errorf("Runtime Class still exists: %s", rs.Primary.ID)
140+
}
141+
}
142+
}
143+
144+
return nil
145+
}
146+
147+
func testAccCheckKubernetesruntime_class_v1Exists(n string, obj *nodev1.RuntimeClass) resource.TestCheckFunc {
148+
return func(s *terraform.State) error {
149+
rs, ok := s.RootModule().Resources[n]
150+
if !ok {
151+
return fmt.Errorf("Not found: %s", n)
152+
}
153+
154+
conn, err := testAccProvider.Meta().(KubeClientsets).MainClientset()
155+
if err != nil {
156+
return err
157+
}
158+
ctx := context.TODO()
159+
160+
out, err := conn.NodeV1().RuntimeClasses().Get(ctx, rs.Primary.ID, metav1.GetOptions{})
161+
if err != nil {
162+
return err
163+
}
164+
165+
*obj = *out
166+
return nil
167+
}
168+
}

0 commit comments

Comments
 (0)