Skip to content

Conversation

@strickvl
Copy link
Contributor

@strickvl strickvl commented Apr 4, 2022

I added functionality to allow users to update stacks that already exist. This shows the basic workflow:

zenml orchestrator register local_orchestrator2 -t local
zenml stack update default -o local_orchestrator2
zenml stack describe default
zenml container-registry register local_registry --type=default --uri=localhost:5000
zenml container-registry update local --uri='somethingelse.com'
zenml container-registry rename local local2
zenml container-registry describe local2
zenml stack rename default new_default
zenml stack update new_default -c local2
zenml stack describe new_default
zenml stack remove-component -c

More details are in the CLI docs (updated as part of this PR). Users can add new stack components to a pre-existing stack, or they can modify already-present stack components. They can also rename their stack and individual stack components.

Remaining tasks:

  • Add REST stack store functionality
  • Remove / refactor out helper function written for test_stack_store which is causing wonky functionality
  • Update CLI docs to add component update and rename functionality

Pre-requisites

Please ensure you have done the following:

  • I have read the CONTRIBUTING.md document.
  • If my change requires a change to docs, I have updated the documentation accordingly.
  • If I have added an integration, I have updated the integrations table.
  • I have added tests to cover my changes.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Other (add details above)

@strickvl strickvl added enhancement New feature or request internal To filter out internal PRs and issues labels Apr 4, 2022
@strickvl strickvl requested review from jwwwb and schustmi April 4, 2022 13:35
Copy link
Contributor

@schustmi schustmi left a comment

Choose a reason for hiding this comment

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

Nice work! Only left a few small comments

Comment on lines 345 to 358
def __check_component(
component: StackComponentWrapper,
) -> Tuple[StackComponentType, str]:
try:
_ = self.get_stack_component(
component_type=component.type, name=component.name
)
except KeyError:
self.register_stack_component(component)
return component.type, component.name

stack_configuration = {
typ: name for typ, name in map(__check_component, stack.components)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can extract this common code from both registering and updating a stack into some separate function that both of them can call?

Copy link
Contributor

@jwwwb jwwwb left a comment

Choose a reason for hiding this comment

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

Oops, I wrote a few comments but forgot to submit the review. Looks good, just have a few small ideas that could be changed.

try:
current_stack = repo.get_stack(stack_name)
except KeyError as e:
console.print(
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this also return from the function? It seems like all the stack_components key access below will fail

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'll just raise a cli_utils.error instead of printing. Good catch.

@abstractmethod
def update_stack_component(
self,
current_component: StackComponentWrapper,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is all unimplemented, Maybe consider leaving it out? But if it does stay in, I think the function signature should not take 2 StackComponentWrappers, but rather a type and name of the component to update, and a wrapper to update it with (same signature as the create stack component)

)


def test_updating_a_new_stack_with_already_registered_components(clean_repo):
Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest maybe testing in the stack store tests, because those are parameterized to test every implementation, whereas this will only test the yaml version I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I've moved it over.

@strickvl strickvl changed the title Update stack components via the CLI Update stack and stack components via the CLI Apr 12, 2022
@strickvl strickvl requested review from schustmi and stefannica and removed request for htahir1 April 25, 2022 14:33
stack_components = current_stack.components

if container_registry_flag:
stack_components = {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could also be solved by a stack_components.pop(StackComponentType.CONTAINER_REGISTRY, None) as well to make it a little shorter. That will also remove a key-value pair from a dictionary in case a value for that key exists.

)
stack_components = current_stack.components

registered_stacks = [stack.name for stack in repo.stacks]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
registered_stacks = [stack.name for stack in repo.stacks]
registered_stacks = {stack.name for stack in repo.stacks}

I would suggest using a set here as it makes conceptually more sense for a lookup

command_group.command(
"update",
context_settings=context_settings,
help=f"Update a new {singular_display_name}.",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
help=f"Update a new {singular_display_name}.",
help=f"Update a registered {singular_display_name}.",

Comment on lines 348 to 351
registered_components = [
component.name
for component in repo.get_stack_components(component_type)
]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
registered_components = [
component.name
for component in repo.get_stack_components(component_type)
]
registered_components = {
component.name
for component in repo.get_stack_components(component_type)
}

for prop in required_properties:
if prop not in parsed_args:
parsed_args[prop] = getattr(current_component, prop)
updated_component = component_class(name=name, **parsed_args)
Copy link
Contributor

Choose a reason for hiding this comment

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

If the component.update worked in the rename method, it might be worth trying it here as well like this:

updated_component = current_component.copy(update=parsed_args)

self._delete_stack_component(component_type, name)

# add the component to the stack store dict and write it to disk
components[component.name] = component.flavor
Copy link
Contributor

Choose a reason for hiding this comment

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

I know that you're already checking for the case that a component exists in the CLI methods (and I definitely think it should be there with a CLI error message), however I think we should have it here as well. Users (or us) might still call this function directly in which case we would just overwrite the existing one without noticing. Maybe a StackComponentExistsError?

try:
self.get_stack(name)
except KeyError:
raise DoesNotExistException(
Copy link
Contributor

Choose a reason for hiding this comment

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

I would keep this as a KeyError (and get rid of the DoesNotExistException entirely) as we use that in all other cases as well.

except KeyError:
self.register_stack_component(component)
return component.type, component.name

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as the stack component, I think we should still have a check here if something with the new name already exists. Probably a StackExistsError?

component_type,
component.name,
)
# tc = session.exec(
Copy link
Contributor

Choose a reason for hiding this comment

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

Can probably be removed? Similar to the local store, I think we should handle a component with that name already existing

session.add(stack)
stack = session.exec(
select(ZenStack).where(ZenStack.name == name)
).first()
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to the local store, I think we should handle a stack with that name already existing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I think this is now handled.

@strickvl
Copy link
Contributor Author

@schustmi Addressed your comments in these latest commits.

@strickvl strickvl requested a review from schustmi April 25, 2022 19:25
Copy link
Contributor

@schustmi schustmi left a comment

Choose a reason for hiding this comment

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

This PR was great a few iterations ago already and it got even better!

Copy link
Contributor

@stefannica stefannica left a comment

Choose a reason for hiding this comment

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

Awesome work ! Thanks so much for considering my suggestions.

f"found with this name."
)
elif name != component.name and component.name in components:
breakpoint()
Copy link
Contributor

Choose a reason for hiding this comment

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

You forgot a breakpoint here :)

@strickvl strickvl merged commit 54181d0 into develop Apr 26, 2022
@strickvl strickvl deleted the feature/ENG-480-update-stack-components branch April 26, 2022 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request internal To filter out internal PRs and issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants