Skip to content
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

Added "planned unit count" to model. #597

Merged
merged 9 commits into from
Sep 10, 2021
Merged

Added "planned unit count" to model. #597

merged 9 commits into from
Sep 10, 2021

Conversation

pengale
Copy link
Contributor

@pengale pengale commented Sep 1, 2021

This is the simplest possible implementation of goal state, designed
to give folks a way to access goal state info, without implementing a
more complete representation of goal state.

This is the simplest possible implementation of goal state, designed
to give folks a way to access goal state info, without implementing a
more complete representation of goal state.
Copy link
Member

@jnsgruk jnsgruk left a comment

Choose a reason for hiding this comment

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

Overall looks good, but some minor changes requested (open to discussion, though :))

ops/model.py Outdated Show resolved Hide resolved
ops/model.py Show resolved Hide resolved
ops/model.py Outdated Show resolved Hide resolved
ops/testing.py Outdated Show resolved Hide resolved
@jameinel
Copy link
Member

jameinel commented Sep 2, 2021 via email

@jnsgruk
Copy link
Member

jnsgruk commented Sep 2, 2021

@jameinel Yeh I think any reference to relations/remote units should be kept out of scope for now.

@sed-i
Copy link
Contributor

sed-i commented Sep 2, 2021

The issue being that if you 'juju deploy ha-app -n 3", each unit comes up,
and until it has gotten to start, it hasn't joined its relations, and it
doesn't see and doesn't show up to the other units. So each unit sees
itself as a standalone.

My impression was that planned_unit_count is for reducing/preventing an "event storm", and was not intended to provide a reliable facility for executing some code only once. iiuc, the same charm code should run fine and produce the same result eventually, with or without relying on planned_unit_count.

@jameinel
Copy link
Member

jameinel commented Sep 2, 2021 via email

@sed-i
Copy link
Contributor

sed-i commented Sep 2, 2021

you want to avoid telling other charms to start sharing their data if you don't have quorum

Makes sense for a startup sequence, but wouldn't juju scale-application still have the same challenge?
So given the charm must be robust enough to handle incremental scale-application, it seem like planned_unit_count is just for reducing the "event storm". Am I missing something?

get_planned_unit_count -> planned_units.

Moved where we expose this to the Application class.
Hat tip to justinmclark's earlier PR, where he figured out the best
way to test this.
ops/testing.py Outdated Show resolved Hide resolved
@jameinel
Copy link
Member

jameinel commented Sep 3, 2021 via email

@rbarry82
Copy link
Contributor

rbarry82 commented Sep 3, 2021

planned_unit_count is also for sanity. Sure, ideally, Charms will handle scale-application. But a charm which requires quorum via Raft is pretty useless as a single/double unit, whether or not it can gracefully scale endlessly at 3+. Telling something which talks to etcd "hey, I'm ready!" when you have a single node, then telling your relations "wait, I'm electing a leader. Wait, I'm electing another leader. Wait, I'm partitioning data" in the next 30 seconds after you said "hey, I'm ready!" is exactly the kind of "event storm" this is trying to avoid.

Once you say "hey, I'm ready!" from Elastic or Cassandra or whatever to some other application, that application will probably start trying to create keys/indexes/tables/whatever, and re-partitioning the data is an expensive process which may or may not block off or dramatically slow external communications, with the admin guide suggesting that you set up a maintenance window for it. Now your "other" charm fails startup and reports an error back to Juju because something went wrong which never should have started in the first place.

Similarly, adding an OSD to Ceph requires adding things to the keyring, adding it to the CRUSH map, and waiting for data to rebalance. This is expensive. If you wait until everything is ready, no rebalance. Or even if you wait until there's very ittle/no data, it's a cheap/fast operation. Telling Cinder/Glance/Swift that Ceph is ready cascades if you have a single node. Now, hypothetically, Swift comes up and thinks it's ready. And something which is related to Swift starts writing data.

And it's a bottleneck/race between "how fast can application X which is writing data to Ceph through Swift perform when Ceph is trying to add a node and rebalance".

Whether or not a charm can handle scale-application is sort of irrelevant from this sense. Just because it can does not mean it should have to, particularly at initial deployment of a bundle where Juju already knows that there are going to be X Ceph/Cassandra/Elastic/Rabbit/Mongo/whatever nodes. It's better for performance, reliability, "event storm", administrator observability, and everything else to simply wait until the HA/distributed application is really "ready".

@jameinel
Copy link
Member

jameinel commented Sep 5, 2021 via email

@pengale pengale requested a review from jnsgruk September 8, 2021 14:56
Copy link
Collaborator

@niemeyer niemeyer left a comment

Choose a reason for hiding this comment

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

This is looking good. Just some comments around comments and concepts:

ops/model.py Outdated
planned unit count for foo would be 3.

We deliberately do not attempt to inspect whether these units are actually running
or not. That is a task left up to the future, when goal state is more mature.
Copy link
Collaborator

Choose a reason for hiding this comment

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

It'd be nice to not refer to "goal state" here. We want to kill that idea altogether in juju, in the sense that the number of pending units is just part of the current state like everything else.

ops/model.py Outdated
def planned_units(self) -> int:
"""Count of "planned" units that will run this application.

We use goal-state here, in the simplest possible way. When we implement goal state
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as above.

ops/model.py Outdated
Includes the current unit in the count.

"""
goal_state = self._run('goal-state', return_output=True, use_json=True)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Might also be worth adding a comment before that line so future readers can understand that perspective. Something along the lines of:

# goal-state as a concept in juju is dying in favor of it being simply the current state,
# so we must not use this API further outside of explicitly designed and agreed cases.

@jnsgruk
Copy link
Member

jnsgruk commented Sep 10, 2021

Nice work, thanks @petevg

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

Successfully merging this pull request may close these issues.

6 participants