Skip to content

Commit

Permalink
Merge pull request juju#17120 from SimonRichardson/model-life
Browse files Browse the repository at this point in the history
juju#17120

Adds the life concept to the model metadata. This will be used as the basis to trigger the model watcher. Any changes to the model metadata allows us to trigger the model watcher.

## Checklist

- [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

There is no wire-up of watchers yet, so just the creation of a model should suffice.


## Links

**Jira card:** JUJU-
  • Loading branch information
jujubot authored Apr 2, 2024
2 parents d5ab962 + 4b41228 commit 0ebb45a
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 25 deletions.
7 changes: 7 additions & 0 deletions core/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/juju/version/v2"

"github.com/juju/juju/core/credential"
"github.com/juju/juju/core/life"
"github.com/juju/juju/core/user"
"github.com/juju/juju/internal/uuid"
)
Expand Down Expand Up @@ -47,6 +48,12 @@ type Model struct {
// Name returns the human friendly name of the model.
Name string

// Life is the current state of the model.
// Options are alive, dying, dead. Every model starts as alive, only
// during the destruction of the model it transitions to dying and then
// dead.
Life life.Value

// UUID is the universally unique identifier of the model.
UUID UUID

Expand Down
6 changes: 3 additions & 3 deletions core/model/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ func (*ModelSuite) TestValidateBranchName(c *gc.C) {
branchName string
valid bool
}{
{"", false},
{GenerationMaster, false},
{"something else", true},
{branchName: "", valid: false},
{branchName: GenerationMaster, valid: false},
{branchName: "something else", valid: true},
} {
err := ValidateBranchName(t.branchName)
if t.valid {
Expand Down
4 changes: 2 additions & 2 deletions domain/credential/state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,8 @@ func (s *credentialSuite) TestModelsUsingCloudCredential(c *gc.C) {
return err
}
result, err := tx.ExecContext(ctx, fmt.Sprintf(`
INSERT INTO model_metadata (model_uuid, name, owner_uuid, model_type_id, cloud_uuid, cloud_credential_uuid)
SELECT %q, %q, %q, 0,
INSERT INTO model_metadata (model_uuid, name, owner_uuid, life_id, model_type_id, cloud_uuid, cloud_credential_uuid)
SELECT %q, %q, %q, 0, 0,
(SELECT uuid FROM cloud WHERE cloud.name="stratus"),
(SELECT uuid FROM cloud_credential cc WHERE cc.name="foobar")`,
modelUUID, name, s.userUUID),
Expand Down
10 changes: 7 additions & 3 deletions domain/model/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/juju/juju/domain"
usererrors "github.com/juju/juju/domain/access/errors"
clouderrors "github.com/juju/juju/domain/cloud/errors"
"github.com/juju/juju/domain/life"
"github.com/juju/juju/domain/model"
modelerrors "github.com/juju/juju/domain/model/errors"
jujudb "github.com/juju/juju/internal/database"
Expand Down Expand Up @@ -152,7 +153,7 @@ func Get(
uuid coremodel.UUID,
) (coremodel.Model, error) {
modelStmt := `
SELECT md.name, cl.name, cr.name, mt.type, u.uuid, cc.cloud_uuid, cc.name, o.name, ccn.name
SELECT md.name, cl.name, cr.name, mt.type, u.uuid, cc.cloud_uuid, cc.name, o.name, ccn.name, l.value
FROM model_metadata AS md
LEFT JOIN model_list ml ON ml.uuid = md.model_uuid
LEFT JOIN cloud cl ON cl.uuid = md.cloud_uuid
Expand All @@ -162,6 +163,7 @@ LEFT JOIN model_type mt ON mt.id = md.model_type_id
LEFT JOIN user u ON u.uuid = md.owner_uuid
LEFT JOIN user o ON o.uuid = cc.owner_uuid
LEFT JOIN cloud ccn ON ccn.uuid = cc.cloud_uuid
LEFT JOIN life l ON l.id = md.life_id
WHERE md.model_uuid = ?
`

Expand All @@ -186,6 +188,7 @@ WHERE md.model_uuid = ?
&credKey.Name,
&credKey.Owner,
&credKey.Cloud,
&model.Life,
)

if errors.Is(err, sql.ErrNoRows) {
Expand Down Expand Up @@ -370,15 +373,16 @@ AND removed = false
INSERT INTO model_metadata (model_uuid,
cloud_uuid,
model_type_id,
life_id,
name,
owner_uuid)
SELECT ?, ?, model_type.id, ?, ?
SELECT ?, ?, model_type.id, ?, ?, ?
FROM model_type
WHERE model_type.type = ?
`

res, err := tx.ExecContext(ctx, stmt,
uuid, cloudUUID, input.Name, input.Owner, modelType,
uuid, cloudUUID, life.Alive, input.Name, input.Owner, modelType,
)
if jujudb.IsErrConstraintPrimaryKey(err) {
return fmt.Errorf("%w for uuid %q", modelerrors.AlreadyExists, uuid)
Expand Down
2 changes: 2 additions & 0 deletions domain/model/state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/juju/juju/cloud"
corecredential "github.com/juju/juju/core/credential"
"github.com/juju/juju/core/life"
coremodel "github.com/juju/juju/core/model"
modeltesting "github.com/juju/juju/core/model/testing"
"github.com/juju/juju/core/permission"
Expand Down Expand Up @@ -132,6 +133,7 @@ func (m *stateSuite) TestGetModel(c *gc.C) {
Name: "my-test-model",
Owner: m.userUUID,
ModelType: coremodel.IAAS,
Life: life.Alive,
})
}

Expand Down
16 changes: 13 additions & 3 deletions domain/schema/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ const (
tableUpgradeInfoControllerNode
tableObjectStoreMetadata
tableSecretBackendRotation
tableModelMetadata
)

// ControllerDDL is used to create the controller database schema at bootstrap.
func ControllerDDL() *schema.Schema {
patches := []func() schema.Patch{
lifeSchema,
leaseSchema,
changeLogSchema,
changeLogControllerNamespacesSchema,
Expand Down Expand Up @@ -59,6 +61,7 @@ func ControllerDDL() *schema.Schema {
changeLogTriggersForTable("upgrade_info_controller_node", "upgrade_info_uuid", tableUpgradeInfoControllerNode),
changeLogTriggersForTable("object_store_metadata_path", "path", tableObjectStoreMetadata),
changeLogTriggersForTableOnColumn("secret_backend_rotation", "backend_uuid", "next_rotation_time", tableSecretBackendRotation),
changeLogTriggersForTable("model_metadata", "model_uuid", tableModelMetadata),

// We need to ensure that the internal and kubernetes backends are immutable after
// they are created by the controller during bootstrap time.
Expand Down Expand Up @@ -142,7 +145,8 @@ INSERT INTO change_log_namespace VALUES
(8, 'autocert_cache', 'autocert cache changes based on the UUID'),
(9, 'upgrade_info_controller_node', 'upgrade info controller node changes based on the upgrade info UUID'),
(10, 'object_store_metadata_path', 'object store metadata path changes based on the path'),
(11, 'secret_backend_rotation', 'secret backend rotation changes based on the backend UUID and next rotation time');
(11, 'secret_backend_rotation', 'secret backend rotation changes based on the backend UUID and next rotation time'),
(12, 'model_metadata', 'model metadata changes based on the model UUID');
`)
}

Expand Down Expand Up @@ -390,6 +394,7 @@ CREATE TABLE model_metadata (
cloud_region_uuid TEXT,
cloud_credential_uuid TEXT,
model_type_id INT NOT NULL,
life_id INT NOT NULL,
name TEXT NOT NULL,
owner_uuid TEXT NOT NULL,
CONSTRAINT fk_model_metadata_model
Expand All @@ -410,6 +415,9 @@ CREATE TABLE model_metadata (
CONSTRAINT fk_model_metadata_owner_uuid
FOREIGN KEY (owner_uuid)
REFERENCES user(uuid)
CONSTRAINT fk_model_metadata_life_id
FOREIGN KEY (life_id)
REFERENCES life(id)
);
CREATE UNIQUE INDEX idx_model_metadata_name_owner
Expand All @@ -431,7 +439,8 @@ SELECT m.uuid,
mt.type AS model_type_type,
mm.name,
mm.owner_uuid,
u.name AS owner_name
u.name AS owner_name,
l.value AS life
FROM model_list m
INNER JOIN model_metadata mm ON m.uuid = mm.model_uuid
INNER JOIN cloud c ON mm.cloud_uuid = c.uuid
Expand All @@ -440,7 +449,8 @@ LEFT JOIN cloud_credential cc ON mm.cloud_credential_uuid = cc.uuid
INNER JOIN user cco ON cc.owner_uuid = cco.uuid
LEFT JOIN cloud ccn ON cc.cloud_uuid = ccn.uuid
INNER JOIN model_type mt ON mm.model_type_id = mt.id
INNER JOIN user u ON mm.owner_uuid = u.uuid;
INNER JOIN user u ON mm.owner_uuid = u.uuid
INNER JOIN life l ON mm.life_id = l.id;
`)
}

Expand Down
20 changes: 20 additions & 0 deletions domain/schema/life.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2024 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package schema

import "github.com/juju/juju/core/database/schema"

func lifeSchema() schema.Patch {
return schema.MakePatch(`
CREATE TABLE life (
id INT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT INTO life VALUES
(0, 'alive'),
(1, 'dying'),
(2, 'dead');
`)
}
14 changes: 0 additions & 14 deletions domain/schema/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,6 @@ CREATE TABLE annotation_%[1]s (
}
}

func lifeSchema() schema.Patch {
return schema.MakePatch(`
CREATE TABLE life (
id INT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT INTO life VALUES
(0, 'alive'),
(1, 'dying'),
(2, 'dead');
`)
}

func changeLogModelNamespaceSchema() schema.Patch {
// Note: These should match exactly the values of the tableNamespaceID
// constants above.
Expand Down
7 changes: 7 additions & 0 deletions domain/schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ func (s *schemaSuite) TestControllerTables(c *gc.C) {
"model_metadata",
"model_type",

// Life
"life",

// Controller config
"controller_config",

Expand Down Expand Up @@ -352,6 +355,10 @@ func (s *schemaSuite) TestControllerTriggers(c *gc.C) {
"trg_log_secret_backend_rotation_next_rotation_time_insert",
"trg_log_secret_backend_rotation_next_rotation_time_update",
"trg_log_secret_backend_rotation_next_rotation_time_delete",

"trg_log_model_metadata_insert",
"trg_log_model_metadata_update",
"trg_log_model_metadata_delete",
)

// These are additional triggers that are not change log triggers, but
Expand Down

0 comments on commit 0ebb45a

Please sign in to comment.