Watch
我理解意思是说:k8s.io/apimachinery/pkg/watch/watch.go 文件是 Kubernetes 中用于实现 watch API 的关键文件之一。该文件定义了用于监听资源对象变化的 Watcher 接口和相关的数据结构。
package watch
import (
"fmt"
"sync"
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/runtime"
)
// Interface can be implemented by anything that knows how to watch and report changes.
type Interface interface {
// Stop stops watching. Will close the channel returned by ResultChan(). Releases
// any resources used by the watch.
Stop()
// ResultChan returns a chan which will receive all the events. If an error occurs
// or Stop() is called, the implementation will close this channel and
// release any resources used by the watch.
ResultChan() <-chan Event
}
// EventType defines the possible types of events.
type EventType string
const (
Added EventType = "ADDED"
Modified EventType = "MODIFIED"
Deleted EventType = "DELETED"
Bookmark EventType = "BOOKMARK"
Error EventType = "ERROR"
)
var (
DefaultChanSize int32 = 100
)
// Event represents a single event to a watched resource.
// +k8s:deepcopy-gen=true
type Event struct {
Type EventType
// Object is:
// * If Type is Added or Modified: the new state of the object.
// * If Type is Deleted: the state of the object immediately before deletion.
// * If Type is Bookmark: the object (instance of a type being watched) where
// only ResourceVersion field is set. On successful restart of watch from a
// bookmark resourceVersion, client is guaranteed to not get repeat event
// nor miss any events.
// * If Type is Error: *api.Status is recommended; other types may make sense
// depending on context.
Object runtime.Object
}
type emptyWatch chan Event
// NewEmptyWatch returns a watch interface that returns no results and is closed.
// May be used in certain error conditions where no information is available but
// an error is not warranted.
func NewEmptyWatch() Interface {
ch := make(chan Event)
close(ch)
return emptyWatch(ch)
}
// Stop implements Interface
func (w emptyWatch) Stop() {
}
// ResultChan implements Interface
func (w emptyWatch) ResultChan() <-chan Event {
return chan Event(w)
}
// FakeWatcher lets you test anything that consumes a watch.Interface; threadsafe.
type FakeWatcher struct {
result chan Event
stopped bool
sync.Mutex
}
func NewFake() *FakeWatcher {
return &FakeWatcher{
result: make(chan Event),
}
}
func NewFakeWithChanSize(size int, blocking bool) *FakeWatcher {
return &FakeWatcher{
result: make(chan Event, size),
}
}
// Stop implements Interface.Stop().
func (f *FakeWatcher) Stop() {
f.Lock()
defer f.Unlock()
if !f.stopped {
klog.V(4).Infof("Stopping fake watcher.")
close(f.result)
f.stopped = true
}
}
func (f *FakeWatcher) IsStopped() bool {
f.Lock()
defer f.Unlock()
return f.stopped
}
// Reset prepares the watcher to be reused.
func (f *FakeWatcher) Reset() {
f.Lock()
defer f.Unlock()
f.stopped = false
f.result = make(chan Event)
}
func (f *FakeWatcher) ResultChan() <-chan Event {
return f.result
}
// Add sends an add event.
func (f *FakeWatcher) Add(obj runtime.Object) {
f.result <- Event{Added, obj}
}
// Modify sends a modify event.
func (f *FakeWatcher) Modify(obj runtime.Object) {
f.result <- Event{Modified, obj}
}
// Delete sends a delete event.
func (f *FakeWatcher) Delete(lastValue runtime.Object) {
f.result <- Event{Deleted, lastValue}
}
// Error sends an Error event.
func (f *FakeWatcher) Error(errValue runtime.Object) {
f.result <- Event{Error, errValue}
}
// Action sends an event of the requested type, for table-based testing.
func (f *FakeWatcher) Action(action EventType, obj runtime.Object) {
f.result <- Event{action, obj}
}
// RaceFreeFakeWatcher lets you test anything that consumes a watch.Interface; threadsafe.
type RaceFreeFakeWatcher struct {
result chan Event
Stopped bool
sync.Mutex
}
func NewRaceFreeFake() *RaceFreeFakeWatcher {
return &RaceFreeFakeWatcher{
result: make(chan Event, DefaultChanSize),
}
}
// Stop implements Interface.Stop().
func (f *RaceFreeFakeWatcher) Stop() {
f.Lock()
defer f.Unlock()
if !f.Stopped {
klog.V(4).Infof("Stopping fake watcher.")
close(f.result)
f.Stopped = true
}
}
func (f *RaceFreeFakeWatcher) IsStopped() bool {
f.Lock()
defer f.Unlock()
return f.Stopped
}
// Reset prepares the watcher to be reused.
func (f *RaceFreeFakeWatcher) Reset() {
f.Lock()
defer f.Unlock()
f.Stopped = false
f.result = make(chan Event, DefaultChanSize)
}
func (f *RaceFreeFakeWatcher) ResultChan() <-chan Event {
f.Lock()
defer f.Unlock()
return f.result
}
// Add sends an add event.
func (f *RaceFreeFakeWatcher) Add(obj runtime.Object) {
f.Lock()
defer f.Unlock()
if !f.Stopped {
select {
case f.result <- Event{Added, obj}:
return
default:
panic(fmt.Errorf("channel full"))
}
}
}
// Modify sends a modify event.
func (f *RaceFreeFakeWatcher) Modify(obj runtime.Object) {
f.Lock()
defer f.Unlock()
if !f.Stopped {
select {
case f.result <- Event{Modified, obj}:
return
default:
panic(fmt.Errorf("channel full"))
}
}
}
// Delete sends a delete event.
func (f *RaceFreeFakeWatcher) Delete(lastValue runtime.Object) {
f.Lock()
defer f.Unlock()
if !f.Stopped {
select {
case f.result <- Event{Deleted, lastValue}:
return
default:
panic(fmt.Errorf("channel full"))
}
}
}
// Error sends an Error event.
func (f *RaceFreeFakeWatcher) Error(errValue runtime.Object) {
f.Lock()
defer f.Unlock()
if !f.Stopped {
select {
case f.result <- Event{Error, errValue}:
return
default:
panic(fmt.Errorf("channel full"))
}
}
}
// Action sends an event of the requested type, for table-based testing.
func (f *RaceFreeFakeWatcher) Action(action EventType, obj runtime.Object) {
f.Lock()
defer f.Unlock()
if !f.Stopped {
select {
case f.result <- Event{action, obj}:
return
default:
panic(fmt.Errorf("channel full"))
}
}
}
// ProxyWatcher lets you wrap your channel in watch Interface. threadsafe.
type ProxyWatcher struct {
result chan Event
stopCh chan struct{}
mutex sync.Mutex
stopped bool
}
var _ Interface = &ProxyWatcher{}
// NewProxyWatcher creates new ProxyWatcher by wrapping a channel
func NewProxyWatcher(ch chan Event) *ProxyWatcher {
return &ProxyWatcher{
result: ch,
stopCh: make(chan struct{}),
stopped: false,
}
}
// Stop implements Interface
func (pw *ProxyWatcher) Stop() {
pw.mutex.Lock()
defer pw.mutex.Unlock()
if !pw.stopped {
pw.stopped = true
close(pw.stopCh)
}
}
// Stopping returns true if Stop() has been called
func (pw *ProxyWatcher) Stopping() bool {
pw.mutex.Lock()
defer pw.mutex.Unlock()
return pw.stopped
}
// ResultChan implements Interface
func (pw *ProxyWatcher) ResultChan() <-chan Event {
return pw.result
}
// StopChan returns stop channel
func (pw *ProxyWatcher) StopChan() <-chan struct{} {
return pw.stopCh
}
我理解意思是说:这段代码是 Kubernetes 中 watch 相关的实现。数据结构主要包含以下内容:
1、Type 类型:
1.1、EventType:定义了事件的类型,包括 Added、Modified、Deleted、Bookmark 和 Error。
1.2、Event:表示一个资源对象的事件,包含事件类型(EventType)和发生变化的对象(runtime.Object)。
1.3、Interface 接口:定义了 watch 的方法,包括 Stop() 和 ResultChan()。
- Stop() 停止watch,关闭结果通道。
- ResultChan() 返回结果通道,接收模拟的事件。
1.4、emptyWatch:是一个别名类型,实际上是 chan Event 的类型。它是用于创建一个没有任何结果和事件的 watch 接口的实现,适用于某些错误情况,其中没有可用的信息,但不需要返回错误。
1.5、RaceFreeFakeWatcher:线程安全的假 watch,用于测试。与 FakeWatcher 类似,可以模拟资源对象的事件,并且具有更好的并发支持。
1.6、ProxyWatcher:通过包装一个通道,代理实现了 Interface 接口,用于包装现有的通道并提供 watch 功能。
我理解意思是说:在实际情况中,可以直接使用 watch.Interface 接口。这个接口是 Kubernetes 提供的用于监听资源变化的通用接口。
1、watch.Interface 接口定义了 Stop() 和 ResultChan() 两个方法,用于停止 watch 和获取结果通道。
2、使用 watch.Interface 接口的好处是,它可以适应不同类型的 watch 实现。你可以使用 Kubernetes 提供的默认 watch 实现,也可以根据自己的需求实现自定义的 watch 。
3、当你需要监听并处理资源对象的变化时,可以创建一个 watch 实例,并通过 ResultChan() 方法接收事件。 watch 会始终返回事件通道,你可以选择在需要时停止 watch。
例如,可以使用以下方式创建一个 watch 实例并监听事件:
watcher := // 创建 watch 实例
eventChan := watcher.ResultChan()
// 在协程中处理事件
go func() {
for event := range eventChan {
// 处理事件
}
}()
// 等待某些条件满足后停止 watch
4、需要注意的是,watch.Interface 接口没有提供对具体资源对象的类型信息。在处理事件时,你需要自行对事件中的对象进行类型断言或其他类型处理操作。
综上所述,当需要监听和处理资源对象的变化时,可以直接使用 watch.Interface 接口。根据自己的需要选择合适的 watch 实现,并通过接口方法获取事件通道进行处理。
但是!在实际情况中,通常会使用 Informer 而不是直接使用 watch.Interface!Informer 是 Kubernetes 提供的更高级别的资源监听和同步机制,它基于 watch.Interface 实现,并提供了更多的功能和便利性。