{"action":"created","comment":{"url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/comments/39962390","id":39962390,"diff_hunk":"@@ -0,0 +1,28 @@\n+class ProxyLoadBalancer\n+  def initialize\n+    all_proxies = SmartProxy.unscoped.with_features(RemoteExecutionProvider.providers.keys)\n+    @jobs = get_counts(all_proxies)\n+  end\n+\n+  # Get the least loaded proxy from the given list of proxies\n+  def next(proxies)\n+    ids = proxies.map(&:id)\n+    proxy = @jobs.reject { |id, _| !ids.include?(id) }.min_by { |_, job_count| job_count }.first","path":"app/services/proxy_load_balancer.rb","position":10,"original_position":10,"commit_id":"fb3e72260fda00d37e347a8d434e0e710cf53ace","original_commit_id":"fb3e72260fda00d37e347a8d434e0e710cf53ace","user":{"login":"iNecas","id":190443,"avatar_url":"https://avatars.githubusercontent.com/u/190443?v=3","gravatar_id":"","url":"https://api.github.com/users/iNecas","html_url":"https://github.com/iNecas","followers_url":"https://api.github.com/users/iNecas/followers","following_url":"https://api.github.com/users/iNecas/following{/other_user}","gists_url":"https://api.github.com/users/iNecas/gists{/gist_id}","starred_url":"https://api.github.com/users/iNecas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iNecas/subscriptions","organizations_url":"https://api.github.com/users/iNecas/orgs","repos_url":"https://api.github.com/users/iNecas/repos","events_url":"https://api.github.com/users/iNecas/events{/privacy}","received_events_url":"https://api.github.com/users/iNecas/received_events","type":"User","site_admin":false},"body":"`select { |proxy, _| proxies.include?(proxy) }` would be bit more natural (both using the proxy as key and using select instead of reject here)","created_at":"2015-09-21T11:53:53Z","updated_at":"2015-09-21T11:53:53Z","html_url":"https://github.com/theforeman/foreman_remote_execution/pull/33#discussion_r39962390","pull_request_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33","_links":{"self":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/comments/39962390"},"html":{"href":"https://github.com/theforeman/foreman_remote_execution/pull/33#discussion_r39962390"},"pull_request":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33"}}},"pull_request":{"url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33","id":44020676,"html_url":"https://github.com/theforeman/foreman_remote_execution/pull/33","diff_url":"https://github.com/theforeman/foreman_remote_execution/pull/33.diff","patch_url":"https://github.com/theforeman/foreman_remote_execution/pull/33.patch","issue_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/33","number":33,"state":"open","locked":false,"title":"fixes #11554, #11827 - execution proxy through subnet, with load balancing","user":{"login":"stbenjam","id":429763,"avatar_url":"https://avatars.githubusercontent.com/u/429763?v=3","gravatar_id":"","url":"https://api.github.com/users/stbenjam","html_url":"https://github.com/stbenjam","followers_url":"https://api.github.com/users/stbenjam/followers","following_url":"https://api.github.com/users/stbenjam/following{/other_user}","gists_url":"https://api.github.com/users/stbenjam/gists{/gist_id}","starred_url":"https://api.github.com/users/stbenjam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stbenjam/subscriptions","organizations_url":"https://api.github.com/users/stbenjam/orgs","repos_url":"https://api.github.com/users/stbenjam/repos","events_url":"https://api.github.com/users/stbenjam/events{/privacy}","received_events_url":"https://api.github.com/users/stbenjam/received_events","type":"User","site_admin":false},"body":"## Background\r\n\r\nCurrently, when you schedule an action, we determine the proxy to handle the request by some magic, in the following order:\r\n\r\n1. We look at all the proxies attached to the host (Puppet, TFTP, DNS) and see if any have remote execution features we're looking for.  We take the first we find.\r\n\r\n1. If you enable the setting `remote_execution_global_proxy`, and we don't find a proxy on the Host, we'll expand our search to all proxies.\r\n\r\n1. If nothing is found, fail for that host.\r\n\r\nThis works, but we need some more granular control over this in order to be deterministic in the proxies we choose in multi-proxy environments, and account for complex networking setups. We want to do it without making the user's life too difficult. \r\n\r\n## Execution Interface\r\n\r\nThis PR adds the concept of an \"Execution Interface.\"  New hosts will automatically get one, and you can change it to be a different interface if desired:\r\n\r\n![newhost](https://cloud.githubusercontent.com/assets/429763/9638100/8e8e52f4-5172-11e5-9703-0d9516706feb.gif)\r\n\r\nThe proxy to use is determined through the subnet assigned to the execution interface. You can actually assign *multiple* remote execution providers.  This buys us a nice way to have load balancing / HA..\r\n\r\n![subnet](https://cloud.githubusercontent.com/assets/429763/9638231/8054b650-5173-11e5-94a7-7606c7583ec5.png)\r\n\r\n### New Work Flow\r\n\r\nThe new process for determining the remote execution proxy:\r\n\r\n1. If the host has an execution interface with a subnet, then we use the proxies associated to that subnet, if any.\r\n\r\n1. Same as 1 above, except now gated by a new setting: `remote_execution_fallback_proxy`\r\n\r\n1. Same as 2 above\r\n\r\n1. Same as 3 above\r\n\r\n## Load Balancing / HA\r\n\r\nThis is not yet implemented, bu we'll round robin load balance requests across the smart proxies for that subnet.  \r\n\r\n## Some questions\r\n\r\n1. How does this setup feel from a usability perspective? Any suggestions?\r\n\r\n1. Should you *also* be able to assign remote execution proxies directly to hosts? The default action would always be inherit from subnet, but a user could want in some cases some one-off overrides.\r\n\r\n1. Are there environments where this setup will not work well?\r\n\r\n1. Any concerns about integration with Katello?\r\n\r\n","created_at":"2015-09-02T17:40:26Z","updated_at":"2015-09-21T11:53:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"342431df79e78c41b660663c2beb8b348a5296f2","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33/commits","review_comments_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33/comments","review_comment_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/comments{/number}","comments_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/33/comments","statuses_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/statuses/fb3e72260fda00d37e347a8d434e0e710cf53ace","head":{"label":"stbenjam:execnic","ref":"execnic","sha":"fb3e72260fda00d37e347a8d434e0e710cf53ace","user":{"login":"stbenjam","id":429763,"avatar_url":"https://avatars.githubusercontent.com/u/429763?v=3","gravatar_id":"","url":"https://api.github.com/users/stbenjam","html_url":"https://github.com/stbenjam","followers_url":"https://api.github.com/users/stbenjam/followers","following_url":"https://api.github.com/users/stbenjam/following{/other_user}","gists_url":"https://api.github.com/users/stbenjam/gists{/gist_id}","starred_url":"https://api.github.com/users/stbenjam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stbenjam/subscriptions","organizations_url":"https://api.github.com/users/stbenjam/orgs","repos_url":"https://api.github.com/users/stbenjam/repos","events_url":"https://api.github.com/users/stbenjam/events{/privacy}","received_events_url":"https://api.github.com/users/stbenjam/received_events","type":"User","site_admin":false},"repo":{"id":38254757,"name":"foreman_remote_execution","full_name":"stbenjam/foreman_remote_execution","owner":{"login":"stbenjam","id":429763,"avatar_url":"https://avatars.githubusercontent.com/u/429763?v=3","gravatar_id":"","url":"https://api.github.com/users/stbenjam","html_url":"https://github.com/stbenjam","followers_url":"https://api.github.com/users/stbenjam/followers","following_url":"https://api.github.com/users/stbenjam/following{/other_user}","gists_url":"https://api.github.com/users/stbenjam/gists{/gist_id}","starred_url":"https://api.github.com/users/stbenjam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stbenjam/subscriptions","organizations_url":"https://api.github.com/users/stbenjam/orgs","repos_url":"https://api.github.com/users/stbenjam/repos","events_url":"https://api.github.com/users/stbenjam/events{/privacy}","received_events_url":"https://api.github.com/users/stbenjam/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stbenjam/foreman_remote_execution","description":"A plugin bringing remote execution to the Foreman, completing the config management functionality with remote management functionality","fork":true,"url":"https://api.github.com/repos/stbenjam/foreman_remote_execution","forks_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/forks","keys_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/teams","hooks_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/hooks","issue_events_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/issues/events{/number}","events_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/events","assignees_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/assignees{/user}","branches_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/branches{/branch}","tags_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/tags","blobs_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/git/refs{/sha}","trees_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/statuses/{sha}","languages_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/languages","stargazers_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/stargazers","contributors_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/contributors","subscribers_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/subscribers","subscription_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/subscription","commits_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/commits{/sha}","git_commits_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/git/commits{/sha}","comments_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/comments{/number}","issue_comment_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/issues/comments{/number}","contents_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/contents/{+path}","compare_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/merges","archive_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/downloads","issues_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/issues{/number}","pulls_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/pulls{/number}","milestones_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/milestones{/number}","notifications_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/labels{/name}","releases_url":"https://api.github.com/repos/stbenjam/foreman_remote_execution/releases{/id}","created_at":"2015-06-29T15:21:51Z","updated_at":"2015-06-29T15:21:51Z","pushed_at":"2015-09-18T19:16:31Z","git_url":"git://github.com/stbenjam/foreman_remote_execution.git","ssh_url":"git@github.com:stbenjam/foreman_remote_execution.git","clone_url":"https://github.com/stbenjam/foreman_remote_execution.git","svn_url":"https://github.com/stbenjam/foreman_remote_execution","homepage":"","size":1384,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"theforeman:master","ref":"master","sha":"440c0c08c9b790c800462ff8fff33172ba1bc1ac","user":{"login":"theforeman","id":1439844,"avatar_url":"https://avatars.githubusercontent.com/u/1439844?v=3","gravatar_id":"","url":"https://api.github.com/users/theforeman","html_url":"https://github.com/theforeman","followers_url":"https://api.github.com/users/theforeman/followers","following_url":"https://api.github.com/users/theforeman/following{/other_user}","gists_url":"https://api.github.com/users/theforeman/gists{/gist_id}","starred_url":"https://api.github.com/users/theforeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theforeman/subscriptions","organizations_url":"https://api.github.com/users/theforeman/orgs","repos_url":"https://api.github.com/users/theforeman/repos","events_url":"https://api.github.com/users/theforeman/events{/privacy}","received_events_url":"https://api.github.com/users/theforeman/received_events","type":"Organization","site_admin":false},"repo":{"id":34800230,"name":"foreman_remote_execution","full_name":"theforeman/foreman_remote_execution","owner":{"login":"theforeman","id":1439844,"avatar_url":"https://avatars.githubusercontent.com/u/1439844?v=3","gravatar_id":"","url":"https://api.github.com/users/theforeman","html_url":"https://github.com/theforeman","followers_url":"https://api.github.com/users/theforeman/followers","following_url":"https://api.github.com/users/theforeman/following{/other_user}","gists_url":"https://api.github.com/users/theforeman/gists{/gist_id}","starred_url":"https://api.github.com/users/theforeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theforeman/subscriptions","organizations_url":"https://api.github.com/users/theforeman/orgs","repos_url":"https://api.github.com/users/theforeman/repos","events_url":"https://api.github.com/users/theforeman/events{/privacy}","received_events_url":"https://api.github.com/users/theforeman/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/theforeman/foreman_remote_execution","description":"A plugin bringing remote execution to the Foreman, completing the config management functionality with remote management functionality","fork":false,"url":"https://api.github.com/repos/theforeman/foreman_remote_execution","forks_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/forks","keys_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/teams","hooks_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/hooks","issue_events_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/events{/number}","events_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/events","assignees_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/assignees{/user}","branches_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/branches{/branch}","tags_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/tags","blobs_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/git/refs{/sha}","trees_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/statuses/{sha}","languages_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/languages","stargazers_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/stargazers","contributors_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/contributors","subscribers_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/subscribers","subscription_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/subscription","commits_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/commits{/sha}","git_commits_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/git/commits{/sha}","comments_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/comments{/number}","issue_comment_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/comments{/number}","contents_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/contents/{+path}","compare_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/merges","archive_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/downloads","issues_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues{/number}","pulls_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls{/number}","milestones_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/milestones{/number}","notifications_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/labels{/name}","releases_url":"https://api.github.com/repos/theforeman/foreman_remote_execution/releases{/id}","created_at":"2015-04-29T14:57:15Z","updated_at":"2015-09-17T20:18:36Z","pushed_at":"2015-09-21T11:39:44Z","git_url":"git://github.com/theforeman/foreman_remote_execution.git","ssh_url":"git@github.com:theforeman/foreman_remote_execution.git","clone_url":"https://github.com/theforeman/foreman_remote_execution.git","svn_url":"https://github.com/theforeman/foreman_remote_execution","homepage":"","size":1978,"stargazers_count":5,"watchers_count":5,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":5,"mirror_url":null,"open_issues_count":6,"forks":5,"open_issues":6,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33"},"html":{"href":"https://github.com/theforeman/foreman_remote_execution/pull/33"},"issue":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/33"},"comments":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/issues/33/comments"},"review_comments":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33/comments"},"review_comment":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/pulls/33/commits"},"statuses":{"href":"https://api.github.com/repos/theforeman/foreman_remote_execution/statuses/fb3e72260fda00d37e347a8d434e0e710cf53ace"}}}}