Extend batch to accept explicit device lists#25542
Extend batch to accept explicit device lists#25542andrewschoen merged 12 commits intoceph:masterfrom
Conversation
8bb3762 to
1047115
Compare
alfredodeza
left a comment
There was a problem hiding this comment.
We would like to see grouping happening with the same sub-command as before, without adding three more sub commands which don't really do anything special for grouping.
In ceph-volume lvm zap we've added recently the ability to accept both devices as positional arguments or devices as part of flags.
This approach could be still used here, something like:
ceph-volume lvm batch --db-devices=/dev/sda --block-devices=/dev/sdb
Which would keep the same API as before, and would need much less refactoring.
| _help = dedent(""" | ||
| Automatically size devices ready for OSD provisioning based on default strategies. | ||
| Automatically size devices ready for OSD provisioning. | ||
| The 'auto' subcommand will automtatically determine the strategy (based on |
There was a problem hiding this comment.
I don't understand why another (3rd level) sub command is needed
There was a problem hiding this comment.
As mentioned above
one cannot have an optional positional argument (the subcommands) and a mandatory positional argument list (the existing DEVICES arguments)
There was a problem hiding this comment.
This is certainly not needed unless you are objecting to anything besides a 3rd level sub-command implementation. We already have this type of arrangement for zap (positional arguments for devices as well as flags defining devices)
There was a problem hiding this comment.
As mentioned in other places this RFC is mostly about the argparsing. I'm absolutely not married to the subcommand structure, I just think this is the clearest approach.
My worry about adding a bunch of new flags is that batch's argument list will grow rather long and confusing. I'll prepare a commit with this style of argparsing to compare.
| The 'auto' subcommand will automtatically determine the strategy (based on | ||
| detection and presence of the drives rotaional flags. | ||
|
|
||
| The 'bluestore' and 'filestore' subcommands allow to specfify lists of |
There was a problem hiding this comment.
why are these subcommands added vs. just using the existing --filestore and --bluestore flags?
There was a problem hiding this comment.
Because having the object store as a subcommand allows for proper separation of bluestore (or filestore) specific arguments. I.e. this allows the argument parser to reject, say the use of --journal-size with bluestore instead of add a code validation (or simply ignore it).
There was a problem hiding this comment.
This is not how any other part of ceph-volume currently operates with both objectstores. Not that it means it can't change, but just to say that there is no need for extra validation to be done. In the case of lvm create for example, if --filestore is specified then any bluestore flag is ignored
|
|
||
| ceph-volume lvm batch --report [DEVICE...] | ||
| ceph-volume lvm batch auto --report [DEVICE...] | ||
| ceph-volume lvm batch bluestore --report |
There was a problem hiding this comment.
if using a sub-command list this one a user has to understand that there are two types of objectstores now. This goes against a design principle in ceph-volume which we (currently) default to bluestore, and that a user doesn't need to understand what an objectstore is or which one does it need.
Yes that is certainly a way to go. I'm just worried that this means |
26e59ae to
1e23caf
Compare
|
@alfredodeza I pushed a version with flag based arg parsing. Note that this still misses a bunch of flags and some flag validation. |
| help='Devices to provision OSDs journal volumes', | ||
| ) | ||
| parser.add_argument( | ||
| '--auto', |
There was a problem hiding this comment.
why would one need to define --auto here instead of assuming automatic behavior if db/wal/journal aren't specified?
There was a problem hiding this comment.
Because without this it would be impossible to deploy standalone OSDs on a mixed group of drives (i.e. a bunch of spinners and ssd's).
Though to be fair --no-auto is probably the better choice here, will update.
1e23caf to
c29d9c5
Compare
|
|
||
| if args.report: | ||
| self.report(args) | ||
| if (self.args.no_auto or self.args.db_devices or |
There was a problem hiding this comment.
this could just use any
| if (self.args.no_auto or self.args.db_devices or | |
| if any([self.args.no_auto, self.args.db_devices, self.args.journal_devices, self.args.wal_devices]): |
There was a problem hiding this comment.
any makes sense for a list of 'truthy' values of unknown length. Whats the benefit here that offsets creating a list purely to use any?
There was a problem hiding this comment.
It's a cosmetic change, but I also think that using any reads better here.
| self.strategy = strategies.bluestore.MixedType( | ||
| self.usable, | ||
| self.db_usable, | ||
| [], |
There was a problem hiding this comment.
why is this an emtpy list if --wal-devices is allowed? shouldn't there be a condition here to accommodate the different options?
There was a problem hiding this comment.
--wal-devices currently only exists as a parameter for the RFC purpose. The bluestore strategy does not yet deploy on three devices. Depending on opinions I'm happy to either add a NotImplemented exception and provide an implementation in a separate PR or remove the argument altogether for now.
| [], | ||
| self.args) | ||
| else: | ||
| self.strategy = strategies.bluestore.SingleType( |
There was a problem hiding this comment.
if this is the SingleType case, why is self.db_usable being passed in along with an empty list for wal devices? SingleType will only deploy OSDs with 1 device only, no db or wal
There was a problem hiding this comment.
Right, a copy-paste error. Amounts to the same code though, will fix this.
| default=[], | ||
| help='Devices to provision OSDs', | ||
| ) | ||
| parser.add_argument( |
There was a problem hiding this comment.
why was all this moved into __init__ ? adding the parsing in the constructor makes it harder to test (there are no tests added with these changes)
There was a problem hiding this comment.
I think __init__ is the right place for argument parsing, since putting it into main requires the run under root just to see the help text. As for testing, as I mentioned in a previous comment, I'll add testing once this is no longer RFC. As for test-ablity: I'm not sure we need to test what argparse does..?
| parser.add_argument( | ||
| '--no-auto', | ||
| action='store_true', | ||
| help=('deploy standalone OSDs if rotational and non-rotational drives' |
There was a problem hiding this comment.
This is not going to hold true for filestore. Saying standalone also reads a bit odd, I don't think we refer to a bluestore OSD with only block (data) defined as standalone. Maybe it would be better to describe that this flag would disable the automatic grouping of devices by checking solid and rotational?
There was a problem hiding this comment.
This is not going to hold true for filestore.
Why not? What if a user wants to deploy standalone (for lack of a better term) filestore OSDs on spinners and SSDs?
Saying
standalonealso reads a bit odd, I don't think we refer to a bluestore OSD with only block (data) defined as standalone. Maybe it would be better to describe that this flag would disable the automatic grouping of devices by checking solid and rotational?
I'm aware of the lack of standard terms here. I'm happy to make this a bit more verbose and clear.
There was a problem hiding this comment.
I'm confused on what the intention of the --no-auto flag is here? A user would need to pass --no-auto and something like --db-devices? If so, can't we just assume they don't want an auto behavior if those flags are passed?
There was a problem hiding this comment.
But what if a user passes a mix of HDD's and SSD's in the devices list but intends to only deploy standalone OSD's (OSDs occupying only one device)? Without --no-auto or similar this is not possible.
There was a problem hiding this comment.
If they have a mix of HDD'S and SSD's then it'd use a MixedType strategy and would not collocate all services on the same device. So this --no-auto flag is an attempt to always make OSDS with everything collocated on the same device regardless of the type of device? If so, maybe naming it --collocated makes more sense? Collocated is the term ceph-ansible used to describe an OSD with either block.db or the journal on the same device as data.
There was a problem hiding this comment.
I'm happy to rename the option, but it is needed in any case.
Ideally we'd have some project wide term to use for the different OSD deployment modes.
src/ceph-volume/ceph_volume/devices/lvm/strategies/filestore.py
Outdated
Show resolved
Hide resolved
| class Strategy(object): | ||
|
|
||
| def __init__(self, devices, args): | ||
| def __init__(self, data_devs, db_devs, wal_devs, args): |
There was a problem hiding this comment.
now that all strategies are inheriting from this, it makes it odd to have the same parent for both filestore and bluestore. Filestore doesn't have a db_dev or a wal_dev but somehow the child classes for filestore use this forcing the code to have to pick either db_devs or wal_devs.
Either these parent classes need to be split into bluestore and filestore or the whole sub-classing would have to go
There was a problem hiding this comment.
Python does not allow for ctor overloading, so I went with the most explicit version (which happens to be bluestore on three devices).
Splitting this into bluestore and filestore specific implementations will again add duplicate code. I took the pragmatic route. I think this can be resolved with better naming and a comment, like
def __init__(self, data_devs, db_or_journal_devs, wal_devs, args):
'''
Note that any filestore strategy will always pass an empty list for wal_devs
'''Not sure what can be gained by going back on the subclassing?
There was a problem hiding this comment.
The proposed implementation is trying to save a few lines of code but adding incorrect definitions for devices (journals aren't present in filestore, and it is using db_devs which don't exist)
The gain here would be that it would be clear that filestore uses journals, not db. At the cost of some duplication. I would prefer clarity over Lines Of Code savings
There was a problem hiding this comment.
Just to be sure: I changed the name prior to your comment.
The saved lines of code actually stem from #25238. Not sure I'd call ~50 loc "a few lines". In any case the main goal was to remove duplicate implementations in four strategy constructors to adhere a bit more to a DRY approach.
I'm certainly happy to add some boilerplate code in order to make a name in an internal implementation less confusing.
| def split_devices_rotational(devices): | ||
| data_devs = [device for device in devices if device.sys_api['rotational'] == '1'] | ||
| db_devs = [device for device in devices if device.sys_api['rotational'] == '0'] | ||
| return data_devs, db_devs |
There was a problem hiding this comment.
what happens here for wal devs? why would this omit them
| self.validate_compute() | ||
|
|
||
| @classmethod | ||
| def with_auto_devices(cls, devices, args): |
There was a problem hiding this comment.
this seems to have been added for test purposes only, was it not possible to declare the auto/non-auto behavior via an argument? Maybe more difficult now that the args moved to init
There was a problem hiding this comment.
This method is used here:
was it not possible to declare the auto/non-auto behavior via an argument? Maybe more difficult now that the args moved to init
Not sure what you mean here? Using auto or no-auto is of course decided by the arguments. When auto is desired the drives still have to be split at some point.
There was a problem hiding this comment.
I think the question is why do we need this class method when the class should be able to figure out if it needs the auto behavior or not by inspecting self.args?
There was a problem hiding this comment.
In the existing code batch inspects args and figures out the strategy, I just kept with that. That could certainly be implemented differently, though I'd argue to find consensus on this feature and refactor things in a later PR.
c29d9c5 to
04abd89
Compare
|
|
||
| if args.report: | ||
| self.report(args) | ||
| if (self.args.no_auto or self.args.db_devices or |
There was a problem hiding this comment.
It's a cosmetic change, but I also think that using any reads better here.
| parser.add_argument( | ||
| '--no-auto', | ||
| action='store_true', | ||
| help=('deploy standalone OSDs if rotational and non-rotational drives' |
There was a problem hiding this comment.
I'm confused on what the intention of the --no-auto flag is here? A user would need to pass --no-auto and something like --db-devices? If so, can't we just assume they don't want an auto behavior if those flags are passed?
| total_lv_size=str(self.total_available_journal_space), | ||
| total_lvs=self.journals_needed, | ||
| block_db_devices=', '.join([d.path for d in self.ssds]), | ||
| block_db_devices=', '.join([d.path for d in self.db_or_journal_devs]), |
There was a problem hiding this comment.
Should this be journal_devices instead of block_db_devices?
There was a problem hiding this comment.
No the template defines this name here https://github.com/ceph/ceph/blob/master/src/ceph-volume/ceph_volume/util/templates.py#L38
| self.computed = {'osds': [], 'vgs': [], 'filtered_devices': args.filtered_devices} | ||
| self.devices = data_devs + wal_devs + db_or_journal_devs | ||
| self.data_devs = data_devs | ||
| self.db_or_journal_devs = db_or_journal_devs |
There was a problem hiding this comment.
Instead of db_or_journal_devs can we have explicit db_devs and journal_devs properties? I think this will make the code easier to understand in the long run.
| self.validate_compute() | ||
|
|
||
| @classmethod | ||
| def with_auto_devices(cls, devices, args): |
There was a problem hiding this comment.
I think the question is why do we need this class method when the class should be able to figure out if it needs the auto behavior or not by inspecting self.args?
|
@alfredodeza @andrewschoen Can I assume this is generally ready to be dressed up for a merge? Are there any fundamental concerns about the arg parsing or something similar? Tests (functional and unit) are on their way. |
|
@jan--f I've been wondering if what you're trying to accomplish here might be better suited in This would also solve problems for others who want the flexibility of |
|
@andrewschoen I'm not sure I understand. This PR intends to add the option to explicitly specify drives for the batch creation of OSDs. |
|
@jan--f ok, so you do need many OSDs created with one call? In that case |
|
jenkins test ceph-volume tox |
|
jenkins test ceph-volume batch all |
|
@jan--f I think that you're right that dressing this up and writing tests is the next step. Once we've got test coverage on the new work and the existing tests passing then we can move forward with this. |
61cd77b to
add6c2e
Compare
|
@jan--f Some of those do look like jenkins troubles, but one of the idempotency checks did find what looks to be a valid failure: |
|
jenkins test ceph-volume tox |
|
@andrewschoen indeed, I see this one locally as well: So it creates the LV's on In any case the behaviour (divide by 0) could be caught be the validation (no data devices but some db-devices). Will add a check. |
|
@andrewschoen I added a test and fix for this scenario. |
25437e1 to
c58fe2f
Compare
ca0d416 to
81061d7
Compare
|
jenkins test ceph-volume batch all |
andrewschoen
left a comment
There was a problem hiding this comment.
This is getting really close. Thanks for working on the functional testing!
I've only found one small testing related concern.
| - batch_cmd.rc != 0 | ||
| - "'strategy changed' not in batch_cmd.stdout" | ||
|
|
||
| - name: run batch --report to see if devices get filtered |
There was a problem hiding this comment.
The command here is missing the slice to only use HDD for the data devices.
It needs to be:
{{ devices[:2] | join(' ') }} --db-devices {{ devices[2:] | join(' ') }}"
This test needs to ensure that running the same command again with --report will show changed: False in the json output. I've noticed that we don't check that json output in the following task, which might be good to add here as well. I realize the rest of the tests don't do that, which was an oversight for sure.
There was a problem hiding this comment.
Yes the slice is missing indeed, coming up. Should we deal with the additional check in a separate PR?
Signed-off-by: Jan Fajerski <jfajerski@suse.com>
81061d7 to
f4f4015
Compare
|
anything still blocking this @andrewschoen @alfredodeza ? |
|
@jan--f it looks like there are flake8 failures from the tox tests. If we can get that resolved I think we're good to go. |
Signed-off-by: Jan Fajerski <jfajerski@suse.com>
Signed-off-by: Jan Fajerski <jfajerski@suse.com>
Also add test case for a MixedStrategy with unusable data devices. Signed-off-by: Jan Fajerski <jfajerski@suse.com>
f4f4015 to
026d5b8
Compare
|
@andrewschoen Thx, good catch. Done. |
|
jenkins test ceph-volume tox |
|
jenkins test ceph-volume batch all |
|
@jan--f thanks for your work here. Would you please create backport PRs for luminous and mimic? Thanks! |
This is the first PR to address parts of http://tracker.ceph.com/issues/37086.
On a high level this adds the ability to batch to accept explicit device lists for data and db/journal.
The RFC here is mostly for the argument parsing. For this PR I added 3 new subcommands to batch:
autoto keep the existing functionality, andbluestoreandfilestore. Other implementations are possible, for example:bluestoreandfilestoresubcommands and move the existing functionality to a flag, e.g.--auto.Imho the implementation here is the cleanest as it allows for proper separation between non-overlapping argument groups (i.e. not having mutual exclusive arguments under the same subcommand) and keeps the existing functionality untouched (besides moving it to a subcommand. Ideally the subcommands would be optional and we could keep the existing functionality as is but one cannot have an optional positional argument (the subcommands) and a mandatory positional argument list (the existing DEVICES arguments), but that would require a not-so-pretty hack to the argument parsing (peeking at the positional and deciding what the appropriate action is)
To fully address http://tracker.ceph.com/issues/37086 a few more PRs are necessary:
I think 1) is neither very hard (as it is new functionality) nor terribly urgent. I started on 2) but this requires a bit of an overhaul how c-v figures out the appropriate sizes for logical volumes. Part of that are two tracker tickets (http://tracker.ceph.com/issues/37590 and http://tracker.ceph.com/issues/37502). I have not yet looked into 3) but since
ceph-volume lvm createcan do that already, most functionality should be in place already.Once there is consensus over the argument parsing I'll clean up the wip commit and add functional testing for the new functionality.