{"action":"created","issue":{"url":"https://api.github.com/repos/fabric/fabric/issues/237","labels_url":"https://api.github.com/repos/fabric/fabric/issues/237/labels{/name}","comments_url":"https://api.github.com/repos/fabric/fabric/issues/237/comments","events_url":"https://api.github.com/repos/fabric/fabric/issues/237/events","html_url":"https://github.com/fabric/fabric/issues/237","id":1437932,"number":237,"title":"Remote Python execution hooks","user":{"login":"bitprophet","id":6088,"avatar_url":"https://avatars.githubusercontent.com/u/6088?v=3","gravatar_id":"","url":"https://api.github.com/users/bitprophet","html_url":"https://github.com/bitprophet","followers_url":"https://api.github.com/users/bitprophet/followers","following_url":"https://api.github.com/users/bitprophet/following{/other_user}","gists_url":"https://api.github.com/users/bitprophet/gists{/gist_id}","starred_url":"https://api.github.com/users/bitprophet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bitprophet/subscriptions","organizations_url":"https://api.github.com/users/bitprophet/orgs","repos_url":"https://api.github.com/users/bitprophet/repos","events_url":"https://api.github.com/users/bitprophet/events{/privacy}","received_events_url":"https://api.github.com/users/bitprophet/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/fabric/fabric/labels/Contrib","name":"Contrib","color":"ededed"},{"url":"https://api.github.com/repos/fabric/fabric/labels/Feature","name":"Feature","color":"40a056"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":12,"created_at":"2011-08-19T01:59:23Z","updated_at":"2015-01-12T00:40:42Z","closed_at":null,"body":"### Description\r\n\r\nJust a placeholder that eventually, if people need the feature and it's easy enough to integrate / makes sense to integrate instead of just saying \"do it yourself, it's just Python\" -- we should consider making it easy to leverage tools for remote Python execution/RPC, such as:\r\n\r\n* [execnet](http://codespeak.net/execnet/)\r\n* [Pushy](http://blog.awilkins.id.au/2011/03/fabric-and-pushy-together-at-last.html) (link goes to blog entry specifically discussing integrating Fabric with it)\r\n* Pyro\r\n* [Salt](http://saltstack.org/)\r\n* [etc](http://wiki.python.org/moin/ParallelProcessing)\r\n\r\nOffhand I think the main draw would be to hook up your Fabric host/user/etc settings into such a tool. So probably something more along the lines of our Django contrib, instead of a core integration (especially since many users may not have Python remotely, so we absolutely would not want to *require* use of such a tool).\r\n\r\n----\r\n\r\nThe author of Pushy also mentions the possibility of using his tool in Fabric as a potential layer on top of Paramiko; I guess the same approach could be applied to the other tools as well.\r\n\r\nNot entirely sure if that would be a good way to go; plus is an eventual decoupling from SSH specifically; minus is that, well, we're pretty SSH specific in a lot of ways (and use a lot of core Paramiko stuff) and I'm not positive it would be worth the loss of focus.\r\n\r\n----\r\n\r\nOriginally submitted by **Jeff Forcier** ([bitprophet](https://github.com/bitprophet)) on **2010-09-20** at **11:43am EDT**\r\n\r\n### Relations\r\n\r\n* Duplicated by #246: Ability to easily remotely execute small Python snippets (rather than shell commands)\r\n"},"comment":{"url":"https://api.github.com/repos/fabric/fabric/issues/comments/69520142","html_url":"https://github.com/fabric/fabric/issues/237#issuecomment-69520142","issue_url":"https://api.github.com/repos/fabric/fabric/issues/237","id":69520142,"user":{"login":"antonylesuisse","id":641600,"avatar_url":"https://avatars.githubusercontent.com/u/641600?v=3","gravatar_id":"","url":"https://api.github.com/users/antonylesuisse","html_url":"https://github.com/antonylesuisse","followers_url":"https://api.github.com/users/antonylesuisse/followers","following_url":"https://api.github.com/users/antonylesuisse/following{/other_user}","gists_url":"https://api.github.com/users/antonylesuisse/gists{/gist_id}","starred_url":"https://api.github.com/users/antonylesuisse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/antonylesuisse/subscriptions","organizations_url":"https://api.github.com/users/antonylesuisse/orgs","repos_url":"https://api.github.com/users/antonylesuisse/repos","events_url":"https://api.github.com/users/antonylesuisse/events{/privacy}","received_events_url":"https://api.github.com/users/antonylesuisse/received_events","type":"User","site_admin":false},"created_at":"2015-01-12T00:40:42Z","updated_at":"2015-01-12T00:40:42Z","body":"This does the job if your functions are self contained:\r\n\r\n  def remotetask(f):\r\n      @wraps(f)\r\n      def wrapper():\r\n          c = 'python -c \"import marshal,types;types.FunctionType(marshal.loads(%r), globals(),%r)()\"'\r\n          c = c % (marshal.dumps(f.func_code),f.func_name)\r\n          run(c)\r\n      return fabric.tasks.WrappedCallableTask(wrapper)\r\n"}}