forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request juju#17156 from SimonRichardson/generate-triggers
juju#17156 Triggers were written whereby any update to the database would cause a new insert into the change log, even if the value was identical. This causes a lot of churn in the change log. We can generate the triggers using the columns from the actual database schema. The triggers will always be correct and always up to date. Part of the change set includes fixing watchers and watcher tests: ### Cloud watcher The watch cloud test wasn't working how it was expected. The upsert was just triggering a new change in the old code, prior to this patch. The cloud-config is currently immutable, I'll open a bug to fix this. As the config is not updated and the trigger prevents a noop change then the test fails. The solution is to then update a field on the cloud that will cause a change. In this case, the endpoint was updated. Bug about cloud-config: https://bugs.launchpad.net/juju/+bug/2066410 ### Model config watcher The model config watch wasn't correct once the generated triggers were added. Firstly, we deleted all of the keys and then re-added them again even if they were the same. This caused a lot of churn in the changestream. The fix was just to ensure that we inserted, updated, and deleted rows correctly. The second problem was that we would see the initial changes from bootstrap and then see them again when the change stream was processing requests. This might be ok for some watchers (I highly doubt that), but the concept of watchers are that, watch changes and then react. For most things that take information from the API server, the initial event is thrown away, so it's pointless trying to get that. It's better to just read the state of the world and then respond to changes. The model_config watcher will now emit an empty initial event and then subsequent events will tell you what has changed. <!-- Why this change is needed and what it does. --> ## Checklist <!-- If an item is not applicable, use `~strikethrough~`. --> - [x] Code style: imports ordered, good names, simple structure, etc - [x] Comments saying why design decisions were made - [x] Go unit tests, with comments saying what you're testing ## QA steps ```sh $ make rebuild-triggers ``` ```sh $ juju bootstrap lxd test $ juju add-model default $ juju deploy ubuntu ``` ## Links **Jira card:** [JUJU-6055](https://warthogs.atlassian.net/browse/JUJU-6055) [JUJU-6055]: https://warthogs.atlassian.net/browse/JUJU-6055?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
- Loading branch information
Showing
39 changed files
with
2,137 additions
and
300 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// Copyright 2024 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package modelconfig | ||
|
||
import ( | ||
"context" | ||
|
||
jc "github.com/juju/testing/checkers" | ||
gc "gopkg.in/check.v1" | ||
|
||
"github.com/juju/juju/cloud" | ||
"github.com/juju/juju/core/changestream" | ||
"github.com/juju/juju/core/credential" | ||
"github.com/juju/juju/core/model" | ||
modeltesting "github.com/juju/juju/core/model/testing" | ||
"github.com/juju/juju/core/permission" | ||
coreuser "github.com/juju/juju/core/user" | ||
"github.com/juju/juju/core/watcher/watchertest" | ||
"github.com/juju/juju/domain" | ||
userbootstrap "github.com/juju/juju/domain/access/bootstrap" | ||
cloudbootstrap "github.com/juju/juju/domain/cloud/bootstrap" | ||
credentialbootstrap "github.com/juju/juju/domain/credential/bootstrap" | ||
domainmodel "github.com/juju/juju/domain/model" | ||
modelbootstrap "github.com/juju/juju/domain/model/bootstrap" | ||
"github.com/juju/juju/domain/model/state/testing" | ||
"github.com/juju/juju/domain/modelconfig/bootstrap" | ||
"github.com/juju/juju/domain/modelconfig/service" | ||
"github.com/juju/juju/domain/modelconfig/state" | ||
"github.com/juju/juju/domain/modeldefaults" | ||
"github.com/juju/juju/environs/config" | ||
changestreamtesting "github.com/juju/juju/internal/changestream/testing" | ||
loggertesting "github.com/juju/juju/internal/logger/testing" | ||
"github.com/juju/juju/internal/uuid" | ||
jujutesting "github.com/juju/juju/testing" | ||
jujuversion "github.com/juju/juju/version" | ||
) | ||
|
||
type modelConfigSuite struct { | ||
changestreamtesting.ControllerSuite | ||
changestreamtesting.ModelSuite | ||
|
||
modelID model.UUID | ||
} | ||
|
||
var _ = gc.Suite(&modelConfigSuite{}) | ||
|
||
func (s *modelConfigSuite) SetUpTest(c *gc.C) { | ||
s.ControllerSuite.SetUpTest(c) | ||
s.ModelSuite.SetUpTest(c) | ||
|
||
userID, fn := userbootstrap.AddUser(coreuser.AdminUserName, permission.ControllerForAccess(permission.SuperuserAccess)) | ||
err := fn(context.Background(), s.ControllerTxnRunner(), s.ControllerSuite.NoopTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
cloudName := "test" | ||
fn = cloudbootstrap.InsertCloud(coreuser.AdminUserName, cloud.Cloud{ | ||
Name: cloudName, | ||
Type: "ec2", | ||
AuthTypes: cloud.AuthTypes{cloud.EmptyAuthType}, | ||
}) | ||
|
||
err = fn(context.Background(), s.ControllerTxnRunner(), s.ControllerSuite.NoopTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
credentialName := "test" | ||
fn = credentialbootstrap.InsertCredential(credential.Key{ | ||
Cloud: cloudName, | ||
Name: credentialName, | ||
Owner: coreuser.AdminUserName, | ||
}, | ||
cloud.NewCredential(cloud.EmptyAuthType, nil), | ||
) | ||
|
||
err = fn(context.Background(), s.ControllerTxnRunner(), s.ControllerSuite.NoopTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
testing.CreateInternalSecretBackend(c, s.ControllerTxnRunner()) | ||
|
||
modelUUID := modeltesting.GenModelUUID(c) | ||
modelFn := modelbootstrap.CreateModel(domainmodel.ModelCreationArgs{ | ||
AgentVersion: jujuversion.Current, | ||
Cloud: cloudName, | ||
Credential: credential.Key{ | ||
Cloud: cloudName, | ||
Name: credentialName, | ||
Owner: coreuser.AdminUserName, | ||
}, | ||
Name: "test", | ||
Owner: userID, | ||
UUID: modelUUID, | ||
}) | ||
s.modelID = modelUUID | ||
|
||
err = modelFn(context.Background(), s.ControllerTxnRunner(), s.ControllerSuite.NoopTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
err = modelbootstrap.CreateReadOnlyModel(modelUUID, uuid.MustNewUUID())(context.Background(), s.ControllerTxnRunner(), s.ModelTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
} | ||
|
||
func (s *modelConfigSuite) TestWatchModelConfig(c *gc.C) { | ||
ctx, cancel := jujutesting.LongWaitContext() | ||
defer cancel() | ||
|
||
var defaults modelDefaultsProviderFunc = func(_ context.Context) (modeldefaults.Defaults, error) { | ||
return modeldefaults.Defaults{ | ||
"foo": modeldefaults.DefaultAttributeValue{ | ||
Source: config.JujuControllerSource, | ||
Value: "bar", | ||
}, | ||
}, nil | ||
} | ||
|
||
attrs := map[string]any{ | ||
"agent-version": jujuversion.Current.String(), | ||
"uuid": s.modelID.String(), | ||
"type": "iaas", | ||
"logging-config": "<root>=ERROR", | ||
} | ||
|
||
st := state.NewState(s.ModelSuite.TxnRunnerFactory()) | ||
factory := domain.NewWatcherFactory( | ||
changestream.NewWatchableDBFactoryForNamespace(s.ModelSuite.GetWatchableDB, s.modelID.String()), | ||
loggertesting.WrapCheckLog(c)) | ||
svc := service.NewWatchableService(defaults, config.ModelValidator(), st, factory) | ||
|
||
watcher, err := svc.Watch() | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
err = bootstrap.SetModelConfig(s.modelID, attrs, defaults)(ctx, s.ControllerTxnRunner(), s.ModelTxnRunner()) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
w := watchertest.NewStringsWatcherC(c, watcher) | ||
|
||
// Changestream becomes idle and then we receive the bootstrap changes | ||
// from the model config. | ||
w.AssertChange("name", "uuid", "type", "foo", "secret-backend", "logging-config") | ||
|
||
// Ensure that the changestream is idle. | ||
s.ModelSuite.AssertChangeStreamIdle(c) | ||
|
||
// Now insert the change and watch it come through. | ||
attrs["logging-config"] = "<root>=WARNING" | ||
|
||
err = svc.SetModelConfig(ctx, attrs) | ||
c.Assert(err, jc.ErrorIsNil) | ||
|
||
s.ModelSuite.AssertChangeStreamIdle(c) | ||
|
||
w.AssertChange("logging-config") | ||
} | ||
|
||
type modelDefaultsProviderFunc func(context.Context) (modeldefaults.Defaults, error) | ||
|
||
func (f modelDefaultsProviderFunc) ModelDefaults( | ||
c context.Context, | ||
) (modeldefaults.Defaults, error) { | ||
return f(c) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2024 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package modelconfig | ||
|
||
import ( | ||
"testing" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
func TestPackage(t *testing.T) { | ||
gc.TestingT(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.