forked from rancher/rancher
-
Notifications
You must be signed in to change notification settings - Fork 1
/
link.go
124 lines (101 loc) · 3.18 KB
/
link.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package namespace
import (
"strings"
"github.com/rancher/norman/httperror"
"github.com/rancher/norman/types"
"github.com/rancher/rancher/pkg/clustermanager"
"github.com/rancher/rancher/pkg/resourcelink"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
printers2 "k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/kubernetes/pkg/printers"
)
var ExportPrinters = map[string]printers.ResourcePrinter{
"json": &printers2.JSONPrinter{},
"yaml": &printers2.YAMLPrinter{},
}
func NewLinkHandler(next types.RequestHandler, manager *clustermanager.Manager) types.RequestHandler {
lh := &yamlLinkHandler{
next: next,
clusterManagement: manager,
}
return lh.LinkHandler
}
type yamlLinkHandler struct {
next types.RequestHandler
clusterManagement *clustermanager.Manager
}
func (s *yamlLinkHandler) callNext(apiContext *types.APIContext, next types.RequestHandler) error {
if s.next != nil {
return s.next(apiContext, next)
} else if next != nil {
return next(apiContext, nil)
}
return httperror.NewAPIError(httperror.NotFound, "link not found")
}
func (s *yamlLinkHandler) LinkHandler(apiContext *types.APIContext, next types.RequestHandler) error {
if apiContext.Link != "yaml" {
return s.callNext(apiContext, next)
}
clusterName := s.clusterManagement.ClusterName(apiContext)
userContext, err := s.clusterManagement.UserContext(clusterName)
if err != nil {
return err
}
ns := apiContext.ID
result := &unstructured.UnstructuredList{}
result.SetAPIVersion("v1")
result.SetKind("List")
resources := apiContext.Request.URL.Query()["resource"]
toExportResourceMappings := getResourcePrefixMap(resources)
for kind, prefix := range toExportResourceMappings {
req := userContext.UnversionedClient.Get().Prefix(prefix).Namespace(ns).Resource(kind)
for k, v := range apiContext.Request.URL.Query() {
req.Param(k, strings.Join(v, ","))
}
for k, v := range apiContext.Request.Header {
if k == "Authorization" {
continue
}
req.SetHeader(k, v...)
}
req.SetHeader("Accept", "*/*")
r, err := req.Do().Get()
if err != nil {
if e, ok := err.(*apierrors.StatusError); ok && e.Status().Code == 403 {
continue
}
return err
}
if list, ok := r.(*unstructured.UnstructuredList); ok {
for _, item := range list.Items {
if len(item.GetOwnerReferences()) == 0 {
result.Items = append(result.Items, item)
}
}
}
}
printer := ExportPrinters["json"]
apiContext.Response.Header().Set("content-type", "application/json")
if apiContext.Request.Header.Get("Accept") == "application/yaml" {
printer = ExportPrinters["yaml"]
apiContext.Response.Header().Set("content-type", "application/yaml")
}
return printer.PrintObj(result, apiContext.Response)
}
//getResourcePrefixMap converts resource path like `/api/v1/pods` to kind-prefix mappings
func getResourcePrefixMap(resources []string) map[string]string {
if len(resources) == 0 {
return resourcelink.ExportResourcePrefixMappings
}
m := map[string]string{}
for _, r := range resources {
idx := strings.LastIndex(r, "/")
if idx == -1 {
m[r] = ""
} else {
m[r[idx+1:]] = r[:idx]
}
}
return m
}