Commit caead741 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #45184 from DirectXMan12/feature/metrics-client-gen-tweaks

Automatic merge from submit-queue (batch tested with PRs 46801, 45184, 45930, 46192, 45563) Tweak client-gen to support metrics API This PR adds support to client-gen for readonly APIs as well as for customizing the resource name used for a given type. This is required to support the clients generated for `k8s.io/metrics/pkg/apis/metrics`. cc @caesarxuchao Currently based on #45180 **Release note**: ```release-note NONE ```
parents d063ce21 be28a99a
......@@ -40,13 +40,15 @@ func NameSystems() namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
lowercaseNamer := namer.NewAllLowercasePluralNamer(pluralExceptions)
return namer.NameSystems{
"public": namer.NewPublicNamer(0),
"private": namer.NewPrivateNamer(0),
"raw": namer.NewRawNamer("", nil),
"publicPlural": namer.NewPublicPluralNamer(pluralExceptions),
"privatePlural": namer.NewPrivatePluralNamer(pluralExceptions),
"allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions),
"allLowercasePlural": lowercaseNamer,
"resource": NewTagOverrideNamer("resourceName", lowercaseNamer),
}
}
......@@ -335,3 +337,27 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
return generator.Packages(packageList)
}
// tagOverrideNamer is a namer which pulls names from a given tag, if specified,
// and otherwise falls back to a different namer.
type tagOverrideNamer struct {
tagName string
fallback namer.Namer
}
func (n *tagOverrideNamer) Name(t *types.Type) string {
if nameOverride := extractTag(n.tagName, t.SecondClosestCommentLines); nameOverride != "" {
return nameOverride
}
return n.fallback.Name(t)
}
// NewTagOverrideNamer creates a namer.Namer which uses the contents of the given tag as
// the name, or falls back to another Namer if the tag is not present.
func NewTagOverrideNamer(tagName string, fallback namer.Namer) namer.Namer {
return &tagOverrideNamer{
tagName: tagName,
fallback: fallback,
}
}
......@@ -150,6 +150,8 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
noMethods := extractBoolTagOrDie("noMethods", t.SecondClosestCommentLines) == true
readonly := extractBoolTagOrDie("readonly", t.SecondClosestCommentLines) == true
if namespaced {
sw.Do(structNamespaced, m)
} else {
......@@ -159,6 +161,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
if !noMethods {
sw.Do(resource, m)
sw.Do(kind, m)
}
if !noMethods && !readonly {
sw.Do(createTemplate, m)
sw.Do(updateTemplate, m)
// Generate the UpdateStatus method if the type has a status
......@@ -167,6 +172,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
}
sw.Do(deleteTemplate, m)
sw.Do(deleteCollectionTemplate, m)
}
if !noMethods {
sw.Do(getTemplate, m)
if hasObjectMeta(t) {
sw.Do(listUsingOptionsTemplate, m)
......@@ -174,6 +182,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
sw.Do(listTemplate, m)
}
sw.Do(watchTemplate, m)
}
if !noMethods && !readonly {
sw.Do(patchTemplate, m)
}
......@@ -198,7 +209,7 @@ type Fake$.type|publicPlural$ struct {
`
var resource = `
var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|allLowercasePlural$"}
var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|resource$"}
`
var kind = `
......
......@@ -102,14 +102,20 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
}
noMethods := extractBoolTagOrDie("noMethods", t.SecondClosestCommentLines) == true
readonly := extractBoolTagOrDie("readonly", t.SecondClosestCommentLines) == true
sw.Do(interfaceTemplate1, m)
if !noMethods {
sw.Do(interfaceTemplate2, m)
// Include the UpdateStatus method if the type has a status
if genStatus(t) {
sw.Do(interfaceUpdateStatusTemplate, m)
if readonly {
sw.Do(interfaceTemplateReadonly, m)
} else {
sw.Do(interfaceTemplate2, m)
// Include the UpdateStatus method if the type has a status
if genStatus(t) {
sw.Do(interfaceUpdateStatusTemplate, m)
}
sw.Do(interfaceTemplate3, m)
}
sw.Do(interfaceTemplate3, m)
}
sw.Do(interfaceTemplate4, m)
......@@ -121,7 +127,7 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
sw.Do(newStructNonNamespaced, m)
}
if !noMethods {
if !noMethods && !readonly {
sw.Do(createTemplate, m)
sw.Do(updateTemplate, m)
// Generate the UpdateStatus method if the type has a status
......@@ -130,9 +136,15 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
}
sw.Do(deleteTemplate, m)
sw.Do(deleteCollectionTemplate, m)
}
if !noMethods {
sw.Do(getTemplate, m)
sw.Do(listTemplate, m)
sw.Do(watchTemplate, m)
}
if !noMethods && !readonly {
sw.Do(patchTemplate, m)
}
......@@ -177,6 +189,11 @@ var interfaceTemplate3 = `
Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)
Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error)`
var interfaceTemplateReadonly = `
Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error)
List(opts $.ListOptions|raw$) (*$.type|raw$List, error)
Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`
var interfaceTemplate4 = `
$.type|public$Expansion
}
......@@ -224,7 +241,7 @@ func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.type|ra
result = &$.type|raw$List{}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Do().
Into(result)
......@@ -237,7 +254,7 @@ func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (res
result = &$.type|raw${}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
Name(name).
VersionedParams(&options, $.schemeParameterCodec|raw$).
Do().
......@@ -251,7 +268,7 @@ var deleteTemplate = `
func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error {
return c.client.Delete().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
Name(name).
Body(options).
Do().
......@@ -264,7 +281,7 @@ var deleteCollectionTemplate = `
func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error {
return c.client.Delete().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
VersionedParams(&listOptions, $.schemeParameterCodec|raw$).
Body(options).
Do().
......@@ -278,7 +295,7 @@ func (c *$.type|privatePlural$) Create($.type|private$ *$.type|raw$) (result *$.
result = &$.type|raw${}
err = c.client.Post().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
Body($.type|private$).
Do().
Into(result)
......@@ -292,7 +309,7 @@ func (c *$.type|privatePlural$) Update($.type|private$ *$.type|raw$) (result *$.
result = &$.type|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
Name($.type|private$.Name).
Body($.type|private$).
Do().
......@@ -309,7 +326,7 @@ func (c *$.type|privatePlural$) UpdateStatus($.type|private$ *$.type|raw$) (resu
result = &$.type|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
Name($.type|private$.Name).
SubResource("status").
Body($.type|private$).
......@@ -325,7 +342,7 @@ func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface
opts.Watch = true
return c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Watch()
}
......@@ -337,7 +354,7 @@ func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []b
result = &$.type|raw${}
err = c.client.Patch(pt).
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Resource("$.type|resource$").
SubResource(subresources...).
Name(name).
Body(data).
......
......@@ -31,3 +31,14 @@ func extractBoolTagOrDie(key string, lines []string) bool {
}
return val
}
// extractTag gets the comment-tags for the key. If the tag did not exist, it
// returns the empty string.
func extractTag(key string, lines []string) string {
val, present := types.ExtractCommentTags("+", lines)[key]
if !present || len(val) < 1 {
return ""
}
return val[0]
}
......@@ -104,3 +104,4 @@ ${informergen} \
vendor/k8s.io/kube-aggregator/hack/update-codegen.sh
vendor/k8s.io/sample-apiserver/hack/update-codegen.sh
vendor/k8s.io/kube-apiextensions-server/hack/update-codegen.sh
vendor/k8s.io/metrics/hack/update-codegen.sh
......@@ -27,5 +27,6 @@ kube::golang::setup_env
vendor/k8s.io/kube-aggregator/hack/verify-codegen.sh
vendor/k8s.io/sample-apiserver/hack/verify-codegen.sh
vendor/k8s.io/kube-apiextensions-server/hack/verify-codegen.sh
vendor/k8s.io/metrics/hack/verify-codegen.sh
"${KUBE_ROOT}/hack/update-codegen.sh" --verify-only
......@@ -360,8 +360,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil))
fakeMetricsClient := &metricsfake.Clientset{}
// NB: we have to sound like Gollum due to gengo's inability to handle already-plural resource names
fakeMetricsClient.AddReactor("list", "podmetricses", func(action core.Action) (handled bool, ret runtime.Object, err error) {
fakeMetricsClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
......
......@@ -70,7 +70,7 @@ func (tc *restClientTestCase) prepareTestClient(t *testing.T) (*metricsfake.Clie
fakeCMClient := &cmfake.FakeCustomMetricsClient{}
if isResource {
fakeMetricsClient.AddReactor("list", "podmetricses", func(action core.Action) (handled bool, ret runtime.Object, err error) {
fakeMetricsClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
metrics := &metricsapi.PodMetricsList{}
for i, containers := range tc.reportedPodMetrics {
metric := metricsapi.PodMetrics{
......
......@@ -135,7 +135,7 @@ func (tc *replicaCalcTestCase) prepareTestClient(t *testing.T) (*fake.Clientset,
fakeMetricsClient := &metricsfake.Clientset{}
// NB: we have to sound like Gollum due to gengo's inability to handle already-plural resource names
fakeMetricsClient.AddReactor("list", "podmetricses", func(action core.Action) (handled bool, ret runtime.Object, err error) {
fakeMetricsClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
if tc.resource != nil {
metrics := &metricsapi.PodMetricsList{}
for i, resValue := range tc.resource.levels {
......
#!/bin/bash
# Copyright 2017 The Kubernetes 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../../../..
METRICS_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
# Register function to be called on EXIT to remove generated binary.
function cleanup {
rm -f "${CLIENTGEN:-}"
}
trap cleanup EXIT
echo "Building client-gen"
CLIENTGEN="${PWD}/client-gen-binary"
go build -o "${CLIENTGEN}" ./cmd/libs/go2idl/client-gen
PREFIX=k8s.io/metrics/pkg/apis
INPUT_BASE="--input-base ${PREFIX}"
CLIENTSET_PATH="--clientset-path k8s.io/metrics/pkg/client/clientset_generated"
${CLIENTGEN} --clientset-name="clientset" ${INPUT_BASE} --input metrics/v1alpha1 ${CLIENTSET_PATH} --output-base ${KUBE_ROOT}/vendor
# we skip informers and listers for metrics, because we don't quite support the requisite operations yet
# we skip generating the internal clientset as it's not really needed
#!/bin/bash
# Copyright 2017 The Kubernetes 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../../../..
METRICS_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
DIFFROOT="${METRICS_ROOT}/pkg"
TMP_DIFFROOT="${METRICS_ROOT}/_tmp/pkg"
_tmp="${METRICS_ROOT}/_tmp"
cleanup() {
rm -rf "${_tmp}"
}
trap "cleanup" EXIT SIGINT
cleanup
mkdir -p "${TMP_DIFFROOT}"
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
"${METRICS_ROOT}/hack/update-codegen.sh"
echo "diffing ${DIFFROOT} against freshly generated codegen"
ret=0
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
if [[ $ret -eq 0 ]]
then
echo "${DIFFROOT} up to date."
else
echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
exit 1
fi
......@@ -17,7 +17,6 @@ go_library(
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/plugin/pkg/client/auth:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1:go_default_library",
......
......@@ -19,7 +19,6 @@ package clientset
import (
glog "github.com/golang/glog"
discovery "k8s.io/client-go/discovery"
_ "k8s.io/client-go/plugin/pkg/client/auth"
rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol"
metricsv1alpha1 "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1"
......
......@@ -12,15 +12,19 @@ go_library(
srcs = [
"clientset_generated.go",
"doc.go",
"register.go",
],
tags = ["automanaged"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/discovery/fake:go_default_library",
"//vendor/k8s.io/client-go/pkg/api:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1:go_default_library",
"//vendor/k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1/fake:go_default_library",
......
......@@ -21,7 +21,6 @@ import (
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery"
fakediscovery "k8s.io/client-go/discovery/fake"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/testing"
clientset "k8s.io/metrics/pkg/client/clientset_generated/clientset"
metricsv1alpha1 "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1"
......@@ -33,7 +32,7 @@ import (
// without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(api.Scheme, api.Codecs.UniversalDecoder())
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects {
if err := o.Add(obj); err != nil {
panic(err)
......
/*
Copyright 2017 The Kubernetes 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 fake
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
metricsv1alpha1 "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
)
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
func init() {
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
AddToScheme(scheme)
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kuberentes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
func AddToScheme(scheme *runtime.Scheme) {
metricsv1alpha1.AddToScheme(scheme)
}
......@@ -30,7 +30,7 @@ type FakeNodeMetricses struct {
Fake *FakeMetricsV1alpha1
}
var nodemetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "nodemetricses"}
var nodemetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "nodes"}
var nodemetricsesKind = schema.GroupVersionKind{Group: "metrics", Version: "v1alpha1", Kind: "NodeMetrics"}
......
......@@ -31,7 +31,7 @@ type FakePodMetricses struct {
ns string
}
var podmetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "podmetricses"}
var podmetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "pods"}
var podmetricsesKind = schema.GroupVersionKind{Group: "metrics", Version: "v1alpha1", Kind: "PodMetrics"}
......
......@@ -35,7 +35,6 @@ type NodeMetricsInterface interface {
Get(name string, options v1.GetOptions) (*v1alpha1.NodeMetrics, error)
List(opts v1.ListOptions) (*v1alpha1.NodeMetricsList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
NodeMetricsExpansion
}
......@@ -76,8 +75,8 @@ func (c *nodeMetricses) List(opts v1.ListOptions) (result *v1alpha1.NodeMetricsL
// Watch returns a watch.Interface that watches the requested nodeMetricses.
func (c *nodeMetricses) Watch(opts v1.ListOptions) (watch.Interface, error) {
opts.Watch = true
return c.client.Get().
Prefix("watch").
Resource("nodes").
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
......
......@@ -35,7 +35,6 @@ type PodMetricsInterface interface {
Get(name string, options v1.GetOptions) (*v1alpha1.PodMetrics, error)
List(opts v1.ListOptions) (*v1alpha1.PodMetricsList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
PodMetricsExpansion
}
......@@ -80,8 +79,8 @@ func (c *podMetricses) List(opts v1.ListOptions) (result *v1alpha1.PodMetricsLis
// Watch returns a watch.Interface that watches the requested podMetricses.
func (c *podMetricses) Watch(opts v1.ListOptions) (watch.Interface, error) {
opts.Watch = true
return c.client.Get().
Prefix("watch").
Namespace(c.ns).
Resource("pods").
VersionedParams(&opts, scheme.ParameterCodec).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment