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

Modify API to remove related files on delete of actions/workflows #5304

Merged
merged 61 commits into from Aug 17, 2021

Conversation

mahesh-orch
Copy link
Contributor

@mahesh-orch mahesh-orch commented Jul 15, 2021

This change is to remove related files of actions/workflows from disk when API called from CLI and web UI (StackStorm/st2web#898). Currently when this delete API is invoked then this only de-register the actions from database and when user reloads the st2 then these actions get registered into database again.

@mahesh-orch mahesh-orch changed the title Modifying API to remove related files on delete of actions/workflows Modify API to remove related files on delete of actions/workflows Jul 15, 2021
@nzlosh
Copy link
Contributor

nzlosh commented Jul 15, 2021

What issue does this PR relate to?

This is a big conceptual shift to StackStorm as a whole since the API does not create/modify or delete files in a pack because it is not authoritative, git is. This change would break the fundamental premise of infrastructure as code and would have changes reverted on the next package upgrade creating a lot of confusion for the lay user.

@amanda11
Copy link
Contributor

amanda11 commented Jul 15, 2021

I think this is related to adding delete functionality into the UI, so the reverse of the workflow composer + that creates a new workflow on disk and in the live pack.
I've not reviewed the code, but I believe that is the context...

However altering the current behaviour of the endpoint might not be the best course of action, as those already using the DELETE endpoint might rely on the fact it deletes from memory and not disk. So I wonder if it should have at least a new parameter to the call that the UI calls, that allows the default behaviour to be unchanged.

The create does at the moment creates files if its passed the data_files parameter - which I presume is sent from the UI.

Copy link
Contributor

@blag blag left a comment

Choose a reason for hiding this comment

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

A few nitpicks that need to be cleaned up.

Also, this code will explode if two different worker processes try to remove the same pack at almost the same time, or if the process cannot remove the files for some reason (eg: permissions issues). Please wrap them in a try/catch block to ignore exceptions where the file is already deleted, and to write a log error if the process doesn't have permission to delete the file.

st2api/st2api/controllers/v1/actions.py Outdated Show resolved Hide resolved
st2api/st2api/controllers/v1/actions.py Outdated Show resolved Hide resolved
@blag
Copy link
Contributor

blag commented Jul 15, 2021

Just (hopefully) clarify a few points here.

This is a big conceptual shift to StackStorm as a whole since the API does not create/modify or delete files in a pack because it is not authoritative, git is.

This is true, but removing the entire pack directory, .git/ and all, is the ultimate authoritative action.

I think this is related to adding delete functionality into the UI, so the reverse of the workflow composer + that creates a new workflow on disk and in the live pack.

As far as I'm aware, the workflow composer does not write the action metadata and workflow file out to disk, it only stores them in the database.

The overall problem here is that StackStorm allows workflows to be created three different ways:

  1. Installed as part of a pack installed via infrastructure-as-code, like in a build pipeline, Dockerfile, Packer script, etc.
  2. Installed as part of a pack installed by a ST2 worker, as part of the packs.install action.
  3. Created manually in the workflow composer/designer.

File management is one of the integration points that the workflow composer/designer lacks.

@amanda11
Copy link
Contributor

amanda11 commented Jul 15, 2021

@blag - agree with most of your points.

I am pretty sure it does write to disk on the composer. It certainly updates the files on edit - as have copied the modified files from the "live" file system to my gitrepo before.

There is logic in the modified file to write the data files out on the api create.

# Write pack data files to disk (if any are provided)
data_files = getattr(action, "data_files", [])
written_data_files = []
if data_files:
written_data_files = self._handle_data_files(
pack_ref=action.pack, data_files=data_files
)

Rules - get written directly to database and not to file (by the UI), but I believe workflows get written to disk and to database - which is inconsistent!!!

@m4dcoder
Copy link
Contributor

m4dcoder commented Jul 15, 2021

This is related to delete of action/workflows in general. The current delete operation via API (invoked from CLI or UI related to StackStorm/st2web#898) just deletes the database registration. If operator does a reload, the action/workflow that was deleted just gets registered to the database again.

If user manages infra and packs with codes, I don't think this affects or changes that paradigm. They can still manage and load packs and actions thru git, puppet, chef, containers, or which ever way they automate their infra.

The target audiences for this change here are mostly action/workflow developers that is using an instance of StackStorm for development to delete an action/workflow.

For consistency sake, I would suggest making changes so that rule creation also writes content to disk.

Copy link
Contributor

@m4dcoder m4dcoder left a comment

Choose a reason for hiding this comment

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

@mahesh-orch

  • Please update the description. The description should explain why you are making this change and how is the change going to work.
  • Please make sure there are unit tests that cover the change.
  • Can we add a confirmation prompt in the CLI to let user know that the operation will delete files and user can OK or back out of the operation?

mahesh-orch and others added 3 commits July 16, 2021 10:22
Co-authored-by: blag <blag@users.noreply.github.com>
Co-authored-by: blag <blag@users.noreply.github.com>
@mahesh-orch
Copy link
Contributor Author

A few nitpicks that need to be cleaned up.

Also, this code will explode if two different worker processes try to remove the same pack at almost the same time, or if the process cannot remove the files for some reason (eg: permissions issues). Please wrap them in a try/catch block to ignore exceptions where the file is already deleted, and to write a log error if the process doesn't have permission to delete the file.

Sure, I will do the suggested changes. Thanks.

@mahesh-orch
Copy link
Contributor Author

@m4dcoder Sure, I will write the unit test to cover the made changes. And I will also work on asking for confirmation prompt in the CLI to let user know removal of files to proceed with users agreement or to back out the operation. Thanks

@mahesh-orch mahesh-orch reopened this Jul 16, 2021
@amanda11
Copy link
Contributor

@m4dcoder if we are going to issue a warning on the CLI and print for confirmation, could we also add a --yes or similar so that you can confirm it on the command line - to make it easier for anyone scripting the cli calls.

Added try except block for handling PermissionError while removing action files from disk. Also, code is added for logging errors.
Added code to add a confirmation prompt in CLI to let user know that the operation will delete files on disk as well. If user says OK then to proceed otherwise to back out the operation.
@mahesh-orch
Copy link
Contributor Author

@blag I have added try except block for handling PermissionError while removing action files from disk. Also, code is added for logging errors. Please review. Thanks.

@mahesh-orch
Copy link
Contributor Author

mahesh-orch commented Jul 19, 2021

@m4dcoder I have added code to add a confirmation prompt in CLI to let user know that the operation will delete files on disk as well. If user says OK then to proceed otherwise to back out the operation. Please review. Thanks.

@@ -735,16 +736,29 @@ def __init__(self, resource, *args, **kwargs):
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
instance = self.get_resource(resource_id, **kwargs)
self.manager.delete(instance, **kwargs)
if isinstance(instance, st2client.models.action.Action):
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to have a cli argument like --yes so that it is possible to delete actions within having to give input. This makes it much easier for anyone using st2 cli in scripts.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, giving the option -y or --yes makes this scriptable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, you should move this changes to the ActionDeleteCommand at https://github.com/StackStorm/st2/blob/master/st2client/st2client/commands/action.py#L280 instead of using if isinstance to check if this resource is an Action.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@amanda11 Sure, I will add functionality to have CLI argument --yes or -y. Thanks.

Copy link
Contributor

@m4dcoder m4dcoder left a comment

Choose a reason for hiding this comment

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

Where are the unit tests?

)
action_metadata_file_path = os.path.join(
BASE_PATH, "packs", pack_name, metadate_file
)
Copy link
Contributor

Choose a reason for hiding this comment

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

The pack base path can be overridden (ref: https://docs.stackstorm.com/packs.html#under-the-hood-pack-basics). Therefore, it is better to use get_pack_base_path @ https://github.com/StackStorm/st2/blob/master/st2common/st2common/content/utils.py#L135 to determine the pack file path.

action_metadata_file_path,
e,
)

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you create a function at https://github.com/StackStorm/st2/blob/master/st2common/st2common/services/packs.py to delete the action entrypoint and action metadata files? Move the path calculation that you did above into this function as well.

@@ -735,16 +736,29 @@ def __init__(self, resource, *args, **kwargs):
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
instance = self.get_resource(resource_id, **kwargs)
self.manager.delete(instance, **kwargs)
if isinstance(instance, st2client.models.action.Action):
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, giving the option -y or --yes makes this scriptable.

@@ -735,16 +736,29 @@ def __init__(self, resource, *args, **kwargs):
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
instance = self.get_resource(resource_id, **kwargs)
self.manager.delete(instance, **kwargs)
if isinstance(instance, st2client.models.action.Action):
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, you should move this changes to the ActionDeleteCommand at https://github.com/StackStorm/st2/blob/master/st2client/st2client/commands/action.py#L280 instead of using if isinstance to check if this resource is an Action.

Moving path calculations and action file remove related code to st2common/services/packs.py
Added `--y` option for action delete command at CLI to make command scriptable
Unit test for newly added code in /st2common/services/packs.py
@mahesh-orch
Copy link
Contributor Author

@blag

@mahesh-orch
Copy link
Contributor Author

mahesh-orch commented Aug 11, 2021

@amanda11 CHANGELOG for modify action delete API has moved to your suggested location. Please review. Thanks.

@mahesh-orch
Copy link
Contributor Author

@cognifloyd The try/except blocks have been placed one after another instead of nesting as per your suggestion. I had made the changes according to @m4dcoder's suggestions. Docstrings are added in test classes to clear specificness of the unit tests in st2common/tests/unit/services/test_packs.py. Please review. Thanks.

Copy link
Contributor

@amanda11 amanda11 left a comment

Choose a reason for hiding this comment

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

Thanks for the updates - my points have all been addressed. Much appreciated.


# asserting delete_action_files_from_pack function raises exception
with self.assertRaises(Exception):
delete_action_files_from_pack(TEST_PACK, entry_point, metadata_file)
Copy link
Contributor

Choose a reason for hiding this comment

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

@mahesh-orch You missed this one I think

Copy link
Contributor

@blag blag left a comment

Choose a reason for hiding this comment

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

I would make some changes, but it's nothing serious.

action_metadata_file_path,
e,
)
if os.path.isfile(action_metadata_file_path):
Copy link
Contributor

Choose a reason for hiding this comment

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

This check is probably redundant, since if os.remove() fails it will throw some sort of exception.

e,
)
if os.path.isfile(action_metadata_file_path):
msg = 'The action file "{0}" could not be removed from disk, please check the logs or ask your StackStorm administrator to check and delete the actions files manually'.format(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm kind of surprised our linting is not catching this long line.

action_entrypoint_file_path,
e,
)
msg = 'The action file "{0}" could not be removed from disk, please check the logs or ask your StackStorm administrator to check and delete the actions files manually'.format(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm kind of surprised that our linting is not catching this long line.

@mahesh-orch
Copy link
Contributor Author

@blag I have done your suggested changes. Also, done similar changes in other files. Please review.

@m4dcoder m4dcoder merged commit 854d352 into StackStorm:master Aug 17, 2021
@m4dcoder m4dcoder deleted the modify_action_delete_api branch August 17, 2021 19:04
@nzlosh
Copy link
Contributor

nzlosh commented Aug 30, 2021

This PR failed to provide sufficient options to remove a database entry without touching the files on disk

--force assumes yes to delete the file. Yet, if you want to only remove the database entry and not touch the contents on disk, you must do it interactively. The force option must take an argument of force yes/no so that non interactive shell commands can be run.

Going on step further, why break existing behaviour when we don't have to? Remove the --force option, and create the option --remove-files instead. This way existing scripts that expect the database entry to be removed will continue to work. Any new scripts that are developed that would like to delete the file from disk can provide the remove-files flag.

@nzlosh
Copy link
Contributor

nzlosh commented Aug 30, 2021

Digging into this change a little more:

I triggered a corner case that isn't handled correctly. If there is a file access error, the database entry is deleted, leaving St2 in an inconsistent state. This operation should be atomic, if the file was requested to be removed and it fails, the database entry should not be removed.

root@u1804:/opt/stackstorm/packs/mongodb# st2 action delete mongodb.user_actionx
The resource files on disk will be deleted. Do you want to continue? (y/n): y
ERROR: 500 Server Error: Internal Server Error
MESSAGE: No permission to delete "/opt/stackstorm/packs/mongodb/actions/user_actionx.py" file from disk for url: http://127.0.0.1:9101/v1/actions/612cf0f24d30afa26ef56b88

Files user_actionx.py and user_actionx.yaml are still present in the pack.

root@u1804:/opt/stackstorm/packs/mongodb# ls actions/
collection_create.py    collection_delete.yaml  database_create.py    database_delete.yaml  lib              user_actionx.yaml  user_delete.py    user_update.yaml
collection_create.yaml  collection_list.py      database_create.yaml  database_list.py      __pycache__      user_create.py     user_delete.yaml  workflows
collection_delete.py    collection_list.yaml    database_delete.py    database_list.yaml    user_actionx.py  user_create.yaml   user_update.py

However, the action user_actionx is gone from the database.

root@u1804:/opt/stackstorm/packs/mongodb# st2 action list --pack=mongodb
+---------------------------+---------+--------------------------------------------------+
| ref                       | pack    | description                                      |
+---------------------------+---------+--------------------------------------------------+
| mongodb.collection_delete | mongodb | Delete a collection in a database.               |
| mongodb.collection_list   | mongodb | List the available collections for the database. |
| mongodb.database_create   | mongodb | Create a database on a mongo server              |
| mongodb.database_delete   | mongodb | List the available collections for the database. |
| mongodb.database_list     | mongodb | List the available databases in a mongo server   |
| mongodb.user_create       | mongodb | Create a mongodb user account                    |
| mongodb.user_delete       | mongodb | Delete an existing database user.                |
| mongodb.user_update       | mongodb | Update an existing database user account.        |
+---------------------------+---------+--------------------------------------------------+

@cognifloyd
Copy link
Member

The opposite applies for the default stackstorm-ha install where the packs filesystem is read-only, so deletes should only affect the db.
Maybe we need a system-wide setting in /etc/st2/st2.conf to enable/disable deleting files.

@nzlosh
Copy link
Contributor

nzlosh commented Aug 30, 2021

I assume you mean for kubernetes. I run StackStorm HA on VMs and the packs are not on read-only filesystems. Regardless of which environment St2 is being run on, the code should be able to handle the situation in a generic and coherent way.

@nzlosh
Copy link
Contributor

nzlosh commented Aug 31, 2021

@mahesh-orch @m4dcoder Please open a new PR to address the issues mentioned above. As it stands, this change prevents removing just the database entry.

@amanda11
Copy link
Contributor

Could we get an issue raised and assign it to 3.6 milestone and 3.6 release project?
I think we can't release without a change as this will mean it's impossible to do a st2 delete without an error raised on the Kubernetes HA with it in the current state.

The idea of making it configurable in st2.conf could address most of the issues,and probably requires changes to both api and cli and doc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/L PR that changes 100-499 lines. Requires some effort to review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants