-
Notifications
You must be signed in to change notification settings - Fork 382
/
dynamic.go
104 lines (86 loc) · 3.39 KB
/
dynamic.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
/*
Copyright 2022 The KCP Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metadata
import (
"fmt"
"net/http"
"strings"
kcpdynamic "github.com/kcp-dev/client-go/dynamic"
dynamic "k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"github.com/kcp-dev/kcp/pkg/server/requestinfo"
)
// NewDynamicMetadataClusterClientForConfig returns a dynamic cluster client that only
// retrieves PartialObjectMetadata-like object, returned as Unstructured.
func NewDynamicMetadataClusterClientForConfig(config *rest.Config) (kcpdynamic.ClusterInterface, error) {
// create special client that only gets PartialObjectMetadata objects. For these we can do
// wildcard requests with different schemas without risking data loss.
metadataConfig := *config
metadataConfig.Wrap(func(rt http.RoundTripper) http.RoundTripper {
// we have to use this way because the dynamic client overrides the content-type :-/
return &metadataTransport{RoundTripper: rt}
})
return kcpdynamic.NewForConfig(&metadataConfig)
}
// NewDynamicMetadataClientForConfig returns a dynamic client that only
// retrieves PartialObjectMetadata-like object, returned as Unstructured.
func NewDynamicMetadataClientForConfig(config *rest.Config) (dynamic.Interface, error) {
// create special client that only gets PartialObjectMetadata objects. For these we can do
// wildcard requests with different schemas without risking data loss.
metadataConfig := *config
metadataConfig.Wrap(func(rt http.RoundTripper) http.RoundTripper {
// we have to use this way because the dynamic client overrides the content-type :-/
return &metadataTransport{RoundTripper: rt}
})
return dynamic.NewForConfig(&metadataConfig)
}
// metadataTransport does what client-go/metadata does, but injected into a dynamic client
// that is expected by the dynamic informers.
type metadataTransport struct {
http.RoundTripper
}
func (t *metadataTransport) RoundTrip(req *http.Request) (*http.Response, error) {
partialType, err := partialType(req)
if err != nil {
return nil, err
}
req.Header.Set("Accept", fmt.Sprintf("application/json;as=%s;g=meta.k8s.io;v=v1", partialType))
return t.RoundTripper.RoundTrip(req)
}
func (t *metadataTransport) WrappedRoundTripper() http.RoundTripper {
return t.RoundTripper
}
func partialType(req *http.Request) (string, error) {
// strip off /clusters/<lcluster>
baseReq := *req
if strings.HasPrefix(req.URL.Path, "/clusters/") {
parts := strings.SplitN(req.URL.Path, "/", 4)
if len(parts) < 4 {
return "", fmt.Errorf("invalid request uri: %s", req.URL.String())
}
baseURL := *req.URL
baseURL.Path = "/" + parts[3]
baseReq.URL = &baseURL
}
info, err := requestinfo.NewFactory().NewRequestInfo(&baseReq)
if err != nil {
return "", err
}
switch info.Verb {
case "list":
return "PartialObjectMetadataList", nil
case "watch", "get":
return "PartialObjectMetadata", nil
}
return "", fmt.Errorf("unexpected verb %q for metadata client", info.Verb)
}