mirror of https://github.com/k3s-io/k3s
Merge pull request #60021 from nikhita/sample-controller-subresources
Automatic merge from submit-queue (batch tested with PRs 60102, 59970, 60021, 62011, 62080). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. sample-controller: add status subresource support Builds on top of https://github.com/kubernetes/kubernetes/pull/55168. **DO NOT MERGE** until https://github.com/kubernetes/kubernetes/pull/55168 is merged. Adding a hold. /hold Update: It is now merged! 🎉 This PR: - Adds an example to show how to use the `/status` subresource with custom resources. - Generates `UpdateStatus` for the `Foo` resource. - Updates the comment in the controller to mention that `UpdateStatus` can now be used. Note: this is not enabled by default because subresources require the feature gate to be enabled and are not on by default. - Updates the README to add feature gate information and examples for `CustomResourceSubresources`. - Updates the README to remove feature gate information for CRD validation since the current example uses `apps/v1` deployments (and thus requires v1.9 anyway). **Release note**: ```release-note NONE ``` /assign sttts munnerzpull/8/head
commit
7bde13f191
|
@ -79,17 +79,44 @@ type User struct {
|
|||
|
||||
To validate custom resources, use the [`CustomResourceValidation`](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#validation) feature.
|
||||
|
||||
This feature is beta and enabled by default in v1.9. If you are using v1.8, enable the feature using
|
||||
the `CustomResourceValidation` feature gate on the [kube-apiserver](https://kubernetes.io/docs/admin/kube-apiserver):
|
||||
This feature is beta and enabled by default in v1.9.
|
||||
|
||||
### Example
|
||||
|
||||
The schema in [`crd-validation.yaml`](./artifacts/examples/crd-validation.yaml) applies the following validation on the custom resource:
|
||||
`spec.replicas` must be an integer and must have a minimum value of 1 and a maximum value of 10.
|
||||
|
||||
In the above steps, use `crd-validation.yaml` to create the CRD:
|
||||
|
||||
```sh
|
||||
--feature-gates=CustomResourceValidation=true
|
||||
# create a CustomResourceDefinition supporting validation
|
||||
$ kubectl create -f artifacts/examples/crd-validation.yaml
|
||||
```
|
||||
|
||||
## Subresources
|
||||
|
||||
Custom Resources support `/status` and `/scale` subresources as an
|
||||
[alpha feature](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#subresources) in v1.10.
|
||||
Enable this feature using the `CustomResourceSubresources` feature gate on the [kube-apiserver](https://kubernetes.io/docs/admin/kube-apiserver):
|
||||
|
||||
```sh
|
||||
--feature-gates=CustomResourceSubresources=true
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
The schema in the [example CRD](./artifacts/examples/crd.yaml) applies the following validation on the custom resource:
|
||||
`spec.replicas` must be an integer and must have a minimum value of 1 and a maximum value of 10.
|
||||
The CRD in [`crd-status-subresource.yaml`](./artifacts/examples/crd-status-subresource.yaml) enables the `/status` subresource
|
||||
for custom resources.
|
||||
This means that [`UpdateStatus`](./controller.go#L330) can be used by the controller to update only the status part of the custom resource.
|
||||
|
||||
To understand why only the status part of the custom resource should be updated, please refer to the [Kubernetes API conventions](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status).
|
||||
|
||||
In the above steps, use `crd-status-subresource.yaml` to create the CRD:
|
||||
|
||||
```sh
|
||||
# create a CustomResourceDefinition supporting the status subresource
|
||||
$ kubectl create -f artifacts/examples/crd-status-subresource.yaml
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: foos.samplecontroller.k8s.io
|
||||
spec:
|
||||
group: samplecontroller.k8s.io
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: Foo
|
||||
plural: foos
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: foos.samplecontroller.k8s.io
|
||||
spec:
|
||||
group: samplecontroller.k8s.io
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: Foo
|
||||
plural: foos
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
properties:
|
||||
replicas:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 10
|
|
@ -9,12 +9,3 @@ spec:
|
|||
kind: Foo
|
||||
plural: foos
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
spec:
|
||||
properties:
|
||||
replicas:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 10
|
||||
|
|
|
@ -327,10 +327,10 @@ func (c *Controller) updateFooStatus(foo *samplev1alpha1.Foo, deployment *appsv1
|
|||
// Or create a copy manually for better performance
|
||||
fooCopy := foo.DeepCopy()
|
||||
fooCopy.Status.AvailableReplicas = deployment.Status.AvailableReplicas
|
||||
// Until #38113 is merged, we must use Update instead of UpdateStatus to
|
||||
// update the Status block of the Foo resource. UpdateStatus will not
|
||||
// allow changes to the Spec of the resource, which is ideal for ensuring
|
||||
// nothing other than resource status has been updated.
|
||||
// If the CustomResourceSubresources feature gate is not enabled,
|
||||
// we must use Update instead of UpdateStatus to update the Status block of the Foo resource.
|
||||
// UpdateStatus will not allow changes to the Spec of the resource,
|
||||
// which is ideal for ensuring nothing other than resource status has been updated.
|
||||
_, err := c.sampleclientset.SamplecontrollerV1alpha1().Foos(foo.Namespace).Update(fooCopy)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
)
|
||||
|
||||
// +genclient
|
||||
// +genclient:noStatus
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Foo is a specification for a Foo resource
|
||||
|
|
|
@ -100,6 +100,18 @@ func (c *FakeFoos) Update(foo *v1alpha1.Foo) (result *v1alpha1.Foo, err error) {
|
|||
return obj.(*v1alpha1.Foo), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeFoos) UpdateStatus(foo *v1alpha1.Foo) (*v1alpha1.Foo, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(foosResource, "status", c.ns, foo), &v1alpha1.Foo{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Foo), err
|
||||
}
|
||||
|
||||
// Delete takes name of the foo and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeFoos) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
|
|
|
@ -37,6 +37,7 @@ type FoosGetter interface {
|
|||
type FooInterface interface {
|
||||
Create(*v1alpha1.Foo) (*v1alpha1.Foo, error)
|
||||
Update(*v1alpha1.Foo) (*v1alpha1.Foo, error)
|
||||
UpdateStatus(*v1alpha1.Foo) (*v1alpha1.Foo, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.Foo, error)
|
||||
|
@ -120,6 +121,22 @@ func (c *foos) Update(foo *v1alpha1.Foo) (result *v1alpha1.Foo, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *foos) UpdateStatus(foo *v1alpha1.Foo) (result *v1alpha1.Foo, err error) {
|
||||
result = &v1alpha1.Foo{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("foos").
|
||||
Name(foo.Name).
|
||||
SubResource("status").
|
||||
Body(foo).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the foo and deletes it. Returns an error if one occurs.
|
||||
func (c *foos) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
|
|
Loading…
Reference in New Issue