diff --git a/deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml b/deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml index 4409afcf79..60faf78315 100644 --- a/deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml +++ b/deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml @@ -6,6 +6,14 @@ metadata: creationTimestamp: null name: policies.k8s.nginx.org spec: + additionalPrinterColumns: + - JSONPath: .status.state + description: Current state of the Policy. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + name: State + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date group: k8s.nginx.org names: kind: Policy @@ -16,6 +24,8 @@ spec: singular: policy preserveUnknownFields: false scope: Namespaced + subresources: + status: {} validation: openAPIV3Schema: description: Policy defines a Policy for VirtualServer and VirtualServerRoute resources. @@ -127,6 +137,16 @@ spec: type: integer zoneSize: type: string + status: + description: PolicyStatus is the status of the policy resource + type: object + properties: + message: + type: string + reason: + type: string + state: + type: string version: v1 versions: - name: v1 diff --git a/deployments/common/crds/k8s.nginx.org_policies.yaml b/deployments/common/crds/k8s.nginx.org_policies.yaml index c4125a1a02..67b3ac36f8 100644 --- a/deployments/common/crds/k8s.nginx.org_policies.yaml +++ b/deployments/common/crds/k8s.nginx.org_policies.yaml @@ -16,7 +16,15 @@ spec: singular: policy scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: Current state of the Policy. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: Policy defines a Policy for VirtualServer and VirtualServerRoute resources. @@ -128,8 +136,20 @@ spec: type: integer zoneSize: type: string + status: + description: PolicyStatus is the status of the policy resource + type: object + properties: + message: + type: string + reason: + type: string + state: + type: string served: true storage: true + subresources: + status: {} status: acceptedNames: kind: "" diff --git a/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml b/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml index 4409afcf79..60faf78315 100644 --- a/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml +++ b/deployments/helm-chart/crds/k8s.nginx.org_policies.yaml @@ -6,6 +6,14 @@ metadata: creationTimestamp: null name: policies.k8s.nginx.org spec: + additionalPrinterColumns: + - JSONPath: .status.state + description: Current state of the Policy. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + name: State + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date group: k8s.nginx.org names: kind: Policy @@ -16,6 +24,8 @@ spec: singular: policy preserveUnknownFields: false scope: Namespaced + subresources: + status: {} validation: openAPIV3Schema: description: Policy defines a Policy for VirtualServer and VirtualServerRoute resources. @@ -127,6 +137,16 @@ spec: type: integer zoneSize: type: string + status: + description: PolicyStatus is the status of the policy resource + type: object + properties: + message: + type: string + reason: + type: string + state: + type: string version: v1 versions: - name: v1 diff --git a/deployments/helm-chart/templates/rbac.yaml b/deployments/helm-chart/templates/rbac.yaml index c43ac1e365..e7caa7b791 100644 --- a/deployments/helm-chart/templates/rbac.yaml +++ b/deployments/helm-chart/templates/rbac.yaml @@ -102,6 +102,7 @@ rules: resources: - virtualservers/status - virtualserverroutes/status + - policies/status verbs: - update {{- end }} diff --git a/deployments/rbac/rbac.yaml b/deployments/rbac/rbac.yaml index b3848b1373..74d47ee26a 100644 --- a/deployments/rbac/rbac.yaml +++ b/deployments/rbac/rbac.yaml @@ -76,6 +76,7 @@ rules: resources: - virtualservers/status - virtualserverroutes/status + - policies/status verbs: - update - apiGroups: diff --git a/docs-web/configuration/global-configuration/reporting-resources-status.md b/docs-web/configuration/global-configuration/reporting-resources-status.md index eed328afe8..f05a4f29ed 100644 --- a/docs-web/configuration/global-configuration/reporting-resources-status.md +++ b/docs-web/configuration/global-configuration/reporting-resources-status.md @@ -110,4 +110,44 @@ The Ingress controller must be configured to report a VirtualServer or VirtualSe See the docs about [ConfigMap keys](/nginx-ingress-controller/configuration/global-configuration/configmap-resource) and [Command-line arguments](/nginx-ingress-controller/configuration/global-configuration/command-line-arguments). -Notes: The Ingress controller does not clear the status of VirtualServer and VirtualServerRoute resources when it is being shut down. \ No newline at end of file +Notes: The Ingress controller does not clear the status of VirtualServer and VirtualServerRoute resources when it is being shut down. + +## Policy Resources + +A Policy resource includes the status field with information about the state of the resource. +You can see the status in the ouput of the `kubectl get policy` command as shown below: +``` +$ kubectl get policy + NAME STATE AGE + webapp-policy Valid 30s +``` +In order to see additional addresses or extra information about the `Status` of the resource, use the following command: +``` +$ kubectl describe policy +. . . +Status: + Message: Configuration for default/webapp-policy was added or updated + Reason: AddedOrUpdated + State: Valid +``` + +### Status Specification +The following fields are reported in Policy status: + +```eval_rst +.. list-table:: + :header-rows: 1 + + * - Field + - Description + - Type + * - ``State`` + - Current state of the resource. Can be ``Valid`` or ``Invalid``. For more information, refer to the ``message`` field. + - ``string`` + * - ``Reason`` + - The reason of the last update. + - ``string`` + * - ``Message`` + - Additional information about the state. + - ``string`` +``` diff --git a/docs-web/configuration/policy-resource.md b/docs-web/configuration/policy-resource.md index 4a882f7642..ab8140a57f 100644 --- a/docs-web/configuration/policy-resource.md +++ b/docs-web/configuration/policy-resource.md @@ -651,4 +651,15 @@ Events: ``` Note how the events section includes a Warning event with the Rejected reason. +Additionally, this information is also available in the `status` field of the Policy resource. Note the Status section of the Policy: + +``` +$ kubectl describe pol webapp-policy +. . . +Status: + Message: Policy default/webapp-policy is invalid and was rejected: spec.accessControl.allow[0]: Invalid value: "10.0.0.": must be a CIDR or IP + Reason: Rejected + State: Invalid +``` + **Note**: If you make an existing resource invalid, the Ingress Controller will reject it. diff --git a/internal/k8s/controller.go b/internal/k8s/controller.go index 6500e43207..7239531c6e 100644 --- a/internal/k8s/controller.go +++ b/internal/k8s/controller.go @@ -324,6 +324,7 @@ func NewLoadBalancerController(input NewLoadBalancerControllerInput) *LoadBalanc ingressLister: &lbc.ingressLister, virtualServerLister: lbc.virtualServerLister, virtualServerRouteLister: lbc.virtualServerRouteLister, + policyLister: lbc.policyLister, keyFunc: keyFunc, confClient: input.ConfClient, } @@ -822,7 +823,7 @@ func (lbc *LoadBalancerController) syncIngressLink(task task) { } } - if lbc.areCustomResourcesEnabled && lbc.reportVsVsrStatusEnabled() { + if lbc.areCustomResourcesEnabled && lbc.reportCustomResourceStatusEnabled() { virtualServers := lbc.configuration.GetResourcesWithFilter(resourceFilter{VirtualServers: true}) glog.V(3).Infof("Updating status for %v VirtualServers", len(virtualServers)) @@ -848,9 +849,25 @@ func (lbc *LoadBalancerController) syncPolicy(task task) { pol := obj.(*conf_v1.Policy) err := validation.ValidatePolicy(pol, lbc.isNginxPlus, lbc.enablePreviewPolicies) if err != nil { - lbc.recorder.Eventf(pol, api_v1.EventTypeWarning, "Rejected", "Policy %v is invalid and was rejected: %v", key, err) + msg := fmt.Sprintf("Policy %v/%v is invalid and was rejected: %v", pol.Namespace, pol.Name, err) + lbc.recorder.Eventf(pol, api_v1.EventTypeWarning, "Rejected", msg) + + if lbc.reportCustomResourceStatusEnabled() { + err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateInvalid, "Rejected", msg) + if err != nil { + glog.V(3).Infof("Failed to update policy %s status: %v", key, err) + } + } } else { - lbc.recorder.Eventf(pol, api_v1.EventTypeNormal, "AddedOrUpdated", "Policy %v was added or updated", key) + msg := fmt.Sprintf("Policy %v/%v was added or updated", pol.Namespace, pol.Name) + lbc.recorder.Eventf(pol, api_v1.EventTypeNormal, "AddedOrUpdated", msg) + + if lbc.reportCustomResourceStatusEnabled() { + err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateValid, "AddedOrUpdated", msg) + if err != nil { + glog.V(3).Infof("Failed to update policy %s status: %v", key, err) + } + } } } @@ -1022,7 +1039,7 @@ func (lbc *LoadBalancerController) processProblems(problems []ConfigurationProbl eventType := api_v1.EventTypeWarning lbc.recorder.Event(p.Object, eventType, p.Reason, p.Message) - if lbc.reportVsVsrStatusEnabled() { + if lbc.reportCustomResourceStatusEnabled() { state := conf_v1.StateWarning if p.IsError { state = conf_v1.StateInvalid @@ -1241,7 +1258,7 @@ func (lbc *LoadBalancerController) UpdateVirtualServerStatusAndEventsOnDelete(vs msg := fmt.Sprintf("VirtualServer %s was rejected %s", getResourceKey(&vsConfig.VirtualServer.ObjectMeta), eventWarningMessage) lbc.recorder.Eventf(vsConfig.VirtualServer, eventType, eventTitle, msg) - if lbc.reportVsVsrStatusEnabled() { + if lbc.reportCustomResourceStatusEnabled() { err := lbc.statusUpdater.UpdateVirtualServerStatus(vsConfig.VirtualServer, state, eventTitle, msg) if err != nil { glog.Errorf("Error when updating the status for VirtualServer %v/%v: %v", vsConfig.VirtualServer.Namespace, vsConfig.VirtualServer.Name, err) @@ -1433,7 +1450,7 @@ func (lbc *LoadBalancerController) updateVirtualServerStatusAndEvents(vsConfig * msg := fmt.Sprintf("Configuration for %v was added or updated %s", getResourceKey(&vsConfig.VirtualServer.ObjectMeta), eventWarningMessage) lbc.recorder.Eventf(vsConfig.VirtualServer, eventType, eventTitle, msg) - if lbc.reportVsVsrStatusEnabled() { + if lbc.reportCustomResourceStatusEnabled() { err := lbc.statusUpdater.UpdateVirtualServerStatus(vsConfig.VirtualServer, state, eventTitle, msg) if err != nil { glog.Errorf("Error when updating the status for VirtualServer %v/%v: %v", vsConfig.VirtualServer.Namespace, vsConfig.VirtualServer.Name, err) @@ -1463,7 +1480,7 @@ func (lbc *LoadBalancerController) updateVirtualServerStatusAndEvents(vsConfig * msg := fmt.Sprintf("Configuration for %v/%v was added or updated %s", vsr.Namespace, vsr.Name, vsrEventWarningMessage) lbc.recorder.Eventf(vsr, vsrEventType, vsrEventTitle, msg) - if lbc.reportVsVsrStatusEnabled() { + if lbc.reportCustomResourceStatusEnabled() { vss := []*conf_v1.VirtualServer{vsConfig.VirtualServer} err := lbc.statusUpdater.UpdateVirtualServerRouteStatusWithReferencedBy(vsr, vsrState, vsrEventTitle, msg, vss) if err != nil { @@ -1571,7 +1588,7 @@ func (lbc *LoadBalancerController) syncService(task task) { } } - if lbc.areCustomResourcesEnabled && lbc.reportVsVsrStatusEnabled() { + if lbc.areCustomResourcesEnabled && lbc.reportCustomResourceStatusEnabled() { virtualServers := lbc.configuration.GetResourcesWithFilter(resourceFilter{VirtualServers: true}) glog.V(3).Infof("Updating status for %v VirtualServers", len(virtualServers)) @@ -1628,8 +1645,8 @@ func (lbc *LoadBalancerController) reportStatusEnabled() bool { return false } -// reportVsVsrStatusEnabled determines if we should attempt to report status for VirtualServers and VirtualServerRoutes. -func (lbc *LoadBalancerController) reportVsVsrStatusEnabled() bool { +// reportCustomResourceStatusEnabled determines if we should attempt to report status for Custom Resources. +func (lbc *LoadBalancerController) reportCustomResourceStatusEnabled() bool { if lbc.isLeaderElectionEnabled { return lbc.leaderElector != nil && lbc.leaderElector.IsLeader() } @@ -1861,6 +1878,34 @@ func (lbc *LoadBalancerController) updateVirtualServerRoutesStatusFromEvents() e return nil } +func (lbc *LoadBalancerController) updatePoliciesStatus() error { + var allErrs []error + for _, obj := range lbc.policyLister.List() { + pol := obj.(*conf_v1.Policy) + + err := validation.ValidatePolicy(pol, lbc.isNginxPlus, lbc.enablePreviewPolicies) + if err != nil { + msg := fmt.Sprintf("Policy %v/%v is invalid and was rejected: %v", pol.Namespace, pol.Name, err) + err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateInvalid, "Rejected", msg) + if err != nil { + allErrs = append(allErrs, err) + } + } else { + msg := fmt.Sprintf("Policy %v/%v was added or updated", pol.Namespace, pol.Name) + err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateValid, "AddedOrUpdated", msg) + if err != nil { + allErrs = append(allErrs, err) + } + } + } + + if len(allErrs) != 0 { + return fmt.Errorf("not all Policies statuses were updated: %v", allErrs) + } + + return nil +} + // EnqueueTransportServerForService enqueues TransportServers for the given service. func (lbc *LoadBalancerController) EnqueueTransportServerForService(service *api_v1.Service) { transportServers := lbc.getTransportServersForService(service) diff --git a/internal/k8s/controller_test.go b/internal/k8s/controller_test.go index cfa7adbd8c..842776e128 100644 --- a/internal/k8s/controller_test.go +++ b/internal/k8s/controller_test.go @@ -23,6 +23,7 @@ import ( meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" ) diff --git a/internal/k8s/leader.go b/internal/k8s/leader.go index 45e6832e02..575dfac464 100644 --- a/internal/k8s/leader.go +++ b/internal/k8s/leader.go @@ -73,6 +73,11 @@ func createLeaderHandler(lbc *LoadBalancerController) leaderelection.LeaderCallb if err != nil { glog.V(3).Infof("error updating VirtualServerRoutes status when starting leading: %v", err) } + + err = lbc.updatePoliciesStatus() + if err != nil { + glog.V(3).Infof("error updating Policies status when starting leading: %v", err) + } } }, OnStoppedLeading: func() { diff --git a/internal/k8s/status.go b/internal/k8s/status.go index 495ef55f0f..2c1779814c 100644 --- a/internal/k8s/status.go +++ b/internal/k8s/status.go @@ -40,6 +40,7 @@ type statusUpdater struct { ingressLister *storeToIngressLister virtualServerLister cache.Store virtualServerRouteLister cache.Store + policyLister cache.Store confClient k8s_nginx.Interface } @@ -558,3 +559,54 @@ func (su *statusUpdater) generateExternalEndpointsFromStatus(status []api_v1.Loa return externalEndpoints } + +func hasPolicyStatusChanged(pol *v1.Policy, state string, reason string, message string) bool { + return pol.Status.State != state || pol.Status.Reason != reason || pol.Status.Message != message +} + +// UpdatePolicyStatus updates the status of a Policy. +func (su *statusUpdater) UpdatePolicyStatus(pol *v1.Policy, state string, reason string, message string) error { + // Get an up-to-date Policy from the Store + polLatest, exists, err := su.policyLister.Get(pol) + if err != nil { + glog.V(3).Infof("error getting policy from Store: %v", err) + return err + } + if !exists { + glog.V(3).Infof("Policy doesn't exist in Store") + return nil + } + + polCopy := polLatest.(*v1.Policy) + + if !hasPolicyStatusChanged(polCopy, state, reason, message) { + return nil + } + + polCopy.Status.State = state + polCopy.Status.Reason = reason + polCopy.Status.Message = message + + _, err = su.confClient.K8sV1().Policies(polCopy.Namespace).UpdateStatus(context.TODO(), polCopy, metav1.UpdateOptions{}) + if err != nil { + glog.V(3).Infof("error setting Policy %v/%v status, retrying: %v", polCopy.Namespace, polCopy.Name, err) + return su.retryUpdatePolicyStatus(polCopy) + } + + return nil +} + +func (su *statusUpdater) retryUpdatePolicyStatus(polCopy *v1.Policy) error { + pol, err := su.confClient.K8sV1().Policies(polCopy.Namespace).Get(context.TODO(), polCopy.Name, metav1.GetOptions{}) + if err != nil { + return err + } + + pol.Status = polCopy.Status + _, err = su.confClient.K8sV1().Policies(pol.Namespace).UpdateStatus(context.TODO(), pol, metav1.UpdateOptions{}) + if err != nil { + return err + } + + return nil +} diff --git a/internal/k8s/status_test.go b/internal/k8s/status_test.go index d8a25233f5..3d17f3ad59 100644 --- a/internal/k8s/status_test.go +++ b/internal/k8s/status_test.go @@ -469,3 +469,64 @@ func TestIsRequiredPort(t *testing.T) { } } } + +func TestHasPolicyStatusChanged(t *testing.T) { + + state := "Valid" + reason := "AddedOrUpdated" + msg := "Configuration was added or updated" + + tests := []struct { + expected bool + pol conf_v1.Policy + }{ + { + expected: false, + pol: conf_v1.Policy{ + Status: conf_v1.PolicyStatus{ + State: state, + Reason: reason, + Message: msg, + }, + }, + }, + { + expected: true, + pol: conf_v1.Policy{ + Status: conf_v1.PolicyStatus{ + State: "DifferentState", + Reason: reason, + Message: msg, + }, + }, + }, + { + expected: true, + pol: conf_v1.Policy{ + Status: conf_v1.PolicyStatus{ + State: state, + Reason: "DifferentReason", + Message: msg, + }, + }, + }, + { + expected: true, + pol: conf_v1.Policy{ + Status: conf_v1.PolicyStatus{ + State: state, + Reason: reason, + Message: "DifferentMessage", + }, + }, + }, + } + + for _, test := range tests { + changed := hasPolicyStatusChanged(&test.pol, state, reason, msg) + + if changed != test.expected { + t.Errorf("hasPolicyStatusChanged(%v, %v, %v, %v) returned %v but expected %v.", test.pol, state, reason, msg, changed, test.expected) + } + } +} diff --git a/pkg/apis/configuration/v1/types.go b/pkg/apis/configuration/v1/types.go index dcbb766b4d..63a7f47b63 100644 --- a/pkg/apis/configuration/v1/types.go +++ b/pkg/apis/configuration/v1/types.go @@ -318,13 +318,24 @@ type VirtualServerRouteStatus struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +kubebuilder:validation:Optional // +kubebuilder:resource:shortName=pol +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state`,description="Current state of the Policy. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller." +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // Policy defines a Policy for VirtualServer and VirtualServerRoute resources. type Policy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec PolicySpec `json:"spec"` + Spec PolicySpec `json:"spec"` + Status PolicyStatus `json:"status"` +} + +// PolicyStatus is the status of the policy resource +type PolicyStatus struct { + State string `json:"state"` + Reason string `json:"reason"` + Message string `json:"message"` } // PolicySpec is the spec of the Policy resource. diff --git a/pkg/apis/configuration/v1/zz_generated.deepcopy.go b/pkg/apis/configuration/v1/zz_generated.deepcopy.go index 604ded5b0c..db90a05473 100644 --- a/pkg/apis/configuration/v1/zz_generated.deepcopy.go +++ b/pkg/apis/configuration/v1/zz_generated.deepcopy.go @@ -402,6 +402,7 @@ func (in *Policy) DeepCopyInto(out *Policy) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status return } @@ -518,6 +519,22 @@ func (in *PolicySpec) DeepCopy() *PolicySpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicyStatus) DeepCopyInto(out *PolicyStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyStatus. +func (in *PolicyStatus) DeepCopy() *PolicyStatus { + if in == nil { + return nil + } + out := new(PolicyStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProxyRequestHeaders) DeepCopyInto(out *ProxyRequestHeaders) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/configuration/v1/fake/fake_policy.go b/pkg/client/clientset/versioned/typed/configuration/v1/fake/fake_policy.go index 1eab606fe4..027e0e8fc9 100644 --- a/pkg/client/clientset/versioned/typed/configuration/v1/fake/fake_policy.go +++ b/pkg/client/clientset/versioned/typed/configuration/v1/fake/fake_policy.go @@ -86,6 +86,18 @@ func (c *FakePolicies) Update(ctx context.Context, policy *configurationv1.Polic return obj.(*configurationv1.Policy), 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 *FakePolicies) UpdateStatus(ctx context.Context, policy *configurationv1.Policy, opts v1.UpdateOptions) (*configurationv1.Policy, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(policiesResource, "status", c.ns, policy), &configurationv1.Policy{}) + + if obj == nil { + return nil, err + } + return obj.(*configurationv1.Policy), err +} + // Delete takes name of the policy and deletes it. Returns an error if one occurs. func (c *FakePolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. diff --git a/pkg/client/clientset/versioned/typed/configuration/v1/policy.go b/pkg/client/clientset/versioned/typed/configuration/v1/policy.go index 9a7632a8fa..63fd8d564a 100644 --- a/pkg/client/clientset/versioned/typed/configuration/v1/policy.go +++ b/pkg/client/clientset/versioned/typed/configuration/v1/policy.go @@ -24,6 +24,7 @@ type PoliciesGetter interface { type PolicyInterface interface { Create(ctx context.Context, policy *v1.Policy, opts metav1.CreateOptions) (*v1.Policy, error) Update(ctx context.Context, policy *v1.Policy, opts metav1.UpdateOptions) (*v1.Policy, error) + UpdateStatus(ctx context.Context, policy *v1.Policy, opts metav1.UpdateOptions) (*v1.Policy, error) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Policy, error) @@ -119,6 +120,22 @@ func (c *policies) Update(ctx context.Context, policy *v1.Policy, opts metav1.Up 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 *policies) UpdateStatus(ctx context.Context, policy *v1.Policy, opts metav1.UpdateOptions) (result *v1.Policy, err error) { + result = &v1.Policy{} + err = c.client.Put(). + Namespace(c.ns). + Resource("policies"). + Name(policy.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(policy). + Do(ctx). + Into(result) + return +} + // Delete takes name of the policy and deletes it. Returns an error if one occurs. func (c *policies) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { return c.client.Delete().