{"action":"created","comment":{"url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/comments/207310897","pull_request_review_id":142889914,"id":207310897,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwNzMxMDg5Nw==","diff_hunk":"@@ -0,0 +1,293 @@\n+package await\n+\n+import (\n+\t\"fmt\"\n+\t\"reflect\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\t\"github.com/golang/glog\"\n+\t\"github.com/pkg/errors\"\n+\t\"github.com/pulumi/pulumi-kubernetes/pkg/openapi\"\n+\t\"github.com/pulumi/pulumi/pkg/diag\"\n+\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n+\t\"k8s.io/apimachinery/pkg/watch\"\n+)\n+\n+// --------------------------------------------------------------------------\n+\n+// POD CHECKING. Routines for checking whether a Pod has been initialized correctly.\n+\n+// --------------------------------------------------------------------------\n+\n+type podChecker struct {\n+\tpodReady           bool\n+\tpodScheduled       bool\n+\tpodScheduledErrors map[string]string\n+\tcontainerErrors    map[string][]string\n+}\n+\n+func makePodChecker() *podChecker {\n+\treturn &podChecker{\n+\t\tpodReady:           false,\n+\t\tpodScheduled:       false,\n+\t\tpodScheduledErrors: map[string]string{},\n+\t\tcontainerErrors:    map[string][]string{},\n+\t}\n+}\n+\n+func (pc *podChecker) check(pod *unstructured.Unstructured) {\n+\t// Attempt to get status to check if pod is ready.\n+\trawStatus, hasStatus := openapi.Pluck(pod.Object, \"status\")\n+\tif !hasStatus {\n+\t\t// No status, kubelet has not yet started to initialize Pod. Do nothing.\n+\t\treturn\n+\t}\n+\tstatus, isMap := rawStatus.(map[string]interface{})\n+\tif !isMap {\n+\t\tglog.V(3).Infof(\"Pod watch received unexpected status type '%s'\",\n+\t\t\treflect.TypeOf(rawStatus))\n+\t\treturn\n+\n+\t}\n+\n+\t// Alway clear all errors so we start fresh.\n+\tpc.clearErrors()\n+\n+\t// Check if the pod is ready.\n+\tswitch phase := status[\"phase\"]; phase {\n+\tcase \"Running\":\n+\t\t// Success.\n+\t\tpc.podReady = true\n+\t\treturn\n+\tcase \"Pending\":\n+\t\tpc.checkPendingPod(pod, status)\n+\t// case \"Succeeded\", \"Failed\", \"Unknown\":\n+\tcase nil, \"\":\n+\t\t// Kubelet has not yet started to initialize Pod. Do nothing.\n+\t\treturn\n+\tdefault:\n+\t\tglog.V(3).Infof(\"Pod '%s' has unknown status phase '%s'\",\n+\t\t\tpod.GetName(), phase)\n+\t}\n+}\n+\n+func (pc *podChecker) checkPendingPod(pod *unstructured.Unstructured, status map[string]interface{}) {\n+\trawConditions, exists := status[\"conditions\"]\n+\tconditions, isSlice := rawConditions.([]interface{})\n+\tif !exists && !isSlice {\n+\t\t// Kubelet has not yet started to initialize Pod. Do nothing.\n+\t\treturn\n+\t}\n+\n+\t// Check if Pod was scheduled. If it wasn't, there's no sense in continuing, because there won't\n+\t// be other errors.\n+\tpodScheduled := false\n+\tpodScheduledCondition := map[string]interface{}{}\n+\tfor _, rawCondition := range conditions {\n+\t\tcondition, isMap := rawCondition.(map[string]interface{})\n+\t\tif !isMap {\n+\t\t\tglog.V(3).Infof(\"Pod '%s' has condition of unknown type: '%s'\", pod.GetName(),\n+\t\t\t\treflect.TypeOf(rawCondition))\n+\t\t\tcontinue\n+\t\t}\n+\t\tif condition[\"type\"] == \"PodScheduled\" {\n+\t\t\tpodScheduled = condition[\"status\"] == trueStatus\n+\t\t\tpodScheduledCondition = condition\n+\t\t}\n+\t}\n+\tif !podScheduled {\n+\t\trawReason, hasReason := podScheduledCondition[\"reason\"]\n+\t\treason, isString := rawReason.(string)\n+\t\tif !hasReason || !isString {\n+\t\t\treturn\n+\t\t}\n+\t\trawMessage, hasMessage := podScheduledCondition[\"message\"]\n+\t\tmessage, isString := rawMessage.(string)\n+\t\tif !hasMessage || !isString {\n+\t\t\treturn\n+\t\t}\n+\t\tpc.podScheduledErrors[reason] = message\n+\t\treturn\n+\t}\n+\n+\t// Collect the errors from any containers that are failing.\n+\trawContainerStatuses, exists := status[\"containerStatuses\"]\n+\tcontainerStatuses, isSlice := rawContainerStatuses.([]interface{})\n+\tif !exists || !isSlice {\n+\t\treturn\n+\t}\n+\tfor _, rawContainerStatus := range containerStatuses {\n+\t\tcontainerStatus, isMap := rawContainerStatus.(map[string]interface{})\n+\t\tif !isMap || containerStatus[\"ready\"] == true {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\t// Best effort attempt to get name of container. (This should always succeed and if it\n+\t\t// doesn't, it's not worth crashing the provider over).\n+\t\trawName := containerStatus[\"name\"]\n+\t\tvar name string\n+\t\tname, _ = rawName.(string)\n+\n+\t\trawWaiting, isWaiting := openapi.Pluck(containerStatus, \"state\", \"waiting\")\n+\t\twaiting, isMap := rawWaiting.(map[string]interface{})\n+\t\tif isWaiting && rawWaiting != nil && isMap {\n+\t\t\tpc.checkWaitingContainer(name, waiting)\n+\t\t}\n+\n+\t\t//\n+\t\t// TODO: terminated\n+\t\t//\n+\t}\n+\n+\t// Exhausted our knowledge of possible error states for Pods. Return.\n+}\n+\n+func (pc *podChecker) checkWaitingContainer(name string, waiting map[string]interface{}) {\n+\trawReason, hasReason := waiting[\"reason\"]\n+\treason, isString := rawReason.(string)\n+\tif !hasReason || !isString || reason == \"\" || reason == \"ContainerCreating\" {\n+\t\treturn\n+\t}\n+\n+\trawMessage, hasMessage := waiting[\"message\"]\n+\tmessage, isString := rawMessage.(string)\n+\tif !hasMessage || !isString {\n+\t\treturn\n+\t}\n+\n+\t// Image pull error has a bunch of useless junk at the beginning of the error message. Try to\n+\t// remove it.\n+\timagePullJunk := \"rpc error: code = Unknown desc = Error response from daemon: \"\n+\tmessage = strings.TrimPrefix(message, imagePullJunk)\n+\n+\tpc.containerErrors[reason] = append(pc.containerErrors[reason], message)\n+}\n+\n+func (pc *podChecker) clearErrors() {\n+\tpc.podScheduledErrors = map[string]string{}\n+\tpc.containerErrors = map[string][]string{}\n+}\n+\n+func (pc *podChecker) errorMessages() []string {\n+\tmessages := []string{}\n+\tfor reason, message := range pc.podScheduledErrors {\n+\t\tmessages = append(messages, fmt.Sprintf(\"Pod unscheduled: [%s] %s\", reason, message))\n+\t}\n+\n+\tfor reason, errors := range pc.containerErrors {\n+\t\tfor _, message := range errors {\n+\t\t\tmessages = append(messages, fmt.Sprintf(\"[%s] %s\", reason, message))\n+\t\t}\n+\t}\n+\treturn messages\n+}\n+\n+// --------------------------------------------------------------------------\n+\n+// POD AWAITING. Routines for waiting until a Pod has been initialized correctly.\n+\n+// --------------------------------------------------------------------------\n+\n+type podInitAwaiter struct {\n+\tpodChecker\n+\tconfig createAwaitConfig\n+}\n+\n+func makePodInitAwaiter(c createAwaitConfig) *podInitAwaiter {\n+\treturn &podInitAwaiter{\n+\t\tconfig:     c,\n+\t\tpodChecker: *makePodChecker(),\n+\t}\n+}\n+\n+func (pia *podInitAwaiter) Await() error {\n+\t//\n+\t// We succeed when `.status.phase` is set to \"Running\".\n+\t//\n+\n+\tpodWatcher, err := pia.config.clientForResource.Watch(metav1.ListOptions{})\n+\tif err != nil {\n+\t\treturn errors.Wrapf(err, \"Could set up watch for Pod object '%s'\",\n+\t\t\tpia.config.currentInputs.GetName())\n+\t}\n+\tdefer podWatcher.Stop()\n+\n+\t// Create timeout channel.\n+\ttimeoutCh := make(chan struct{})\n+\tgo func() {\n+\t\ttime.Sleep(5 * time.Minute)\n+\t\ttimeoutCh <- struct{}{}\n+\t}()\n+\n+\treturn pia.await(podWatcher, timeoutCh)","path":"pkg/await/core_pod.go","position":224,"original_position":224,"commit_id":"898b24ae61f4c96f43fc06eb55ba46047ccd05b0","original_commit_id":"898b24ae61f4c96f43fc06eb55ba46047ccd05b0","user":{"login":"swgillespie","id":1871912,"node_id":"MDQ6VXNlcjE4NzE5MTI=","avatar_url":"https://avatars2.githubusercontent.com/u/1871912?v=4","gravatar_id":"","url":"https://api.github.com/users/swgillespie","html_url":"https://github.com/swgillespie","followers_url":"https://api.github.com/users/swgillespie/followers","following_url":"https://api.github.com/users/swgillespie/following{/other_user}","gists_url":"https://api.github.com/users/swgillespie/gists{/gist_id}","starred_url":"https://api.github.com/users/swgillespie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swgillespie/subscriptions","organizations_url":"https://api.github.com/users/swgillespie/orgs","repos_url":"https://api.github.com/users/swgillespie/repos","events_url":"https://api.github.com/users/swgillespie/events{/privacy}","received_events_url":"https://api.github.com/users/swgillespie/received_events","type":"User","site_admin":false},"body":"`pia.await(podWatcher, time.Tick(5 * time.Minute))` should work too","created_at":"2018-08-02T17:31:50Z","updated_at":"2018-08-02T17:37:36Z","html_url":"https://github.com/pulumi/pulumi-kubernetes/pull/112#discussion_r207310897","pull_request_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/comments/207310897"},"html":{"href":"https://github.com/pulumi/pulumi-kubernetes/pull/112#discussion_r207310897"},"pull_request":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112"}}},"pull_request":{"url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112","id":204663467,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA0NjYzNDY3","html_url":"https://github.com/pulumi/pulumi-kubernetes/pull/112","diff_url":"https://github.com/pulumi/pulumi-kubernetes/pull/112.diff","patch_url":"https://github.com/pulumi/pulumi-kubernetes/pull/112.patch","issue_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/112","number":112,"state":"open","locked":false,"title":"Implement status-rich updates","user":{"login":"hausdorff","id":1409156,"node_id":"MDQ6VXNlcjE0MDkxNTY=","avatar_url":"https://avatars1.githubusercontent.com/u/1409156?v=4","gravatar_id":"","url":"https://api.github.com/users/hausdorff","html_url":"https://github.com/hausdorff","followers_url":"https://api.github.com/users/hausdorff/followers","following_url":"https://api.github.com/users/hausdorff/following{/other_user}","gists_url":"https://api.github.com/users/hausdorff/gists{/gist_id}","starred_url":"https://api.github.com/users/hausdorff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hausdorff/subscriptions","organizations_url":"https://api.github.com/users/hausdorff/orgs","repos_url":"https://api.github.com/users/hausdorff/repos","events_url":"https://api.github.com/users/hausdorff/events{/privacy}","received_events_url":"https://api.github.com/users/hausdorff/received_events","type":"User","site_admin":false},"body":"This PR principally contains the logic for status-rich updates of the key \"complex\" Kubernetes resources (_i.e._, `Pod`, `Service`, and `Deployment`), as well as fixes for a set of bugs that affect this change.\r\n\r\nThe changes related to the status-rich updates themselves essentially have two parts:\r\n\r\n* **A series of playback tests.** We used CarbonQL to observe changes to these key resources under various circumstances, and then encoded those as tests \"playing back\" those events. This was designed to (1) give a transparent view of what these \"complex\" awaiters do, and (2) give us a rigorous backbone on top of which to ensure the correctness of this code.\r\n* **A set of three \"complex awaiter\" objects.** These objects are essentially structs that are each wrapped around an event loop that is continuously observing events from several streams (_i.e._, updates to one or more resources from the API server, plus channels each for timeout and cancellation). As events are received, these objects update the known state of the resources so that helpful intermediate errors can be displayed.\r\n\r\nThe rest of the changes are ancillary fixes to make this experience good. Most of these are small bugs.","created_at":"2018-07-29T21:57:22Z","updated_at":"2018-08-02T17:37:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"db98931532217d468844869cfa90d378cd39dde6","assignee":null,"assignees":[],"requested_reviewers":[{"login":"pgavlin","id":1224093,"node_id":"MDQ6VXNlcjEyMjQwOTM=","avatar_url":"https://avatars2.githubusercontent.com/u/1224093?v=4","gravatar_id":"","url":"https://api.github.com/users/pgavlin","html_url":"https://github.com/pgavlin","followers_url":"https://api.github.com/users/pgavlin/followers","following_url":"https://api.github.com/users/pgavlin/following{/other_user}","gists_url":"https://api.github.com/users/pgavlin/gists{/gist_id}","starred_url":"https://api.github.com/users/pgavlin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pgavlin/subscriptions","organizations_url":"https://api.github.com/users/pgavlin/orgs","repos_url":"https://api.github.com/users/pgavlin/repos","events_url":"https://api.github.com/users/pgavlin/events{/privacy}","received_events_url":"https://api.github.com/users/pgavlin/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":986161431,"node_id":"MDU6TGFiZWw5ODYxNjE0MzE=","url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/labels/kubernetes/inner-dev-loop","name":"kubernetes/inner-dev-loop","color":"b913d3","default":false}],"milestone":{"url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/milestones/6","html_url":"https://github.com/pulumi/pulumi-kubernetes/milestone/6","labels_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/milestones/6/labels","id":3162768,"node_id":"MDk6TWlsZXN0b25lMzE2Mjc2OA==","number":6,"title":"0.16","description":"","creator":{"login":"joeduffy","id":3953235,"node_id":"MDQ6VXNlcjM5NTMyMzU=","avatar_url":"https://avatars3.githubusercontent.com/u/3953235?v=4","gravatar_id":"","url":"https://api.github.com/users/joeduffy","html_url":"https://github.com/joeduffy","followers_url":"https://api.github.com/users/joeduffy/followers","following_url":"https://api.github.com/users/joeduffy/following{/other_user}","gists_url":"https://api.github.com/users/joeduffy/gists{/gist_id}","starred_url":"https://api.github.com/users/joeduffy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joeduffy/subscriptions","organizations_url":"https://api.github.com/users/joeduffy/orgs","repos_url":"https://api.github.com/users/joeduffy/repos","events_url":"https://api.github.com/users/joeduffy/events{/privacy}","received_events_url":"https://api.github.com/users/joeduffy/received_events","type":"User","site_admin":false},"open_issues":17,"closed_issues":16,"state":"open","created_at":"2018-03-05T17:23:30Z","updated_at":"2018-08-02T00:19:37Z","due_on":"2018-08-05T07:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112/commits","review_comments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112/comments","review_comment_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/112/comments","statuses_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/statuses/898b24ae61f4c96f43fc06eb55ba46047ccd05b0","head":{"label":"pulumi:hausdorff/updates","ref":"hausdorff/updates","sha":"898b24ae61f4c96f43fc06eb55ba46047ccd05b0","user":{"login":"pulumi","id":21992475,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIxOTkyNDc1","avatar_url":"https://avatars0.githubusercontent.com/u/21992475?v=4","gravatar_id":"","url":"https://api.github.com/users/pulumi","html_url":"https://github.com/pulumi","followers_url":"https://api.github.com/users/pulumi/followers","following_url":"https://api.github.com/users/pulumi/following{/other_user}","gists_url":"https://api.github.com/users/pulumi/gists{/gist_id}","starred_url":"https://api.github.com/users/pulumi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulumi/subscriptions","organizations_url":"https://api.github.com/users/pulumi/orgs","repos_url":"https://api.github.com/users/pulumi/repos","events_url":"https://api.github.com/users/pulumi/events{/privacy}","received_events_url":"https://api.github.com/users/pulumi/received_events","type":"Organization","site_admin":false},"repo":{"id":116869354,"node_id":"MDEwOlJlcG9zaXRvcnkxMTY4NjkzNTQ=","name":"pulumi-kubernetes","full_name":"pulumi/pulumi-kubernetes","owner":{"login":"pulumi","id":21992475,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIxOTkyNDc1","avatar_url":"https://avatars0.githubusercontent.com/u/21992475?v=4","gravatar_id":"","url":"https://api.github.com/users/pulumi","html_url":"https://github.com/pulumi","followers_url":"https://api.github.com/users/pulumi/followers","following_url":"https://api.github.com/users/pulumi/following{/other_user}","gists_url":"https://api.github.com/users/pulumi/gists{/gist_id}","starred_url":"https://api.github.com/users/pulumi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulumi/subscriptions","organizations_url":"https://api.github.com/users/pulumi/orgs","repos_url":"https://api.github.com/users/pulumi/repos","events_url":"https://api.github.com/users/pulumi/events{/privacy}","received_events_url":"https://api.github.com/users/pulumi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pulumi/pulumi-kubernetes","description":"A Kubernetes Pulumi resource provider, providing the full Kubernetes API to multiple languages","fork":false,"url":"https://api.github.com/repos/pulumi/pulumi-kubernetes","forks_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/forks","keys_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/teams","hooks_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/hooks","issue_events_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/events","assignees_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/tags","blobs_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/languages","stargazers_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/stargazers","contributors_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/contributors","subscribers_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/subscribers","subscription_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/subscription","commits_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/merges","archive_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/downloads","issues_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/deployments","created_at":"2018-01-09T20:50:33Z","updated_at":"2018-07-28T00:58:25Z","pushed_at":"2018-08-02T07:42:38Z","git_url":"git://github.com/pulumi/pulumi-kubernetes.git","ssh_url":"git@github.com:pulumi/pulumi-kubernetes.git","clone_url":"https://github.com/pulumi/pulumi-kubernetes.git","svn_url":"https://github.com/pulumi/pulumi-kubernetes","homepage":"","size":644,"stargazers_count":14,"watchers_count":14,"language":"TypeScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":33,"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":4,"open_issues":33,"watchers":14,"default_branch":"master"}},"base":{"label":"pulumi:master","ref":"master","sha":"43f160cdfee7c73717a17e0ca7f419a200080901","user":{"login":"pulumi","id":21992475,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIxOTkyNDc1","avatar_url":"https://avatars0.githubusercontent.com/u/21992475?v=4","gravatar_id":"","url":"https://api.github.com/users/pulumi","html_url":"https://github.com/pulumi","followers_url":"https://api.github.com/users/pulumi/followers","following_url":"https://api.github.com/users/pulumi/following{/other_user}","gists_url":"https://api.github.com/users/pulumi/gists{/gist_id}","starred_url":"https://api.github.com/users/pulumi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulumi/subscriptions","organizations_url":"https://api.github.com/users/pulumi/orgs","repos_url":"https://api.github.com/users/pulumi/repos","events_url":"https://api.github.com/users/pulumi/events{/privacy}","received_events_url":"https://api.github.com/users/pulumi/received_events","type":"Organization","site_admin":false},"repo":{"id":116869354,"node_id":"MDEwOlJlcG9zaXRvcnkxMTY4NjkzNTQ=","name":"pulumi-kubernetes","full_name":"pulumi/pulumi-kubernetes","owner":{"login":"pulumi","id":21992475,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIxOTkyNDc1","avatar_url":"https://avatars0.githubusercontent.com/u/21992475?v=4","gravatar_id":"","url":"https://api.github.com/users/pulumi","html_url":"https://github.com/pulumi","followers_url":"https://api.github.com/users/pulumi/followers","following_url":"https://api.github.com/users/pulumi/following{/other_user}","gists_url":"https://api.github.com/users/pulumi/gists{/gist_id}","starred_url":"https://api.github.com/users/pulumi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pulumi/subscriptions","organizations_url":"https://api.github.com/users/pulumi/orgs","repos_url":"https://api.github.com/users/pulumi/repos","events_url":"https://api.github.com/users/pulumi/events{/privacy}","received_events_url":"https://api.github.com/users/pulumi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pulumi/pulumi-kubernetes","description":"A Kubernetes Pulumi resource provider, providing the full Kubernetes API to multiple languages","fork":false,"url":"https://api.github.com/repos/pulumi/pulumi-kubernetes","forks_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/forks","keys_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/teams","hooks_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/hooks","issue_events_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/events","assignees_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/tags","blobs_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/languages","stargazers_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/stargazers","contributors_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/contributors","subscribers_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/subscribers","subscription_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/subscription","commits_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/merges","archive_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/downloads","issues_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/pulumi/pulumi-kubernetes/deployments","created_at":"2018-01-09T20:50:33Z","updated_at":"2018-07-28T00:58:25Z","pushed_at":"2018-08-02T07:42:38Z","git_url":"git://github.com/pulumi/pulumi-kubernetes.git","ssh_url":"git@github.com:pulumi/pulumi-kubernetes.git","clone_url":"https://github.com/pulumi/pulumi-kubernetes.git","svn_url":"https://github.com/pulumi/pulumi-kubernetes","homepage":"","size":644,"stargazers_count":14,"watchers_count":14,"language":"TypeScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":33,"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":4,"open_issues":33,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112"},"html":{"href":"https://github.com/pulumi/pulumi-kubernetes/pull/112"},"issue":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/112"},"comments":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/issues/112/comments"},"review_comments":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112/comments"},"review_comment":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/pulls/112/commits"},"statuses":{"href":"https://api.github.com/repos/pulumi/pulumi-kubernetes/statuses/898b24ae61f4c96f43fc06eb55ba46047ccd05b0"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"swgillespie"}}