This repository has been archived by the owner on Nov 20, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
custom.go
99 lines (87 loc) · 2.97 KB
/
custom.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package app
import (
"context"
featuresv1alpha1 "github.com/criticalstack/stackapps/api/v1alpha1"
"github.com/criticalstack/ui/internal/log"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type hookType string
const (
createHook hookType = "Create"
updateHook hookType = "Update"
deleteHook hookType = "Delete"
)
type hookKey struct {
t hookType
gv schema.GroupKind
}
type hook func(*Controller, client.Client, echo.Context) (Map, error)
var (
customHooks = map[hookKey]hook{
{createHook, schema.GroupKind{Group: featuresv1alpha1.GroupName, Kind: "StackApp"}}: createStackApp,
{updateHook, schema.GroupKind{Group: featuresv1alpha1.GroupName, Kind: "StackApp"}}: updateStackApp,
{deleteHook, schema.GroupKind{Kind: "Node"}}: deleteNodeOrMachine,
}
)
// TODO(ktravis): do we want to do these for other types of routes beyond "list all"? Probably better to implement any
// defaulting/custom logic behavior in a more k8s native way when possible
func (x *Controller) transformResourceList(c echo.Context, cli client.Client, gvk schema.GroupVersionKind, list *unstructured.UnstructuredList) error {
if len(list.Items) == 0 {
return nil
}
switch {
case gvk.GroupVersion().String() == "v1" && gvk.Kind == "Pod":
return x.transformPodsList(c, cli, list)
default:
}
return nil
}
// NOTE(ktravis): ideally this should be (is currently?) managed by requests from the frontend to watch these pods and
// their events - but rather than break it here is the current solution
func (x *Controller) transformPodsList(c echo.Context, cli client.Client, list *unstructured.UnstructuredList) error {
needEvents := make(map[string]*unstructured.Unstructured)
for i := range list.Items {
pod := &list.Items[i]
switch p, _, _ := unstructured.NestedString(pod.Object, "status", "phase"); p {
case "Running", "Succeeded":
// skip event check
default:
needEvents[string(pod.GetUID())] = pod
}
}
if len(needEvents) == 0 {
return nil
}
var events unstructured.UnstructuredList
events.SetGroupVersionKind(schema.GroupVersionKind{Version: "v1", Kind: "Event"})
opts := &client.ListOptions{
FieldSelector: fields.OneTermEqualSelector("involvedObject.kind", "Pod"),
Raw: &metav1.ListOptions{
ResourceVersion: c.QueryParam("ResourceVersion"),
},
}
if err := cli.List(context.TODO(), &events, opts); err != nil {
log.Error("failed to list pod events", zap.Error(err))
return err
}
for _, e := range events.Items {
uid, ok, _ := unstructured.NestedString(e.Object, "involvedObject", "uid")
if !ok {
log.Errorf("no uid in event: %v", e)
continue
}
pod, ok := needEvents[uid]
if !ok {
continue
}
evts, _ := pod.Object["events"].([]interface{})
pod.Object["events"] = append(evts, e.Object)
}
return nil
}