{"action":"created","comment":{"url":"https://api.github.com/repos/openshift/origin/pulls/comments/31429600","id":31429600,"diff_hunk":"@@ -0,0 +1,138 @@\n+package admission\n+\n+import (\n+\t\"errors\"\n+\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/admission\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/api\"\n+\tapierrors \"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors\"\n+\tkclient \"github.com/GoogleCloudPlatform/kubernetes/pkg/client\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/fields\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/labels\"\n+\n+\t\"fmt\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime\"\n+\t\"github.com/GoogleCloudPlatform/kubernetes/pkg/watch\"\n+\tosclient \"github.com/openshift/origin/pkg/client\"\n+\trouteapi \"github.com/openshift/origin/pkg/route/api\"\n+)\n+\n+// This plugin must be manually initialized, it requires an openshift client which is not\n+// available via the factory interface normally used in NewFromPlugins.\n+\n+// NewRouteAdmissionPlugin creates a new route admission plugin to enforce uniqueness.\n+func NewRouteAdmissionPlugin(kClient kclient.Interface, osClient osclient.Interface) (admission.Interface, error) {\n+\tif kClient == nil || osClient == nil {\n+\t\treturn nil, errors.New(\"kube client and openshift client are required\")\n+\t}\n+\n+\tstore := cache.NewStore(StoreKeyFunc)\n+\treflector := cache.NewReflector(\n+\t\t&cache.ListWatch{\n+\t\t\tListFunc: func() (runtime.Object, error) {\n+\t\t\t\treturn osClient.Routes(api.NamespaceAll).List(labels.Everything(), fields.Everything())\n+\t\t\t},\n+\t\t\tWatchFunc: func(resourceVersion string) (watch.Interface, error) {\n+\t\t\t\treturn osClient.Routes(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), resourceVersion)\n+\t\t\t},\n+\t\t},\n+\t\t&routeapi.Route{},\n+\t\tstore,\n+\t\t0,\n+\t)\n+\treflector.Run()\n+\n+\treturn &routeUniqueness{\n+\t\tkClient:    kClient,\n+\t\tosClient:   osClient,\n+\t\trouteStore: store,\n+\t}, nil\n+}\n+\n+// routeUniqueness implements the plugin that validates route uniqueness.\n+type routeUniqueness struct {\n+\tkClient    kclient.Interface\n+\tosClient   osclient.Interface\n+\trouteStore cache.Store\n+}\n+\n+// Admit ensures that the route in the form of scheme://host/path does not already exist in the\n+// system.  Rules for admission:\n+// 1.  If you're adding a route it must have a unique scheme, host, path combination\n+// 2.  If you're updating a route you may not update it to a scheme, host, path combination that\n+//     already exists (used by checking the namespace and name of the route)\n+func (p *routeUniqueness) Admit(a admission.Attributes) error {\n+\tif a.GetResource() != \"routes\" {\n+\t\treturn nil\n+\t}\n+\tif a.GetOperation() == \"DELETE\" {\n+\t\treturn nil\n+\t}\n+\n+\troute, ok := a.GetObject().(*routeapi.Route)\n+\tif !ok {\n+\t\treturn apierrors.NewBadRequest(\"Resource was marked with kind Route but was unable to be converted\")\n+\t}\n+\trouteKey := MakeRouteKey(route)\n+\n+\t// see if we can find a route that matches the scheme, host, path combination\n+\tfoundObj, exists, err := p.routeStore.GetByKey(routeKey)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\t// if no existing route is found this is ok to create\n+\tif !exists {\n+\t\treturn nil\n+\t}\n+\t// if updating then the namespace and name must match in order to accept the update\n+\tfound, ok := foundObj.(*routeapi.Route)\n+\tif !ok {\n+\t\treturn fmt.Errorf(\"Invalid object found in store, unable to convert to route %v\", foundObj)","path":"pkg/route/admission/admission.go","position":91,"original_position":91,"commit_id":"b4d8b09dee7f1cda4fc138d32bb117f22c7e3619","original_commit_id":"b4d8b09dee7f1cda4fc138d32bb117f22c7e3619","user":{"login":"derekwaynecarr","id":6233452,"avatar_url":"https://avatars.githubusercontent.com/u/6233452?v=3","gravatar_id":"","url":"https://api.github.com/users/derekwaynecarr","html_url":"https://github.com/derekwaynecarr","followers_url":"https://api.github.com/users/derekwaynecarr/followers","following_url":"https://api.github.com/users/derekwaynecarr/following{/other_user}","gists_url":"https://api.github.com/users/derekwaynecarr/gists{/gist_id}","starred_url":"https://api.github.com/users/derekwaynecarr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/derekwaynecarr/subscriptions","organizations_url":"https://api.github.com/users/derekwaynecarr/orgs","repos_url":"https://api.github.com/users/derekwaynecarr/repos","events_url":"https://api.github.com/users/derekwaynecarr/events{/privacy}","received_events_url":"https://api.github.com/users/derekwaynecarr/received_events","type":"User","site_admin":false},"body":"you need to always return api server styled errors to avoid logging crap and confusing apisever.\r\n\r\nreturn admission.NewForbidden(a, fmt.Errorf(\"...\"))","created_at":"2015-06-01T14:24:45Z","updated_at":"2015-06-01T14:24:45Z","html_url":"https://github.com/openshift/origin/pull/2606#discussion_r31429600","pull_request_url":"https://api.github.com/repos/openshift/origin/pulls/2606","_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments/31429600"},"html":{"href":"https://github.com/openshift/origin/pull/2606#discussion_r31429600"},"pull_request":{"href":"https://api.github.com/repos/openshift/origin/pulls/2606"}}},"pull_request":{"url":"https://api.github.com/repos/openshift/origin/pulls/2606","id":36528618,"html_url":"https://github.com/openshift/origin/pull/2606","diff_url":"https://github.com/openshift/origin/pull/2606.diff","patch_url":"https://github.com/openshift/origin/pull/2606.patch","issue_url":"https://api.github.com/repos/openshift/origin/issues/2606","number":2606,"state":"open","locked":false,"title":"BZ 1219420 - Do not admit routes with the same scheme/host/path","user":{"login":"pweil-","id":5230419,"avatar_url":"https://avatars.githubusercontent.com/u/5230419?v=3","gravatar_id":"","url":"https://api.github.com/users/pweil-","html_url":"https://github.com/pweil-","followers_url":"https://api.github.com/users/pweil-/followers","following_url":"https://api.github.com/users/pweil-/following{/other_user}","gists_url":"https://api.github.com/users/pweil-/gists{/gist_id}","starred_url":"https://api.github.com/users/pweil-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pweil-/subscriptions","organizations_url":"https://api.github.com/users/pweil-/orgs","repos_url":"https://api.github.com/users/pweil-/repos","events_url":"https://api.github.com/users/pweil-/events{/privacy}","received_events_url":"https://api.github.com/users/pweil-/received_events","type":"User","site_admin":false},"body":"As discussed with @danmcp and @liggitt.  We will not admit duplicate routes.  \r\n\r\nRules:\r\n\r\n1.  Routes will be considered unique by the scheme/host/path combination.  A route will any type of TLS will be considered as using the https scheme for admission purposes.\r\n1.  When adding, if the unique key already exists then deny\r\n1.  When updating, if the unique key already exists only admit if it is the same namespace/name\r\n\r\nOf note:  Admission controllers do not have access to an openshift client which is required to maintain the route store.  To work around this I used the `admission.NewChainHandler` function to add a pre-initialized plugin to the chain of plugins created by `admission.NewFromPlugins`.  This method is currently marked as \"for test use\".  @derekwaynecarr PTAL at that section.\r\n\r\n@liggitt @smarterclayton PTAL\r\n","created_at":"2015-05-29T17:46:37Z","updated_at":"2015-06-01T14:24:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f9cecdbf4057c864048c34585319a18f97f4efee","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openshift/origin/pulls/2606/commits","review_comments_url":"https://api.github.com/repos/openshift/origin/pulls/2606/comments","review_comment_url":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openshift/origin/issues/2606/comments","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/b4d8b09dee7f1cda4fc138d32bb117f22c7e3619","head":{"label":"pweil-:route-admission","ref":"route-admission","sha":"b4d8b09dee7f1cda4fc138d32bb117f22c7e3619","user":{"login":"pweil-","id":5230419,"avatar_url":"https://avatars.githubusercontent.com/u/5230419?v=3","gravatar_id":"","url":"https://api.github.com/users/pweil-","html_url":"https://github.com/pweil-","followers_url":"https://api.github.com/users/pweil-/followers","following_url":"https://api.github.com/users/pweil-/following{/other_user}","gists_url":"https://api.github.com/users/pweil-/gists{/gist_id}","starred_url":"https://api.github.com/users/pweil-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pweil-/subscriptions","organizations_url":"https://api.github.com/users/pweil-/orgs","repos_url":"https://api.github.com/users/pweil-/repos","events_url":"https://api.github.com/users/pweil-/events{/privacy}","received_events_url":"https://api.github.com/users/pweil-/received_events","type":"User","site_admin":false},"repo":{"id":24119315,"name":"origin","full_name":"pweil-/origin","owner":{"login":"pweil-","id":5230419,"avatar_url":"https://avatars.githubusercontent.com/u/5230419?v=3","gravatar_id":"","url":"https://api.github.com/users/pweil-","html_url":"https://github.com/pweil-","followers_url":"https://api.github.com/users/pweil-/followers","following_url":"https://api.github.com/users/pweil-/following{/other_user}","gists_url":"https://api.github.com/users/pweil-/gists{/gist_id}","starred_url":"https://api.github.com/users/pweil-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pweil-/subscriptions","organizations_url":"https://api.github.com/users/pweil-/orgs","repos_url":"https://api.github.com/users/pweil-/repos","events_url":"https://api.github.com/users/pweil-/events{/privacy}","received_events_url":"https://api.github.com/users/pweil-/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/pweil-/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":true,"url":"https://api.github.com/repos/pweil-/origin","forks_url":"https://api.github.com/repos/pweil-/origin/forks","keys_url":"https://api.github.com/repos/pweil-/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pweil-/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pweil-/origin/teams","hooks_url":"https://api.github.com/repos/pweil-/origin/hooks","issue_events_url":"https://api.github.com/repos/pweil-/origin/issues/events{/number}","events_url":"https://api.github.com/repos/pweil-/origin/events","assignees_url":"https://api.github.com/repos/pweil-/origin/assignees{/user}","branches_url":"https://api.github.com/repos/pweil-/origin/branches{/branch}","tags_url":"https://api.github.com/repos/pweil-/origin/tags","blobs_url":"https://api.github.com/repos/pweil-/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pweil-/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pweil-/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/pweil-/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pweil-/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/pweil-/origin/languages","stargazers_url":"https://api.github.com/repos/pweil-/origin/stargazers","contributors_url":"https://api.github.com/repos/pweil-/origin/contributors","subscribers_url":"https://api.github.com/repos/pweil-/origin/subscribers","subscription_url":"https://api.github.com/repos/pweil-/origin/subscription","commits_url":"https://api.github.com/repos/pweil-/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/pweil-/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/pweil-/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/pweil-/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/pweil-/origin/contents/{+path}","compare_url":"https://api.github.com/repos/pweil-/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pweil-/origin/merges","archive_url":"https://api.github.com/repos/pweil-/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pweil-/origin/downloads","issues_url":"https://api.github.com/repos/pweil-/origin/issues{/number}","pulls_url":"https://api.github.com/repos/pweil-/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/pweil-/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/pweil-/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pweil-/origin/labels{/name}","releases_url":"https://api.github.com/repos/pweil-/origin/releases{/id}","created_at":"2014-09-16T21:53:06Z","updated_at":"2015-04-27T15:24:14Z","pushed_at":"2015-06-01T12:10:25Z","git_url":"git://github.com/pweil-/origin.git","ssh_url":"git@github.com:pweil-/origin.git","clone_url":"https://github.com/pweil-/origin.git","svn_url":"https://github.com/pweil-/origin","homepage":"https://openshift.github.io","size":113099,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"openshift:master","ref":"master","sha":"955b61448f547e55ee9635910e446d1cb1b6061c","user":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"repo":{"id":22442668,"name":"origin","full_name":"openshift/origin","owner":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openshift/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":false,"url":"https://api.github.com/repos/openshift/origin","forks_url":"https://api.github.com/repos/openshift/origin/forks","keys_url":"https://api.github.com/repos/openshift/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openshift/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openshift/origin/teams","hooks_url":"https://api.github.com/repos/openshift/origin/hooks","issue_events_url":"https://api.github.com/repos/openshift/origin/issues/events{/number}","events_url":"https://api.github.com/repos/openshift/origin/events","assignees_url":"https://api.github.com/repos/openshift/origin/assignees{/user}","branches_url":"https://api.github.com/repos/openshift/origin/branches{/branch}","tags_url":"https://api.github.com/repos/openshift/origin/tags","blobs_url":"https://api.github.com/repos/openshift/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openshift/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openshift/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/openshift/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/openshift/origin/languages","stargazers_url":"https://api.github.com/repos/openshift/origin/stargazers","contributors_url":"https://api.github.com/repos/openshift/origin/contributors","subscribers_url":"https://api.github.com/repos/openshift/origin/subscribers","subscription_url":"https://api.github.com/repos/openshift/origin/subscription","commits_url":"https://api.github.com/repos/openshift/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/openshift/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/openshift/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/openshift/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/openshift/origin/contents/{+path}","compare_url":"https://api.github.com/repos/openshift/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openshift/origin/merges","archive_url":"https://api.github.com/repos/openshift/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openshift/origin/downloads","issues_url":"https://api.github.com/repos/openshift/origin/issues{/number}","pulls_url":"https://api.github.com/repos/openshift/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/openshift/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/openshift/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openshift/origin/labels{/name}","releases_url":"https://api.github.com/repos/openshift/origin/releases{/id}","created_at":"2014-07-30T20:04:05Z","updated_at":"2015-06-01T12:48:30Z","pushed_at":"2015-06-01T14:24:37Z","git_url":"git://github.com/openshift/origin.git","ssh_url":"git@github.com:openshift/origin.git","clone_url":"https://github.com/openshift/origin.git","svn_url":"https://github.com/openshift/origin","homepage":"http://www.openshift.org","size":190393,"stargazers_count":450,"watchers_count":450,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":224,"mirror_url":null,"open_issues_count":257,"forks":224,"open_issues":257,"watchers":450,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/2606"},"html":{"href":"https://github.com/openshift/origin/pull/2606"},"issue":{"href":"https://api.github.com/repos/openshift/origin/issues/2606"},"comments":{"href":"https://api.github.com/repos/openshift/origin/issues/2606/comments"},"review_comments":{"href":"https://api.github.com/repos/openshift/origin/pulls/2606/comments"},"review_comment":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openshift/origin/pulls/2606/commits"},"statuses":{"href":"https://api.github.com/repos/openshift/origin/statuses/b4d8b09dee7f1cda4fc138d32bb117f22c7e3619"}}}}