istio
1/*
2Copyright Istio Authors
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package status18
19import (20"istio.io/api/meta/v1alpha1"21"istio.io/istio/pilot/pkg/features"22"istio.io/istio/pilot/pkg/model"23"istio.io/istio/pkg/config"24"istio.io/istio/pkg/config/schema/gvk"25)
26
27// Manager allows multiple controllers to provide input into configuration
28// status without needlessly doubling the number of writes, or overwriting
29// one another. Each status controller calls newController, passing in
30// an arbitrary status modification function, and then calls EnqueueStatusUpdate
31// when an individual resource is ready to be updated with the relevant data.
32type Manager struct {33// TODO: is Resource the right abstraction?34store model.ConfigStore35workers WorkerQueue
36}
37
38func NewManager(store model.ConfigStore) *Manager {39writeFunc := func(m *config.Config, istatus any) {40scope.Debugf("writing status for resource %s/%s", m.Namespace, m.Name)41status := istatus.(GenerationProvider)42m.Status = status.Unwrap()43_, err := store.UpdateStatus(*m)44if err != nil {45// TODO: need better error handling46scope.Errorf("Encountered unexpected error updating status for %v, will try again later: %s", m, err)47return48}49}50retrieveFunc := func(resource Resource) *config.Config {51scope.Debugf("retrieving config for status update: %s/%s", resource.Namespace, resource.Name)52k, ok := gvk.FromGVR(resource.GroupVersionResource)53if !ok {54scope.Warnf("GVR %v could not be identified", resource.GroupVersionResource)55return nil56}57
58current := store.Get(k, resource.Name, resource.Namespace)59return current60}61return &Manager{62store: store,63workers: NewWorkerPool(writeFunc, retrieveFunc, uint(features.StatusMaxWorkers)),64}65}
66
67func (m *Manager) Start(stop <-chan struct{}) {68scope.Info("Starting status manager")69
70ctx := NewIstioContext(stop)71m.workers.Run(ctx)72}
73
74// CreateGenericController provides an interface for a status update function to be
75// called in series with other controllers, minimizing the number of actual
76// api server writes sent from various status controllers. The UpdateFunc
77// must take the target resource status and arbitrary context information as
78// parameters, and return the updated status value. Multiple controllers
79// will be called in series, so the input status may not have been written
80// to the API server yet, and the output status may be modified by other
81// controllers before it is written to the server.
82func (m *Manager) CreateGenericController(fn UpdateFunc) *Controller {83result := &Controller{84fn: fn,85workers: m.workers,86}87return result88}
89
90func (m *Manager) CreateIstioStatusController(fn func(status *v1alpha1.IstioStatus, context any) *v1alpha1.IstioStatus) *Controller {91wrapper := func(status any, context any) GenerationProvider {92var input *v1alpha1.IstioStatus93if status != nil {94converted := status.(*IstioGenerationProvider)95input = converted.IstioStatus96}97result := fn(input, context)98return &IstioGenerationProvider{result}99}100result := &Controller{101fn: wrapper,102workers: m.workers,103}104return result105}
106
107type UpdateFunc func(status any, context any) GenerationProvider108
109type Controller struct {110fn UpdateFunc
111workers WorkerQueue
112}
113
114// EnqueueStatusUpdateResource informs the manager that this controller would like to
115// update the status of target, using the information in context. Once the status
116// workers are ready to perform this update, the controller's UpdateFunc
117// will be called with target and context as input.
118func (c *Controller) EnqueueStatusUpdateResource(context any, target Resource) {119// TODO: buffer this with channel120c.workers.Push(target, c, context)121}
122
123func (c *Controller) Delete(r Resource) {124c.workers.Delete(r)125}
126