-
-
Notifications
You must be signed in to change notification settings - Fork 751
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
Common pack lib for sensors and actions #3658
Conversation
and actions are placed. | ||
|
||
For example, if the pack is at /opt/stackstorm/packs/my_pack, you can place | ||
common library code for actions and sensors in /opt/stackstorm/packs/my_pack/lib/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@lakshmi-kannan Great work! Import StyleI prefer With this import style, will python actions be able to reference this directory like so : Dependencies in requirementsYes, i plan on having common code reference dependencies defined in the pack's requirements.txt. Thank you very much for this feature! |
I would also prefer |
inherit_parent_virtualenv=True) | ||
pack_common_libs_path = get_pack_common_libs_path(pack_db=pack_db) | ||
|
||
env['PYTHONPATH'] = pack_common_libs_path + ':' + sandbox_python_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thinking out loud - is adding it to the front of the python path the right thing to do? :)
@@ -174,6 +174,7 @@ def _register_pack_db(self, pack_name, pack_dir): | |||
# Include a list of pack files | |||
pack_file_list = get_file_list(directory=pack_dir, exclude_patterns=EXCLUDE_FILE_PATTERNS) | |||
content['files'] = pack_file_list | |||
content['pack'] = pack_dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be pack
-> path
:D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I've the fix locally. Haven't pushed yet.
|
||
:rtype: ``str`` | ||
""" | ||
pack_dir = getattr(pack_db, 'path', None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess having this path here static is fine, although in other places we dynamically resolve entry point, etc.
@nmaludy That's why supporting it would be a pain. Plus, for remote SSH actions, we copy over actions/lib. I don't want people to get confused with that lib with this lib dir :). I'll document this but still this is going to be a source of confusions. Therefore, I am going to not support lib.base but allow modules in ${pack_dir}/lib/ to be imported by name like import foo (and not import lib.foo)
This would be strongly discouraged although this might work due to our implementation. "lib" folder is supposed to contain only common code that is then used in pythonic sensors and actions. Lib cannot contain actual st2 content. I am debating if I should rename lib to something like "common" to avoid confusions down the road. |
@lakshmi-kannan makes total sense as to the supportability and backwards compatibility of existing code. Although I prefer the name lib/, I like the idea of renaming it to common/ to avoid confusion. When you say "lib cannot contain actual st2 content", does this mean it cannot contain action and sensor code? Will the code in lib/ still be able to access st2 functions like the pack's config and the key/value store? One final question, will lib/ require an init.py file to work? |
Code in lib/ cannot call functions in action or sensor. This would be poor code design IMO. Code in lib/ can be called by both sensor and action. That's why it's called "lib". I assume data mangling functions, common client library code not pushed to pypi etc, common utility functions will go in files in lib. We will not support calling sensor or action code in lib. We can never do that with the way we isolate the sanboxed env for actions and sensors.
I can see this can be useful down the road but the initial pass will not address this. This is a complete feature by itself and I won't take it on in my first pass here.
Yes, I answered this already somewhere but yes, lib should a python package. Otherwise, imports won't work. |
* master: Remove debugging 'docker ps' Add clarifying comments about the Docker cleanup Remove any created Docker volumes before and after build
@Kami @lakshmi-kannan are we going to include this change as part of |
@lakshmi-kannan I'm fine if we can document it. And ideally, if we can also make it fail loudly in scenarios like that (but that might not be possible, at least easily - would need to dig in to say for sure though). |
@Kami Here is an example of how it breaks
If we want to do runtime check, this is going to be hard. Maybe we can add this to the linter to stop people from doing this? |
I think having a linter or similar would be hard, because we would probably manually keep a list of the "reserved" / system module names. So I'm not aware of any easy solution besides namespacing / prefixing user modules with lib. or similar. The more problematic thing is that it's not just stdlib package / module names, but any package / module which is available in the virtualenv which could make it quite annoying and action developers would need to get quite creative with the names. |
@Kami and I discussed this in slack. In conclusion, a lot of packs already have a 'lib' folder and do imports like from lib.action import foo. By merging this PR, we will break things I think. It's better to not merge this until we can confirm we won't break existing packs that use "lib". |
Yeah, sadly this feature is a lot more complicated then we would hope for - if we continued with the current approach it has a potential to break existing code (potentially in obscure manner which would cause unnecessary confusion and bad UX). Only good option we can think of is namespacing the imports - e.g. something like The problem with the name spacing is that they are two ways to achieve it:
I'm strongly against the first approach. The code should also work if user runs it outside StackStorm environment (possible to re-use it, easier to develop and troubleshoot, etc.). Second approach would mean it only works with new code and packs which are also Python packages. I'm fine with that, the problem is that now package root would also need to contain |
@Kami I created this pack to test our theory that these changes might break if actions and sensors have "lib" folder inside them. I was thinking it shouldn't and it looks like it doesn't. Here is a sample pack https://github.com/lakshmi-kannan/lib_test with a pack level lib folder and a lib folder inside sensors/ and actions/. Both actions and sensors import from pack lib and lib folders inside actions/ and sensors/ respectively. The sensor runs fine and also the actions. I verified that there are no import issues. I'll scan exchange and see if there are any other type of imports I need to test. Also, I'll port these tests to st2tests. Summary: Looks like there is still hope! |
@@ -106,3 +106,6 @@ pack_group = stanley | |||
[mistral] | |||
v2_base_url = http://127.0.0.1:8989/v2 | |||
jitter_interval = 0 | |||
|
|||
[packs] | |||
enable_common_libs = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have [system]
where we have other packs related options there so there are some inconsistencies.
Anyway, I'm fine with this for now.
conf/st2.conf.sample
Outdated
@@ -292,3 +292,6 @@ local_timezone = America/Los_Angeles | |||
# Base https URL to access st2 Web UI. This is used to constructhistory URLs that are sent out when chatops is used to kick off executions. | |||
webui_base_url = https://localhost | |||
|
|||
[packs] | |||
# Enable/Disable support for pack common libs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs some clarification and link to the docs.
* master: (68 commits) Re-generate requirements.txt file. Add missing empty requirements.txt files. Update runner stevedore metadata and use actual runner name from runner.yaml for stevedore extension / driver name instead of using the Python module name. Add a changelog entry. Add changelog entry. Upgrade various Python deps to latest stable versions. Move import to reduce import time. Fix performance regression and move imports in-line to avoid import overhead (400+ms). Add functions for retrieving a list of dynamically registered runners. Add BACKENDS_NAMESPACE constant so it's consistent with auth backends. Add missing requirements.txt to action chain runner. Add "get_metadata()" function to each runner module, make sure we include runner.yaml as part of module data, add missing __all__ definitions. Add stevedore entrypoint metadata to each runner Python package setup.py file. Update changelog. Add changelog entry for #3802. Add changelog entry for #3810. Add a docstring. Mock action has no _log_level property, make code more robust. Fix lint. Add a changelog entry. ...
@@ -105,7 +109,8 @@ def pre_run(self): | |||
def run(self, action_parameters): | |||
LOG.debug('Running pythonrunner.') | |||
LOG.debug('Getting pack name.') | |||
pack = self.get_pack_name() | |||
pack = self.get_pack_ref() | |||
pack_db = Pack.get_by_ref(pack) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess there could be some races now - e.g. when pack is being removed and the model is removed first, but then again, we can't really guarantee proper behavior during pack removal process anyway.
pack_common_libs_path = get_pack_common_libs_path(pack_db=pack_db) | ||
|
||
if self._enable_common_pack_libs and pack_common_libs_path: | ||
env['PYTHONPATH'] = pack_common_libs_path + ':' + sandbox_python_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please also add some unit tests which assert on the actual PYTHONPATH
for various scenarios (libs path is enabled, disabled, etc.)?
If they are already there, please ignore my comment, but I didn't see any. I only see st2tests
test, but it only seems to be testing one code path (common libs enabled). Should be straight forward to add a unit test - Python runner action can just print PYTHONPATH and we can assert on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in ce6fb89
* master: Use Python's built-in '==' instead of rolling our own dictionary equality check function Add changelog entry for #3833. Add a unit test which verifies that runner container correctly scopes temporary auth token to the user which ran the action. Add tests for filtering with the search operator Add tests for new payload module Correct a few failure messages in test assertions Add tests for operators where criteria_pattern is None Add tests for get_operator and get_allowed_operators Add unit tests for search operator Add a 'search' operator to the rules engine, and move PayloadLookup into its own module: st2common.util.payload
* master: (33 commits) Fix "liveactions" vs "executions" manager naming mismatch & add example Add return, remove now obsolete tests. Update st2 whoami CLI command to also include auth token expire time. Update /api/v1/user API endpoint to also include information about token expiration time in case user authenticated via auth token. Use numeric constants. Update pack.yaml Minor edit to changelog entry Add "datastore_service" property to sensor service so it has a consistent api with the action service. Fix lint. Update 'st2 whoami' CLI command to utilize new /api/v1/user API endpoint. Update CHANGELOG.rst Add clarifying comment. Move sleep to the right place. Add sleep to avoid race. Add changelog entry. Add tests for the mock service methods. Add method wrappers on the action and sensor service. Also add get_user_info method to the corresponding mock class. Add new get_user_info method to datastore service. Change controller and API endpoint path from whoami to user. ...
* master: (25 commits) Add script for listing available / installed action runners. Add period at the end of sentence in CHANGELOG Update copyright date. To avoid package naming conflicts, rename inquirery runner module and package from just "inquirer" to "inquirer". Add "stackstorm-runner-" prefix to all the Package names for action runners. Update changelog entry. Update more of the affected tests to use new, non-deprecated paths. Fix some of the affected tests. Add make target for running just the runners tests. Update affected runner tests. Update affected tests. Update __all__. Update runner registration code so it also supports new runner module locations. Throw a more user friendly exception. Make sure we correctly include runner.yaml file in the final package. Make all action runners proper Python packages. Soft-retrieve schema, and check to ensure it's not empty before masking Force key lookup for schema in mask_secrets Ensure executions API properly masks inquiry responses Use MASKED_ATTRIBUTE_VALUE in lieu of string literals ...
Python and other runners were refactored to be fully standalone and not require db connection, but #3658 PR inadvertently introduced DB dependency. This PR works around that by only retrieving PackDB object from the database if common libs functionality is enabled and ignore database related errors. Note: Common lib functionality is a new feature and is not needed on AWS Lambada.
closes: #3490, closes: #2220
Example
Common lib code in /opt/stackstorm/packs/examples/lib/
Using the common lib code in an action
TODO
Feedback needed
As you can see in the action consuming the lib, the import line looks so
from base import get_environ
I want all the feature requesters like @andrew-regan @ytjohn @nmaludy to weigh in on if this works for them or do they need something like
from lib.base import get_environ
I think this should work the way we have done sandboxing but I want to know if this is something you really want it to work?