github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/status.go (about) 1 package k8s 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "reflect" 8 "strconv" 9 "strings" 10 11 "github.com/golang/glog" 12 conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" 13 v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" 14 conf_v1alpha1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1" 15 k8s_nginx "github.com/nginxinc/kubernetes-ingress/pkg/client/clientset/versioned" 16 api_v1 "k8s.io/api/core/v1" 17 networking "k8s.io/api/networking/v1beta1" 18 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 typednetworking "k8s.io/client-go/kubernetes/typed/networking/v1beta1" 20 21 "k8s.io/apimachinery/pkg/util/intstr" 22 "k8s.io/client-go/kubernetes" 23 "k8s.io/client-go/tools/cache" 24 ) 25 26 // statusUpdater reports Ingress, VirtualServer and VirtualServerRoute status information via the kubernetes 27 // API. For external information, it primarily reports the IP or host of the LoadBalancer Service exposing the 28 // Ingress Controller, or an external IP specified in the ConfigMap. 29 type statusUpdater struct { 30 client kubernetes.Interface 31 namespace string 32 externalServiceName string 33 externalStatusAddress string 34 externalServiceAddresses []string 35 externalServicePorts string 36 bigIPAddress string 37 bigIPPorts string 38 externalEndpoints []v1.ExternalEndpoint 39 status []api_v1.LoadBalancerIngress 40 keyFunc func(obj interface{}) (string, error) 41 ingressLister *storeToIngressLister 42 virtualServerLister cache.Store 43 virtualServerRouteLister cache.Store 44 transportServerLister cache.Store 45 policyLister cache.Store 46 confClient k8s_nginx.Interface 47 } 48 49 func (su *statusUpdater) UpdateExternalEndpointsForResources(resource []Resource) error { 50 failed := false 51 52 for _, r := range resource { 53 err := su.UpdateExternalEndpointsForResource(r) 54 if err != nil { 55 failed = true 56 } 57 } 58 59 if failed { 60 return fmt.Errorf("not all Resources updated") 61 } 62 63 return nil 64 } 65 66 func (su *statusUpdater) UpdateExternalEndpointsForResource(r Resource) error { 67 switch impl := r.(type) { 68 case *IngressConfiguration: 69 var ings []networking.Ingress 70 ings = append(ings, *impl.Ingress) 71 72 for _, fm := range impl.Minions { 73 ings = append(ings, *fm.Ingress) 74 } 75 76 return su.BulkUpdateIngressStatus(ings) 77 case *VirtualServerConfiguration: 78 failed := false 79 80 err := su.updateVirtualServerExternalEndpoints(impl.VirtualServer) 81 if err != nil { 82 failed = true 83 } 84 85 for _, vsr := range impl.VirtualServerRoutes { 86 err := su.updateVirtualServerRouteExternalEndpoints(vsr) 87 if err != nil { 88 failed = true 89 } 90 } 91 92 if failed { 93 return fmt.Errorf("not all Resources updated") 94 } 95 } 96 97 return nil 98 } 99 100 // ClearIngressStatus clears the Ingress status. 101 func (su *statusUpdater) ClearIngressStatus(ing networking.Ingress) error { 102 return su.updateIngressWithStatus(ing, []api_v1.LoadBalancerIngress{}) 103 } 104 105 // UpdateIngressStatus updates the status on the selected Ingress. 106 func (su *statusUpdater) UpdateIngressStatus(ing networking.Ingress) error { 107 return su.updateIngressWithStatus(ing, su.status) 108 } 109 110 // updateIngressWithStatus sets the provided status on the selected Ingress. 111 func (su *statusUpdater) updateIngressWithStatus(ing networking.Ingress, status []api_v1.LoadBalancerIngress) error { 112 // Get an up-to-date Ingress from the Store 113 key, err := su.keyFunc(&ing) 114 if err != nil { 115 glog.V(3).Infof("error getting key for ing: %v", err) 116 return err 117 } 118 ingCopy, exists, err := su.ingressLister.GetByKeySafe(key) 119 if err != nil { 120 glog.V(3).Infof("error getting ing from Store by key: %v", err) 121 return err 122 } 123 if !exists { 124 glog.V(3).Infof("ing doesn't exist in Store") 125 return nil 126 } 127 128 // No need to update status 129 if reflect.DeepEqual(ingCopy.Status.LoadBalancer.Ingress, status) { 130 return nil 131 } 132 133 ingCopy.Status.LoadBalancer.Ingress = status 134 clientIngress := su.client.NetworkingV1beta1().Ingresses(ingCopy.Namespace) 135 _, err = clientIngress.UpdateStatus(context.TODO(), ingCopy, metav1.UpdateOptions{}) 136 if err != nil { 137 glog.V(3).Infof("error setting ingress status: %v", err) 138 err = su.retryStatusUpdate(clientIngress, ingCopy) 139 if err != nil { 140 glog.V(3).Infof("error retrying status update: %v", err) 141 return err 142 } 143 } 144 glog.V(3).Infof("updated status for ing: %v %v", ing.Namespace, ing.Name) 145 return nil 146 } 147 148 // BulkUpdateIngressStatus sets the status field on the selected Ingresses, specifically 149 // the External IP field. 150 func (su *statusUpdater) BulkUpdateIngressStatus(ings []networking.Ingress) error { 151 if len(ings) < 1 { 152 glog.V(3).Info("no ingresses to update") 153 return nil 154 } 155 failed := false 156 for _, ing := range ings { 157 err := su.updateIngressWithStatus(ing, su.status) 158 if err != nil { 159 failed = true 160 } 161 } 162 if failed { 163 return fmt.Errorf("not all Ingresses updated") 164 } 165 return nil 166 } 167 168 // retryStatusUpdate fetches a fresh copy of the Ingress from the k8s API, checks if it still needs to be 169 // updated, and then attempts to update. We often need to fetch fresh copies due to the 170 // k8s API using ResourceVersion to stop updates on stale items. 171 func (su *statusUpdater) retryStatusUpdate(clientIngress typednetworking.IngressInterface, ingCopy *networking.Ingress) error { 172 apiIng, err := clientIngress.Get(context.TODO(), ingCopy.Name, metav1.GetOptions{}) 173 if err != nil { 174 glog.V(3).Infof("error getting ingress resource: %v", err) 175 return err 176 } 177 if !reflect.DeepEqual(ingCopy.Status.LoadBalancer, apiIng.Status.LoadBalancer) { 178 glog.V(3).Infof("retrying update status for ingress: %v, %v", ingCopy.Namespace, ingCopy.Name) 179 apiIng.Status.LoadBalancer = ingCopy.Status.LoadBalancer 180 _, err := clientIngress.UpdateStatus(context.TODO(), apiIng, metav1.UpdateOptions{}) 181 if err != nil { 182 glog.V(3).Infof("update retry failed: %v", err) 183 } 184 return err 185 } 186 return nil 187 } 188 189 // saveStatus saves the string array of IPs or addresses that we will set as status 190 // on all the Ingresses that we manage. 191 func (su *statusUpdater) saveStatus(ips []string) { 192 statusIngs := []api_v1.LoadBalancerIngress{} 193 for _, ip := range ips { 194 if net.ParseIP(ip) == nil { 195 statusIngs = append(statusIngs, api_v1.LoadBalancerIngress{Hostname: ip}) 196 } else { 197 statusIngs = append(statusIngs, api_v1.LoadBalancerIngress{IP: ip}) 198 } 199 } 200 su.status = statusIngs 201 } 202 203 var intPorts = [2]int32{80, 443} 204 var stringPorts = [2]string{"http", "https"} 205 206 func isRequiredPort(port intstr.IntOrString) bool { 207 if port.Type == intstr.Int { 208 for _, p := range intPorts { 209 if p == port.IntVal { 210 return true 211 } 212 } 213 } else if port.Type == intstr.String { 214 for _, p := range stringPorts { 215 if p == port.StrVal { 216 return true 217 } 218 } 219 } 220 221 return false 222 } 223 224 func getExternalServicePorts(svc *api_v1.Service) string { 225 var ports []string 226 if svc == nil { 227 return "" 228 } 229 230 for _, port := range svc.Spec.Ports { 231 if isRequiredPort(port.TargetPort) { 232 ports = append(ports, strconv.Itoa(int(port.Port))) 233 } 234 } 235 236 return fmt.Sprintf("[%v]", strings.Join(ports, ",")) 237 } 238 239 func getExternalServiceAddress(svc *api_v1.Service) []string { 240 addresses := []string{} 241 if svc == nil { 242 return addresses 243 } 244 245 if svc.Spec.Type == api_v1.ServiceTypeExternalName { 246 addresses = append(addresses, svc.Spec.ExternalName) 247 return addresses 248 } 249 250 for _, ip := range svc.Status.LoadBalancer.Ingress { 251 if ip.IP == "" { 252 addresses = append(addresses, ip.Hostname) 253 } else { 254 addresses = append(addresses, ip.IP) 255 } 256 } 257 addresses = append(addresses, svc.Spec.ExternalIPs...) 258 return addresses 259 } 260 261 // SaveStatusFromExternalStatus saves the status from a string. 262 // For use with the external-status-address ConfigMap setting. 263 // This method does not update ingress status - statusUpdater.UpdateIngressStatus must be called separately. 264 func (su *statusUpdater) SaveStatusFromExternalStatus(externalStatusAddress string) { 265 su.externalStatusAddress = externalStatusAddress 266 if externalStatusAddress == "" { 267 // if external-status-address was removed from configMap 268 269 // fall back on external service if it exists 270 if len(su.externalServiceAddresses) > 0 { 271 su.saveStatus(su.externalServiceAddresses) 272 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 273 return 274 } 275 276 // fall back on IngressLink if it exists 277 if su.bigIPAddress != "" { 278 su.saveStatus([]string{su.bigIPAddress}) 279 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 280 return 281 } 282 } 283 ips := []string{} 284 ips = append(ips, su.externalStatusAddress) 285 su.saveStatus(ips) 286 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 287 } 288 289 // ClearStatusFromExternalService clears the saved status from the External Service 290 func (su *statusUpdater) ClearStatusFromExternalService() { 291 su.SaveStatusFromExternalService(nil) 292 } 293 294 // SaveStatusFromExternalService saves the external IP or address from the service. 295 // This method does not update ingress status - UpdateIngressStatus must be called separately. 296 func (su *statusUpdater) SaveStatusFromExternalService(svc *api_v1.Service) { 297 ips := getExternalServiceAddress(svc) 298 su.externalServiceAddresses = ips 299 ports := getExternalServicePorts(svc) 300 su.externalServicePorts = ports 301 if su.externalStatusAddress != "" { 302 glog.V(3).Info("skipping external service address/ports - external-status-address is set and takes precedence") 303 return 304 } 305 su.saveStatus(ips) 306 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 307 } 308 309 func (su *statusUpdater) SaveStatusFromIngressLink(ip string) { 310 su.bigIPAddress = ip 311 su.bigIPPorts = "[80,443]" 312 313 if su.externalStatusAddress != "" { 314 glog.V(3).Info("skipping IngressLink address - external-status-address is set and takes precedence") 315 return 316 } 317 318 ips := []string{su.bigIPAddress} 319 su.saveStatus(ips) 320 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 321 } 322 323 func (su *statusUpdater) ClearStatusFromIngressLink() { 324 su.bigIPAddress = "" 325 su.bigIPPorts = "" 326 327 if su.externalStatusAddress != "" { 328 glog.V(3).Info("skipping IngressLink address - external-status-address is set and takes precedence") 329 return 330 } 331 332 ips := []string{} 333 su.saveStatus(ips) 334 su.externalEndpoints = su.generateExternalEndpointsFromStatus(su.status) 335 } 336 337 func (su *statusUpdater) retryUpdateTransportServerStatus(tsCopy *conf_v1alpha1.TransportServer) error { 338 ts, err := su.confClient.K8sV1alpha1().TransportServers(tsCopy.Namespace).Get(context.TODO(), tsCopy.Name, metav1.GetOptions{}) 339 if err != nil { 340 return err 341 } 342 343 ts.Status = tsCopy.Status 344 _, err = su.confClient.K8sV1alpha1().TransportServers(ts.Namespace).UpdateStatus(context.TODO(), ts, metav1.UpdateOptions{}) 345 if err != nil { 346 return err 347 } 348 349 return nil 350 } 351 352 func (su *statusUpdater) retryUpdateVirtualServerStatus(vsCopy *conf_v1.VirtualServer) error { 353 vs, err := su.confClient.K8sV1().VirtualServers(vsCopy.Namespace).Get(context.TODO(), vsCopy.Name, metav1.GetOptions{}) 354 if err != nil { 355 return err 356 } 357 358 vs.Status = vsCopy.Status 359 _, err = su.confClient.K8sV1().VirtualServers(vs.Namespace).UpdateStatus(context.TODO(), vs, metav1.UpdateOptions{}) 360 if err != nil { 361 return err 362 } 363 364 return nil 365 } 366 367 func (su *statusUpdater) retryUpdateVirtualServerRouteStatus(vsrCopy *conf_v1.VirtualServerRoute) error { 368 vsr, err := su.confClient.K8sV1().VirtualServerRoutes(vsrCopy.Namespace).Get(context.TODO(), vsrCopy.Name, metav1.GetOptions{}) 369 if err != nil { 370 return err 371 } 372 373 vsr.Status = vsrCopy.Status 374 _, err = su.confClient.K8sV1().VirtualServerRoutes(vsr.Namespace).UpdateStatus(context.TODO(), vsr, metav1.UpdateOptions{}) 375 if err != nil { 376 return err 377 } 378 379 return nil 380 } 381 382 func hasVsStatusChanged(vs *conf_v1.VirtualServer, state string, reason string, message string) bool { 383 if vs.Status.State != state { 384 return true 385 } 386 387 if vs.Status.Reason != reason { 388 return true 389 } 390 391 if vs.Status.Message != message { 392 return true 393 } 394 395 return false 396 } 397 398 // UpdateTransportServerStatus updates the status of a TransportServer. 399 func (su *statusUpdater) UpdateTransportServerStatus(ts *conf_v1alpha1.TransportServer, state string, reason string, message string) error { 400 tsLatest, exists, err := su.transportServerLister.Get(ts) 401 if err != nil { 402 glog.V(3).Infof("error getting TransportServer from Store: %v", err) 403 return err 404 } 405 if !exists { 406 glog.V(3).Infof("TransportServer doesn't exist in Store") 407 return nil 408 } 409 410 if !hasTsStatusChanged(tsLatest.(*conf_v1alpha1.TransportServer), state, reason, message) { 411 return nil 412 } 413 414 tsCopy := tsLatest.(*conf_v1alpha1.TransportServer).DeepCopy() 415 tsCopy.Status.State = state 416 tsCopy.Status.Reason = reason 417 tsCopy.Status.Message = message 418 419 _, err = su.confClient.K8sV1alpha1().TransportServers(tsCopy.Namespace).UpdateStatus(context.TODO(), tsCopy, metav1.UpdateOptions{}) 420 if err != nil { 421 glog.V(3).Infof("error setting TransportServer %v/%v status, retrying: %v", tsCopy.Namespace, tsCopy.Name, err) 422 return su.retryUpdateTransportServerStatus(tsCopy) 423 } 424 return err 425 } 426 427 func hasTsStatusChanged(ts *conf_v1alpha1.TransportServer, state string, reason string, message string) bool { 428 if ts.Status.State != state { 429 return true 430 } 431 if ts.Status.Reason != reason { 432 return true 433 } 434 if ts.Status.Message != message { 435 return true 436 } 437 return false 438 } 439 440 // UpdateVirtualServerStatus updates the status of a VirtualServer. 441 func (su *statusUpdater) UpdateVirtualServerStatus(vs *conf_v1.VirtualServer, state string, reason string, message string) error { 442 // Get an up-to-date VirtualServer from the Store 443 vsLatest, exists, err := su.virtualServerLister.Get(vs) 444 if err != nil { 445 glog.V(3).Infof("error getting VirtualServer from Store: %v", err) 446 return err 447 } 448 if !exists { 449 glog.V(3).Infof("VirtualServer doesn't exist in Store") 450 return nil 451 } 452 453 vsCopy := vsLatest.(*conf_v1.VirtualServer).DeepCopy() 454 455 if !hasVsStatusChanged(vsCopy, state, reason, message) { 456 return nil 457 } 458 459 vsCopy.Status.State = state 460 vsCopy.Status.Reason = reason 461 vsCopy.Status.Message = message 462 vsCopy.Status.ExternalEndpoints = su.externalEndpoints 463 464 _, err = su.confClient.K8sV1().VirtualServers(vsCopy.Namespace).UpdateStatus(context.TODO(), vsCopy, metav1.UpdateOptions{}) 465 if err != nil { 466 glog.V(3).Infof("error setting VirtualServer %v/%v status, retrying: %v", vsCopy.Namespace, vsCopy.Name, err) 467 return su.retryUpdateVirtualServerStatus(vsCopy) 468 } 469 return err 470 } 471 472 func hasVsrStatusChanged(vsr *conf_v1.VirtualServerRoute, state string, reason string, message string, referencedByString string) bool { 473 if vsr.Status.State != state { 474 return true 475 } 476 477 if vsr.Status.Reason != reason { 478 return true 479 } 480 481 if vsr.Status.Message != message { 482 return true 483 } 484 485 if referencedByString != "" && vsr.Status.ReferencedBy != referencedByString { 486 return true 487 } 488 489 return false 490 } 491 492 // UpdateVirtualServerRouteStatusWithReferencedBy updates the status of a VirtualServerRoute, including the referencedBy field. 493 func (su *statusUpdater) UpdateVirtualServerRouteStatusWithReferencedBy(vsr *conf_v1.VirtualServerRoute, state string, reason string, message string, referencedBy []*v1.VirtualServer) error { 494 var referencedByString string 495 if len(referencedBy) != 0 { 496 vs := referencedBy[0] 497 referencedByString = fmt.Sprintf("%v/%v", vs.Namespace, vs.Name) 498 } 499 500 // Get an up-to-date VirtualServerRoute from the Store 501 vsrLatest, exists, err := su.virtualServerRouteLister.Get(vsr) 502 if err != nil { 503 glog.V(3).Infof("error getting VirtualServerRoute from Store: %v", err) 504 return err 505 } 506 if !exists { 507 glog.V(3).Infof("VirtualServerRoute doesn't exist in Store") 508 return nil 509 } 510 511 vsrCopy := vsrLatest.(*conf_v1.VirtualServerRoute).DeepCopy() 512 513 vsrCopy.Status.State = state 514 vsrCopy.Status.Reason = reason 515 vsrCopy.Status.Message = message 516 vsrCopy.Status.ReferencedBy = referencedByString 517 vsrCopy.Status.ExternalEndpoints = su.externalEndpoints 518 519 _, err = su.confClient.K8sV1().VirtualServerRoutes(vsrCopy.Namespace).UpdateStatus(context.TODO(), vsrCopy, metav1.UpdateOptions{}) 520 if err != nil { 521 glog.V(3).Infof("error setting VirtualServerRoute %v/%v status, retrying: %v", vsrCopy.Namespace, vsrCopy.Name, err) 522 return su.retryUpdateVirtualServerRouteStatus(vsrCopy) 523 } 524 return err 525 } 526 527 // UpdateVirtualServerRouteStatus updates the status of a VirtualServerRoute. 528 // This method does not clear or update the referencedBy field of the status. 529 // If you need to update the referencedBy field, use UpdateVirtualServerRouteStatusWithReferencedBy instead. 530 func (su *statusUpdater) UpdateVirtualServerRouteStatus(vsr *conf_v1.VirtualServerRoute, state string, reason string, message string) error { 531 // Get an up-to-date VirtualServerRoute from the Store 532 vsrLatest, exists, err := su.virtualServerRouteLister.Get(vsr) 533 if err != nil { 534 glog.V(3).Infof("error getting VirtualServerRoute from Store: %v", err) 535 return err 536 } 537 if !exists { 538 glog.V(3).Infof("VirtualServerRoute doesn't exist in Store") 539 return nil 540 } 541 542 vsrCopy := vsrLatest.(*conf_v1.VirtualServerRoute).DeepCopy() 543 544 if !hasVsrStatusChanged(vsrCopy, state, reason, message, "") { 545 return nil 546 } 547 548 vsrCopy.Status.State = state 549 vsrCopy.Status.Reason = reason 550 vsrCopy.Status.Message = message 551 vsrCopy.Status.ExternalEndpoints = su.externalEndpoints 552 553 _, err = su.confClient.K8sV1().VirtualServerRoutes(vsrCopy.Namespace).UpdateStatus(context.TODO(), vsrCopy, metav1.UpdateOptions{}) 554 if err != nil { 555 glog.V(3).Infof("error setting VirtualServerRoute %v/%v status, retrying: %v", vsrCopy.Namespace, vsrCopy.Name, err) 556 return su.retryUpdateVirtualServerRouteStatus(vsrCopy) 557 } 558 return err 559 } 560 561 func (su *statusUpdater) updateVirtualServerExternalEndpoints(vs *conf_v1.VirtualServer) error { 562 // Get a pristine VirtualServer from the Store 563 vsLatest, exists, err := su.virtualServerLister.Get(vs) 564 if err != nil { 565 glog.V(3).Infof("error getting VirtualServer from Store: %v", err) 566 return err 567 } 568 if !exists { 569 glog.V(3).Infof("VirtualServer doesn't exist in Store") 570 return nil 571 } 572 573 vsCopy := vsLatest.(*conf_v1.VirtualServer).DeepCopy() 574 vsCopy.Status.ExternalEndpoints = su.externalEndpoints 575 576 _, err = su.confClient.K8sV1().VirtualServers(vsCopy.Namespace).UpdateStatus(context.TODO(), vsCopy, metav1.UpdateOptions{}) 577 if err != nil { 578 glog.V(3).Infof("error setting VirtualServer %v/%v status, retrying: %v", vsCopy.Namespace, vsCopy.Name, err) 579 return su.retryUpdateVirtualServerStatus(vsCopy) 580 } 581 return err 582 } 583 584 func (su *statusUpdater) updateVirtualServerRouteExternalEndpoints(vsr *conf_v1.VirtualServerRoute) error { 585 // Get an up-to-date VirtualServerRoute from the Store 586 vsrLatest, exists, err := su.virtualServerRouteLister.Get(vsr) 587 if err != nil { 588 glog.V(3).Infof("error getting VirtualServerRoute from Store: %v", err) 589 return err 590 } 591 if !exists { 592 glog.V(3).Infof("VirtualServerRoute doesn't exist in Store") 593 return nil 594 } 595 596 vsrCopy := vsrLatest.(*conf_v1.VirtualServerRoute).DeepCopy() 597 vsrCopy.Status.ExternalEndpoints = su.externalEndpoints 598 599 _, err = su.confClient.K8sV1().VirtualServerRoutes(vsrCopy.Namespace).UpdateStatus(context.TODO(), vsrCopy, metav1.UpdateOptions{}) 600 if err != nil { 601 glog.V(3).Infof("error setting VirtualServerRoute %v/%v status, retrying: %v", vsrCopy.Namespace, vsrCopy.Name, err) 602 return su.retryUpdateVirtualServerRouteStatus(vsrCopy) 603 } 604 return err 605 } 606 607 func (su *statusUpdater) generateExternalEndpointsFromStatus(status []api_v1.LoadBalancerIngress) []conf_v1.ExternalEndpoint { 608 var externalEndpoints []conf_v1.ExternalEndpoint 609 for _, lb := range status { 610 ports := su.externalServicePorts 611 if su.bigIPPorts != "" { 612 ports = su.bigIPPorts 613 } 614 615 endpoint := conf_v1.ExternalEndpoint{IP: lb.IP, Ports: ports} 616 externalEndpoints = append(externalEndpoints, endpoint) 617 } 618 619 return externalEndpoints 620 } 621 622 func hasPolicyStatusChanged(pol *v1.Policy, state string, reason string, message string) bool { 623 return pol.Status.State != state || pol.Status.Reason != reason || pol.Status.Message != message 624 } 625 626 // UpdatePolicyStatus updates the status of a Policy. 627 func (su *statusUpdater) UpdatePolicyStatus(pol *v1.Policy, state string, reason string, message string) error { 628 // Get an up-to-date Policy from the Store 629 polLatest, exists, err := su.policyLister.Get(pol) 630 if err != nil { 631 glog.V(3).Infof("error getting policy from Store: %v", err) 632 return err 633 } 634 if !exists { 635 glog.V(3).Infof("Policy doesn't exist in Store") 636 return nil 637 } 638 639 polCopy := polLatest.(*v1.Policy) 640 641 if !hasPolicyStatusChanged(polCopy, state, reason, message) { 642 return nil 643 } 644 645 polCopy.Status.State = state 646 polCopy.Status.Reason = reason 647 polCopy.Status.Message = message 648 649 _, err = su.confClient.K8sV1().Policies(polCopy.Namespace).UpdateStatus(context.TODO(), polCopy, metav1.UpdateOptions{}) 650 if err != nil { 651 glog.V(3).Infof("error setting Policy %v/%v status, retrying: %v", polCopy.Namespace, polCopy.Name, err) 652 return su.retryUpdatePolicyStatus(polCopy) 653 } 654 655 return nil 656 } 657 658 func (su *statusUpdater) retryUpdatePolicyStatus(polCopy *v1.Policy) error { 659 pol, err := su.confClient.K8sV1().Policies(polCopy.Namespace).Get(context.TODO(), polCopy.Name, metav1.GetOptions{}) 660 if err != nil { 661 return err 662 } 663 664 pol.Status = polCopy.Status 665 _, err = su.confClient.K8sV1().Policies(pol.Namespace).UpdateStatus(context.TODO(), pol, metav1.UpdateOptions{}) 666 if err != nil { 667 return err 668 } 669 670 return nil 671 }