-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provider/kubernetes: Add support for pod (#13571)
Add support for K8s pod
- Loading branch information
1 parent
6177b47
commit a5c208e
Showing
14 changed files
with
4,646 additions
and
487 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/builtin/providers/kubernetes" | ||
"github.com/hashicorp/terraform/plugin" | ||
) | ||
|
||
func main() { | ||
plugin.Serve(&plugin.ServeOpts{ | ||
ProviderFunc: kubernetes.Provider, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package kubernetes | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"k8s.io/apimachinery/pkg/api/resource" | ||
) | ||
|
||
func suppressEquivalentResourceQuantity(k, old, new string, d *schema.ResourceData) bool { | ||
oldQ, err := resource.ParseQuantity(old) | ||
if err != nil { | ||
return false | ||
} | ||
newQ, err := resource.ParseQuantity(new) | ||
if err != nil { | ||
return false | ||
} | ||
return oldQ.Cmp(newQ) == 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
195 changes: 195 additions & 0 deletions
195
builtin/providers/kubernetes/resource_kubernetes_pod.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
package kubernetes | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
pkgApi "k8s.io/apimachinery/pkg/types" | ||
api "k8s.io/kubernetes/pkg/api/v1" | ||
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" | ||
) | ||
|
||
func resourceKubernetesPod() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceKubernetesPodCreate, | ||
Read: resourceKubernetesPodRead, | ||
Update: resourceKubernetesPodUpdate, | ||
Delete: resourceKubernetesPodDelete, | ||
Exists: resourceKubernetesPodExists, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"metadata": namespacedMetadataSchema("pod", true), | ||
"spec": { | ||
Type: schema.TypeList, | ||
Description: "Spec of the pod owned by the cluster", | ||
Required: true, | ||
MaxItems: 1, | ||
Elem: &schema.Resource{ | ||
Schema: podSpecFields(), | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
func resourceKubernetesPodCreate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*kubernetes.Clientset) | ||
|
||
metadata := expandMetadata(d.Get("metadata").([]interface{})) | ||
spec, err := expandPodSpec(d.Get("spec").([]interface{})) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
spec.AutomountServiceAccountToken = ptrToBool(false) | ||
|
||
pod := api.Pod{ | ||
ObjectMeta: metadata, | ||
Spec: spec, | ||
} | ||
|
||
log.Printf("[INFO] Creating new pod: %#v", pod) | ||
out, err := conn.CoreV1().Pods(metadata.Namespace).Create(&pod) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
log.Printf("[INFO] Submitted new pod: %#v", out) | ||
|
||
d.SetId(buildId(out.ObjectMeta)) | ||
|
||
stateConf := &resource.StateChangeConf{ | ||
Target: []string{"Running"}, | ||
Pending: []string{"Pending"}, | ||
Timeout: 5 * time.Minute, | ||
Refresh: func() (interface{}, string, error) { | ||
out, err := conn.CoreV1().Pods(metadata.Namespace).Get(metadata.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
log.Printf("[ERROR] Received error: %#v", err) | ||
return out, "Error", err | ||
} | ||
|
||
statusPhase := fmt.Sprintf("%v", out.Status.Phase) | ||
log.Printf("[DEBUG] Pods %s status received: %#v", out.Name, statusPhase) | ||
return out, statusPhase, nil | ||
}, | ||
} | ||
_, err = stateConf.WaitForState() | ||
if err != nil { | ||
return err | ||
} | ||
log.Printf("[INFO] Pod %s created", out.Name) | ||
|
||
return resourceKubernetesPodRead(d, meta) | ||
} | ||
|
||
func resourceKubernetesPodUpdate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*kubernetes.Clientset) | ||
namespace, name := idParts(d.Id()) | ||
ops := patchMetadata("metadata.0.", "/metadata/", d) | ||
if d.HasChange("spec") { | ||
specOps, err := patchPodSpec("/spec", "spec.0.", d) | ||
if err != nil { | ||
return err | ||
} | ||
ops = append(ops, specOps...) | ||
} | ||
data, err := ops.MarshalJSON() | ||
if err != nil { | ||
return fmt.Errorf("Failed to marshal update operations: %s", err) | ||
} | ||
|
||
log.Printf("[INFO] Updating pod %s: %s", d.Id(), ops) | ||
|
||
out, err := conn.CoreV1().Pods(namespace).Patch(name, pkgApi.JSONPatchType, data) | ||
if err != nil { | ||
return err | ||
} | ||
log.Printf("[INFO] Submitted updated pod: %#v", out) | ||
|
||
d.SetId(buildId(out.ObjectMeta)) | ||
return resourceKubernetesPodRead(d, meta) | ||
} | ||
|
||
func resourceKubernetesPodRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*kubernetes.Clientset) | ||
namespace, name := idParts(d.Id()) | ||
|
||
log.Printf("[INFO] Reading pod %s", name) | ||
pod, err := conn.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) | ||
if err != nil { | ||
log.Printf("[DEBUG] Received error: %#v", err) | ||
return err | ||
} | ||
log.Printf("[INFO] Received pod: %#v", pod) | ||
|
||
err = d.Set("metadata", flattenMetadata(pod.ObjectMeta)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
podSpec, err := flattenPodSpec(pod.Spec) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = d.Set("spec", podSpec) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
|
||
} | ||
|
||
func resourceKubernetesPodDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*kubernetes.Clientset) | ||
namespace, name := idParts(d.Id()) | ||
log.Printf("[INFO] Deleting pod: %#v", name) | ||
err := conn.CoreV1().Pods(namespace).Delete(name, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = resource.Retry(1*time.Minute, func() *resource.RetryError { | ||
out, err := conn.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) | ||
if err != nil { | ||
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 { | ||
return nil | ||
} | ||
return resource.NonRetryableError(err) | ||
} | ||
|
||
log.Printf("[DEBUG] Current state of pod: %#v", out.Status.Phase) | ||
e := fmt.Errorf("Pod %s still exists (%s)", name, out.Status.Phase) | ||
return resource.RetryableError(e) | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("[INFO] Pod %s deleted", name) | ||
|
||
d.SetId("") | ||
return nil | ||
} | ||
|
||
func resourceKubernetesPodExists(d *schema.ResourceData, meta interface{}) (bool, error) { | ||
conn := meta.(*kubernetes.Clientset) | ||
|
||
namespace, name := idParts(d.Id()) | ||
log.Printf("[INFO] Checking pod %s", name) | ||
_, err := conn.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) | ||
if err != nil { | ||
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 { | ||
return false, nil | ||
} | ||
log.Printf("[DEBUG] Received error: %#v", err) | ||
} | ||
return true, err | ||
} |
Oops, something went wrong.