89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package etcd
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
storepkg "github.com/cirruslabs/orchard/internal/controller/store"
|
|
"github.com/cirruslabs/orchard/pkg/resource/v1"
|
|
clientv3 "go.etcd.io/etcd/client/v3"
|
|
)
|
|
|
|
func (store *Store) WatchVM(ctx context.Context, vmName string) (chan storepkg.WatchMessage[v1.VM], chan error, error) {
|
|
watchCh := make(chan storepkg.WatchMessage[v1.VM], 1)
|
|
errCh := make(chan error, 1)
|
|
key := store.VMKey(vmName)
|
|
|
|
response, err := store.client.Get(ctx, key)
|
|
if err != nil {
|
|
return nil, nil, mapErr(err)
|
|
}
|
|
|
|
exists := len(response.Kvs) != 0
|
|
watchRevision := response.Header.Revision + 1
|
|
if exists {
|
|
var vm v1.VM
|
|
if err := json.Unmarshal(response.Kvs[0].Value, &vm); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
vm.Version = uint64(response.Kvs[0].ModRevision)
|
|
|
|
watchCh <- storepkg.WatchMessage[v1.VM]{
|
|
Type: storepkg.WatchMessageTypeAdded,
|
|
Object: vm,
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
defer close(watchCh)
|
|
defer close(errCh)
|
|
|
|
watchResponses := store.client.Watch(ctx, key, clientv3.WithRev(watchRevision))
|
|
for watchResponse := range watchResponses {
|
|
if err := watchResponse.Err(); err != nil {
|
|
errCh <- mapErr(err)
|
|
|
|
return
|
|
}
|
|
|
|
for _, event := range watchResponse.Events {
|
|
switch event.Type {
|
|
case clientv3.EventTypeDelete:
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
exists = false
|
|
select {
|
|
case watchCh <- storepkg.WatchMessage[v1.VM]{Type: storepkg.WatchMessageTypeDeleted}:
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
case clientv3.EventTypePut:
|
|
var vm v1.VM
|
|
if err := json.Unmarshal(event.Kv.Value, &vm); err != nil {
|
|
errCh <- err
|
|
|
|
return
|
|
}
|
|
vm.Version = uint64(event.Kv.ModRevision)
|
|
|
|
messageType := storepkg.WatchMessageTypeAdded
|
|
if exists {
|
|
messageType = storepkg.WatchMessageTypeModified
|
|
}
|
|
exists = true
|
|
|
|
select {
|
|
case watchCh <- storepkg.WatchMessage[v1.VM]{Type: messageType, Object: vm}:
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
return watchCh, errCh, nil
|
|
}
|