Merge pull request #51638 from mfojtik/client-gen-custom-methods

Automatic merge from submit-queue (batch tested with PRs 51805, 51725, 50925, 51474, 51638)

Allow custom client verbs to be generated using client-gen

This change will allow to define custom verbs for resources using the following new tag:

```
// +genclient:method=Foo,verb=create,subresource=foo,input=Bar,output=k8s.io/pkg/api.Blah
```

This will generate client method `Foo(bar *Bar) (*api.Blah, error)` (format depends on the particular verb type)

With this change we can add `UpdateScale()` and `GetScale()` into all scalable resources. Note that intention of this PR is not to fix the Scale(), but that is used as an example of this new capability.
Additionally this will also allow us to get rid of `// +genclient:noStatus` and fix guessing of the "updateStatus" subresource presence based on the existence of '.Status' field.
Basically you will have to add following into all types you want to generate `UpdateStatus()` for:

```
// +genclient:method=UpdateStatus,verb=update,subresource=status
```

This allows further extension of the client without writing an expansion (which proved to be pain to maintain and copy...). Also allows to customize native CRUD methods if needed (input/output types).

```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2017-09-03 11:10:09 -07:00 committed by GitHub
commit bee221cca9
37 changed files with 1237 additions and 53 deletions

View File

@ -42,6 +42,9 @@ type DeploymentInterface interface {
List(opts v1.ListOptions) (*v1beta1.DeploymentList, error) List(opts v1.ListOptions) (*v1beta1.DeploymentList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Deployment, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Deployment, err error)
GetScale(deploymentName string, options v1.GetOptions) (*v1beta1.Scale, error)
UpdateScale(deploymentName string, scale *v1beta1.Scale) (*v1beta1.Scale, error)
DeploymentExpansion DeploymentExpansion
} }
@ -170,3 +173,31 @@ func (c *deployments) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the deployment, and returns the corresponding v1beta1.Scale object, and an error if there is any.
func (c *deployments) GetScale(deploymentName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *deployments) UpdateScale(deploymentName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -136,3 +136,25 @@ func (c *FakeDeployments) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*v1beta1.Deployment), err return obj.(*v1beta1.Deployment), err
} }
// GetScale takes name of the deployment, and returns the corresponding scale object, and an error if there is any.
func (c *FakeDeployments) GetScale(deploymentName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(deploymentsResource, c.ns, "scale", deploymentName), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeDeployments) UpdateScale(deploymentName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "scale", c.ns, scale), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}

View File

@ -136,3 +136,25 @@ func (c *FakeReplicaSets) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*v1beta1.ReplicaSet), err return obj.(*v1beta1.ReplicaSet), err
} }
// GetScale takes name of the replicaSet, and returns the corresponding scale object, and an error if there is any.
func (c *FakeReplicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(replicasetsResource, c.ns, "scale", replicaSetName), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeReplicaSets) UpdateScale(replicaSetName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "scale", c.ns, scale), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}

View File

@ -42,6 +42,9 @@ type ReplicaSetInterface interface {
List(opts v1.ListOptions) (*v1beta1.ReplicaSetList, error) List(opts v1.ListOptions) (*v1beta1.ReplicaSetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ReplicaSet, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ReplicaSet, err error)
GetScale(replicaSetName string, options v1.GetOptions) (*v1beta1.Scale, error)
UpdateScale(replicaSetName string, scale *v1beta1.Scale) (*v1beta1.Scale, error)
ReplicaSetExpansion ReplicaSetExpansion
} }
@ -170,3 +173,31 @@ func (c *replicaSets) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the replicaSet, and returns the corresponding v1beta1.Scale object, and an error if there is any.
func (c *replicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *replicaSets) UpdateScale(replicaSetName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -2633,6 +2633,8 @@ type ReplicationControllerCondition struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/extensions.Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/extensions.Scale,result=k8s.io/kubernetes/pkg/apis/extensions.Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicationController represents the configuration of a replication controller. // ReplicationController represents the configuration of a replication controller.

View File

@ -23,6 +23,8 @@ import (
) )
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/extensions.Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/extensions.Scale,result=k8s.io/kubernetes/pkg/apis/extensions.Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// StatefulSet represents a set of pods with consistent identities. // StatefulSet represents a set of pods with consistent identities.

View File

@ -166,6 +166,8 @@ type ThirdPartyResourceData struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type Deployment struct { type Deployment struct {
@ -753,6 +755,8 @@ type IngressBackend struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicaSet represents the configuration of a replica set. // ReplicaSet represents the configuration of a replica set.

View File

@ -16,6 +16,7 @@ go_library(
], ],
deps = [ deps = [
"//pkg/apis/apps:go_default_library", "//pkg/apis/apps:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset/scheme:go_default_library", "//pkg/client/clientset_generated/internalclientset/scheme:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",

View File

@ -15,6 +15,7 @@ go_library(
], ],
deps = [ deps = [
"//pkg/apis/apps:go_default_library", "//pkg/apis/apps:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/apps/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/apps/internalversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",

View File

@ -24,6 +24,7 @@ import (
watch "k8s.io/apimachinery/pkg/watch" watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing" testing "k8s.io/client-go/testing"
apps "k8s.io/kubernetes/pkg/apis/apps" apps "k8s.io/kubernetes/pkg/apis/apps"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
) )
// FakeStatefulSets implements StatefulSetInterface // FakeStatefulSets implements StatefulSetInterface
@ -136,3 +137,25 @@ func (c *FakeStatefulSets) Patch(name string, pt types.PatchType, data []byte, s
} }
return obj.(*apps.StatefulSet), err return obj.(*apps.StatefulSet), err
} }
// GetScale takes name of the statefulSet, and returns the corresponding scale object, and an error if there is any.
func (c *FakeStatefulSets) GetScale(statefulSetName string, options v1.GetOptions) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(statefulsetsResource, c.ns, "scale", statefulSetName), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeStatefulSets) UpdateScale(statefulSetName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "scale", c.ns, scale), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}

View File

@ -22,6 +22,7 @@ import (
watch "k8s.io/apimachinery/pkg/watch" watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
apps "k8s.io/kubernetes/pkg/apis/apps" apps "k8s.io/kubernetes/pkg/apis/apps"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme" scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme"
) )
@ -42,6 +43,9 @@ type StatefulSetInterface interface {
List(opts v1.ListOptions) (*apps.StatefulSetList, error) List(opts v1.ListOptions) (*apps.StatefulSetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *apps.StatefulSet, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *apps.StatefulSet, err error)
GetScale(statefulSetName string, options v1.GetOptions) (*extensions.Scale, error)
UpdateScale(statefulSetName string, scale *extensions.Scale) (*extensions.Scale, error)
StatefulSetExpansion StatefulSetExpansion
} }
@ -170,3 +174,31 @@ func (c *statefulSets) Patch(name string, pt types.PatchType, data []byte, subre
Into(result) Into(result)
return return
} }
// GetScale takes name of the statefulSet, and returns the corresponding extensions.Scale object, and an error if there is any.
func (c *statefulSets) GetScale(statefulSetName string, options v1.GetOptions) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("statefulsets").
Name(statefulSetName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *statefulSets) UpdateScale(statefulSetName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("statefulsets").
Name(statefulSetName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -37,6 +37,7 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/ref:go_default_library", "//pkg/api/ref:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset/scheme:go_default_library", "//pkg/client/clientset_generated/internalclientset/scheme:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",

View File

@ -34,6 +34,7 @@ go_library(
], ],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",

View File

@ -24,6 +24,7 @@ import (
watch "k8s.io/apimachinery/pkg/watch" watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing" testing "k8s.io/client-go/testing"
api "k8s.io/kubernetes/pkg/api" api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
) )
// FakeReplicationControllers implements ReplicationControllerInterface // FakeReplicationControllers implements ReplicationControllerInterface
@ -136,3 +137,25 @@ func (c *FakeReplicationControllers) Patch(name string, pt types.PatchType, data
} }
return obj.(*api.ReplicationController), err return obj.(*api.ReplicationController), err
} }
// GetScale takes name of the replicationController, and returns the corresponding scale object, and an error if there is any.
func (c *FakeReplicationControllers) GetScale(replicationControllerName string, options v1.GetOptions) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(replicationcontrollersResource, c.ns, "scale", replicationControllerName), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeReplicationControllers) UpdateScale(replicationControllerName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(replicationcontrollersResource, "scale", c.ns, scale), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}

View File

@ -22,6 +22,7 @@ import (
watch "k8s.io/apimachinery/pkg/watch" watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
api "k8s.io/kubernetes/pkg/api" api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme" scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme"
) )
@ -42,6 +43,9 @@ type ReplicationControllerInterface interface {
List(opts v1.ListOptions) (*api.ReplicationControllerList, error) List(opts v1.ListOptions) (*api.ReplicationControllerList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *api.ReplicationController, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *api.ReplicationController, err error)
GetScale(replicationControllerName string, options v1.GetOptions) (*extensions.Scale, error)
UpdateScale(replicationControllerName string, scale *extensions.Scale) (*extensions.Scale, error)
ReplicationControllerExpansion ReplicationControllerExpansion
} }
@ -170,3 +174,31 @@ func (c *replicationControllers) Patch(name string, pt types.PatchType, data []b
Into(result) Into(result)
return return
} }
// GetScale takes name of the replicationController, and returns the corresponding extensions.Scale object, and an error if there is any.
func (c *replicationControllers) GetScale(replicationControllerName string, options v1.GetOptions) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("replicationcontrollers").
Name(replicationControllerName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *replicationControllers) UpdateScale(replicationControllerName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("replicationcontrollers").
Name(replicationControllerName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -42,6 +42,9 @@ type DeploymentInterface interface {
List(opts v1.ListOptions) (*extensions.DeploymentList, error) List(opts v1.ListOptions) (*extensions.DeploymentList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *extensions.Deployment, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *extensions.Deployment, err error)
GetScale(deploymentName string, options v1.GetOptions) (*extensions.Scale, error)
UpdateScale(deploymentName string, scale *extensions.Scale) (*extensions.Scale, error)
DeploymentExpansion DeploymentExpansion
} }
@ -170,3 +173,31 @@ func (c *deployments) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the deployment, and returns the corresponding extensions.Scale object, and an error if there is any.
func (c *deployments) GetScale(deploymentName string, options v1.GetOptions) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *deployments) UpdateScale(deploymentName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -136,3 +136,25 @@ func (c *FakeDeployments) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*extensions.Deployment), err return obj.(*extensions.Deployment), err
} }
// GetScale takes name of the deployment, and returns the corresponding scale object, and an error if there is any.
func (c *FakeDeployments) GetScale(deploymentName string, options v1.GetOptions) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(deploymentsResource, c.ns, "scale", deploymentName), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeDeployments) UpdateScale(deploymentName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "scale", c.ns, scale), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}

View File

@ -136,3 +136,25 @@ func (c *FakeReplicaSets) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*extensions.ReplicaSet), err return obj.(*extensions.ReplicaSet), err
} }
// GetScale takes name of the replicaSet, and returns the corresponding scale object, and an error if there is any.
func (c *FakeReplicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(replicasetsResource, c.ns, "scale", replicaSetName), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeReplicaSets) UpdateScale(replicaSetName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "scale", c.ns, scale), &extensions.Scale{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Scale), err
}

View File

@ -42,6 +42,9 @@ type ReplicaSetInterface interface {
List(opts v1.ListOptions) (*extensions.ReplicaSetList, error) List(opts v1.ListOptions) (*extensions.ReplicaSetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *extensions.ReplicaSet, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *extensions.ReplicaSet, err error)
GetScale(replicaSetName string, options v1.GetOptions) (*extensions.Scale, error)
UpdateScale(replicaSetName string, scale *extensions.Scale) (*extensions.Scale, error)
ReplicaSetExpansion ReplicaSetExpansion
} }
@ -170,3 +173,31 @@ func (c *replicaSets) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the replicaSet, and returns the corresponding extensions.Scale object, and an error if there is any.
func (c *replicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *replicaSets) UpdateScale(replicaSetName string, scale *extensions.Scale) (result *extensions.Scale, err error) {
result = &extensions.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -77,6 +77,8 @@ type Scale struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// StatefulSet represents a set of pods with consistent identities. // StatefulSet represents a set of pods with consistent identities.

View File

@ -2977,6 +2977,8 @@ type ReplicationControllerCondition struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/extensions/v1beta1.Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/extensions/v1beta1.Scale,result=k8s.io/api/extensions/v1beta1.Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicationController represents the configuration of a replication controller. // ReplicationController represents the configuration of a replication controller.

View File

@ -158,6 +158,8 @@ type ThirdPartyResourceData struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Deployment enables declarative updates for Pods and ReplicaSets. // Deployment enables declarative updates for Pods and ReplicaSets.
@ -766,6 +768,8 @@ type IngressBackend struct {
} }
// +genclient // +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicaSet represents the configuration of a ReplicaSet. // ReplicaSet represents the configuration of a ReplicaSet.

View File

@ -136,3 +136,25 @@ func (c *FakeStatefulSets) Patch(name string, pt types.PatchType, data []byte, s
} }
return obj.(*v1beta2.StatefulSet), err return obj.(*v1beta2.StatefulSet), err
} }
// GetScale takes name of the statefulSet, and returns the corresponding scale object, and an error if there is any.
func (c *FakeStatefulSets) GetScale(statefulSetName string, options v1.GetOptions) (result *v1beta2.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(statefulsetsResource, c.ns, "scale", statefulSetName), &v1beta2.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta2.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeStatefulSets) UpdateScale(statefulSetName string, scale *v1beta2.Scale) (result *v1beta2.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "scale", c.ns, scale), &v1beta2.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta2.Scale), err
}

View File

@ -42,6 +42,9 @@ type StatefulSetInterface interface {
List(opts v1.ListOptions) (*v1beta2.StatefulSetList, error) List(opts v1.ListOptions) (*v1beta2.StatefulSetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta2.StatefulSet, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta2.StatefulSet, err error)
GetScale(statefulSetName string, options v1.GetOptions) (*v1beta2.Scale, error)
UpdateScale(statefulSetName string, scale *v1beta2.Scale) (*v1beta2.Scale, error)
StatefulSetExpansion StatefulSetExpansion
} }
@ -170,3 +173,31 @@ func (c *statefulSets) Patch(name string, pt types.PatchType, data []byte, subre
Into(result) Into(result)
return return
} }
// GetScale takes name of the statefulSet, and returns the corresponding v1beta2.Scale object, and an error if there is any.
func (c *statefulSets) GetScale(statefulSetName string, options v1.GetOptions) (result *v1beta2.Scale, err error) {
result = &v1beta2.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("statefulsets").
Name(statefulSetName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *statefulSets) UpdateScale(statefulSetName string, scale *v1beta2.Scale) (result *v1beta2.Scale, err error) {
result = &v1beta2.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("statefulsets").
Name(statefulSetName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -35,6 +35,7 @@ go_library(
], ],
deps = [ deps = [
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library", "//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",

View File

@ -34,6 +34,7 @@ go_library(
], ],
deps = [ deps = [
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library", "//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",

View File

@ -18,6 +18,7 @@ package fake
import ( import (
core_v1 "k8s.io/api/core/v1" core_v1 "k8s.io/api/core/v1"
v1beta1 "k8s.io/api/extensions/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels" labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
@ -136,3 +137,25 @@ func (c *FakeReplicationControllers) Patch(name string, pt types.PatchType, data
} }
return obj.(*core_v1.ReplicationController), err return obj.(*core_v1.ReplicationController), err
} }
// GetScale takes name of the replicationController, and returns the corresponding scale object, and an error if there is any.
func (c *FakeReplicationControllers) GetScale(replicationControllerName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(replicationcontrollersResource, c.ns, "scale", replicationControllerName), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeReplicationControllers) UpdateScale(replicationControllerName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(replicationcontrollersResource, "scale", c.ns, scale), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}

View File

@ -18,6 +18,7 @@ package v1
import ( import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
v1beta1 "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types" types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch" watch "k8s.io/apimachinery/pkg/watch"
@ -42,6 +43,9 @@ type ReplicationControllerInterface interface {
List(opts meta_v1.ListOptions) (*v1.ReplicationControllerList, error) List(opts meta_v1.ListOptions) (*v1.ReplicationControllerList, error)
Watch(opts meta_v1.ListOptions) (watch.Interface, error) Watch(opts meta_v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ReplicationController, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ReplicationController, err error)
GetScale(replicationControllerName string, options meta_v1.GetOptions) (*v1beta1.Scale, error)
UpdateScale(replicationControllerName string, scale *v1beta1.Scale) (*v1beta1.Scale, error)
ReplicationControllerExpansion ReplicationControllerExpansion
} }
@ -170,3 +174,31 @@ func (c *replicationControllers) Patch(name string, pt types.PatchType, data []b
Into(result) Into(result)
return return
} }
// GetScale takes name of the replicationController, and returns the corresponding v1beta1.Scale object, and an error if there is any.
func (c *replicationControllers) GetScale(replicationControllerName string, options meta_v1.GetOptions) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("replicationcontrollers").
Name(replicationControllerName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *replicationControllers) UpdateScale(replicationControllerName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("replicationcontrollers").
Name(replicationControllerName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -42,6 +42,9 @@ type DeploymentInterface interface {
List(opts v1.ListOptions) (*v1beta1.DeploymentList, error) List(opts v1.ListOptions) (*v1beta1.DeploymentList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Deployment, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Deployment, err error)
GetScale(deploymentName string, options v1.GetOptions) (*v1beta1.Scale, error)
UpdateScale(deploymentName string, scale *v1beta1.Scale) (*v1beta1.Scale, error)
DeploymentExpansion DeploymentExpansion
} }
@ -170,3 +173,31 @@ func (c *deployments) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the deployment, and returns the corresponding v1beta1.Scale object, and an error if there is any.
func (c *deployments) GetScale(deploymentName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *deployments) UpdateScale(deploymentName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("deployments").
Name(deploymentName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -136,3 +136,25 @@ func (c *FakeDeployments) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*v1beta1.Deployment), err return obj.(*v1beta1.Deployment), err
} }
// GetScale takes name of the deployment, and returns the corresponding scale object, and an error if there is any.
func (c *FakeDeployments) GetScale(deploymentName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(deploymentsResource, c.ns, "scale", deploymentName), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeDeployments) UpdateScale(deploymentName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "scale", c.ns, scale), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}

View File

@ -136,3 +136,25 @@ func (c *FakeReplicaSets) Patch(name string, pt types.PatchType, data []byte, su
} }
return obj.(*v1beta1.ReplicaSet), err return obj.(*v1beta1.ReplicaSet), err
} }
// GetScale takes name of the replicaSet, and returns the corresponding scale object, and an error if there is any.
func (c *FakeReplicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetSubresourceAction(replicasetsResource, c.ns, "scale", replicaSetName), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}
// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *FakeReplicaSets) UpdateScale(replicaSetName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "scale", c.ns, scale), &v1beta1.Scale{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Scale), err
}

View File

@ -42,6 +42,9 @@ type ReplicaSetInterface interface {
List(opts v1.ListOptions) (*v1beta1.ReplicaSetList, error) List(opts v1.ListOptions) (*v1beta1.ReplicaSetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error) Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ReplicaSet, err error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ReplicaSet, err error)
GetScale(replicaSetName string, options v1.GetOptions) (*v1beta1.Scale, error)
UpdateScale(replicaSetName string, scale *v1beta1.Scale) (*v1beta1.Scale, error)
ReplicaSetExpansion ReplicaSetExpansion
} }
@ -170,3 +173,31 @@ func (c *replicaSets) Patch(name string, pt types.PatchType, data []byte, subres
Into(result) Into(result)
return return
} }
// GetScale takes name of the replicaSet, and returns the corresponding v1beta1.Scale object, and an error if there is any.
func (c *replicaSets) GetScale(replicaSetName string, options v1.GetOptions) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Get().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any.
func (c *replicaSets) UpdateScale(replicaSetName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) {
result = &v1beta1.Scale{}
err = c.client.Put().
Namespace(c.ns).
Resource("replicasets").
Name(replicaSetName).
SubResource("scale").
Body(scale).
Do().
Into(result)
return
}

View File

@ -47,6 +47,17 @@ func NewGetAction(resource schema.GroupVersionResource, namespace, name string)
return action return action
} }
func NewGetSubresourceAction(resource schema.GroupVersionResource, namespace, subresource, name string) GetActionImpl {
action := GetActionImpl{}
action.Verb = "get"
action.Resource = resource
action.Subresource = subresource
action.Namespace = namespace
action.Name = name
return action
}
func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl { func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl {
action := ListActionImpl{} action := ListActionImpl{}
action.Verb = "list" action.Verb = "list"
@ -70,6 +81,20 @@ func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersio
return action return action
} }
func NewListSubresourceAction(resource schema.GroupVersionResource, name, subresource string, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl {
action := ListActionImpl{}
action.Verb = "list"
action.Resource = resource
action.Subresource = subresource
action.Kind = kind
action.Namespace = namespace
action.Name = name
labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
return action
}
func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl { func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl {
action := CreateActionImpl{} action := CreateActionImpl{}
action.Verb = "create" action.Verb = "create"
@ -89,6 +114,18 @@ func NewCreateAction(resource schema.GroupVersionResource, namespace string, obj
return action return action
} }
func NewCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource string, namespace string, object runtime.Object) CreateActionImpl {
action := CreateActionImpl{}
action.Verb = "create"
action.Resource = resource
action.Subresource = subresource
action.Namespace = namespace
action.Name = name
action.Object = object
return action
}
func NewRootUpdateAction(resource schema.GroupVersionResource, object runtime.Object) UpdateActionImpl { func NewRootUpdateAction(resource schema.GroupVersionResource, object runtime.Object) UpdateActionImpl {
action := UpdateActionImpl{} action := UpdateActionImpl{}
action.Verb = "update" action.Verb = "update"
@ -389,6 +426,7 @@ func (a GetActionImpl) GetName() string {
type ListActionImpl struct { type ListActionImpl struct {
ActionImpl ActionImpl
Kind schema.GroupVersionKind Kind schema.GroupVersionKind
Name string
ListRestrictions ListRestrictions ListRestrictions ListRestrictions
} }
@ -402,6 +440,7 @@ func (a ListActionImpl) GetListRestrictions() ListRestrictions {
type CreateActionImpl struct { type CreateActionImpl struct {
ActionImpl ActionImpl
Name string
Object runtime.Object Object runtime.Object
} }

View File

@ -19,6 +19,7 @@ package fake
import ( import (
"io" "io"
"path/filepath" "path/filepath"
"strings"
"k8s.io/gengo/generator" "k8s.io/gengo/generator"
"k8s.io/gengo/namer" "k8s.io/gengo/namer"
@ -108,6 +109,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
const pkgClientGoTesting = "k8s.io/client-go/testing" const pkgClientGoTesting = "k8s.io/client-go/testing"
m := map[string]interface{}{ m := map[string]interface{}{
"type": t, "type": t,
"inputType": t,
"resultType": t,
"subresourcePath": "",
"package": pkg, "package": pkg,
"Package": namer.IC(pkg), "Package": namer.IC(pkg),
"namespaced": !tags.NonNamespaced, "namespaced": !tags.NonNamespaced,
@ -139,7 +143,10 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
"NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}), "NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}),
"NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}), "NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}),
"NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}), "NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}),
"NewCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceAction"}),
"NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}), "NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}),
"NewGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceAction"}),
"NewListSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListSubresourceAction"}),
"NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}), "NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}),
"NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}), "NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}),
"NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}), "NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}),
@ -193,9 +200,88 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
sw.Do(patchTemplate, m) sw.Do(patchTemplate, m)
} }
// generate extended client methods
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
m["inputType"] = &inputType
m["resultType"] = &resultType
m["subresourcePath"] = e.SubResourcePath
if e.HasVerb("get") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m)
}
}
if e.HasVerb("list") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m)
}
}
// TODO: Figure out schemantic for watching a sub-resource.
if e.HasVerb("watch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m)
}
if e.HasVerb("create") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m)
}
}
if e.HasVerb("update") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m)
}
}
// TODO: Figure out schemantic for deleting a sub-resource (what arguments
// are passed, does it need two names? etc.
if e.HasVerb("delete") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m)
}
if e.HasVerb("patch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m)
}
}
return sw.Error() return sw.Error()
} }
// adjustTemplate adjust the origin verb template using the expansion name.
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
}
// template for the struct that implements the type's interface // template for the struct that implements the type's interface
var structNamespaced = ` var structNamespaced = `
// Fake$.type|publicPlural$ implements $.type|public$Interface // Fake$.type|publicPlural$ implements $.type|public$Interface
@ -234,6 +320,19 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type
} }
` `
var listSubresourceTemplate = `
// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *Fake$.type|publicPlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewListSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.type|allLowercasePlural$Kind, c.ns, opts), &$.resultType|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.resultType|raw$List{})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$List), err
}
`
var listUsingOptionsTemplate = ` var listUsingOptionsTemplate = `
// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. // List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors.
func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
@ -259,15 +358,28 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type
` `
var getTemplate = ` var getTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.type|private$ object, and an error if there is any. // Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.type|raw$, err error) { func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${}) $if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.resultType|raw${})
$else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.type|raw${})$end$ $else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.resultType|raw${})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*$.type|raw$), err return obj.(*$.resultType|raw$), err
}
`
var getSubresourceTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *Fake$.type|publicPlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name), &$.resultType|raw${})
$else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
} }
` `
@ -291,30 +403,55 @@ func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw
return err return err
} }
` `
var createTemplate = ` var createTemplate = `
// Create takes the representation of a $.type|private$ and creates it. Returns the server's representation of the $.type|private$, and an error, if there is any. // Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Create($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { func (c *Fake$.type|publicPlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) $if .namespaced$Invokes($.NewCreateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootCreateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$ $else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*$.type|raw$), err return obj.(*$.resultType|raw$), err
}
`
var createSubresourceTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
} }
` `
var updateTemplate = ` var updateTemplate = `
// Update takes the representation of a $.type|private$ and updates it. Returns the server's representation of the $.type|private$, and an error, if there is any. // Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Update($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { func (c *Fake$.type|publicPlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) $if .namespaced$Invokes($.NewUpdateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootUpdateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var updateSubresourceTemplate = `
// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${})
$else$Invokes($.NewRootUpdateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$ $else$Invokes($.NewRootUpdateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*$.type|raw$), err return obj.(*$.resultType|raw$), err
} }
` `
@ -342,14 +479,14 @@ func (c *Fake$.type|publicPlural$) Watch(opts $.ListOptions|raw$) ($.watchInterf
` `
var patchTemplate = ` var patchTemplate = `
// Patch applies the patch and returns the patched $.type|private$. // Patch applies the patch and returns the patched $.resultType|private$.
func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error) { func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, data, subresources... ), &$.type|raw${}) $if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, data, subresources... ), &$.resultType|raw${})
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, data, subresources...), &$.type|raw${})$end$ $else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, data, subresources...), &$.resultType|raw${})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*$.type|raw$), err return obj.(*$.resultType|raw$), err
} }
` `

View File

@ -77,12 +77,61 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
if err != nil { if err != nil {
return err return err
} }
type extendedInterfaceMethod struct {
template string
args map[string]interface{}
}
extendedMethods := []extendedInterfaceMethod{}
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
// TODO: Extract this to some helper method as this code is copied into
// 2 other places.
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
var updatedVerbtemplate string
if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists {
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
} else {
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
}
extendedMethods = append(extendedMethods, extendedInterfaceMethod{
template: updatedVerbtemplate,
args: map[string]interface{}{
"type": t,
"inputType": &inputType,
"resultType": &resultType,
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
},
})
}
m := map[string]interface{}{ m := map[string]interface{}{
"type": t, "type": t,
"inputType": t,
"resultType": t,
"package": pkg, "package": pkg,
"Package": namer.IC(pkg), "Package": namer.IC(pkg),
"namespaced": !tags.NonNamespaced, "namespaced": !tags.NonNamespaced,
"Group": namer.IC(g.group), "Group": namer.IC(g.group),
"subresource": false,
"subresourcePath": "",
"GroupVersion": namer.IC(g.group) + namer.IC(g.version), "GroupVersion": namer.IC(g.group) + namer.IC(g.version),
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
@ -105,7 +154,16 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
if !genStatus(t) { if !genStatus(t) {
tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus") tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus")
} }
sw.Do(generateInterface(tags), m) interfaceSuffix := ""
if len(extendedMethods) > 0 {
interfaceSuffix = "\n"
}
sw.Do("\n"+generateInterface(tags)+interfaceSuffix, m)
// add extended verbs into interface
for _, v := range extendedMethods {
sw.Do(v.template+interfaceSuffix, v.args)
}
} }
sw.Do(interfaceTemplate4, m) sw.Do(interfaceTemplate4, m)
@ -150,9 +208,88 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
sw.Do(patchTemplate, m) sw.Do(patchTemplate, m)
} }
// generate expansion methods
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
m["inputType"] = &inputType
m["resultType"] = &resultType
m["subresourcePath"] = e.SubResourcePath
if e.HasVerb("get") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m)
}
}
if e.HasVerb("list") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m)
}
}
// TODO: Figure out schemantic for watching a sub-resource.
if e.HasVerb("watch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m)
}
if e.HasVerb("create") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m)
}
}
if e.HasVerb("update") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m)
}
}
// TODO: Figure out schemantic for deleting a sub-resource (what arguments
// are passed, does it need two names? etc.
if e.HasVerb("delete") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m)
}
if e.HasVerb("patch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m)
}
}
return sw.Error() return sw.Error()
} }
// adjustTemplate adjust the origin verb template using the expansion name.
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
}
func generateInterface(tags util.Tags) string { func generateInterface(tags util.Tags) string {
// need an ordered list here to guarantee order of generated methods. // need an ordered list here to guarantee order of generated methods.
out := []string{} out := []string{}
@ -164,16 +301,23 @@ func generateInterface(tags util.Tags) string {
return strings.Join(out, "\n") return strings.Join(out, "\n")
} }
var subresourceDefaultVerbTemplates = map[string]string{
"create": `Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`,
"list": `List($.type|private$Name string, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`,
"update": `Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`,
"get": `Get($.type|private$Name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`,
}
var defaultVerbTemplates = map[string]string{ var defaultVerbTemplates = map[string]string{
"create": `Create(*$.type|raw$) (*$.type|raw$, error)`, "create": `Create(*$.inputType|raw$) (*$.resultType|raw$, error)`,
"update": `Update(*$.type|raw$) (*$.type|raw$, error)`, "update": `Update(*$.inputType|raw$) (*$.resultType|raw$, error)`,
"updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`, "updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`,
"delete": `Delete(name string, options *$.DeleteOptions|raw$) error`, "delete": `Delete(name string, options *$.DeleteOptions|raw$) error`,
"deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`, "deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`,
"get": `Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error)`, "get": `Get(name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`,
"list": `List(opts $.ListOptions|raw$) (*$.type|raw$List, error)`, "list": `List(opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`,
"watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`, "watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`,
"patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error)`, "patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error)`,
} }
// group client will implement this interface. // group client will implement this interface.
@ -238,11 +382,10 @@ func new$.type|publicPlural$(c *$.GroupVersion$Client) *$.type|privatePlural$ {
} }
} }
` `
var listTemplate = ` var listTemplate = `
// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. // List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
result = &$.type|raw$List{} result = &$.resultType|raw$List{}
err = c.client.Get(). err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$ $if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$"). Resource("$.type|resource$").
@ -252,10 +395,27 @@ func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.type|ra
return return
} }
` `
var listSubresourceTemplate = `
// List takes $.type|raw$ name, label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *$.type|privatePlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
result = &$.resultType|raw$List{}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var getTemplate = ` var getTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.type|private$ object, and an error if there is any. // Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.type|raw$, err error) { func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
result = &$.type|raw${} result = &$.resultType|raw${}
err = c.client.Get(). err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$ $if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$"). Resource("$.type|resource$").
@ -267,6 +427,22 @@ func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (res
} }
` `
var getSubresourceTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|raw$ object, and an error if there is any.
func (c *$.type|privatePlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
VersionedParams(&options, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var deleteTemplate = ` var deleteTemplate = `
// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. // Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs.
func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error { func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error {
@ -293,14 +469,46 @@ func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$,
} }
` `
var createTemplate = ` var createSubresourceTemplate = `
// Create takes the representation of a $.type|private$ and creates it. Returns the server's representation of the $.type|private$, and an error, if there is any. // Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Create($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { func (c *$.type|privatePlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.type|raw${} result = &$.resultType|raw${}
err = c.client.Post(). err = c.client.Post().
$if .namespaced$Namespace(c.ns).$end$ $if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$"). Resource("$.type|resource$").
Body($.type|private$). Name($.type|private$Name).
SubResource("$.subresourcePath$").
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var createTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Post().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var updateSubresourceTemplate = `
// Update takes the top resource name and the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
Body($.inputType|private$).
Do(). Do().
Into(result) Into(result)
return return
@ -308,14 +516,14 @@ func (c *$.type|privatePlural$) Create($.type|private$ *$.type|raw$) (result *$.
` `
var updateTemplate = ` var updateTemplate = `
// Update takes the representation of a $.type|private$ and updates it. Returns the server's representation of the $.type|private$, and an error, if there is any. // Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Update($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { func (c *$.type|privatePlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.type|raw${} result = &$.resultType|raw${}
err = c.client.Put(). err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$ $if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$"). Resource("$.type|resource$").
Name($.type|private$.Name). Name($.inputType|private$.Name).
Body($.type|private$). Body($.inputType|private$).
Do(). Do().
Into(result) Into(result)
return return
@ -353,9 +561,9 @@ func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface
` `
var patchTemplate = ` var patchTemplate = `
// Patch applies the patch and returns the patched $.type|private$. // Patch applies the patch and returns the patched $.resultType|private$.
func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error) { func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) {
result = &$.type|raw${} result = &$.resultType|raw${}
err = c.client.Patch(pt). err = c.client.Patch(pt).
$if .namespaced$Namespace(c.ns).$end$ $if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$"). Resource("$.type|resource$").

View File

@ -32,6 +32,7 @@ var supportedTags = []string{
"genclient:skipVerbs", "genclient:skipVerbs",
"genclient:noStatus", "genclient:noStatus",
"genclient:readonly", "genclient:readonly",
"genclient:method",
} }
// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs. // SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs.
@ -54,6 +55,96 @@ var ReadonlyVerbs = []string{
"watch", "watch",
} }
// genClientPrefix is the default prefix for all genclient tags.
const genClientPrefix = "genclient:"
// unsupportedExtensionVerbs is a list of verbs we don't support generating
// extension client functions for.
var unsupportedExtensionVerbs = []string{
"updateStatus",
"deleteCollection",
"watch",
"delete",
}
// inputTypeSupportedVerbs is a list of verb types that supports overriding the
// input argument type.
var inputTypeSupportedVerbs = []string{
"create",
"update",
}
// resultTypeSupportedVerbs is a list of verb types that supports overriding the
// resulting type.
var resultTypeSupportedVerbs = []string{
"create",
"update",
"get",
"list",
"patch",
}
// Extensions allows to extend the default set of client verbs
// (CRUD+watch+patch+list+deleteCollection) for a given type with custom defined
// verbs. Custom verbs can have custom input and result types and also allow to
// use a sub-resource in a request instead of top-level resource type.
//
// Example:
//
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
//
// type ReplicaSet struct { ... }
//
// The 'method=UpdateScale' is the name of the client function.
// The 'verb=update' here means the client function will use 'PUT' action.
// The 'subresource=scale' means we will use SubResource template to generate this client function.
// The 'input' is the input type used for creation (function argument).
// The 'result' (not needed in this case) is the result type returned from the
// client function.
//
type extension struct {
// VerbName is the name of the custom verb (Scale, Instantiate, etc..)
VerbName string
// VerbType is the type of the verb (only verbs from SupportedVerbs are
// supported)
VerbType string
// SubResourcePath defines a path to a sub-resource to use in the request.
// (optional)
SubResourcePath string
// InputTypeOverride overrides the input parameter type for the verb. By
// default the original type is used. Overriding the input type only works for
// "create" and "update" verb types. The given type must exists in the same
// package as the original type.
// (optional)
InputTypeOverride string
// ResultTypeOverride overrides the resulting object type for the verb. By
// default the original type is used. Overriding the result type works.
// (optional)
ResultTypeOverride string
}
// IsSubresource indicates if this extension should generate the sub-resource.
func (e *extension) IsSubresource() bool {
return len(e.SubResourcePath) > 0
}
// HasVerb checks if the extension matches the given verb.
func (e *extension) HasVerb(verb string) bool {
return e.VerbType == verb
}
// Input returns the input override package path and the type.
func (e *extension) Input() (string, string) {
parts := strings.Split(e.InputTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}
// Result returns the result override package path and the type.
func (e *extension) Result() (string, string) {
parts := strings.Split(e.ResultTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}
// Tags represents a genclient configuration for a single type. // Tags represents a genclient configuration for a single type.
type Tags struct { type Tags struct {
// +genclient // +genclient
@ -67,6 +158,8 @@ type Tags struct {
// +genclient:skipVerbs=get,update // +genclient:skipVerbs=get,update
// +genclient:onlyVerbs=create,delete // +genclient:onlyVerbs=create,delete
SkipVerbs []string SkipVerbs []string
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
Extensions []extension
} }
// HasVerb returns true if we should include the given verb in final client interface and // HasVerb returns true if we should include the given verb in final client interface and
@ -103,25 +196,25 @@ func ParseClientGenTags(lines []string) (Tags, error) {
if len(value) > 0 && len(value[0]) > 0 { if len(value) > 0 && len(value[0]) > 0 {
return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value) return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value)
} }
_, ret.NonNamespaced = values["genclient:nonNamespaced"] _, ret.NonNamespaced = values[genClientPrefix+"nonNamespaced"]
// Check the old format and error when used // Check the old format and error when used
if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 { if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 {
return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0]) return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0])
} }
_, ret.NoVerbs = values["genclient:noVerbs"] _, ret.NoVerbs = values[genClientPrefix+"noVerbs"]
_, ret.NoStatus = values["genclient:noStatus"] _, ret.NoStatus = values[genClientPrefix+"noStatus"]
onlyVerbs := []string{} onlyVerbs := []string{}
if _, isReadonly := values["genclient:readonly"]; isReadonly { if _, isReadonly := values[genClientPrefix+"readonly"]; isReadonly {
onlyVerbs = ReadonlyVerbs onlyVerbs = ReadonlyVerbs
} }
// Check the old format and error when used // Check the old format and error when used
if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 { if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 {
return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0]) return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0])
} }
if v, exists := values["genclient:skipVerbs"]; exists { if v, exists := values[genClientPrefix+"skipVerbs"]; exists {
ret.SkipVerbs = strings.Split(v[0], ",") ret.SkipVerbs = strings.Split(v[0], ",")
} }
if v, exists := values["genclient:onlyVerbs"]; exists || len(onlyVerbs) > 0 { if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 {
if len(v) > 0 { if len(v) > 0 {
onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...) onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...)
} }
@ -146,16 +239,101 @@ func ParseClientGenTags(lines []string) (Tags, error) {
} }
ret.SkipVerbs = skipVerbs ret.SkipVerbs = skipVerbs
} }
var err error
if ret.Extensions, err = parseClientExtensions(values); err != nil {
return ret, err
}
return ret, validateClientGenTags(values) return ret, validateClientGenTags(values)
} }
func parseClientExtensions(tags map[string][]string) ([]extension, error) {
var ret []extension
for name, values := range tags {
if !strings.HasPrefix(name, genClientPrefix+"method") {
continue
}
for _, value := range values {
// the value comes in this form: "Foo,verb=create"
ext := extension{}
parts := strings.Split(value, ",")
if len(parts) == 0 {
return nil, fmt.Errorf("invalid of empty extension verb name: %q", value)
}
// The first part represents the name of the extension
ext.VerbName = parts[0]
if len(ext.VerbName) == 0 {
return nil, fmt.Errorf("must specify a verb name (// +genclient:method=Foo,verb=create)")
}
// Parse rest of the arguments
params := parts[1:]
for _, p := range params {
parts := strings.Split(p, "=")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid extension tag specification %q", p)
}
key, val := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
if len(val) == 0 {
return nil, fmt.Errorf("empty value of %q for %q extension", key, ext.VerbName)
}
switch key {
case "verb":
ext.VerbType = val
case "subresource":
ext.SubResourcePath = val
case "input":
ext.InputTypeOverride = val
case "result":
ext.ResultTypeOverride = val
default:
return nil, fmt.Errorf("unknown extension configuration key %q", key)
}
}
// Validate resulting extension configuration
if len(ext.VerbType) == 0 {
return nil, fmt.Errorf("verb type must be specified (use '// +genclient:method=%s,verb=create')", ext.VerbName)
}
if len(ext.ResultTypeOverride) > 0 {
supported := false
for _, v := range resultTypeSupportedVerbs {
if ext.VerbType == v {
supported = true
break
}
}
if !supported {
return nil, fmt.Errorf("%s: result type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, resultTypeSupportedVerbs)
}
}
if len(ext.InputTypeOverride) > 0 {
supported := false
for _, v := range inputTypeSupportedVerbs {
if ext.VerbType == v {
supported = true
break
}
}
if !supported {
return nil, fmt.Errorf("%s: input type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, inputTypeSupportedVerbs)
}
}
for _, t := range unsupportedExtensionVerbs {
if ext.VerbType == t {
return nil, fmt.Errorf("verb %q is not supported by extension generator", ext.VerbType)
}
}
ret = append(ret, ext)
}
}
return ret, nil
}
// validateTags validates that only supported genclient tags were provided. // validateTags validates that only supported genclient tags were provided.
func validateClientGenTags(values map[string][]string) error { func validateClientGenTags(values map[string][]string) error {
for _, k := range supportedTags { for _, k := range supportedTags {
delete(values, k) delete(values, k)
} }
for key := range values { for key := range values {
if strings.HasPrefix(key, "genclient") { if strings.HasPrefix(key, strings.TrimSuffix(genClientPrefix, ":")) {
return errors.New("unknown tag detected: " + key) return errors.New("unknown tag detected: " + key)
} }
} }

View File

@ -82,3 +82,67 @@ func TestParseTags(t *testing.T) {
} }
} }
} }
func TestParseTagsExtension(t *testing.T) {
testCases := map[string]struct {
lines []string
expectedExtensions []extension
expectError bool
}{
"simplest extension": {
lines: []string{`+genclient:method=Foo,verb=create`},
expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}},
},
"multiple extensions": {
lines: []string{`+genclient:method=Foo,verb=create`, `+genclient:method=Bar,verb=get`},
expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}, {VerbName: "Bar", VerbType: "get"}},
},
"extension without verb": {
lines: []string{`+genclient:method`},
expectError: true,
},
"extension without verb type": {
lines: []string{`+genclient:method=Foo`},
expectError: true,
},
"sub-resource extension": {
lines: []string{`+genclient:method=Foo,verb=create,subresource=bar`},
expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create", SubResourcePath: "bar"}},
},
"output type extension": {
lines: []string{`+genclient:method=Foos,verb=list,result=Bars`},
expectedExtensions: []extension{{VerbName: "Foos", VerbType: "list", ResultTypeOverride: "Bars"}},
},
"input type extension": {
lines: []string{`+genclient:method=Foo,verb=update,input=Bar`},
expectedExtensions: []extension{{VerbName: "Foo", VerbType: "update", InputTypeOverride: "Bar"}},
},
"unknown verb type extension": {
lines: []string{`+genclient:method=Foo,verb=explode`},
expectedExtensions: nil,
expectError: true,
},
"invalid verb extension": {
lines: []string{`+genclient:method=Foo,unknown=bar`},
expectedExtensions: nil,
expectError: true,
},
"empty verb extension subresource": {
lines: []string{`+genclient:method=Foo,verb=get,subresource=`},
expectedExtensions: nil,
expectError: true,
},
}
for key, c := range testCases {
result, err := ParseClientGenTags(c.lines)
if err != nil && !c.expectError {
t.Fatalf("[%s] unexpected error: %v", key, err)
}
if err != nil && c.expectError {
t.Logf("[%s] got expected error: %+v", key, err)
}
if !c.expectError && !reflect.DeepEqual(result.Extensions, c.expectedExtensions) {
t.Errorf("[%s] expected %#+v to be %#+v", key, result.Extensions, c.expectedExtensions)
}
}
}