Move Incus gateway package to go-cowsql - #13
Conversation
ffeba03 to
0234630
Compare
|
@masnax a few things I picked up:
Sorry for not commenting in line but given it's a single huge commit, I ended up cloning locally and digging through things there. I think it'd also be good to put golangci-lint in place as part of this change and run it with a pretty strict config (I'd base it off our crazy IncusOS one and then turn off the few things that make sense). |
4d563dd to
7dc06ca
Compare
|
That should take care of most of them, just 2 to go (Incus package audit and retriable ForceTx) Here's the full set of Incus dependencies: incusapi "github.com/lxc/incus/v7/shared/api"
incusproc "github.com/lxc/incus/v7/shared/subprocess"
incusrevert "github.com/lxc/incus/v7/shared/revert"
incustcp "github.com/lxc/incus/v7/shared/tcp"
incustls "github.com/lxc/incus/v7/shared/tls"
incusutil "github.com/lxc/incus/v7/shared/util"The only tough one here is
Not sure how you're getting that one, any error that returns true for package main
func main() {
transaction.Retry(context.Background(), 10, func(ctx context.Context) error { return errors.New("database is locked") })
}And it seems to get past that line just fine.
This is the recent logic you added to Incus to make NotifyAlive less aggressive. Only change is it returns the whole error set and leaves it up to the caller what to do with the errors, given the policy. I did it this way because Incus' definition of a connection error seems tied to how it sets up the client.
It's on purpose that The real callback wrapped in This follows OC's logic where the transaction is begun by the first DB query/exec call, which implicitly occurs in the Though you did remind me that I forgot to add retries for the |
|
Hello guys, I didn't quite go through the details yet, and maybe I'm getting the wrong impression, but it feels that this change is somehow Incus (or Incus-ecosystem) specific. Please could you provide a bit more details about how you're going to consume this code? I suppose that you now have something other than Incus that will need it. Perhaps it'd be cleaner to keep this code in a standalone project? That way go-cowsql would keep providing the low-level primitives, and this clustering code would be an opinionated implementation of higher-level functionalities. Just gut feeling, happy to discuss further. |
|
Hey @freeekanayaka, The goal is to provide an easy integration point for projects who want to use cowsql from Go. It's based on a stripped down version of the Incus implementation and we're planning on using that to add cowsql support to Operations Center and are also looking into using it for OpenFGA. I think having it as a separate package within go-cowsql should be fine and will make it easier to discover and also give us a bit more motivation to actively test and update go-cowsql's go.mod ;) But I don't want it to have any negative impact to anyone who doesn't want to use this higher level client, which is why we're looking at cleaning up the external dependencies in go.mod (which would also be a problem for something like OpenFGA, so having this be an external repo wouldn't help anyway). |
|
So just to check if I'm understanding this correctly: we have to concerns to would be directly or indirectly addressed by this PR, 1) make high-level clustering logic re-usable beyond Incus 2) make go-cowsql more "active" so its go.mod will be updated more frequently and won't get stale over time? I'm not entirely sure if 2) is what you meant in your reply, I'm a bit confused there. |
|
Yeah, 2) is effectively a consequence of 1). If instead of landing the higher level fixes in Incus and potentially have folks have to sync that into other codebases, we had that logic in go-cowsql, then those same folks would come here to fix such issues, would have an interest in getting more CI tests and automatic dependency reviews and updates directly in go-cowsql rather than fanning this work across a variety of downstream projects. The fact that the entire logic is in a separate |
|
Ok, then the concerns I have are 1) if we introduce additional dependencies needed by the cluster package, those would become go-cowsql level dependencies that all consumers of go-cowsql would pull in right? 2) this PR has barely any test coverage, so it would be hard to spot regressions solely based on go-cowsql tests (we'd presumably have to run Incus tests to validate any change to the cluster package?). |
|
One thing that would be nice to have would be a test MVP (e.g. in a cluster/cluster_test.go file) that uses the cluster machinery and showcases how to use it and that has some reasonable level of validation/testing. FWIW there's no particular AI-related policy for go-cowsql, so I'd be ok if that part gets written using an agent if deemed more convenient. |
|
|
Ok thanks. Maybe we should also some communicate that the cluster module is still experimental and interfaces might change. |
| github.com/Rican7/retry v0.3.1 | ||
| github.com/goccy/go-yaml v1.19.2 | ||
| github.com/google/renameio/v2 v2.0.2 | ||
| github.com/lxc/incus/v7 v7.4.0 |
There was a problem hiding this comment.
As @stgraber already alluded, I'd say pulling-in Incus as dependency should be avoided, and the number of new dependencies introduced by this PR should ideally be really minimal (afaict this is mostly wiring/networking code that should not need anything fancy).
Also, perhaps introducing some import-level versioning (e.g. github/cowsql/go-cowsql/v0) would be wise until we know that interfaces are stable and we won't need backward-compat breakages.
|
@masnax some test failures. Also would be good to expand the test matrix to include:
All of that should be perfectly fine and easy to do with the free Github Actions runners. |
b3edbc7 to
4d8eb08
Compare
|
I was able to reproduce that last test failure on the main branch as well after running |
|
@masnax did some automated comparison of logic with Incus and found a few things.
diff --git a/cluster/db/transaction/context.go b/cluster/db/transaction/context.go
index 9ed0026..669d27a 100644
--- a/cluster/db/transaction/context.go
+++ b/cluster/db/transaction/context.go
@@ -257,6 +257,10 @@ func (t *transactionContainer) Rollback() error {
}
err := t.tx.Rollback()
+
+ // Forget the finished transaction so a retry opens a fresh one.
+ t.tx = nil
+
if !errors.Is(err, sql.ErrTxDone) {
return err
}
Other smaller issues in bulk:
Issues that already exist in Incus and which we should fix in both:
|
The function mentioned here is optional, it's there mainly for the example package and OC. Incus would continue to use its own role rebalance implementation.
This is the check that was fixed a few weeks ago, prior to that it would always either panic or return true, so I just dropped the false check entirely instead, given it's never been reached in practice.
Line numbers are all wrong here (notify.go has about 100 lines, not 500). But in any case, this was addressed earlier: since go-cowsql isn't setting up the Incus dialer, it leaves it up to the caller to judge which errors are skippable based on the policy.
The not-found fallback checks the
No change needed here, should be addressed in the Incus implementation by passing in a context with a 10s timeout.
For this one, I don't know if this code path has ever executed because it's based on the COWSQL version string which has been hardcoded at 1 for a long time. |
The example implementation at example/node.go:161 returns an error instead of nil, false, nil, so the found branch can never fire with the example. |
|
Couple more nits that were found:
|
|
Other than that last point (not sure if actually an issue), this looks good to me. |
|
@freeekanayaka do you want to take a look before we hit merge? Logic wise, this only affects the new package, changes outside of the new package are only there to satisfy the golangci-lint config, so shouldn't be any real functional changes in there. We also now have a fair bit more tests being run which should help. I think my plan from here on would be to merge this, do the Incus conversion, do the Operations Center implementation and once we're happy with all of those, no regression or anything, then we can tag a new release of go-cowsql. This is purely an addition so we don't need a new major or anything. If after some time we somehow find that this is the only real way go-cowsql is consumed, we could do a major bump which would remove the app package, but I think we're a long way from that, if ever. |
|
Thanks @stgraber I'll take a look |
|
Hello, I gave a very quick look, istm that there are changes unrelated to the gateway package. Looks like they are mostly style-related changes accross the whole codebase. Please can we extract those changes into a separate PR, so they can be reviewed/merged separately? Thanks |
|
My preference would be to have a PR of each independent type of change. E.g: 1) bumping CI dependencies (ubuntu 26.04) 2) style-related changes ("if err := foo(); bar() -> err := foo() \n if err { bar() }") etc. This way it's clear to assess the impact of each change and be sure they are unrelated. |
|
@masnax can you make a separate CI & static analysis PR which adds in the golangci-lint config and fixes the existing codebase, then adds the new Github workflow test matrix? That will be trivial to review and merge, then we can have this PR effectively only touch the new Go package. |
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
…from db Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
|
@freeekanayaka want to take a look? It's all good on my end from a manual review and automated review. PR is now self-contained to a single additional Go package and only testify gets added to go.mod. Next once merged will be to move Incus over to it, getting us a bunch more validation through Incus' extensive clustering testsuite. Then we can move on to do Operations Center and other projects where we want that logic. |
|
@stgraber thanks, the example shows a working wiring and has tests and that's very useful. It seems there's quite a bit of boilerplate/wiring needed for consumers, but I understand the functionality is complex and this is needed for the moment to maintain enough flexibility. If it's enough for you guys I'm okay with merging, will do that now. |
Thanks! And yeah, for a very simple implementation, the |
This moves Incus' current implementations for cluster management over to go-cowsql, to then be consumed by Incus and other projects that want to use the same pattern.
There are 4 interfaces that must be implemented externally:
Clusterfor the gateway's management of cluster member node info in the global cowsql databaseNodefor the gateway's management of cached cluster member node info in the local databaseStatefor system non-database related state informationTransactorfor defining transaction behaviour on concurrent access, and managing connection timeouts.