{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/ingress/pulls/comments/89617001","pull_request_review_id":10161678,"id":89617001,"diff_hunk":"@@ -0,0 +1,1076 @@\n+/*\n+Copyright 2015 The Kubernetes Authors.\n+\n+Licensed under the Apache License, Version 2.0 (the \"License\");\n+you may not use this file except in compliance with the License.\n+You may obtain a copy of the License at\n+\n+    http://www.apache.org/licenses/LICENSE-2.0\n+\n+Unless required by applicable law or agreed to in writing, software\n+distributed under the License is distributed on an \"AS IS\" BASIS,\n+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+See the License for the specific language governing permissions and\n+limitations under the License.\n+*/\n+\n+package controller\n+\n+import (\n+\t\"fmt\"\n+\t\"net/http\"\n+\t\"reflect\"\n+\t\"sort\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"github.com/golang/glog\"\n+\n+\t\"k8s.io/kubernetes/pkg/api\"\n+\t\"k8s.io/kubernetes/pkg/apis/extensions\"\n+\t\"k8s.io/kubernetes/pkg/client/cache\"\n+\tclientset \"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset\"\n+\tunversionedcore \"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion\"\n+\t\"k8s.io/kubernetes/pkg/client/record\"\n+\t\"k8s.io/kubernetes/pkg/fields\"\n+\t\"k8s.io/kubernetes/pkg/healthz\"\n+\t\"k8s.io/kubernetes/pkg/util/flowcontrol\"\n+\t\"k8s.io/kubernetes/pkg/util/intstr\"\n+\n+\tcache_store \"k8s.io/ingress/core/pkg/cache\"\n+\t\"k8s.io/ingress/core/pkg/ingress\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/auth\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/authreq\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/authtls\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/cors\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/healthcheck\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/ipwhitelist\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/proxy\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/ratelimit\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/rewrite\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/secureupstream\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/service\"\n+\t\"k8s.io/ingress/core/pkg/ingress/annotations/sslpassthrough\"\n+\t\"k8s.io/ingress/core/pkg/ingress/status\"\n+\t\"k8s.io/ingress/core/pkg/k8s\"\n+\tlocal_strings \"k8s.io/ingress/core/pkg/strings\"\n+\t\"k8s.io/ingress/core/pkg/task\"\n+)\n+\n+const (\n+\tdefUpstreamName          = \"upstream-default-backend\"\n+\tdefServerName            = \"_\"\n+\tpodStoreSyncedPollPeriod = 1 * time.Second\n+\trootLocation             = \"/\"\n+\n+\t// ingressClassKey picks a specific \"class\" for the Ingress. The controller\n+\t// only processes Ingresses with this annotation either unset, or set\n+\t// to either the configured value or the empty string.\n+\tingressClassKey = \"kubernetes.io/ingress.class\"\n+)\n+\n+var (\n+\t// list of ports that cannot be used by TCP or UDP services\n+\treservedPorts = []string{\"80\", \"443\", \"8181\", \"18080\"}\n+)\n+\n+// Interface holds the methods to handle an Ingress backend\n+type Interface interface {\n+\tStart()\n+\tStop() error\n+\n+\tInfo() string\n+\n+\thealthz.HealthzChecker\n+}\n+\n+// GenericController watches the kubernetes api and adds/removes services from the loadbalancer\n+type GenericController struct {\n+\thealthz.HealthzChecker\n+\n+\tcfg *Configuration\n+\n+\tingController  *cache.Controller\n+\tendpController *cache.Controller\n+\tsvcController  *cache.Controller\n+\tsecrController *cache.Controller\n+\tmapController  *cache.Controller\n+\n+\tingLister  cache_store.StoreToIngressLister\n+\tsvcLister  cache.StoreToServiceLister\n+\tendpLister cache.StoreToEndpointsLister\n+\tsecrLister cache_store.StoreToSecretsLister\n+\tmapLister  cache_store.StoreToConfigmapLister\n+\n+\trecorder record.EventRecorder\n+\n+\tsyncQueue *task.Queue\n+\n+\tsyncStatus status.Sync\n+\n+\t// controller for SSL certificates\n+\tsslCertTracker *sslCertTracker\n+\t// TaskQueue in charge of keep the secrets referenced from Ingress\n+\t// in sync with the files on disk\n+\tsecretQueue *task.Queue\n+\n+\tsyncRateLimiter flowcontrol.RateLimiter\n+\n+\t// stopLock is used to enforce only a single call to Stop is active.\n+\t// Needed because we allow stopping through an http endpoint and\n+\t// allowing concurrent stoppers leads to stack traces.\n+\tstopLock *sync.Mutex\n+\n+\tstopCh chan struct{}\n+}\n+\n+// Configuration contains all the settings required by an Ingress controller\n+type Configuration struct {\n+\tClient *clientset.Clientset\n+\n+\tResyncPeriod   time.Duration\n+\tDefaultService string\n+\tIngressClass   string\n+\tNamespace      string\n+\tConfigMapName  string\n+\t// optional\n+\tTCPConfigMapName string\n+\t// optional\n+\tUDPConfigMapName      string\n+\tDefaultSSLCertificate string\n+\tDefaultHealthzURL     string\n+\t// optional\n+\tPublishService string\n+\n+\tBackend ingress.Controller\n+}\n+\n+// newIngressController creates an Ingress controller\n+func newIngressController(config *Configuration) Interface {\n+\n+\teventBroadcaster := record.NewBroadcaster()\n+\teventBroadcaster.StartLogging(glog.Infof)\n+\teventBroadcaster.StartRecordingToSink(unversionedcore.EventSinkImpl{\n+\t\tInterface: config.Client.Core().Events(config.Namespace),\n+\t})\n+\n+\tic := GenericController{\n+\t\tcfg:             config,\n+\t\tstopLock:        &sync.Mutex{},\n+\t\tstopCh:          make(chan struct{}),\n+\t\tsyncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.1, 1),\n+\t\trecorder: eventBroadcaster.NewRecorder(api.EventSource{\n+\t\t\tComponent: \"ingress-controller\",\n+\t\t}),\n+\t\tsslCertTracker: newSSLCertTracker(),\n+\t}\n+\n+\tic.syncQueue = task.NewTaskQueue(ic.sync)\n+\tic.secretQueue = task.NewTaskQueue(ic.syncSecret)\n+\n+\t// from here to the end of the method all the code is just boilerplate\n+\t// required to watch Ingress, Secrets, ConfigMaps and Endoints.\n+\t// This is used to detect new content, updates or removals and act accordingly\n+\tingEventHandler := cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc: func(obj interface{}) {\n+\t\t\taddIng := obj.(*extensions.Ingress)\n+\t\t\tif !IsValidClass(addIng, config.IngressClass) {\n+\t\t\t\tglog.Infof(\"ignoring add for ingress %v based on annotation %v\", addIng.Name, ingressClassKey)\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t\tic.recorder.Eventf(addIng, api.EventTypeNormal, \"CREATE\", fmt.Sprintf(\"Ingress %s/%s\", addIng.Namespace, addIng.Name))\n+\t\t\tic.syncQueue.Enqueue(obj)\n+\t\t},\n+\t\tDeleteFunc: func(obj interface{}) {\n+\t\t\tdelIng := obj.(*extensions.Ingress)\n+\t\t\tif !IsValidClass(delIng, config.IngressClass) {\n+\t\t\t\tglog.Infof(\"ignoring add for ingress %v based on annotation %v\", delIng.Name, ingressClassKey)\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t\tic.recorder.Eventf(delIng, api.EventTypeNormal, \"DELETE\", fmt.Sprintf(\"Ingress %s/%s\", delIng.Namespace, delIng.Name))\n+\t\t\tic.syncQueue.Enqueue(obj)\n+\t\t},\n+\t\tUpdateFunc: func(old, cur interface{}) {\n+\t\t\tcurIng := cur.(*extensions.Ingress)\n+\t\t\tif !IsValidClass(curIng, config.IngressClass) {\n+\t\t\t\treturn\n+\t\t\t}\n+\n+\t\t\tif !reflect.DeepEqual(old, cur) {\n+\t\t\t\tupIng := cur.(*extensions.Ingress)\n+\t\t\t\tic.recorder.Eventf(upIng, api.EventTypeNormal, \"UPDATE\", fmt.Sprintf(\"Ingress %s/%s\", upIng.Namespace, upIng.Name))\n+\t\t\t\tic.syncQueue.Enqueue(cur)\n+\t\t\t}\n+\t\t},\n+\t}\n+\n+\tsecrEventHandler := cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc: func(obj interface{}) {\n+\t\t\tsec := obj.(*api.Secret)\n+\t\t\tic.secretQueue.Enqueue(sec)\n+\t\t},\n+\t\tDeleteFunc: func(obj interface{}) {\n+\t\t\tsec := obj.(*api.Secret)\n+\t\t\tic.sslCertTracker.Delete(fmt.Sprintf(\"%v/%v\", sec.Namespace, sec.Name))\n+\t\t},\n+\t\tUpdateFunc: func(old, cur interface{}) {\n+\t\t\tif !reflect.DeepEqual(old, cur) {\n+\t\t\t\tsec := cur.(*api.Secret)\n+\t\t\t\tic.secretQueue.Enqueue(sec)\n+\t\t\t}\n+\t\t},\n+\t}\n+\n+\teventHandler := cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc: func(obj interface{}) {\n+\t\t\tic.syncQueue.Enqueue(obj)\n+\t\t},\n+\t\tDeleteFunc: func(obj interface{}) {\n+\t\t\tic.syncQueue.Enqueue(obj)\n+\t\t},\n+\t\tUpdateFunc: func(old, cur interface{}) {\n+\t\t\tif !reflect.DeepEqual(old, cur) {\n+\t\t\t\tic.syncQueue.Enqueue(cur)\n+\t\t\t}\n+\t\t},\n+\t}\n+\n+\tmapEventHandler := cache.ResourceEventHandlerFuncs{\n+\t\tUpdateFunc: func(old, cur interface{}) {\n+\t\t\tif !reflect.DeepEqual(old, cur) {\n+\t\t\t\tupCmap := cur.(*api.ConfigMap)\n+\t\t\t\tmapKey := fmt.Sprintf(\"%s/%s\", upCmap.Namespace, upCmap.Name)\n+\t\t\t\t// updates to configuration configmaps can trigger an update\n+\t\t\t\tif mapKey == ic.cfg.ConfigMapName || mapKey == ic.cfg.TCPConfigMapName || mapKey == ic.cfg.UDPConfigMapName {\n+\t\t\t\t\tic.recorder.Eventf(upCmap, api.EventTypeNormal, \"UPDATE\", fmt.Sprintf(\"ConfigMap %v\", mapKey))\n+\t\t\t\t\tic.syncQueue.Enqueue(cur)\n+\t\t\t\t}\n+\t\t\t}\n+\t\t},\n+\t}\n+\n+\tic.ingLister.Store, ic.ingController = cache.NewInformer(\n+\t\tcache.NewListWatchFromClient(ic.cfg.Client.Extensions().RESTClient(), \"ingresses\", ic.cfg.Namespace, fields.Everything()),\n+\t\t&extensions.Ingress{}, ic.cfg.ResyncPeriod, ingEventHandler)\n+\n+\tic.endpLister.Store, ic.endpController = cache.NewInformer(\n+\t\tcache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), \"endpoints\", ic.cfg.Namespace, fields.Everything()),\n+\t\t&api.Endpoints{}, ic.cfg.ResyncPeriod, eventHandler)\n+\n+\tic.secrLister.Store, ic.secrController = cache.NewInformer(\n+\t\tcache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), \"secrets\", ic.cfg.Namespace, fields.Everything()),\n+\t\t&api.Secret{}, ic.cfg.ResyncPeriod, secrEventHandler)\n+\n+\tic.mapLister.Store, ic.mapController = cache.NewInformer(\n+\t\tcache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), \"configmaps\", ic.cfg.Namespace, fields.Everything()),\n+\t\t&api.ConfigMap{}, ic.cfg.ResyncPeriod, mapEventHandler)\n+\n+\tic.svcLister.Indexer, ic.svcController = cache.NewIndexerInformer(\n+\t\tcache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), \"services\", ic.cfg.Namespace, fields.Everything()),\n+\t\t&api.Service{},\n+\t\tic.cfg.ResyncPeriod,\n+\t\tcache.ResourceEventHandlerFuncs{},\n+\t\tcache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})\n+\n+\tic.syncStatus = status.NewStatusSyncer(status.Config{\n+\t\tClient:         config.Client,\n+\t\tPublishService: ic.cfg.PublishService,\n+\t\tIngressLister:  ic.ingLister,\n+\t})\n+\n+\treturn ic\n+}\n+\n+func (ic *GenericController) controllersInSync() bool {\n+\treturn ic.ingController.HasSynced() &&\n+\t\tic.svcController.HasSynced() &&\n+\t\tic.endpController.HasSynced() &&\n+\t\tic.secrController.HasSynced() &&\n+\t\tic.mapController.HasSynced()\n+}\n+\n+// Name returns the healthcheck name\n+func (ic GenericController) Name() string {\n+\treturn \"Ingress Controller\"\n+}\n+\n+// Check returns if the nginx healthz endpoint is returning ok (status code 200)\n+func (ic GenericController) Check(_ *http.Request) error {\n+\tres, err := http.Get(\"http://127.0.0.1:18080/healthz\")","path":"core/pkg/ingress/controller/controller.go","position":293,"original_position":301,"commit_id":"16c580054509b4b3451ae7636d17949678ebc2ae","original_commit_id":"ed9a416b01a4dc7635b28bca163f3b83e4a6c71d","user":{"login":"aledbf","id":161571,"avatar_url":"https://avatars.githubusercontent.com/u/161571?v=3","gravatar_id":"","url":"https://api.github.com/users/aledbf","html_url":"https://github.com/aledbf","followers_url":"https://api.github.com/users/aledbf/followers","following_url":"https://api.github.com/users/aledbf/following{/other_user}","gists_url":"https://api.github.com/users/aledbf/gists{/gist_id}","starred_url":"https://api.github.com/users/aledbf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aledbf/subscriptions","organizations_url":"https://api.github.com/users/aledbf/orgs","repos_url":"https://api.github.com/users/aledbf/repos","events_url":"https://api.github.com/users/aledbf/events{/privacy}","received_events_url":"https://api.github.com/users/aledbf/received_events","type":"User","site_admin":false},"body":"> Is this an example implementation \r\n\r\nGenericController provides the boilerplate and should not contain specific information about the backend (like nginx). The idea is that if you want to write an ingress controller for XX it should be similar to https://github.com/kubernetes/ingress/blob/master/controllers/nginx/pkg/cmd/controller/nginx.go (only the template part)\r\n","created_at":"2016-11-25T13:24:45Z","updated_at":"2016-11-25T13:24:45Z","html_url":"https://github.com/kubernetes/ingress/pull/15#discussion_r89617001","pull_request_url":"https://api.github.com/repos/kubernetes/ingress/pulls/15","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/comments/89617001"},"html":{"href":"https://github.com/kubernetes/ingress/pull/15#discussion_r89617001"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/15"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/ingress/pulls/15","id":93401245,"html_url":"https://github.com/kubernetes/ingress/pull/15","diff_url":"https://github.com/kubernetes/ingress/pull/15.diff","patch_url":"https://github.com/kubernetes/ingress/pull/15.patch","issue_url":"https://api.github.com/repos/kubernetes/ingress/issues/15","number":15,"state":"closed","locked":false,"title":"Split implementations from generic code","user":{"login":"aledbf","id":161571,"avatar_url":"https://avatars.githubusercontent.com/u/161571?v=3","gravatar_id":"","url":"https://api.github.com/users/aledbf","html_url":"https://github.com/aledbf","followers_url":"https://api.github.com/users/aledbf/followers","following_url":"https://api.github.com/users/aledbf/following{/other_user}","gists_url":"https://api.github.com/users/aledbf/gists{/gist_id}","starred_url":"https://api.github.com/users/aledbf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aledbf/subscriptions","organizations_url":"https://api.github.com/users/aledbf/orgs","repos_url":"https://api.github.com/users/aledbf/repos","events_url":"https://api.github.com/users/aledbf/events{/privacy}","received_events_url":"https://api.github.com/users/aledbf/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-11-11T21:29:02Z","updated_at":"2016-11-25T13:24:45Z","closed_at":"2016-11-24T00:39:20Z","merged_at":"2016-11-24T00:39:20Z","merge_commit_sha":"850af9329d8ca58c82299a529c5abd88a7591446","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/ingress/pulls/15/commits","review_comments_url":"https://api.github.com/repos/kubernetes/ingress/pulls/15/comments","review_comment_url":"https://api.github.com/repos/kubernetes/ingress/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/ingress/issues/15/comments","statuses_url":"https://api.github.com/repos/kubernetes/ingress/statuses/16c580054509b4b3451ae7636d17949678ebc2ae","head":{"label":"aledbf:merge-aledbf","ref":"merge-aledbf","sha":"16c580054509b4b3451ae7636d17949678ebc2ae","user":{"login":"aledbf","id":161571,"avatar_url":"https://avatars.githubusercontent.com/u/161571?v=3","gravatar_id":"","url":"https://api.github.com/users/aledbf","html_url":"https://github.com/aledbf","followers_url":"https://api.github.com/users/aledbf/followers","following_url":"https://api.github.com/users/aledbf/following{/other_user}","gists_url":"https://api.github.com/users/aledbf/gists{/gist_id}","starred_url":"https://api.github.com/users/aledbf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aledbf/subscriptions","organizations_url":"https://api.github.com/users/aledbf/orgs","repos_url":"https://api.github.com/users/aledbf/repos","events_url":"https://api.github.com/users/aledbf/events{/privacy}","received_events_url":"https://api.github.com/users/aledbf/received_events","type":"User","site_admin":false},"repo":{"id":72895783,"name":"ingress","full_name":"aledbf/ingress","owner":{"login":"aledbf","id":161571,"avatar_url":"https://avatars.githubusercontent.com/u/161571?v=3","gravatar_id":"","url":"https://api.github.com/users/aledbf","html_url":"https://github.com/aledbf","followers_url":"https://api.github.com/users/aledbf/followers","following_url":"https://api.github.com/users/aledbf/following{/other_user}","gists_url":"https://api.github.com/users/aledbf/gists{/gist_id}","starred_url":"https://api.github.com/users/aledbf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aledbf/subscriptions","organizations_url":"https://api.github.com/users/aledbf/orgs","repos_url":"https://api.github.com/users/aledbf/repos","events_url":"https://api.github.com/users/aledbf/events{/privacy}","received_events_url":"https://api.github.com/users/aledbf/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aledbf/ingress","description":"Ingress controllers","fork":true,"url":"https://api.github.com/repos/aledbf/ingress","forks_url":"https://api.github.com/repos/aledbf/ingress/forks","keys_url":"https://api.github.com/repos/aledbf/ingress/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aledbf/ingress/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aledbf/ingress/teams","hooks_url":"https://api.github.com/repos/aledbf/ingress/hooks","issue_events_url":"https://api.github.com/repos/aledbf/ingress/issues/events{/number}","events_url":"https://api.github.com/repos/aledbf/ingress/events","assignees_url":"https://api.github.com/repos/aledbf/ingress/assignees{/user}","branches_url":"https://api.github.com/repos/aledbf/ingress/branches{/branch}","tags_url":"https://api.github.com/repos/aledbf/ingress/tags","blobs_url":"https://api.github.com/repos/aledbf/ingress/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aledbf/ingress/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aledbf/ingress/git/refs{/sha}","trees_url":"https://api.github.com/repos/aledbf/ingress/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aledbf/ingress/statuses/{sha}","languages_url":"https://api.github.com/repos/aledbf/ingress/languages","stargazers_url":"https://api.github.com/repos/aledbf/ingress/stargazers","contributors_url":"https://api.github.com/repos/aledbf/ingress/contributors","subscribers_url":"https://api.github.com/repos/aledbf/ingress/subscribers","subscription_url":"https://api.github.com/repos/aledbf/ingress/subscription","commits_url":"https://api.github.com/repos/aledbf/ingress/commits{/sha}","git_commits_url":"https://api.github.com/repos/aledbf/ingress/git/commits{/sha}","comments_url":"https://api.github.com/repos/aledbf/ingress/comments{/number}","issue_comment_url":"https://api.github.com/repos/aledbf/ingress/issues/comments{/number}","contents_url":"https://api.github.com/repos/aledbf/ingress/contents/{+path}","compare_url":"https://api.github.com/repos/aledbf/ingress/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aledbf/ingress/merges","archive_url":"https://api.github.com/repos/aledbf/ingress/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aledbf/ingress/downloads","issues_url":"https://api.github.com/repos/aledbf/ingress/issues{/number}","pulls_url":"https://api.github.com/repos/aledbf/ingress/pulls{/number}","milestones_url":"https://api.github.com/repos/aledbf/ingress/milestones{/number}","notifications_url":"https://api.github.com/repos/aledbf/ingress/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aledbf/ingress/labels{/name}","releases_url":"https://api.github.com/repos/aledbf/ingress/releases{/id}","deployments_url":"https://api.github.com/repos/aledbf/ingress/deployments","created_at":"2016-11-05T00:39:04Z","updated_at":"2016-11-10T21:42:21Z","pushed_at":"2016-11-24T03:13:11Z","git_url":"git://github.com/aledbf/ingress.git","ssh_url":"git@github.com:aledbf/ingress.git","clone_url":"https://github.com/aledbf/ingress.git","svn_url":"https://github.com/aledbf/ingress","homepage":null,"size":18647,"stargazers_count":0,"watchers_count":0,"language":"Go","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":"d1e8a629caf120a318c23effd7decd70f92cb46d","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":72891330,"name":"ingress","full_name":"kubernetes/ingress","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/ingress","description":"Ingress controllers","fork":false,"url":"https://api.github.com/repos/kubernetes/ingress","forks_url":"https://api.github.com/repos/kubernetes/ingress/forks","keys_url":"https://api.github.com/repos/kubernetes/ingress/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/ingress/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/ingress/teams","hooks_url":"https://api.github.com/repos/kubernetes/ingress/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/ingress/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/ingress/events","assignees_url":"https://api.github.com/repos/kubernetes/ingress/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/ingress/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/ingress/tags","blobs_url":"https://api.github.com/repos/kubernetes/ingress/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/ingress/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/ingress/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/ingress/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/ingress/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/ingress/languages","stargazers_url":"https://api.github.com/repos/kubernetes/ingress/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/ingress/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/ingress/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/ingress/subscription","commits_url":"https://api.github.com/repos/kubernetes/ingress/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/ingress/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/ingress/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/ingress/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/ingress/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/ingress/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/ingress/merges","archive_url":"https://api.github.com/repos/kubernetes/ingress/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/ingress/downloads","issues_url":"https://api.github.com/repos/kubernetes/ingress/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/ingress/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/ingress/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/ingress/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/ingress/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/ingress/releases{/id}","deployments_url":"https://api.github.com/repos/kubernetes/ingress/deployments","created_at":"2016-11-04T22:54:14Z","updated_at":"2016-11-23T03:22:28Z","pushed_at":"2016-11-25T12:34:38Z","git_url":"git://github.com/kubernetes/ingress.git","ssh_url":"git@github.com:kubernetes/ingress.git","clone_url":"https://github.com/kubernetes/ingress.git","svn_url":"https://github.com/kubernetes/ingress","homepage":null,"size":18658,"stargazers_count":15,"watchers_count":15,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":19,"forks":6,"open_issues":19,"watchers":15,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/15"},"html":{"href":"https://github.com/kubernetes/ingress/pull/15"},"issue":{"href":"https://api.github.com/repos/kubernetes/ingress/issues/15"},"comments":{"href":"https://api.github.com/repos/kubernetes/ingress/issues/15/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/15/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/ingress/pulls/15/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/ingress/statuses/16c580054509b4b3451ae7636d17949678ebc2ae"}}}}
{"actor":{"display_login":"aledbf"}}