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

lifecycle: clean after deleting container #1587

Merged
merged 11 commits into from Oct 30, 2017

Conversation

kalikiana
Copy link
Contributor

@kalikiana kalikiana commented Oct 4, 2017

  • Have you followed the guidelines for contributing?
  • Have you signed the CLA?
  • If this is a bugfix. Have you checked that there is a bug report open for the issue you are trying to fix on bug reports?
  • If this is a new feature. Have you discussed the design on the forum?
  • Have you successfully run ./runtests.sh static?
  • Have you successfully run ./runtests.sh unit?

See the forum discussion.

@kalikiana kalikiana self-assigned this Oct 6, 2017
project_options = get_project_options(**kwargs)
container_config = env.get_container_config()
if container_config.use_container:
step = step or 'pull'
if container_config.use_container and step == 'pull' and not parts:
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get this @kalikiana. I might be doing something wrong while testing it, but it seems to me that this still just deletes the container.
The execute method in lxd checks if we are cleaning, and if so, it just deletes the container.
In this pr I see nothing to modify that behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry about that. It looks like the second commit was lost... I re-did the missing piece. So: clean should be called with the container to delete it, in all other cases "normal" lifecycle clean is used so that it works even if the container is broken or already deleted.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to rectify the poor separation of concerns, here. We're going to great lengths to ensure we only ever call lifecycle.containerbuild('clean') if step == 'pull' and not parts, with no apparent reason. We then proceed to pass the step as well as the parts (that we just ensured was empty) to the very generic-sounding lifecycle.containerbuild() method. That method then calls the very generic-sounding lxd.Project().execute() method. Finally, that method checks to see if we're cleaning the pull step with no parts, in which case it blows the container away.

I'd like to see lxd.Project().execute() be written more generically. If it was asked to clean with no parts, fine, blow the container away. If it was asked to clean with parts, do nothing. If something else, call super(). Then we don't have to let the conditions where the container needs to be removed leak to this line, where we're checking those conditions again. We can simply call lifecycle.containerbuild('clean') just like we call lifecycle.clean() and expect it to do the right thing.

@kalikiana
Copy link
Contributor Author

Note: All but the snap test have passed

Copy link
Contributor

@kyrofa kyrofa left a comment

Choose a reason for hiding this comment

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

Good progress here, thank you! However, there's a concerns leakage that looks like a bug waiting to happen. I suggest we fix that.

project_options = get_project_options(**kwargs)
container_config = env.get_container_config()
if container_config.use_container:
step = step or 'pull'
if container_config.use_container and step == 'pull' and not parts:
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to rectify the poor separation of concerns, here. We're going to great lengths to ensure we only ever call lifecycle.containerbuild('clean') if step == 'pull' and not parts, with no apparent reason. We then proceed to pass the step as well as the parts (that we just ensured was empty) to the very generic-sounding lifecycle.containerbuild() method. That method then calls the very generic-sounding lxd.Project().execute() method. Finally, that method checks to see if we're cleaning the pull step with no parts, in which case it blows the container away.

I'd like to see lxd.Project().execute() be written more generically. If it was asked to clean with no parts, fine, blow the container away. If it was asked to clean with parts, do nothing. If something else, call super(). Then we don't have to let the conditions where the container needs to be removed leak to this line, where we're checking those conditions again. We can simply call lifecycle.containerbuild('clean') just like we call lifecycle.clean() and expect it to do the right thing.

@kalikiana
Copy link
Contributor Author

@kyrofa Somehow I can reply... something's off with GitHub since today I think. In any case, I changed it as per your suggestion and the logic is only in lxd.py now.

if step == 'clean':
# we don't execute clean here but rely on CLI to do it
# clean with no parts deletes the container
if self._get_container_status() and args == ['--step', 'pull']:
Copy link
Contributor

@kyrofa kyrofa Oct 11, 2017

Choose a reason for hiding this comment

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

I think re-purposing this function to clean is both confusing (clean is not a lifecycle step, and then one sees --step pull and gets more confused) and is causing the diff of this PR to be larger than it needs to be (changing the step from None to 'pull' everywhere, which seems unnecessary). How difficult would it be to simply add a clean function here that accepts a step (the step being cleaned) and args?

Copy link
Contributor

Choose a reason for hiding this comment

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

Eh, I changed my mind on defaulting step to pull at a higher level, otherwise you'll need to treat None and 'pull' as equivalent here. However, I would still like to see a clean function here instead of execute.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I reverted the default change now. It's not essential to the PR, it just seemed like a simplification.

And I replaced the subclass' execute logic with a delete method - now lifecycle remains in charge and reading lxd.py doesn't require any knowledge of what lifecycle does with it.

if not step:
step = 'pull'

def clean(project_options, parts, step):
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just default step='pull' so it continues working the way it was?

@@ -653,7 +653,7 @@ def test_clean_removes_global_state(self):
plugin: nil
""")
lifecycle.execute('pull', self.project_options)
lifecycle.clean(self.project_options, parts=None)
lifecycle.clean(self.project_options, parts=None, step='pull')
Copy link
Contributor

Choose a reason for hiding this comment

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

If you use pull as the default, this is unnecessary.

@kalikiana
Copy link
Contributor Author

Tests are green again!

kyrofa
kyrofa previously approved these changes Oct 13, 2017
Copy link
Contributor

@kyrofa kyrofa left a comment

Choose a reason for hiding this comment

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

This seems fine to me, now. We'll need to refactor it if the container ever needs to actually do something when individual parts or steps are cleaned, but this solves the problem for now.

Copy link
Contributor

@come-maiz come-maiz left a comment

Choose a reason for hiding this comment

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

If I understand correctly, this calls the clean commands outside of the container. I can see no issue right now, but I think this has the potential to break. I think that if the build is done in the container, the clean should execute in there too. But for now, I think this is a good improvement. Maybe we care about this when it becomes an issue, not now.

@sergiusens
Copy link
Collaborator

the business logic seems to have spread a bit too much into the cli components, hasn't it?

@kyrofa
Copy link
Contributor

kyrofa commented Oct 16, 2017

Yes indeed.

Copy link
Collaborator

@sergiusens sergiusens left a comment

Choose a reason for hiding this comment

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

Sorry to say, but it would be good to prevent leaking too much into this.

It is acceptable if you want to surface UI (click.echo, echo.warn or prompts) but not for usage of moving common logic.

I would personally rather have it repeated.

@kalikiana
Copy link
Contributor Author

@sergiusens I moved all logic back into the container, in the clean() method. Lifecycle knows nothing again like it did before.

Copy link
Contributor

@come-maiz come-maiz left a comment

Choose a reason for hiding this comment

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

To me, this looks more readable than before. Reapproving.

@kyrofa kyrofa dismissed their stale review October 24, 2017 17:14

Significant change occurred.

@kalikiana
Copy link
Contributor Author

I updated the branch against master (no change in code, but it now lives in _project.py).

@sergiusens sergiusens added this to the 2.35 milestone Oct 26, 2017
@kalikiana kalikiana dismissed sergiusens’s stale review October 26, 2017 21:04

Moved the logic back into the container, out of lifecycle. Needs re-checking.

@@ -175,11 +177,12 @@ def clean(parts, step, **kwargs):
"""
project_options = get_project_options(**kwargs)
container_config = env.get_container_config()
step = step or 'pull'
Copy link
Contributor

@kyrofa kyrofa Oct 30, 2017

Choose a reason for hiding this comment

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

You can fix LP: #1727445 right here by not doing this and handling both cases within Project.clean().

@sergiusens sergiusens added the Bug Actual bad behavior that don't fall into maintenance or documentation label Oct 30, 2017
@sergiusens sergiusens merged commit daca461 into canonical:master Oct 30, 2017
@sergiusens sergiusens mentioned this pull request Nov 1, 2017
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Actual bad behavior that don't fall into maintenance or documentation
Projects
17.10
Awaiting triage
Development

Successfully merging this pull request may close these issues.

None yet

4 participants