Skip to content

feat(dqlite): model status service layer #18393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 26, 2024

Conversation

ycliuhw
Copy link
Member

@ycliuhw ycliuhw commented Nov 20, 2024

This PR introduces the a new service method in the model domain package for the model status feature:

  • Status - the model status will be computed in the service layer and returned as:
    • destroying if the model is being destroyed;
    • suspended if the model has an invalid cloud credential;
    • busy if the model is being migrated;
    • in other cases, it returns available;

Drive-by:

  • after discussion, we decided to compute all model statuses, so the model status DDL has been removed.

Checklist

  • Code style: imports ordered, good names, simple structure, etc
  • Comments saying why design decisions were made
  • Go unit tests, with comments saying what you're testing
  • Integration tests, with comments saying what you're testing
  • doc.go added or updated in changed packages

QA steps

unit tests.

Documentation changes

No

Links

Jira card: JUJU-7099

@hpidcock hpidcock added the 4.0 label Nov 20, 2024
@ycliuhw ycliuhw requested review from tlm and wallyworld November 20, 2024 06:58
@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from 65f0ed0 to a0d1a46 Compare November 21, 2024 01:26
@tlm
Copy link
Member

tlm commented Nov 21, 2024

Hey @ycliuhw,

Cheers for the PR. Are we able to move this implementation into the model service (https://github.com/juju/juju/blob/main/domain/model/service/modelservice.go) ?

@ycliuhw ycliuhw force-pushed the model-status-service-layer branch 2 times, most recently from ed99cde to d9547a2 Compare November 22, 2024 05:51
@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from d9547a2 to 2ec3f7f Compare November 22, 2024 05:54
@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from 0650424 to 62a5c35 Compare November 22, 2024 06:08
Copy link
Member

@tlm tlm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cheers @ycliuhw, Ignore any comments I have made that you are already on top of. I will get cracking on the state layer.

return s.modelSt.Delete(ctx, s.modelID)
}

// Status returns the status of the model.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should include the word "current" I think. For example "Status returns the current status of the model".

We should also document the possible error returns that could result from this function.

For example model not found is a likely scenario even if small.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state does not exist yet. We could probably assume the state should return a not found error at least.

if modelState.Destroying {
return model.StatusInfo{
Status: corestatus.Destroying,
Message: "the model is being destroyed",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't seem to be setting the time field on any off these computed status values.

Copy link
Member Author

@ycliuhw ycliuhw Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because we don't know the time of the status change.
If you can figure out where we can find it, feel free to include the time in the result returned from the state.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to ensure the timestamp for the underlying source is modelled. Until then, the caller can interpret zero time as "unknown". We should make sure to update things like juju status to avoid printing junk.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that is what we want to do? Should we just not set time.Now() at least that has meaning over time.Zero().

If we tell the client to start doing is == time.Zero it means we have changed the contract of the api and we should technically bump the apiserver facade version.

Keep it simple I say.

@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from 4779d10 to b54f522 Compare November 25, 2024 05:18
Copy link
Member

@tlm tlm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking good. Just a couple of small things.

@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from b54f522 to 89bc0b8 Compare November 25, 2024 06:12
Copy link
Member

@wallyworld wallyworld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to remove "busy" as a status that can be set

@@ -8,8 +8,7 @@ INSERT INTO model_status_value VALUES
(0, 'error'),
(1, 'available'),
-- We set the model status to busy when the model is being upgraded.
(2, 'busy'),
(3, 'suspended');
(2, 'busy');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going to derive this from whether a model is migrating, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still use busy for upgrade.

Copy link
Member

@wallyworld wallyworld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please change timestamp to time.Time rather than a pointer. I originally gave a +1 to make progress but we should make this change before landing.

Copy link
Member

@wallyworld wallyworld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until timestamp is modelled, we'll need to ensure things like juju status do not print junk when the timestamp is zero.

if modelState.Destroying {
return model.StatusInfo{
Status: corestatus.Destroying,
Message: "the model is being destroyed",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to ensure the timestamp for the underlying source is modelled. Until then, the caller can interpret zero time as "unknown". We should make sure to update things like juju status to avoid printing junk.

@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from 5b3ea7d to 9ace4ef Compare November 26, 2024 02:19
Copy link
Member

@tlm tlm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ta @ycliuhw, just a few quick comments.

if modelState.Destroying {
return model.StatusInfo{
Status: corestatus.Destroying,
Message: "the model is being destroyed",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that is what we want to do? Should we just not set time.Now() at least that has meaning over time.Zero().

If we tell the client to start doing is == time.Zero it means we have changed the contract of the api and we should technically bump the apiserver facade version.

Keep it simple I say.

@ycliuhw ycliuhw force-pushed the model-status-service-layer branch from 9ace4ef to 5d26091 Compare November 26, 2024 04:50
@ycliuhw
Copy link
Member Author

ycliuhw commented Nov 26, 2024

/merge

@jujubot jujubot merged commit 2c0a80f into juju:main Nov 26, 2024
20 of 21 checks passed
@tlm tlm mentioned this pull request Nov 26, 2024
3 tasks
jujubot added a commit that referenced this pull request Nov 28, 2024
#18437

This PR introduces several clean up tasks to the model state around moving over to internal errors and also better defining some of the types we use on the database.

The main goal of this PR is to introduce a new state method for fetching a model's "state". That is the various state various parts of the model are in at any given time so that a model status can be derived from data. It has been decided to implement model status in this way instead of a specific table in the database to track the status of a model. With this approach we are able to calculate the status of model at a given time and not have the complex logic needed to control status setting for a model from several places in the code base.

This PR was done in conjunction with #18393

## 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
- ~[ ] [Integration tests](https://github.com/juju/juju/tree/main/tests), with comments saying what you're testing~
- ~[ ] [doc.go](https://discourse.charmhub.io/t/readme-in-packages/451) added or updated in changed packages~

## QA steps

Unit tests are enough for now.

## Documentation changes

N/A

## Links

**Jira card:** JUJU-7100
Copy link
Member

@manadart manadart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tlm, @ycliuhw Can we do a follow up to this one please?

// ModelState is the model state required by this service. This is the model
// database state, not the controller state.
type ModelState interface {
	// Create creates a new model with all of its associated metadata.
	Create(context.Context, model.ReadOnlyModelCreationArgs) error

	// Delete deletes a model.
	Delete(context.Context, coremodel.UUID) error

	// Model returns the read only model information set in the database.
	Model(context.Context) (coremodel.ReadOnlyModel, error)
}

// ControllerState is the controller state required by this service. This is the
// controller database, not the model state.
type ControllerState interface {
	// GetModel returns the model with the given UUID.
	GetModel(context.Context, coremodel.UUID) (coremodel.Model, error)

	// GetModelState returns the model state for the given model.
	// It returns [modelerrors.NotFound] if the model does not exist for the given UUID.
	GetModelState(context.Context, coremodel.UUID) (model.ModelState, error)
}

This is semantically clunky. We have 2 things with the same name, but with entirely different meanings, used within a paragraph of code. I suggest ModelStatus.

GetStatus is returning a derived StatusInfo, but we will need access to the non-derived status via the service. Can we:

  • Change GetStatus to GetStatusInfo.
  • Implement a GetStatus that returns the ModelState (proposed as ModelStatus above).
  • Include Importing in the struct above and the v_model_state view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants