{"action":"created","comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/comments/24224221","id":24224221,"diff_hunk":"@@ -0,0 +1,222 @@\n+# Persistent Stores\n+\n+This document proposes a model for managing persistent, cluster-scoped storage for applications requiring long lived data.\n+\n+### tl;dr\n+\n+`PersistentStore` objects contain a VolumeSource with a lifecycle greater than the pods it is used by.  Many types of VolumeSources can be implemented as volume plugins, with each implementing an interface for use within a controller.  A pod with persistence requirements (specifically pod.spec.volumes.volume.persistenceRequirements) is bound to a matching VolumeSource from a pool of available stores.  PersistentStore objects give that VolumeSource longevity.\n+\n+A `PersistentStoreController` manages the creation, attachment, and reclamation of PersistentStore objects for one VolumeSource.  Implementations must be pluggable to support many types of controllers for many types of VolumeSources. The controller can advise the scheduler on host selection, keeping volume rules contained within the provider.  All cloud provider credentials are isolated to the store controller's host.\n+\n+`PersistentStoreBinder` watches for pods with persistence requirements and matches the request with what is available in the pool.\n+\n+`PersistenceRequirements` expresses the capabilities and performance attributes of the underlying VolumeSource.  Allow discovery\n+of storage by its capabilities and use those capabilities as pod storage requirements.\n+\n+Kubernetes makes no guarantees at runtime that the underlying storage exists or is available.  High availability is left to the storage provider.\n+\n+## Goals\n+\n+* Allow administrators to describe available storage\n+* Allow pod authors to discover and request persistence for their volumes\n+* Enforce security through access control lists and securing storage to the same namespace as the pod volume\n+* Enforce quotas through admission control\n+* Ensure developers can rely on storage being available without being closely bound to a particular disk, server, network, or storage device.\n+\n+\n+#### Allow admins to describe and create available storage\n+\n+Admins can describe storage using a `PersistentStoreController` for each type of VolumeSource being managed or create storage directly by using the `PersistentStore` API.  Storage created manually still requires a PersistentStoreController and accompanying interface to allow management by the cluster.\n+\n+\n+```\n+\t\n+\tPersistentStore\n+\t\tTypeMeta\n+\t\tObjectMeta\n+\t\t\tName - internal name\n+\t\t\tLabels - labeled like Volume.PersistenceRequirements.Selector\n+\t\tSpec\n+\t\t\tVolumeSource -- backed by one of these:\n+\t\t\t\tHostPath\n+\t\t\t\tEmptyDir\n+\t\t\t\tGitRepo\t\n+\t\t\t\tGCEPersistentDisk { modes: ReadWriteOnce | ReadOnlyMany }\n+\t\t\t\tAWSElasticBlockStore { modes: ReadWriteOnce }\n+\t\t\t\tNFSMount { modes: ReadWriteOnce | ReadOnlyMany | ReadWriteMany }\n+\t\t\t\t*** many volume plugins\n+\t\t\t// volumes can be orphaned.  allow never delete.\n+\t\t\tRetentionPolicy StoreRetentionPolicy\n+\t\tStatus\n+\t\t\tPhase\n+\t\t\tCurrentMounts\tMountList\n+\t\t\tLastMounts\t\tMountList\n+\t\t\tPodRef\t\t\tObjectReference -- the pod originally requesting persistence\n+\t\t\t\n+\n+\t// Manages one type of PersistentStore\n+\tPersistentStoreController\n+\t\tName\n+\t\tSpec\n+\t\t\tVolumeSource\n+\t\t\t\tGCEPersistentDisk { modes: ReadWriteOnce | ReadOnlyMany, resources: 5gb 30iops, .48 throughput  }\n+\t\t\tMaxInstances  100\n+\t\t\tIncrementBy   10\n+\t\tStatus\n+\t\t\tInstanceCount\n+\t\t\t\n+\n+\t//\n+\t//  addition to VolumeSource\n+\t//\t\n+\ttype MountMode byte\n+\t\n+\tconst (\n+\t\tReadWriteOnce MountMode = 1 << iota\n+\t\tReadOnlyMany\n+\t\tReadWriteMany\n+\t)\n+\t\n+\tfunc (vs *VolumeSource) canMount(mode MountMode) bool {\n+\t\treturn vs.modes & mode != 0\n+\t}\n+\t\n+```\n+\n+> To manually create storage, an admin would, for example, create a GCE VM, create, attach, and format 20 persistent disks.  The IDs are saved and the admin then creates 20 persistent-disk.json files and POSTs each GCE_PD to the API.  There are many ways to script adding stores to a cluster.\n+\n+\n+\n+#### Pod to specify storage requirements\n+\n+```\n+\n+\tPod.Spec.Volumes.Volume \n+\t\t\tName\n+\t\t\tVolumeSource -- to be bound with available storage from the pool\n+\t\t\tPersistenceRequirements\n+\t\t\t\tMode\t\t\t\tReadWriteOnce | ReadOnlyMany\n+\t\t\t\tRetentionPolicy \tStoreRetentionPolicy (RetainOnDelete|RecycleOnDelete)\t\t\t\tResources\t\t\tResourcesList (size, iops, throughput)\n+\t\t\t\tSelector\t\t\tLabels to identify the PersistentStore backing implementation\n+\n+```\n+\n+`PersistenceRequirements` are the capabilities and performance characteristics a pod author can request and rely on for the entire lifecycle of the volume.  Requests for storage that do not match available storage will go unfulfilled.\n+\n+\n+#### Storage discovery \n+\n+An API and CLI is needed to view available and in-use stores by namespace.\n+\n+**Use Case**:  Susie needs to crunch some data and serve it afterwards.  A single pod to create data is sufficient, but she estimates needing 10 web front ends to serve the data afterwards.  For this use case, the data does not change once created.  Susie first looks to see what is available in the cluster.\n+\n+```\n+$ cluster/kubectl.sh get storage\n+\n+NAME                LABELS              MODES               RESOURCES\n+_pv_vol_01          name=my-data        RWO,ROX             size=5gb,iops=30\n+_pv_vol_02                              RWO,ROX             size=5gb,iops=30\n+_pv_vol_03          name=other-data     RWO,ROX             size=25gb,iops=30\n+\n+```\n+\n+#### Request persistent storage for a pod\n+\n+Susie is happy to see storage that can be mounted many times (ReadOnlyMany).  That satisfies her load balancer requirement.  Susie creates an pod image with her number crunching code and requests persistence for her volume.\n+\n+Susie's YAML looks something like this for the pod that creates her data:\n+\n+\n+```yaml\n+\n+id: creator-of-data\n+kind: Pod\n+namespace: ns\n+apiVersion: v1beta1\n+desiredState:\n+  manifest:\n+    version: v1beta1\n+    id: creator-of-data\n+    containers:\n+      - name: numbercruncher\n+        image: ns/makesomdata:v1\n+        command:\n+          - /run.sh\n+        volumeMounts:\n+          - name: data\n+            mountPath: /some_data\n+    volumes:\n+      - name: data\n+        persistenceRequirements:\n+        \tavailableModes: readwriteonce | readonlymany\n+        \tcurrentMode: readwriteonce\n+        \tretentionPolicy: retainondelete\n+        \tresources:\n+        \t\t- size: 5\n+        \tselector:\n+        \t\t- name: my-persistent-data\n+labels:\n+  name: creator-of-data\n+\n+```\n+\n+#### Behind the curtain\n+\n+`PersistentStoreBinder` is watching for new pods with `PersistenceRequirements`.  The binder compares the request to all available stores and binds it to the closest match.\n+\n+To bind:\n+\n+* Set PersistentStore.Status.PodRef = pod that originally requested persistence\n+* Set PersistentStore.Labels = PersistenceRequirements.Selector","path":"docs/design/persistent-storage.md","position":181,"original_position":170,"commit_id":"d6b2058846e66c9d5755a629682b7a8cb54e0e25","original_commit_id":"0bb4d356a10c4d6f87ccc146139fdb1bbd3f3fd9","user":{"login":"thockin","id":5595220,"avatar_url":"https://avatars.githubusercontent.com/u/5595220?v=3","gravatar_id":"","url":"https://api.github.com/users/thockin","html_url":"https://github.com/thockin","followers_url":"https://api.github.com/users/thockin/followers","following_url":"https://api.github.com/users/thockin/following{/other_user}","gists_url":"https://api.github.com/users/thockin/gists{/gist_id}","starred_url":"https://api.github.com/users/thockin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thockin/subscriptions","organizations_url":"https://api.github.com/users/thockin/orgs","repos_url":"https://api.github.com/users/thockin/repos","events_url":"https://api.github.com/users/thockin/events{/privacy}","received_events_url":"https://api.github.com/users/thockin/received_events","type":"User","site_admin":false},"body":"So you're trying to cut out one user step, but you still have a notion of a claim object, you've just overlaid it on the offer object.  What's awkward to me is that you try to use the same specification for \"allocate a PS for me\" and \"re-attach a PS for me\" - but those are very different things!\r\n\r\nGetting an empty volume when you expected to get something you had previously prepared seems like a Bad Thing.\r\n\r\nWhat if we considered something like:\r\n\r\n* Adam Admin creates a PersistentStore object of type PD, named data-depot-1 in the root of the API (no namespace).\r\n\r\n* Beula creates a Pod in namespace nifty-network, with a volume of type \"NewPersistent\", with fields like claimName=nifty-data, claimLabels, and requirements.\r\n\r\n* A PersistentStoreClaim object is created in the Beula's nifty-network namespace, named nifty-data, with labels as specced before.\r\n\r\n* The PSBinder finds a PSController that owns a PS that could satisfy the requirements and binds that PS to the PSClaim\r\n\r\n* The pod is scheduled and runs to completion.\r\n\r\n* The PSClaim still exists.\r\n\r\n* Beula creates another Pod in namespace nifty-network, with a volume of type \"Persistent\", with fields like claimName=nifty-data, claimLabels, and requirements.\r\n\r\n* The PSClaim object is resolved and the pod is scheduled.\r\n\r\n* When the pod is deleted, the PSClaim still exists.\r\n\r\n* Beula gets a nag email from Adam Admin saying that she has a Claim on a PS and if she is done with it, could she please release it.  She does.\r\n\r\n\r\nI'm not sure the implicit claim creation is worth the effort - if it is a whole distinct step, is that so bad?  This is all about pet storage right?  Pets have names and indentities and owners.\r\n","created_at":"2015-02-06T06:03:34Z","updated_at":"2015-02-06T06:03:34Z","html_url":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055#discussion_r24224221","pull_request_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055","_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/comments/24224221"},"html":{"href":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055#discussion_r24224221"},"pull_request":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055"}}},"pull_request":{"url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055","id":28556617,"html_url":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055","diff_url":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055.diff","patch_url":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055.patch","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/4055","number":4055,"state":"open","locked":false,"title":"[Proposal] Persistent Storage","user":{"login":"markturansky","id":8001968,"avatar_url":"https://avatars.githubusercontent.com/u/8001968?v=3","gravatar_id":"","url":"https://api.github.com/users/markturansky","html_url":"https://github.com/markturansky","followers_url":"https://api.github.com/users/markturansky/followers","following_url":"https://api.github.com/users/markturansky/following{/other_user}","gists_url":"https://api.github.com/users/markturansky/gists{/gist_id}","starred_url":"https://api.github.com/users/markturansky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markturansky/subscriptions","organizations_url":"https://api.github.com/users/markturansky/orgs","repos_url":"https://api.github.com/users/markturansky/repos","events_url":"https://api.github.com/users/markturansky/events{/privacy}","received_events_url":"https://api.github.com/users/markturansky/received_events","type":"User","site_admin":false},"body":"Continuing the conversation from #3318 ...\r\n\r\n@bgrant0607 Based on your feedback, I arrived at another design with just a single new top level object.  All of the concepts you addressed in your comments are to be found in the new design.  Quite a bit more is expressed in fewer moving parts.  \r\n\r\n@thockin I think several of your questions and concerns from #3318 are addressed by the redesign.\r\n\r\nOverall, fewer moving pieces in this design, a complete story of volume re-use from a pod to replController, a way to create and replenish available storage, and expansions of volumes in @thockin's new framework.\r\n\r\nYour feedback is appreciated!\r\n\r\n/cc @smarterclayton ","created_at":"2015-02-03T14:37:00Z","updated_at":"2015-02-06T06:03:34Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4e2bd89d92de4a9468c50482ed970195b6d32de4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055/commits","review_comments_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055/comments","review_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/comments/{number}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/4055/comments","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/statuses/d6b2058846e66c9d5755a629682b7a8cb54e0e25","head":{"label":"markturansky:persistent_storage","ref":"persistent_storage","sha":"d6b2058846e66c9d5755a629682b7a8cb54e0e25","user":{"login":"markturansky","id":8001968,"avatar_url":"https://avatars.githubusercontent.com/u/8001968?v=3","gravatar_id":"","url":"https://api.github.com/users/markturansky","html_url":"https://github.com/markturansky","followers_url":"https://api.github.com/users/markturansky/followers","following_url":"https://api.github.com/users/markturansky/following{/other_user}","gists_url":"https://api.github.com/users/markturansky/gists{/gist_id}","starred_url":"https://api.github.com/users/markturansky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markturansky/subscriptions","organizations_url":"https://api.github.com/users/markturansky/orgs","repos_url":"https://api.github.com/users/markturansky/repos","events_url":"https://api.github.com/users/markturansky/events{/privacy}","received_events_url":"https://api.github.com/users/markturansky/received_events","type":"User","site_admin":false},"repo":{"id":24423869,"name":"kubernetes","full_name":"markturansky/kubernetes","owner":{"login":"markturansky","id":8001968,"avatar_url":"https://avatars.githubusercontent.com/u/8001968?v=3","gravatar_id":"","url":"https://api.github.com/users/markturansky","html_url":"https://github.com/markturansky","followers_url":"https://api.github.com/users/markturansky/followers","following_url":"https://api.github.com/users/markturansky/following{/other_user}","gists_url":"https://api.github.com/users/markturansky/gists{/gist_id}","starred_url":"https://api.github.com/users/markturansky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markturansky/subscriptions","organizations_url":"https://api.github.com/users/markturansky/orgs","repos_url":"https://api.github.com/users/markturansky/repos","events_url":"https://api.github.com/users/markturansky/events{/privacy}","received_events_url":"https://api.github.com/users/markturansky/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/markturansky/kubernetes","description":"Container Cluster Manager","fork":true,"url":"https://api.github.com/repos/markturansky/kubernetes","forks_url":"https://api.github.com/repos/markturansky/kubernetes/forks","keys_url":"https://api.github.com/repos/markturansky/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/markturansky/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/markturansky/kubernetes/teams","hooks_url":"https://api.github.com/repos/markturansky/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/markturansky/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/markturansky/kubernetes/events","assignees_url":"https://api.github.com/repos/markturansky/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/markturansky/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/markturansky/kubernetes/tags","blobs_url":"https://api.github.com/repos/markturansky/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/markturansky/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/markturansky/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/markturansky/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/markturansky/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/markturansky/kubernetes/languages","stargazers_url":"https://api.github.com/repos/markturansky/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/markturansky/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/markturansky/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/markturansky/kubernetes/subscription","commits_url":"https://api.github.com/repos/markturansky/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/markturansky/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/markturansky/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/markturansky/kubernetes/issues/comments/{number}","contents_url":"https://api.github.com/repos/markturansky/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/markturansky/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/markturansky/kubernetes/merges","archive_url":"https://api.github.com/repos/markturansky/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/markturansky/kubernetes/downloads","issues_url":"https://api.github.com/repos/markturansky/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/markturansky/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/markturansky/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/markturansky/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/markturansky/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/markturansky/kubernetes/releases{/id}","created_at":"2014-09-24T16:55:04Z","updated_at":"2015-02-06T02:47:47Z","pushed_at":"2015-02-06T02:49:26Z","git_url":"git://github.com/markturansky/kubernetes.git","ssh_url":"git@github.com:markturansky/kubernetes.git","clone_url":"https://github.com/markturansky/kubernetes.git","svn_url":"https://github.com/markturansky/kubernetes","homepage":null,"size":30771,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2,"mirror_url":null,"open_issues_count":0,"forks":2,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"GoogleCloudPlatform:master","ref":"master","sha":"7f5ed541f794348ae6279414cf70523a4d5133cc","user":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":20580498,"name":"kubernetes","full_name":"GoogleCloudPlatform/kubernetes","owner":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/kubernetes","description":"Container Cluster Manager","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/comments/{number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/releases{/id}","created_at":"2014-06-06T22:56:04Z","updated_at":"2015-02-06T05:46:14Z","pushed_at":"2015-02-06T05:46:14Z","git_url":"git://github.com/GoogleCloudPlatform/kubernetes.git","ssh_url":"git@github.com:GoogleCloudPlatform/kubernetes.git","clone_url":"https://github.com/GoogleCloudPlatform/kubernetes.git","svn_url":"https://github.com/GoogleCloudPlatform/kubernetes","homepage":"http://kubernetes.io","size":71242,"stargazers_count":6093,"watchers_count":6093,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1042,"mirror_url":null,"open_issues_count":664,"forks":1042,"open_issues":664,"watchers":6093,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055"},"html":{"href":"https://github.com/GoogleCloudPlatform/kubernetes/pull/4055"},"issue":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/4055"},"comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/issues/4055/comments"},"review_comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055/comments"},"review_comment":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/pulls/4055/commits"},"statuses":{"href":"https://api.github.com/repos/GoogleCloudPlatform/kubernetes/statuses/d6b2058846e66c9d5755a629682b7a8cb54e0e25"}}}}