Skip to content

Commit 3ca73af

Browse files
committed
feat: support new Bootstrapped and Errored watch events
In the regular COSI, new event types are enabled immediately. With protobuf client, new types are enabled when using new COSI client, old COSI client against new server won't receive new events, as old implementation panics on nil Resource in the event structure. Fixes #175 Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
1 parent 0aec1ea commit 3ca73af

19 files changed

Lines changed: 520 additions & 212 deletions

File tree

.kres.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ spec:
55
- --experimental_allow_proto3_optional
66
vtProtobufEnabled: true
77
specs:
8-
- source: https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/resource.proto
8+
- source: https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/resource.proto
99
subdirectory: v1alpha1/
1010
genGateway: true
1111
external: false
12-
- source: https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/state.proto
12+
- source: https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/state.proto
1313
subdirectory: v1alpha1/
1414
genGateway: true
1515
external: false
16-
- source: https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/runtime.proto
16+
- source: https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/runtime.proto
1717
subdirectory: v1alpha1/
1818
genGateway: true
1919
external: false
20-
- source: https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/meta.proto
20+
- source: https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/meta.proto
2121
subdirectory: v1alpha1/
2222
genGateway: true
2323
external: false

Dockerfile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
44
#
5-
# Generated on 2022-11-21T12:24:35Z by kres latest.
5+
# Generated on 2022-11-25T18:59:30Z by kres 3ac53a8.
66

77
ARG TOOLCHAIN
88

@@ -21,10 +21,10 @@ RUN markdownlint --ignore "CHANGELOG.md" --ignore "**/node_modules/**" --ignore
2121

2222
# collects proto specs
2323
FROM scratch AS proto-specs
24-
ADD https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/resource.proto /api/v1alpha1/
25-
ADD https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/state.proto /api/v1alpha1/
26-
ADD https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/runtime.proto /api/v1alpha1/
27-
ADD https://raw.githubusercontent.com/cosi-project/specification/c0f4e7ba6f9a4c7b857b7d110bff3dc5d523cacf/proto/v1alpha1/meta.proto /api/v1alpha1/
24+
ADD https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/resource.proto /api/v1alpha1/
25+
ADD https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/state.proto /api/v1alpha1/
26+
ADD https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/runtime.proto /api/v1alpha1/
27+
ADD https://raw.githubusercontent.com/cosi-project/specification/aec70d02f588efc9463b85e551057313c9754dda/proto/v1alpha1/meta.proto /api/v1alpha1/
2828
ADD api/key_storage/key_storage.proto /api/key_storage/
2929

3030
# base toolchain image

api/v1alpha1/state.pb.go

Lines changed: 177 additions & 145 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha1/state_vtproto.pb.go

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require (
1414
github.com/grpc-ecosystem/grpc-gateway/v2 v2.13.0
1515
github.com/hashicorp/go-memdb v1.3.4
1616
github.com/hashicorp/go-multierror v1.1.1
17-
github.com/siderolabs/gen v0.4.0
17+
github.com/siderolabs/gen v0.4.1
1818
github.com/siderolabs/go-pointer v1.0.0
1919
github.com/siderolabs/go-retry v0.3.2
2020
github.com/siderolabs/protoenc v0.2.0
@@ -31,6 +31,7 @@ require (
3131
require (
3232
github.com/ProtonMail/go-crypto v0.0.0-20220822140716-1678d6eb0cbe // indirect
3333
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f // indirect
34+
github.com/benbjohnson/clock v1.1.0 // indirect
3435
github.com/cloudflare/circl v1.1.0 // indirect
3536
github.com/davecgh/go-spew v1.1.1 // indirect
3637
github.com/hashicorp/errwrap v1.0.0 // indirect

go.sum

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V
66
github.com/ProtonMail/gopenpgp/v2 v2.4.10 h1:EYgkxzwmQvsa6kxxkgP1AwzkFqKHscF2UINxaSn6rdI=
77
github.com/ProtonMail/gopenpgp/v2 v2.4.10/go.mod h1:CTRA7/toc/4DxDy5Du4hPDnIZnJvXSeQ8LsRTOUJoyc=
88
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
9+
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
910
github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4=
1011
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
1112
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
@@ -48,8 +49,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
4849
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
4950
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5051
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
51-
github.com/siderolabs/gen v0.4.0 h1:t+f2TimPoAGBNeXW3qLQBlbDC5GnFik+E/4PWL/uf9c=
52-
github.com/siderolabs/gen v0.4.0/go.mod h1:vzcXVRNpo9j2tyQJU+9ZQ1J6yoebX9KL1TkHt18HNqw=
52+
github.com/siderolabs/gen v0.4.1 h1:NoPmxjLFwOGRFaKypk2hoT5/XIzoM6AhF0eqy61bQLk=
53+
github.com/siderolabs/gen v0.4.1/go.mod h1:wS8tFq7sn5vqKAuyS30vJUig3tX5v6q79VG4KfUnILM=
5354
github.com/siderolabs/go-pointer v1.0.0 h1:6TshPKep2doDQJAAtHUuHWXbca8ZfyRySjSBT/4GsMU=
5455
github.com/siderolabs/go-pointer v1.0.0/go.mod h1:HTRFUNYa3R+k0FFKNv11zgkaCLzEkWVzoYZ433P3kHc=
5556
github.com/siderolabs/go-retry v0.3.2 h1:FzWslFm4y8RY1wU0gIskm0oZHOpsSibZqlR8N8/k4Eo=

pkg/controller/protobuf/protobuf_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/stretchr/testify/require"
1313
suiterunner "github.com/stretchr/testify/suite"
1414
"google.golang.org/grpc"
15+
"google.golang.org/grpc/credentials/insecure"
1516

1617
"github.com/cosi-project/runtime/api/v1alpha1"
1718
"github.com/cosi-project/runtime/pkg/controller/conformance"
@@ -72,7 +73,7 @@ func TestProtobufConformance(t *testing.T) {
7273
suite.grpcServer.Serve(l) //nolint:errcheck
7374
}()
7475

75-
suite.grpcConn, err = grpc.Dial("unix://"+suite.sock.Name(), grpc.WithInsecure()) //nolint:staticcheck
76+
suite.grpcConn, err = grpc.Dial("unix://"+suite.sock.Name(), grpc.WithTransportCredentials(insecure.NewCredentials()))
7677
require.NoError(t, err)
7778

7879
stateClient := v1alpha1.NewStateClient(suite.grpcConn)

pkg/controller/runtime/runtime.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,18 @@ type Runtime struct { //nolint:govet
2929
state state.State
3030
logger *zap.Logger
3131

32-
watchCh chan state.Event
33-
watchedMu sync.Mutex
34-
watched map[watchKey]struct{}
32+
watchCh chan state.Event
33+
watchErrors chan error
34+
watchedMu sync.Mutex
35+
watched map[watchKey]struct{}
3536

3637
controllersMu sync.RWMutex
3738
controllersCond *sync.Cond
3839
controllersRunning int
3940
controllers map[string]*adapter
4041

41-
runCtx context.Context //nolint:containedctx
42+
runCtx context.Context //nolint:containedctx
43+
runCtxCancel context.CancelFunc
4244
}
4345

4446
type watchKey struct {
@@ -53,6 +55,7 @@ func NewRuntime(st state.State, logger *zap.Logger) (*Runtime, error) {
5355
logger: logger,
5456
controllers: make(map[string]*adapter),
5557
watchCh: make(chan state.Event),
58+
watchErrors: make(chan error, 1),
5659
watched: make(map[watchKey]struct{}),
5760
}
5861

@@ -131,9 +134,11 @@ func (runtime *Runtime) Run(ctx context.Context) error {
131134
return fmt.Errorf("runtime has already been started")
132135
}
133136

134-
runtime.runCtx = ctx
137+
runtime.runCtx, runtime.runCtxCancel = context.WithCancel(ctx)
135138

136139
if err := runtime.setupWatches(); err != nil {
140+
runtime.runCtxCancel()
141+
137142
return err
138143
}
139144

@@ -163,17 +168,25 @@ func (runtime *Runtime) Run(ctx context.Context) error {
163168
return err
164169
}
165170

166-
<-runtime.runCtx.Done()
171+
var watchErr error
172+
173+
select {
174+
case <-runtime.runCtx.Done():
175+
case watchErr = <-runtime.watchErrors:
176+
watchErr = fmt.Errorf("controller runtime watch error: %w", watchErr)
177+
}
167178

168179
runtime.controllersMu.Lock()
169180

181+
runtime.runCtxCancel()
182+
170183
for runtime.controllersRunning > 0 {
171184
runtime.controllersCond.Wait()
172185
}
173186

174187
runtime.controllersMu.Unlock()
175188

176-
return nil
189+
return watchErr
177190
}
178191

179192
// GetDependencyGraph returns dependency graph between resources and controllers.
@@ -231,6 +244,13 @@ func (runtime *Runtime) processWatched() {
231244
case e = <-runtime.watchCh:
232245
}
233246

247+
if e.Type == state.Errored {
248+
// watch failed, we need to abort
249+
runtime.watchErrors <- e.Error
250+
251+
return
252+
}
253+
234254
md := e.Resource.Metadata()
235255

236256
controllers, err := runtime.depDB.GetDependentControllers(controller.Input{

pkg/controller/runtime/runtime_test.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,25 @@
55
package runtime_test
66

77
import (
8+
"context"
9+
"strconv"
810
"testing"
11+
"time"
912

13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
1015
suiterunner "github.com/stretchr/testify/suite"
1116
"go.uber.org/goleak"
17+
"go.uber.org/zap/zaptest"
1218

1319
"github.com/cosi-project/runtime/pkg/controller/conformance"
1420
"github.com/cosi-project/runtime/pkg/controller/runtime"
15-
"github.com/cosi-project/runtime/pkg/logging"
1621
"github.com/cosi-project/runtime/pkg/state"
1722
"github.com/cosi-project/runtime/pkg/state/impl/inmem"
1823
"github.com/cosi-project/runtime/pkg/state/impl/namespaced"
1924
)
2025

2126
func TestRuntimeConformance(t *testing.T) {
22-
t.Parallel()
23-
2427
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
2528

2629
suite := &conformance.RuntimeSuite{}
@@ -29,11 +32,50 @@ func TestRuntimeConformance(t *testing.T) {
2932

3033
var err error
3134

32-
logger := logging.DefaultLogger()
35+
logger := zaptest.NewLogger(t)
3336

3437
suite.Runtime, err = runtime.NewRuntime(suite.State, logger)
3538
suite.Require().NoError(err)
3639
}
3740

3841
suiterunner.Run(t, suite)
3942
}
43+
44+
func TestRuntimeWatchError(t *testing.T) {
45+
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
46+
47+
// create a state with tiny capacity
48+
st := state.WrapCore(namespaced.NewState(func(ns string) state.CoreState {
49+
return inmem.NewStateWithOptions(inmem.WithHistoryCapacity(10), inmem.WithHistoryGap(5))(ns)
50+
}))
51+
52+
logger := zaptest.NewLogger(t)
53+
runtime, err := runtime.NewRuntime(st, logger)
54+
require.NoError(t, err)
55+
56+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
57+
t.Cleanup(cancel)
58+
59+
errCh := make(chan error)
60+
61+
go func() {
62+
errCh <- runtime.Run(ctx)
63+
}()
64+
65+
require.NoError(t, runtime.RegisterController(&conformance.IntToStrController{
66+
SourceNamespace: "default",
67+
TargetNamespace: "default",
68+
}))
69+
70+
// overfill the history buffer
71+
for i := 0; i < 10000; i++ {
72+
require.NoError(t, st.Create(ctx, conformance.NewIntResource("default", strconv.Itoa(i), i)))
73+
}
74+
75+
err = <-errCh
76+
require.Error(t, err)
77+
78+
assert.EqualError(t, err, "controller runtime watch error: buffer overrun")
79+
80+
cancel()
81+
}

0 commit comments

Comments
 (0)