{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/community/pulls/comments/96949443","pull_request_review_id":17548796,"id":96949443,"diff_hunk":"@@ -0,0 +1,85 @@\n+<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->\n+\n+<!-- BEGIN STRIP_FOR_RELEASE -->\n+\n+<img src=\"http://kubernetes.io/kubernetes/img/warning.png\" alt=\"WARNING\"\n+     width=\"25\" height=\"25\">\n+<img src=\"http://kubernetes.io/kubernetes/img/warning.png\" alt=\"WARNING\"\n+     width=\"25\" height=\"25\">\n+<img src=\"http://kubernetes.io/kubernetes/img/warning.png\" alt=\"WARNING\"\n+     width=\"25\" height=\"25\">\n+<img src=\"http://kubernetes.io/kubernetes/img/warning.png\" alt=\"WARNING\"\n+     width=\"25\" height=\"25\">\n+<img src=\"http://kubernetes.io/kubernetes/img/warning.png\" alt=\"WARNING\"\n+     width=\"25\" height=\"25\">\n+\n+<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>\n+\n+If you are using a released version of Kubernetes, you should\n+refer to the docs that go with that version.\n+\n+<!-- TAG RELEASE_LINK, added by the munger automatically -->\n+<strong>\n+The latest release of this document can be found\n+[here](http://releases.k8s.io/release-1.3/docs/proposals/kubectl-extension.md).\n+\n+Documentation for other releases can be found at\n+[releases.k8s.io](http://releases.k8s.io).\n+</strong>\n+--\n+\n+<!-- END STRIP_FOR_RELEASE -->\n+\n+<!-- END MUNGE: UNVERSIONED_WARNING -->\n+\n+# Kubectl Extension\n+\n+Abstract\n+--------\n+\n+Allow `kubectl` to be extended to include other commands that can provide new functionality without recompiling Kubectl\n+\n+\n+Motivation and Background\n+-------------------------\n+\n+Kubernetes is designed to be a composable and extensible system, with the ability to add new APIs and features via Third Party Resources\n+or API federation, by making the server provide functionality that eases writing generic clients, and by supporting other authentication\n+systems. Given that `kubectl` is the primary method for interacting with the server, some new extensions are difficult to make usable\n+for end users without recompiling that command. In addition, it is difficult to prototype new functionality for kubectl outside of the\n+Kubernetes source tree.\n+\n+Ecosystem tools like OpenShift, Deis, and Helm add additional workflow around kubectl targeted at the end user. It is beneficial\n+to encourage workflows to develop around Kubernetes without requiring them to be part of Kubernetes to both the end user community\n+and the Kubernetes developer community.\n+\n+There are many tools that currently offer CLI extension for the same reasons - [Git](https://www.kernel.org/pub/software/scm/git/docs/howto/new-command.html) and\n+[Heroku](https://devcenter.heroku.com/articles/developing-cli-plug-ins#creating-the-package) are two relevant examples in the space.\n+\n+\n+Proposal\n+--------\n+\n+Define a system for `kubectl` that allows new subcommands and subcommand trees to be added by placing an executable in a specific\n+location on disk, like Git.  Allow third parties to extend kubectl by placing their extensions in that directory. Ensure that help\n+and other logic correctly includes those extensions.\n+\n+A kubectl command extension would be an executable located in `EXEC_PATH` (an arbitrary directory to be defined that follows similar\n+conventions in Linux) with a name pattern like `kubectl-COMMAND[-SUBCOMMAND[...]]` with one or many sub parts. The presence of\n+a command extension overrides any built in command.\n+\n+A key requirement is that the lookup be fast (since it would be invoked on every execution of `kubectl`) and so some true extension\n+behavior (such as complex inference of commands) may not be supported in order to reduce the complexity of the lookup.\n+\n+Kubectl would lazily include the appropriate commands in preference to the internal command structure if detected (a user asking for\n+`kubectl a b c` would *first* check for `kubectl-a-b-c`, `kubectl-a-b`, or `kubectl-a` before loading the internal command).","path":"contributors/design-proposals/kubectl-extension.md","position":75,"original_position":75,"commit_id":"4323d9048781a2d84b7372a30ed1c6d953c781bc","original_commit_id":"4323d9048781a2d84b7372a30ed1c6d953c781bc","user":{"login":"technosophos","id":89193,"avatar_url":"https://avatars.githubusercontent.com/u/89193?v=3","gravatar_id":"","url":"https://api.github.com/users/technosophos","html_url":"https://github.com/technosophos","followers_url":"https://api.github.com/users/technosophos/followers","following_url":"https://api.github.com/users/technosophos/following{/other_user}","gists_url":"https://api.github.com/users/technosophos/gists{/gist_id}","starred_url":"https://api.github.com/users/technosophos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/technosophos/subscriptions","organizations_url":"https://api.github.com/users/technosophos/orgs","repos_url":"https://api.github.com/users/technosophos/repos","events_url":"https://api.github.com/users/technosophos/events{/privacy}","received_events_url":"https://api.github.com/users/technosophos/received_events","type":"User","site_admin":false},"body":"For Helm, we backed off this approach because it got very confusing to the user. It was nearly impossible to tell whether a command was executing a plugin or not.\r\n\r\nEnvision this from the user's perspective. User A has command `kubectl foo bar baz`. User B tries to execute the same command, and it doesn't work. User A doesn't know which of their many installed plugins provides this behavior. How do they resolve the situation?\r\n\r\nOur solution was to only expose a top level subcommand to plugins. This leads to a flat top-level namespace, but also makes it very clear which plugin is being invoked.\r\n\r\nAs a side benefit, it made the help system much simpler.","created_at":"2017-01-19T20:23:20Z","updated_at":"2017-01-19T20:23:20Z","html_url":"https://github.com/kubernetes/community/pull/122#discussion_r96949443","pull_request_url":"https://api.github.com/repos/kubernetes/community/pulls/122","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/community/pulls/comments/96949443"},"html":{"href":"https://github.com/kubernetes/community/pull/122#discussion_r96949443"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/community/pulls/122"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/community/pulls/122","id":96140898,"html_url":"https://github.com/kubernetes/community/pull/122","diff_url":"https://github.com/kubernetes/community/pull/122.diff","patch_url":"https://github.com/kubernetes/community/pull/122.patch","issue_url":"https://api.github.com/repos/kubernetes/community/issues/122","number":122,"state":"open","locked":false,"title":"Proposal: kubectl extension","user":{"login":"smarterclayton","id":1163175,"avatar_url":"https://avatars.githubusercontent.com/u/1163175?v=3","gravatar_id":"","url":"https://api.github.com/users/smarterclayton","html_url":"https://github.com/smarterclayton","followers_url":"https://api.github.com/users/smarterclayton/followers","following_url":"https://api.github.com/users/smarterclayton/following{/other_user}","gists_url":"https://api.github.com/users/smarterclayton/gists{/gist_id}","starred_url":"https://api.github.com/users/smarterclayton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smarterclayton/subscriptions","organizations_url":"https://api.github.com/users/smarterclayton/orgs","repos_url":"https://api.github.com/users/smarterclayton/repos","events_url":"https://api.github.com/users/smarterclayton/events{/privacy}","received_events_url":"https://api.github.com/users/smarterclayton/received_events","type":"User","site_admin":false},"body":"From: kubernetes/kubernetes#30086","created_at":"2016-12-01T18:10:19Z","updated_at":"2017-01-19T20:23:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"127e6938ee447c32f30cec059c1b3916a7f32b91","assignee":{"login":"fabianofranz","id":158611,"avatar_url":"https://avatars.githubusercontent.com/u/158611?v=3","gravatar_id":"","url":"https://api.github.com/users/fabianofranz","html_url":"https://github.com/fabianofranz","followers_url":"https://api.github.com/users/fabianofranz/followers","following_url":"https://api.github.com/users/fabianofranz/following{/other_user}","gists_url":"https://api.github.com/users/fabianofranz/gists{/gist_id}","starred_url":"https://api.github.com/users/fabianofranz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabianofranz/subscriptions","organizations_url":"https://api.github.com/users/fabianofranz/orgs","repos_url":"https://api.github.com/users/fabianofranz/repos","events_url":"https://api.github.com/users/fabianofranz/events{/privacy}","received_events_url":"https://api.github.com/users/fabianofranz/received_events","type":"User","site_admin":false},"assignees":[{"login":"fabianofranz","id":158611,"avatar_url":"https://avatars.githubusercontent.com/u/158611?v=3","gravatar_id":"","url":"https://api.github.com/users/fabianofranz","html_url":"https://github.com/fabianofranz","followers_url":"https://api.github.com/users/fabianofranz/followers","following_url":"https://api.github.com/users/fabianofranz/following{/other_user}","gists_url":"https://api.github.com/users/fabianofranz/gists{/gist_id}","starred_url":"https://api.github.com/users/fabianofranz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabianofranz/subscriptions","organizations_url":"https://api.github.com/users/fabianofranz/orgs","repos_url":"https://api.github.com/users/fabianofranz/repos","events_url":"https://api.github.com/users/fabianofranz/events{/privacy}","received_events_url":"https://api.github.com/users/fabianofranz/received_events","type":"User","site_admin":false},{"login":"pwittrock","id":7882754,"avatar_url":"https://avatars.githubusercontent.com/u/7882754?v=3","gravatar_id":"","url":"https://api.github.com/users/pwittrock","html_url":"https://github.com/pwittrock","followers_url":"https://api.github.com/users/pwittrock/followers","following_url":"https://api.github.com/users/pwittrock/following{/other_user}","gists_url":"https://api.github.com/users/pwittrock/gists{/gist_id}","starred_url":"https://api.github.com/users/pwittrock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pwittrock/subscriptions","organizations_url":"https://api.github.com/users/pwittrock/orgs","repos_url":"https://api.github.com/users/pwittrock/repos","events_url":"https://api.github.com/users/pwittrock/events{/privacy}","received_events_url":"https://api.github.com/users/pwittrock/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/community/pulls/122/commits","review_comments_url":"https://api.github.com/repos/kubernetes/community/pulls/122/comments","review_comment_url":"https://api.github.com/repos/kubernetes/community/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/community/issues/122/comments","statuses_url":"https://api.github.com/repos/kubernetes/community/statuses/4323d9048781a2d84b7372a30ed1c6d953c781bc","head":{"label":"smarterclayton:kubectl_extension","ref":"kubectl_extension","sha":"4323d9048781a2d84b7372a30ed1c6d953c781bc","user":{"login":"smarterclayton","id":1163175,"avatar_url":"https://avatars.githubusercontent.com/u/1163175?v=3","gravatar_id":"","url":"https://api.github.com/users/smarterclayton","html_url":"https://github.com/smarterclayton","followers_url":"https://api.github.com/users/smarterclayton/followers","following_url":"https://api.github.com/users/smarterclayton/following{/other_user}","gists_url":"https://api.github.com/users/smarterclayton/gists{/gist_id}","starred_url":"https://api.github.com/users/smarterclayton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smarterclayton/subscriptions","organizations_url":"https://api.github.com/users/smarterclayton/orgs","repos_url":"https://api.github.com/users/smarterclayton/repos","events_url":"https://api.github.com/users/smarterclayton/events{/privacy}","received_events_url":"https://api.github.com/users/smarterclayton/received_events","type":"User","site_admin":false},"repo":{"id":75316472,"name":"community","full_name":"smarterclayton/community","owner":{"login":"smarterclayton","id":1163175,"avatar_url":"https://avatars.githubusercontent.com/u/1163175?v=3","gravatar_id":"","url":"https://api.github.com/users/smarterclayton","html_url":"https://github.com/smarterclayton","followers_url":"https://api.github.com/users/smarterclayton/followers","following_url":"https://api.github.com/users/smarterclayton/following{/other_user}","gists_url":"https://api.github.com/users/smarterclayton/gists{/gist_id}","starred_url":"https://api.github.com/users/smarterclayton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smarterclayton/subscriptions","organizations_url":"https://api.github.com/users/smarterclayton/orgs","repos_url":"https://api.github.com/users/smarterclayton/repos","events_url":"https://api.github.com/users/smarterclayton/events{/privacy}","received_events_url":"https://api.github.com/users/smarterclayton/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/smarterclayton/community","description":"Kubernetes community content","fork":true,"url":"https://api.github.com/repos/smarterclayton/community","forks_url":"https://api.github.com/repos/smarterclayton/community/forks","keys_url":"https://api.github.com/repos/smarterclayton/community/keys{/key_id}","collaborators_url":"https://api.github.com/repos/smarterclayton/community/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/smarterclayton/community/teams","hooks_url":"https://api.github.com/repos/smarterclayton/community/hooks","issue_events_url":"https://api.github.com/repos/smarterclayton/community/issues/events{/number}","events_url":"https://api.github.com/repos/smarterclayton/community/events","assignees_url":"https://api.github.com/repos/smarterclayton/community/assignees{/user}","branches_url":"https://api.github.com/repos/smarterclayton/community/branches{/branch}","tags_url":"https://api.github.com/repos/smarterclayton/community/tags","blobs_url":"https://api.github.com/repos/smarterclayton/community/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/smarterclayton/community/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/smarterclayton/community/git/refs{/sha}","trees_url":"https://api.github.com/repos/smarterclayton/community/git/trees{/sha}","statuses_url":"https://api.github.com/repos/smarterclayton/community/statuses/{sha}","languages_url":"https://api.github.com/repos/smarterclayton/community/languages","stargazers_url":"https://api.github.com/repos/smarterclayton/community/stargazers","contributors_url":"https://api.github.com/repos/smarterclayton/community/contributors","subscribers_url":"https://api.github.com/repos/smarterclayton/community/subscribers","subscription_url":"https://api.github.com/repos/smarterclayton/community/subscription","commits_url":"https://api.github.com/repos/smarterclayton/community/commits{/sha}","git_commits_url":"https://api.github.com/repos/smarterclayton/community/git/commits{/sha}","comments_url":"https://api.github.com/repos/smarterclayton/community/comments{/number}","issue_comment_url":"https://api.github.com/repos/smarterclayton/community/issues/comments{/number}","contents_url":"https://api.github.com/repos/smarterclayton/community/contents/{+path}","compare_url":"https://api.github.com/repos/smarterclayton/community/compare/{base}...{head}","merges_url":"https://api.github.com/repos/smarterclayton/community/merges","archive_url":"https://api.github.com/repos/smarterclayton/community/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/smarterclayton/community/downloads","issues_url":"https://api.github.com/repos/smarterclayton/community/issues{/number}","pulls_url":"https://api.github.com/repos/smarterclayton/community/pulls{/number}","milestones_url":"https://api.github.com/repos/smarterclayton/community/milestones{/number}","notifications_url":"https://api.github.com/repos/smarterclayton/community/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/smarterclayton/community/labels{/name}","releases_url":"https://api.github.com/repos/smarterclayton/community/releases{/id}","deployments_url":"https://api.github.com/repos/smarterclayton/community/deployments","created_at":"2016-12-01T17:33:49Z","updated_at":"2016-12-01T17:33:51Z","pushed_at":"2016-12-22T04:16:45Z","git_url":"git://github.com/smarterclayton/community.git","ssh_url":"git@github.com:smarterclayton/community.git","clone_url":"https://github.com/smarterclayton/community.git","svn_url":"https://github.com/smarterclayton/community","homepage":"","size":6791,"stargazers_count":0,"watchers_count":0,"language":"Makefile","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"kubernetes:master","ref":"master","sha":"82bd9ab60913e5f5f612bc1a1065aeade6be2fe9","user":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"repo":{"id":57939112,"name":"community","full_name":"kubernetes/community","owner":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes/community","description":"Kubernetes community content","fork":false,"url":"https://api.github.com/repos/kubernetes/community","forks_url":"https://api.github.com/repos/kubernetes/community/forks","keys_url":"https://api.github.com/repos/kubernetes/community/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/community/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/community/teams","hooks_url":"https://api.github.com/repos/kubernetes/community/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/community/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/community/events","assignees_url":"https://api.github.com/repos/kubernetes/community/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/community/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/community/tags","blobs_url":"https://api.github.com/repos/kubernetes/community/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/community/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/community/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/community/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/community/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/community/languages","stargazers_url":"https://api.github.com/repos/kubernetes/community/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/community/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/community/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/community/subscription","commits_url":"https://api.github.com/repos/kubernetes/community/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/community/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/community/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/community/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/community/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/community/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/community/merges","archive_url":"https://api.github.com/repos/kubernetes/community/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/community/downloads","issues_url":"https://api.github.com/repos/kubernetes/community/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/community/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/community/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/community/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/community/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/community/releases{/id}","deployments_url":"https://api.github.com/repos/kubernetes/community/deployments","created_at":"2016-05-03T03:36:05Z","updated_at":"2017-01-19T15:45:29Z","pushed_at":"2017-01-19T19:59:31Z","git_url":"git://github.com/kubernetes/community.git","ssh_url":"git@github.com:kubernetes/community.git","clone_url":"https://github.com/kubernetes/community.git","svn_url":"https://github.com/kubernetes/community","homepage":"","size":7030,"stargazers_count":148,"watchers_count":148,"language":"Makefile","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":155,"mirror_url":null,"open_issues_count":56,"forks":155,"open_issues":56,"watchers":148,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/community/pulls/122"},"html":{"href":"https://github.com/kubernetes/community/pull/122"},"issue":{"href":"https://api.github.com/repos/kubernetes/community/issues/122"},"comments":{"href":"https://api.github.com/repos/kubernetes/community/issues/122/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/community/pulls/122/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/community/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/community/pulls/122/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/community/statuses/4323d9048781a2d84b7372a30ed1c6d953c781bc"}}}}
{"actor":{"display_login":"technosophos"}}