From 4aaf4a08ac6138cc6013a3c3f95d9e87337288bb Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 28 Jun 2017 09:02:07 +0100 Subject: [PATCH] Expose last warnings from eventlog for Pod+PVC+SVC --- kubernetes/event_helpers.go | 67 +++++++++++++++++++ ...urce_kubernetes_persistent_volume_claim.go | 24 ++----- kubernetes/resource_kubernetes_pod.go | 6 +- kubernetes/resource_kubernetes_service.go | 8 ++- 4 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 kubernetes/event_helpers.go diff --git a/kubernetes/event_helpers.go b/kubernetes/event_helpers.go new file mode 100644 index 0000000000..56723cf58b --- /dev/null +++ b/kubernetes/event_helpers.go @@ -0,0 +1,67 @@ +package kubernetes + +import ( + "fmt" + "log" + "sort" + + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + api "k8s.io/kubernetes/pkg/api/v1" + kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" +) + +func getLastWarningsForObject(conn *kubernetes.Clientset, metadata meta_v1.ObjectMeta, kind string, limit int) ([]api.Event, error) { + fs := fields.Set(map[string]string{ + "involvedObject.name": metadata.Name, + "involvedObject.namespace": metadata.Namespace, + "involvedObject.kind": kind, + }).String() + log.Printf("[DEBUG] Looking up events via this selector: %q", fs) + out, err := conn.CoreV1().Events(metadata.Namespace).List(meta_v1.ListOptions{ + FieldSelector: fs, + }) + if err != nil { + return nil, err + } + + // It would be better to sort & filter on the server-side + // but API doesn't seem to support it + var warnings []api.Event + + // Bring latest events to the top, for easy access + sort.Slice(out.Items, func(i, j int) bool { + return out.Items[i].LastTimestamp.After(out.Items[j].LastTimestamp.Time) + }) + + log.Printf("[DEBUG] Received %d events for %s/%s (%s)", + len(out.Items), metadata.Namespace, metadata.Name, kind) + + warnCount := 0 + uniqueWarnings := make(map[string]api.Event, 0) + for _, e := range out.Items { + if warnCount >= limit { + break + } + + if e.Type == api.EventTypeWarning { + _, found := uniqueWarnings[e.Message] + if found { + continue + } + warnings = append(warnings, e) + uniqueWarnings[e.Message] = e + warnCount++ + } + } + + return warnings, nil +} + +func stringifyEvents(events []api.Event) string { + var output string + for _, e := range events { + output += fmt.Sprintf("\n * %s: %s", e.Reason, e.Message) + } + return output +} diff --git a/kubernetes/resource_kubernetes_persistent_volume_claim.go b/kubernetes/resource_kubernetes_persistent_volume_claim.go index 6c71685096..a6e1ce520c 100644 --- a/kubernetes/resource_kubernetes_persistent_volume_claim.go +++ b/kubernetes/resource_kubernetes_persistent_volume_claim.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform/helper/schema" "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" pkgApi "k8s.io/apimachinery/pkg/types" api "k8s.io/kubernetes/pkg/api/v1" kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" @@ -166,7 +165,6 @@ func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta name := out.ObjectMeta.Name if d.Get("wait_until_bound").(bool) { - var lastEvent api.Event stateConf := &resource.StateChangeConf{ Target: []string{"Bound"}, Pending: []string{"Pending"}, @@ -178,20 +176,6 @@ func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta return out, "", err } - events, err := conn.CoreV1().Events(metadata.Namespace).List(meta_v1.ListOptions{ - FieldSelector: fields.Set(map[string]string{ - "involvedObject.name": metadata.Name, - "involvedObject.namespace": metadata.Namespace, - "involvedObject.kind": "PersistentVolumeClaim", - }).String(), - }) - if err != nil { - return out, "", err - } - if len(events.Items) > 0 { - lastEvent = events.Items[0] - } - statusPhase := fmt.Sprintf("%v", out.Status.Phase) log.Printf("[DEBUG] Persistent volume claim %s status received: %#v", out.Name, statusPhase) return out, statusPhase, nil @@ -199,11 +183,11 @@ func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta } _, err = stateConf.WaitForState() if err != nil { - reason := "" - if lastEvent.Reason != "" { - reason = fmt.Sprintf(". Reason: %s: %s", lastEvent.Reason, lastEvent.Message) + lastWarnings, wErr := getLastWarningsForObject(conn, out.ObjectMeta, "PersistentVolumeClaim", 3) + if wErr != nil { + return wErr } - return fmt.Errorf("%s%s", err, reason) + return fmt.Errorf("%s%s", err, stringifyEvents(lastWarnings)) } } log.Printf("[INFO] Persistent volume claim %s created", out.Name) diff --git a/kubernetes/resource_kubernetes_pod.go b/kubernetes/resource_kubernetes_pod.go index 68bd6e7b6c..157a6ccded 100644 --- a/kubernetes/resource_kubernetes_pod.go +++ b/kubernetes/resource_kubernetes_pod.go @@ -82,7 +82,11 @@ func resourceKubernetesPodCreate(d *schema.ResourceData, meta interface{}) error } _, err = stateConf.WaitForState() if err != nil { - return err + lastWarnings, wErr := getLastWarningsForObject(conn, out.ObjectMeta, "Pod", 3) + if wErr != nil { + return wErr + } + return fmt.Errorf("%s%s", err, stringifyEvents(lastWarnings)) } log.Printf("[INFO] Pod %s created", out.Name) diff --git a/kubernetes/resource_kubernetes_service.go b/kubernetes/resource_kubernetes_service.go index 02eff26e02..cbac0eea46 100644 --- a/kubernetes/resource_kubernetes_service.go +++ b/kubernetes/resource_kubernetes_service.go @@ -176,10 +176,14 @@ func resourceKubernetesServiceCreate(d *schema.ResourceData, meta interface{}) e } return resource.RetryableError(fmt.Errorf( - "Waiting for load balancer %q to assign IP/hostname", d.Id())) + "Waiting for service %q to assign IP/hostname for a load balancer", d.Id())) }) if err != nil { - return err + lastWarnings, wErr := getLastWarningsForObject(conn, out.ObjectMeta, "Service", 3) + if wErr != nil { + return wErr + } + return fmt.Errorf("%s%s", err, stringifyEvents(lastWarnings)) } }