{"action":"created","comment":{"url":"https://api.github.com/repos/linkerd/linkerd2/pulls/comments/210371319","pull_request_review_id":146572620,"id":210371319,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMDM3MTMxOQ==","diff_hunk":"@@ -0,0 +1,309 @@\n+package main\n+\n+import (\n+\t\"crypto/sha256\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"strings\"\n+\n+\t\"github.com/ghodss/yaml\"\n+\t\"github.com/golang/glog\"\n+\t\"k8s.io/api/admission/v1beta1\"\n+\tadmissionregistrationv1beta1 \"k8s.io/api/admissionregistration/v1beta1\"\n+\tcorev1 \"k8s.io/api/core/v1\"\n+\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\t\"k8s.io/apimachinery/pkg/runtime\"\n+\t\"k8s.io/apimachinery/pkg/runtime/serializer\"\n+\t\"k8s.io/kubernetes/pkg/apis/core/v1\"\n+)\n+\n+var (\n+\truntimeScheme = runtime.NewScheme()\n+\tcodecs        = serializer.NewCodecFactory(runtimeScheme)\n+\tdeserializer  = codecs.UniversalDeserializer()\n+\n+\t// (https://github.com/kubernetes/kubernetes/issues/57982)\n+\tdefaulter = runtime.ObjectDefaulter(runtimeScheme)\n+)\n+\n+var ignoredNamespaces = []string{\n+\tmetav1.NamespaceSystem,\n+\tmetav1.NamespacePublic,\n+}\n+\n+const (\n+\tadmissionWebhookAnnotationInjectKey = \"sidecar-injector-webhook.linkerd.io/inject\"\n+\tadmissionWebhookAnnotationStatusKey = \"sidecar-injector-webhook.linkerd.io/status\"\n+)\n+\n+type WebhookServer struct {\n+\tsidecarConfig *Config\n+\tserver        *http.Server\n+}\n+\n+// Webhook Server parameters\n+type WhSvrParameters struct {\n+\tport           int    // webhook server port\n+\tcertFile       string // path to the x509 certificate for https\n+\tkeyFile        string // path to the x509 private key matching `CertFile`\n+\tsidecarCfgFile string // path to sidecar injector configuration file\n+}\n+\n+type Config struct {\n+\tContainers []corev1.Container `yaml:\"containers\"`\n+\tVolumes    []corev1.Volume    `yaml:\"volumes\"`\n+}\n+\n+type patchOperation struct {\n+\tOp    string      `json:\"op\"`\n+\tPath  string      `json:\"path\"`\n+\tValue interface{} `json:\"value,omitempty\"`\n+}\n+\n+func init() {\n+\t_ = corev1.AddToScheme(runtimeScheme)\n+\t_ = admissionregistrationv1beta1.AddToScheme(runtimeScheme)\n+\t// defaulting with webhooks:\n+\t// https://github.com/kubernetes/kubernetes/issues/57982\n+\t_ = v1.AddToScheme(runtimeScheme)\n+}\n+\n+// (https://github.com/kubernetes/kubernetes/issues/57982)\n+func applyDefaultsWorkaround(containers []corev1.Container, volumes []corev1.Volume) {\n+\tdefaulter.Default(&corev1.Pod{\n+\t\tSpec: corev1.PodSpec{\n+\t\t\tContainers: containers,\n+\t\t\tVolumes:    volumes,\n+\t\t},\n+\t})\n+}\n+\n+func loadConfig(configFile string) (*Config, error) {\n+\tdata, err := ioutil.ReadFile(configFile)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tglog.Infof(\"New configuration: sha256sum %x\", sha256.Sum256(data))\n+\n+\tvar cfg Config\n+\tif err := yaml.Unmarshal(data, &cfg); err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\treturn &cfg, nil\n+}\n+\n+// Check whether the target resoured need to be mutated\n+func mutationRequired(ignoredList []string, metadata *metav1.ObjectMeta) bool {\n+\t// skip special kubernete system namespaces\n+\tfor _, namespace := range ignoredList {\n+\t\tif metadata.Namespace == namespace {\n+\t\t\tglog.Infof(\"Skip mutation for %v for it' in special namespace:%v\", metadata.Name, metadata.Namespace)\n+\t\t\treturn false\n+\t\t}\n+\t}\n+\n+\tannotations := metadata.GetAnnotations()\n+\tif annotations == nil {\n+\t\tannotations = map[string]string{}\n+\t}\n+\n+\tstatus := annotations[admissionWebhookAnnotationStatusKey]\n+\n+\t// determine whether to perform mutation based on annotation for the target resource\n+\tvar required bool\n+\tif strings.ToLower(status) == \"injected\" {\n+\t\trequired = false\n+\t} else {\n+\t\tswitch strings.ToLower(annotations[admissionWebhookAnnotationInjectKey]) {\n+\t\tdefault:\n+\t\t\trequired = false\n+\t\tcase \"y\", \"yes\", \"true\", \"on\":\n+\t\t\trequired = true\n+\t\t}\n+\t}\n+\n+\tglog.Infof(\"Mutation policy for %v/%v: status: %q required:%v\", metadata.Namespace, metadata.Name, status, required)\n+\treturn required\n+}\n+\n+func addContainer(target, added []corev1.Container, basePath string) (patch []patchOperation) {\n+\tfirst := len(target) == 0\n+\tvar value interface{}\n+\tfor _, add := range added {\n+\t\tvalue = add\n+\t\tpath := basePath\n+\t\tif first {\n+\t\t\tfirst = false\n+\t\t\tvalue = []corev1.Container{add}\n+\t\t} else {\n+\t\t\tpath = path + \"/-\"\n+\t\t}\n+\t\tpatch = append(patch, patchOperation{\n+\t\t\tOp:    \"add\",\n+\t\t\tPath:  path,\n+\t\t\tValue: value,\n+\t\t})\n+\t}\n+\treturn patch\n+}\n+\n+func addVolume(target, added []corev1.Volume, basePath string) (patch []patchOperation) {\n+\tfirst := len(target) == 0\n+\tvar value interface{}\n+\tfor _, add := range added {\n+\t\tvalue = add\n+\t\tpath := basePath\n+\t\tif first {\n+\t\t\tfirst = false\n+\t\t\tvalue = []corev1.Volume{add}\n+\t\t} else {\n+\t\t\tpath = path + \"/-\"\n+\t\t}\n+\t\tpatch = append(patch, patchOperation{\n+\t\t\tOp:    \"add\",\n+\t\t\tPath:  path,\n+\t\t\tValue: value,\n+\t\t})\n+\t}\n+\treturn patch\n+}\n+\n+func updateAnnotation(target map[string]string, added map[string]string) (patch []patchOperation) {\n+\tfor key, value := range added {\n+\t\tif target == nil || target[key] == \"\" {\n+\t\t\ttarget = map[string]string{}\n+\t\t\tpatch = append(patch, patchOperation{\n+\t\t\t\tOp:   \"add\",\n+\t\t\t\tPath: \"/metadata/annotations\",\n+\t\t\t\tValue: map[string]string{\n+\t\t\t\t\tkey: value,\n+\t\t\t\t},\n+\t\t\t})\n+\t\t} else {\n+\t\t\tpatch = append(patch, patchOperation{\n+\t\t\t\tOp:    \"replace\",\n+\t\t\t\tPath:  \"/metadata/annotations/\" + key,\n+\t\t\t\tValue: value,\n+\t\t\t})\n+\t\t}\n+\t}\n+\treturn patch\n+}\n+\n+// create mutation patch for resoures\n+func createPatch(pod *corev1.Pod, sidecarConfig *Config, annotations map[string]string) ([]byte, error) {\n+\tvar patch []patchOperation\n+\n+\tpatch = append(patch, addContainer(pod.Spec.Containers, sidecarConfig.Containers, \"/spec/containers\")...)\n+\tpatch = append(patch, addVolume(pod.Spec.Volumes, sidecarConfig.Volumes, \"/spec/volumes\")...)\n+\tpatch = append(patch, updateAnnotation(pod.Annotations, annotations)...)\n+\n+\treturn json.Marshal(patch)\n+}\n+\n+// main mutation process\n+func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {\n+\treq := ar.Request\n+\tvar pod corev1.Pod\n+\tif err := json.Unmarshal(req.Object.Raw, &pod); err != nil {\n+\t\tglog.Errorf(\"Could not unmarshal raw object: %v\", err)\n+\t\treturn &v1beta1.AdmissionResponse{\n+\t\t\tResult: &metav1.Status{\n+\t\t\t\tMessage: err.Error(),\n+\t\t\t},\n+\t\t}\n+\t}\n+\n+\tglog.Infof(\"AdmissionReview for Kind=%v, Namespace=%v Name=%v (%v) UID=%v patchOperation=%v UserInfo=%v\",\n+\t\treq.Kind, req.Namespace, req.Name, pod.Name, req.UID, req.Operation, req.UserInfo)\n+\n+\t// determine whether to perform mutation\n+\tif !mutationRequired(ignoredNamespaces, &pod.ObjectMeta) {\n+\t\tglog.Infof(\"Skipping mutation for %s/%s due to policy check\", pod.Namespace, pod.Name)\n+\t\treturn &v1beta1.AdmissionResponse{\n+\t\t\tAllowed: true,\n+\t\t}\n+\t}\n+\n+\t// Workaround: https://github.com/kubernetes/kubernetes/issues/57982\n+\tapplyDefaultsWorkaround(whsvr.sidecarConfig.Containers, whsvr.sidecarConfig.Volumes)\n+\tannotations := map[string]string{admissionWebhookAnnotationStatusKey: \"injected\"}\n+\tpatchBytes, err := createPatch(&pod, whsvr.sidecarConfig, annotations)\n+\tif err != nil {\n+\t\treturn &v1beta1.AdmissionResponse{\n+\t\t\tResult: &metav1.Status{\n+\t\t\t\tMessage: err.Error(),\n+\t\t\t},\n+\t\t}\n+\t}\n+\n+\tglog.Infof(\"AdmissionResponse: patch=%v\\n\", string(patchBytes))\n+\treturn &v1beta1.AdmissionResponse{\n+\t\tAllowed: true,\n+\t\tPatch:   patchBytes,\n+\t\tPatchType: func() *v1beta1.PatchType {\n+\t\t\tpt := v1beta1.PatchTypeJSONPatch\n+\t\t\treturn &pt\n+\t\t}(),\n+\t}\n+}\n+\n+// Serve method for webhook server\n+func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {\n+\tglog.Info(\"Webhook incoming!!\")\n+\n+\tvar body []byte\n+\tif r.Body != nil {\n+\t\tif data, err := ioutil.ReadAll(r.Body); err == nil {","path":"sidecar-injection/webhook.go","position":260,"original_position":260,"commit_id":"a1ac10cd786529e1debf5b99b8869318edd3b791","original_commit_id":"a1ac10cd786529e1debf5b99b8869318edd3b791","user":{"login":"ihcsim","id":1330522,"node_id":"MDQ6VXNlcjEzMzA1MjI=","avatar_url":"https://avatars1.githubusercontent.com/u/1330522?v=4","gravatar_id":"","url":"https://api.github.com/users/ihcsim","html_url":"https://github.com/ihcsim","followers_url":"https://api.github.com/users/ihcsim/followers","following_url":"https://api.github.com/users/ihcsim/following{/other_user}","gists_url":"https://api.github.com/users/ihcsim/gists{/gist_id}","starred_url":"https://api.github.com/users/ihcsim/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ihcsim/subscriptions","organizations_url":"https://api.github.com/users/ihcsim/orgs","repos_url":"https://api.github.com/users/ihcsim/repos","events_url":"https://api.github.com/users/ihcsim/events{/privacy}","received_events_url":"https://api.github.com/users/ihcsim/received_events","type":"User","site_admin":false},"body":"I think we should handle the case of `err !=nil`. Otherwise, the `empty body` error below will be returned to the user which can be misleading.","created_at":"2018-08-15T18:52:36Z","updated_at":"2018-08-15T18:52:36Z","html_url":"https://github.com/linkerd/linkerd2/pull/1423#discussion_r210371319","pull_request_url":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/comments/210371319"},"html":{"href":"https://github.com/linkerd/linkerd2/pull/1423#discussion_r210371319"},"pull_request":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423"}}},"pull_request":{"url":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423","id":207004821,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA3MDA0ODIx","html_url":"https://github.com/linkerd/linkerd2/pull/1423","diff_url":"https://github.com/linkerd/linkerd2/pull/1423.diff","patch_url":"https://github.com/linkerd/linkerd2/pull/1423.patch","issue_url":"https://api.github.com/repos/linkerd/linkerd2/issues/1423","number":1423,"state":"open","locked":false,"title":"WIP: Introduce mutating webhook for sidecar injection.","user":{"login":"Bedotech","id":627329,"node_id":"MDQ6VXNlcjYyNzMyOQ==","avatar_url":"https://avatars0.githubusercontent.com/u/627329?v=4","gravatar_id":"","url":"https://api.github.com/users/Bedotech","html_url":"https://github.com/Bedotech","followers_url":"https://api.github.com/users/Bedotech/followers","following_url":"https://api.github.com/users/Bedotech/following{/other_user}","gists_url":"https://api.github.com/users/Bedotech/gists{/gist_id}","starred_url":"https://api.github.com/users/Bedotech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bedotech/subscriptions","organizations_url":"https://api.github.com/users/Bedotech/orgs","repos_url":"https://api.github.com/users/Bedotech/repos","events_url":"https://api.github.com/users/Bedotech/events{/privacy}","received_events_url":"https://api.github.com/users/Bedotech/received_events","type":"User","site_admin":false},"body":"For manage deployment with linkerd2 with other tools like helm is really\r\nimportant to make the pod injection at the lower level we can.\r\n\r\n#561 Using MutatingWebhook (new k8s 1.9) we can modify a pod before the pod\r\nis created.\r\n\r\nSo far i have created:\r\n* new container called 'sidecar-injection'\r\n* update install profile for add 'sidecar-injection'\r\n* create for now fake webhook for test integration\r\n\r\nThis PR is really WIP, before we have to solve:\r\n* Ho we issue certificate for webhook in k8s\r\n* Link the webhook inject handler with existing api for sidecar\r\ninjection.\r\n* code review.\r\n\r\nSigned-off-by: Mattia Rossi <mattia.rossi@criptalia.it>","created_at":"2018-08-08T13:18:52Z","updated_at":"2018-08-15T18:52:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4441a7cecb7567c2568c30dfb70ff21652f5ed20","assignee":{"login":"Bedotech","id":627329,"node_id":"MDQ6VXNlcjYyNzMyOQ==","avatar_url":"https://avatars0.githubusercontent.com/u/627329?v=4","gravatar_id":"","url":"https://api.github.com/users/Bedotech","html_url":"https://github.com/Bedotech","followers_url":"https://api.github.com/users/Bedotech/followers","following_url":"https://api.github.com/users/Bedotech/following{/other_user}","gists_url":"https://api.github.com/users/Bedotech/gists{/gist_id}","starred_url":"https://api.github.com/users/Bedotech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bedotech/subscriptions","organizations_url":"https://api.github.com/users/Bedotech/orgs","repos_url":"https://api.github.com/users/Bedotech/repos","events_url":"https://api.github.com/users/Bedotech/events{/privacy}","received_events_url":"https://api.github.com/users/Bedotech/received_events","type":"User","site_admin":false},"assignees":[{"login":"Bedotech","id":627329,"node_id":"MDQ6VXNlcjYyNzMyOQ==","avatar_url":"https://avatars0.githubusercontent.com/u/627329?v=4","gravatar_id":"","url":"https://api.github.com/users/Bedotech","html_url":"https://github.com/Bedotech","followers_url":"https://api.github.com/users/Bedotech/followers","following_url":"https://api.github.com/users/Bedotech/following{/other_user}","gists_url":"https://api.github.com/users/Bedotech/gists{/gist_id}","starred_url":"https://api.github.com/users/Bedotech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bedotech/subscriptions","organizations_url":"https://api.github.com/users/Bedotech/orgs","repos_url":"https://api.github.com/users/Bedotech/repos","events_url":"https://api.github.com/users/Bedotech/events{/privacy}","received_events_url":"https://api.github.com/users/Bedotech/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423/commits","review_comments_url":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423/comments","review_comment_url":"https://api.github.com/repos/linkerd/linkerd2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/linkerd/linkerd2/issues/1423/comments","statuses_url":"https://api.github.com/repos/linkerd/linkerd2/statuses/a1ac10cd786529e1debf5b99b8869318edd3b791","head":{"label":"criptalia:add-mutating-webhook-for-sidecar-injection","ref":"add-mutating-webhook-for-sidecar-injection","sha":"a1ac10cd786529e1debf5b99b8869318edd3b791","user":{"login":"criptalia","id":36248946,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM2MjQ4OTQ2","avatar_url":"https://avatars2.githubusercontent.com/u/36248946?v=4","gravatar_id":"","url":"https://api.github.com/users/criptalia","html_url":"https://github.com/criptalia","followers_url":"https://api.github.com/users/criptalia/followers","following_url":"https://api.github.com/users/criptalia/following{/other_user}","gists_url":"https://api.github.com/users/criptalia/gists{/gist_id}","starred_url":"https://api.github.com/users/criptalia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/criptalia/subscriptions","organizations_url":"https://api.github.com/users/criptalia/orgs","repos_url":"https://api.github.com/users/criptalia/repos","events_url":"https://api.github.com/users/criptalia/events{/privacy}","received_events_url":"https://api.github.com/users/criptalia/received_events","type":"Organization","site_admin":false},"repo":{"id":144014516,"node_id":"MDEwOlJlcG9zaXRvcnkxNDQwMTQ1MTY=","name":"linkerd2","full_name":"criptalia/linkerd2","owner":{"login":"criptalia","id":36248946,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM2MjQ4OTQ2","avatar_url":"https://avatars2.githubusercontent.com/u/36248946?v=4","gravatar_id":"","url":"https://api.github.com/users/criptalia","html_url":"https://github.com/criptalia","followers_url":"https://api.github.com/users/criptalia/followers","following_url":"https://api.github.com/users/criptalia/following{/other_user}","gists_url":"https://api.github.com/users/criptalia/gists{/gist_id}","starred_url":"https://api.github.com/users/criptalia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/criptalia/subscriptions","organizations_url":"https://api.github.com/users/criptalia/orgs","repos_url":"https://api.github.com/users/criptalia/repos","events_url":"https://api.github.com/users/criptalia/events{/privacy}","received_events_url":"https://api.github.com/users/criptalia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/criptalia/linkerd2","description":"Ultralight service mesh for Kubernetes","fork":true,"url":"https://api.github.com/repos/criptalia/linkerd2","forks_url":"https://api.github.com/repos/criptalia/linkerd2/forks","keys_url":"https://api.github.com/repos/criptalia/linkerd2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/criptalia/linkerd2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/criptalia/linkerd2/teams","hooks_url":"https://api.github.com/repos/criptalia/linkerd2/hooks","issue_events_url":"https://api.github.com/repos/criptalia/linkerd2/issues/events{/number}","events_url":"https://api.github.com/repos/criptalia/linkerd2/events","assignees_url":"https://api.github.com/repos/criptalia/linkerd2/assignees{/user}","branches_url":"https://api.github.com/repos/criptalia/linkerd2/branches{/branch}","tags_url":"https://api.github.com/repos/criptalia/linkerd2/tags","blobs_url":"https://api.github.com/repos/criptalia/linkerd2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/criptalia/linkerd2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/criptalia/linkerd2/git/refs{/sha}","trees_url":"https://api.github.com/repos/criptalia/linkerd2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/criptalia/linkerd2/statuses/{sha}","languages_url":"https://api.github.com/repos/criptalia/linkerd2/languages","stargazers_url":"https://api.github.com/repos/criptalia/linkerd2/stargazers","contributors_url":"https://api.github.com/repos/criptalia/linkerd2/contributors","subscribers_url":"https://api.github.com/repos/criptalia/linkerd2/subscribers","subscription_url":"https://api.github.com/repos/criptalia/linkerd2/subscription","commits_url":"https://api.github.com/repos/criptalia/linkerd2/commits{/sha}","git_commits_url":"https://api.github.com/repos/criptalia/linkerd2/git/commits{/sha}","comments_url":"https://api.github.com/repos/criptalia/linkerd2/comments{/number}","issue_comment_url":"https://api.github.com/repos/criptalia/linkerd2/issues/comments{/number}","contents_url":"https://api.github.com/repos/criptalia/linkerd2/contents/{+path}","compare_url":"https://api.github.com/repos/criptalia/linkerd2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/criptalia/linkerd2/merges","archive_url":"https://api.github.com/repos/criptalia/linkerd2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/criptalia/linkerd2/downloads","issues_url":"https://api.github.com/repos/criptalia/linkerd2/issues{/number}","pulls_url":"https://api.github.com/repos/criptalia/linkerd2/pulls{/number}","milestones_url":"https://api.github.com/repos/criptalia/linkerd2/milestones{/number}","notifications_url":"https://api.github.com/repos/criptalia/linkerd2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/criptalia/linkerd2/labels{/name}","releases_url":"https://api.github.com/repos/criptalia/linkerd2/releases{/id}","deployments_url":"https://api.github.com/repos/criptalia/linkerd2/deployments","created_at":"2018-08-08T13:03:11Z","updated_at":"2018-08-08T13:03:14Z","pushed_at":"2018-08-09T14:34:17Z","git_url":"git://github.com/criptalia/linkerd2.git","ssh_url":"git@github.com:criptalia/linkerd2.git","clone_url":"https://github.com/criptalia/linkerd2.git","svn_url":"https://github.com/criptalia/linkerd2","homepage":"https://linkerd.io","size":7175,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"linkerd:master","ref":"master","sha":"82940990e94b779ffcd92b96164dccf88001f5e8","user":{"login":"linkerd","id":25301026,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MzAxMDI2","avatar_url":"https://avatars3.githubusercontent.com/u/25301026?v=4","gravatar_id":"","url":"https://api.github.com/users/linkerd","html_url":"https://github.com/linkerd","followers_url":"https://api.github.com/users/linkerd/followers","following_url":"https://api.github.com/users/linkerd/following{/other_user}","gists_url":"https://api.github.com/users/linkerd/gists{/gist_id}","starred_url":"https://api.github.com/users/linkerd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkerd/subscriptions","organizations_url":"https://api.github.com/users/linkerd/orgs","repos_url":"https://api.github.com/users/linkerd/repos","events_url":"https://api.github.com/users/linkerd/events{/privacy}","received_events_url":"https://api.github.com/users/linkerd/received_events","type":"Organization","site_admin":false},"repo":{"id":113106184,"node_id":"MDEwOlJlcG9zaXRvcnkxMTMxMDYxODQ=","name":"linkerd2","full_name":"linkerd/linkerd2","owner":{"login":"linkerd","id":25301026,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1MzAxMDI2","avatar_url":"https://avatars3.githubusercontent.com/u/25301026?v=4","gravatar_id":"","url":"https://api.github.com/users/linkerd","html_url":"https://github.com/linkerd","followers_url":"https://api.github.com/users/linkerd/followers","following_url":"https://api.github.com/users/linkerd/following{/other_user}","gists_url":"https://api.github.com/users/linkerd/gists{/gist_id}","starred_url":"https://api.github.com/users/linkerd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkerd/subscriptions","organizations_url":"https://api.github.com/users/linkerd/orgs","repos_url":"https://api.github.com/users/linkerd/repos","events_url":"https://api.github.com/users/linkerd/events{/privacy}","received_events_url":"https://api.github.com/users/linkerd/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/linkerd/linkerd2","description":"Ultralight service mesh for Kubernetes","fork":false,"url":"https://api.github.com/repos/linkerd/linkerd2","forks_url":"https://api.github.com/repos/linkerd/linkerd2/forks","keys_url":"https://api.github.com/repos/linkerd/linkerd2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/linkerd/linkerd2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/linkerd/linkerd2/teams","hooks_url":"https://api.github.com/repos/linkerd/linkerd2/hooks","issue_events_url":"https://api.github.com/repos/linkerd/linkerd2/issues/events{/number}","events_url":"https://api.github.com/repos/linkerd/linkerd2/events","assignees_url":"https://api.github.com/repos/linkerd/linkerd2/assignees{/user}","branches_url":"https://api.github.com/repos/linkerd/linkerd2/branches{/branch}","tags_url":"https://api.github.com/repos/linkerd/linkerd2/tags","blobs_url":"https://api.github.com/repos/linkerd/linkerd2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/linkerd/linkerd2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/linkerd/linkerd2/git/refs{/sha}","trees_url":"https://api.github.com/repos/linkerd/linkerd2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/linkerd/linkerd2/statuses/{sha}","languages_url":"https://api.github.com/repos/linkerd/linkerd2/languages","stargazers_url":"https://api.github.com/repos/linkerd/linkerd2/stargazers","contributors_url":"https://api.github.com/repos/linkerd/linkerd2/contributors","subscribers_url":"https://api.github.com/repos/linkerd/linkerd2/subscribers","subscription_url":"https://api.github.com/repos/linkerd/linkerd2/subscription","commits_url":"https://api.github.com/repos/linkerd/linkerd2/commits{/sha}","git_commits_url":"https://api.github.com/repos/linkerd/linkerd2/git/commits{/sha}","comments_url":"https://api.github.com/repos/linkerd/linkerd2/comments{/number}","issue_comment_url":"https://api.github.com/repos/linkerd/linkerd2/issues/comments{/number}","contents_url":"https://api.github.com/repos/linkerd/linkerd2/contents/{+path}","compare_url":"https://api.github.com/repos/linkerd/linkerd2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/linkerd/linkerd2/merges","archive_url":"https://api.github.com/repos/linkerd/linkerd2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/linkerd/linkerd2/downloads","issues_url":"https://api.github.com/repos/linkerd/linkerd2/issues{/number}","pulls_url":"https://api.github.com/repos/linkerd/linkerd2/pulls{/number}","milestones_url":"https://api.github.com/repos/linkerd/linkerd2/milestones{/number}","notifications_url":"https://api.github.com/repos/linkerd/linkerd2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/linkerd/linkerd2/labels{/name}","releases_url":"https://api.github.com/repos/linkerd/linkerd2/releases{/id}","deployments_url":"https://api.github.com/repos/linkerd/linkerd2/deployments","created_at":"2017-12-04T23:16:56Z","updated_at":"2018-08-15T18:31:04Z","pushed_at":"2018-08-15T18:31:02Z","git_url":"git://github.com/linkerd/linkerd2.git","ssh_url":"git@github.com:linkerd/linkerd2.git","clone_url":"https://github.com/linkerd/linkerd2.git","svn_url":"https://github.com/linkerd/linkerd2","homepage":"https://linkerd.io","size":7271,"stargazers_count":2306,"watchers_count":2306,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":135,"mirror_url":null,"archived":false,"open_issues_count":213,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":135,"open_issues":213,"watchers":2306,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423"},"html":{"href":"https://github.com/linkerd/linkerd2/pull/1423"},"issue":{"href":"https://api.github.com/repos/linkerd/linkerd2/issues/1423"},"comments":{"href":"https://api.github.com/repos/linkerd/linkerd2/issues/1423/comments"},"review_comments":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423/comments"},"review_comment":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/linkerd/linkerd2/pulls/1423/commits"},"statuses":{"href":"https://api.github.com/repos/linkerd/linkerd2/statuses/a1ac10cd786529e1debf5b99b8869318edd3b791"}},"author_association":"NONE"}}
{"actor":{"display_login":"ihcsim"}}