{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/comments/214042292","pull_request_review_id":151007714,"id":214042292,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxNDA0MjI5Mg==","diff_hunk":"@@ -0,0 +1,1233 @@\n+/*\n+Copyright 2018 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\"context\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"reflect\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"sync/atomic\"\n+\t\"testing\"\n+\t\"time\"\n+\n+\t\"github.com/golang/glog\"\n+\n+\t\"github.com/container-storage-interface/spec/lib/go/csi/v0\"\n+\tcrdv1 \"github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1\"\n+\tclientset \"github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned\"\n+\t\"github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/fake\"\n+\tinformers \"github.com/kubernetes-csi/external-snapshotter/pkg/client/informers/externalversions\"\n+\tstoragelisters \"github.com/kubernetes-csi/external-snapshotter/pkg/client/listers/volumesnapshot/v1alpha1\"\n+\t\"k8s.io/api/core/v1\"\n+\tstoragev1 \"k8s.io/api/storage/v1\"\n+\tstoragev1beta1 \"k8s.io/api/storage/v1beta1\"\n+\t\"k8s.io/apimachinery/pkg/api/resource\"\n+\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\t\"k8s.io/apimachinery/pkg/runtime\"\n+\t\"k8s.io/apimachinery/pkg/types\"\n+\t\"k8s.io/apimachinery/pkg/util/diff\"\n+\t\"k8s.io/apimachinery/pkg/util/wait\"\n+\t\"k8s.io/apimachinery/pkg/watch\"\n+\t\"k8s.io/client-go/kubernetes\"\n+\tkubefake \"k8s.io/client-go/kubernetes/fake\"\n+\tcore \"k8s.io/client-go/testing\"\n+\t\"k8s.io/client-go/tools/cache\"\n+\t\"k8s.io/client-go/tools/record\"\n+)\n+\n+// This is a unit test framework for snapshot controller.\n+// It fills the controller with test snapshots/contents and can simulate these\n+// scenarios:\n+// 1) Call syncSnapshot/syncContent once.\n+// 2) Call syncSnapshot/syncContent several times (both simulating \"snapshot/content\n+//    modified\" events and periodic sync), until the controller settles down and\n+//    does not modify anything.\n+// 3) Simulate almost real API server/etcd and call add/update/delete\n+//    content/snapshot.\n+// In all these scenarios, when the test finishes, the framework can compare\n+// resulting snapshots/contents with list of expected snapshots/contents and report\n+// differences.\n+\n+// controllerTest contains a single controller test input.\n+// Each test has initial set of contents and snapshots that are filled into the\n+// controller before the test starts. The test then contains a reference to\n+// function to call as the actual test. Available functions are:\n+//   - testSyncSnapshot - calls syncSnapshot on the first snapshot in initialSnapshots.\n+//   - testSyncSnapshotError - calls syncSnapshot on the first snapshot in initialSnapshots\n+//                          and expects an error to be returned.\n+//   - testSyncContent - calls syncContent on the first content in initialContents.\n+//   - any custom function for specialized tests.\n+// The test then contains list of contents/snapshots that are expected at the end\n+// of the test and list of generated events.\n+type controllerTest struct {\n+\t// Name of the test, for logging\n+\tname string\n+\t// Initial content of controller content cache.\n+\tinitialContents []*crdv1.VolumeSnapshotContent\n+\t// Expected content of controller content cache at the end of the test.\n+\texpectedContents []*crdv1.VolumeSnapshotContent\n+\t// Initial content of controller snapshot cache.\n+\tinitialSnapshots []*crdv1.VolumeSnapshot\n+\t// Expected content of controller snapshot cache at the end of the test.\n+\texpectedSnapshots []*crdv1.VolumeSnapshot\n+\t// Initial content of controller volume cache.\n+\tinitialVolumes []*v1.PersistentVolume\n+\t// Initial content of controller claim cache.\n+\tinitialClaims []*v1.PersistentVolumeClaim\n+\t// Initial content of controller StorageClass cache.\n+\tinitialStorageClasses []*storagev1.StorageClass\n+\t// Initial content of controller Secret cache.\n+\tinitialSecrets []*v1.Secret\n+\t// Expected events - any event with prefix will pass, we don't check full\n+\t// event message.\n+\texpectedEvents []string\n+\t// Errors to produce on matching action\n+\terrors []reactorError\n+\t// List of expected CSI Create snapshot calls\n+\texpectedCreateCalls []createCall\n+\t// List of expected CSI Delete snapshot calls\n+\texpectedDeleteCalls []deleteCall\n+\t// List of expected CSI list snapshot calls\n+\texpectedListCalls []listCall\n+\t// Function to call as the test.\n+\ttest testCall\n+}\n+\n+type testCall func(ctrl *csiSnapshotController, reactor *snapshotReactor, test controllerTest) error\n+\n+const testNamespace = \"default\"\n+const mockDriverName = \"csi-mock-plugin\"\n+\n+var versionConflictError = errors.New(\"VersionError\")\n+var nocontents []*crdv1.VolumeSnapshotContent\n+var nosnapshots []*crdv1.VolumeSnapshot\n+var noevents = []string{}\n+var noerrors = []reactorError{}\n+\n+// snapshotReactor is a core.Reactor that simulates etcd and API server. It\n+// stores:\n+// - Latest version of snapshots contents saved by the controller.\n+// - Queue of all saves (to simulate \"content/snapshot updated\" events). This queue\n+//   contains all intermediate state of an object - e.g. a snapshot.VolumeName\n+//   is updated first and snapshot.Phase second. This queue will then contain both\n+//   updates as separate entries.\n+// - Number of changes since the last call to snapshotReactor.syncAll().\n+// - Optionally, content and snapshot fake watchers which should be the same ones\n+//   used by the controller. Any time an event function like deleteContentEvent\n+//   is called to simulate an event, the reactor's stores are updated and the\n+//   controller is sent the event via the fake watcher.\n+// - Optionally, list of error that should be returned by reactor, simulating\n+//   etcd / API server failures. These errors are evaluated in order and every\n+//   error is returned only once. I.e. when the reactor finds matching\n+//   reactorError, it return appropriate error and removes the reactorError from\n+//   the list.\n+type snapshotReactor struct {\n+\tsecrets              map[string]*v1.Secret\n+\tstorageClasses       map[string]*storagev1.StorageClass\n+\tvolumes              map[string]*v1.PersistentVolume\n+\tclaims               map[string]*v1.PersistentVolumeClaim\n+\tcontents             map[string]*crdv1.VolumeSnapshotContent\n+\tsnapshots            map[string]*crdv1.VolumeSnapshot\n+\tchangedObjects       []interface{}\n+\tchangedSinceLastSync int\n+\tctrl                 *csiSnapshotController\n+\tfakeContentWatch     *watch.FakeWatcher\n+\tfakeSnapshotWatch    *watch.FakeWatcher\n+\tlock                 sync.Mutex\n+\terrors               []reactorError\n+}\n+\n+// reactorError is an error that is returned by test reactor (=simulated\n+// etcd+/API server) when an action performed by the reactor matches given verb\n+// (\"get\", \"update\", \"create\", \"delete\" or \"*\"\") on given resource\n+// (\"volumesnapshotcontents\", \"volumesnapshots\" or \"*\").\n+type reactorError struct {\n+\tverb     string\n+\tresource string\n+\terror    error\n+}\n+\n+// React is a callback called by fake kubeClient from the controller.\n+// In other words, every snapshot/content change performed by the controller ends\n+// here.\n+// This callback checks versions of the updated objects and refuse those that\n+// are too old (simulating real etcd).\n+// All updated objects are stored locally to keep track of object versions and\n+// to evaluate test results.\n+// All updated objects are also inserted into changedObjects queue and\n+// optionally sent back to the controller via its watchers.\n+func (r *snapshotReactor) React(action core.Action) (handled bool, ret runtime.Object, err error) {\n+\tr.lock.Lock()\n+\tdefer r.lock.Unlock()\n+\n+\tglog.V(4).Infof(\"reactor got operation %q on %q\", action.GetVerb(), action.GetResource())\n+\n+\t// Inject error when requested\n+\terr = r.injectReactError(action)\n+\tif err != nil {\n+\t\treturn true, nil, err\n+\t}\n+\n+\t// Test did not request to inject an error, continue simulating API server.\n+\tswitch {\n+\tcase action.Matches(\"create\", \"volumesnapshotcontents\"):\n+\t\tobj := action.(core.UpdateAction).GetObject()\n+\t\tcontent := obj.(*crdv1.VolumeSnapshotContent)\n+\n+\t\t// check the content does not exist\n+\t\t_, found := r.contents[content.Name]\n+\t\tif found {\n+\t\t\treturn true, nil, fmt.Errorf(\"Cannot create content %s: content already exists\", content.Name)\n+\t\t}\n+\n+\t\t// Store the updated object to appropriate places.\n+\t\tr.contents[content.Name] = content\n+\t\tr.changedObjects = append(r.changedObjects, content)\n+\t\tr.changedSinceLastSync++\n+\t\tglog.V(4).Infof(\"created content %s\", content.Name)\n+\t\treturn true, content, nil\n+\n+\tcase action.Matches(\"update\", \"volumesnapshotcontents\"):\n+\t\tobj := action.(core.UpdateAction).GetObject()\n+\t\tcontent := obj.(*crdv1.VolumeSnapshotContent)\n+\n+\t\t// Check and bump object version\n+\t\tstoredVolume, found := r.contents[content.Name]\n+\t\tif found {\n+\t\t\tstoredVer, _ := strconv.Atoi(storedVolume.ResourceVersion)\n+\t\t\trequestedVer, _ := strconv.Atoi(content.ResourceVersion)\n+\t\t\tif storedVer != requestedVer {\n+\t\t\t\treturn true, obj, versionConflictError\n+\t\t\t}\n+\t\t\t// Don't modify the existing object\n+\t\t\tcontent = content.DeepCopy()\n+\t\t\tcontent.ResourceVersion = strconv.Itoa(storedVer + 1)\n+\t\t} else {\n+\t\t\treturn true, nil, fmt.Errorf(\"Cannot update content %s: content not found\", content.Name)\n+\t\t}\n+\n+\t\t// Store the updated object to appropriate places.\n+\t\tr.contents[content.Name] = content\n+\t\tr.changedObjects = append(r.changedObjects, content)\n+\t\tr.changedSinceLastSync++\n+\t\tglog.V(4).Infof(\"saved updated content %s\", content.Name)\n+\t\treturn true, content, nil\n+\n+\tcase action.Matches(\"update\", \"volumesnapshots\"):\n+\t\tobj := action.(core.UpdateAction).GetObject()\n+\t\tsnapshot := obj.(*crdv1.VolumeSnapshot)\n+\n+\t\t// Check and bump object version\n+\t\tstoredSnapshot, found := r.snapshots[snapshot.Name]\n+\t\tif found {\n+\t\t\tstoredVer, _ := strconv.Atoi(storedSnapshot.ResourceVersion)\n+\t\t\trequestedVer, _ := strconv.Atoi(snapshot.ResourceVersion)\n+\t\t\tif storedVer != requestedVer {\n+\t\t\t\treturn true, obj, versionConflictError\n+\t\t\t}\n+\t\t\t// Don't modify the existing object\n+\t\t\tsnapshot = snapshot.DeepCopy()\n+\t\t\tsnapshot.ResourceVersion = strconv.Itoa(storedVer + 1)\n+\t\t} else {\n+\t\t\treturn true, nil, fmt.Errorf(\"Cannot update snapshot %s: snapshot not found\", snapshot.Name)\n+\t\t}\n+\n+\t\t// Store the updated object to appropriate places.\n+\t\tr.snapshots[snapshot.Name] = snapshot\n+\t\tr.changedObjects = append(r.changedObjects, snapshot)\n+\t\tr.changedSinceLastSync++\n+\t\tglog.V(4).Infof(\"saved updated snapshot %s\", snapshot.Name)\n+\t\treturn true, snapshot, nil\n+\n+\tcase action.Matches(\"get\", \"volumesnapshotcontents\"):\n+\t\tname := action.(core.GetAction).GetName()\n+\t\tcontent, found := r.contents[name]\n+\t\tif found {\n+\t\t\tglog.V(4).Infof(\"GetVolume: found %s\", content.Name)\n+\t\t\treturn true, content, nil\n+\t\t} else {\n+\t\t\tglog.V(4).Infof(\"GetVolume: content %s not found\", name)\n+\t\t\treturn true, nil, fmt.Errorf(\"Cannot find content %s\", name)","path":"pkg/controller/framework_test.go","position":268,"original_position":268,"commit_id":"8d2504ad9ce4b5f872e127836759185ec9802826","original_commit_id":"b4d60c92a6e315fada4cf5323efe56f483fdf7c8","user":{"login":"xing-yang","id":1185309,"node_id":"MDQ6VXNlcjExODUzMDk=","avatar_url":"https://avatars1.githubusercontent.com/u/1185309?v=4","gravatar_id":"","url":"https://api.github.com/users/xing-yang","html_url":"https://github.com/xing-yang","followers_url":"https://api.github.com/users/xing-yang/followers","following_url":"https://api.github.com/users/xing-yang/following{/other_user}","gists_url":"https://api.github.com/users/xing-yang/gists{/gist_id}","starred_url":"https://api.github.com/users/xing-yang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xing-yang/subscriptions","organizations_url":"https://api.github.com/users/xing-yang/orgs","repos_url":"https://api.github.com/users/xing-yang/repos","events_url":"https://api.github.com/users/xing-yang/events{/privacy}","received_events_url":"https://api.github.com/users/xing-yang/received_events","type":"User","site_admin":false},"body":"s/Cannot/cannot\r\n\r\nSame comments in other similar places.","created_at":"2018-08-30T14:00:00Z","updated_at":"2018-08-30T14:09:40Z","html_url":"https://github.com/kubernetes-csi/external-snapshotter/pull/12#discussion_r214042292","pull_request_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/comments/214042292"},"html":{"href":"https://github.com/kubernetes-csi/external-snapshotter/pull/12#discussion_r214042292"},"pull_request":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12","id":210015661,"node_id":"MDExOlB1bGxSZXF1ZXN0MjEwMDE1NjYx","html_url":"https://github.com/kubernetes-csi/external-snapshotter/pull/12","diff_url":"https://github.com/kubernetes-csi/external-snapshotter/pull/12.diff","patch_url":"https://github.com/kubernetes-csi/external-snapshotter/pull/12.patch","issue_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/12","number":12,"state":"open","locked":false,"title":"Add UT for Snapshot controller","user":{"login":"wackxu","id":30396467,"node_id":"MDQ6VXNlcjMwMzk2NDY3","avatar_url":"https://avatars1.githubusercontent.com/u/30396467?v=4","gravatar_id":"","url":"https://api.github.com/users/wackxu","html_url":"https://github.com/wackxu","followers_url":"https://api.github.com/users/wackxu/followers","following_url":"https://api.github.com/users/wackxu/following{/other_user}","gists_url":"https://api.github.com/users/wackxu/gists{/gist_id}","starred_url":"https://api.github.com/users/wackxu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wackxu/subscriptions","organizations_url":"https://api.github.com/users/wackxu/orgs","repos_url":"https://api.github.com/users/wackxu/repos","events_url":"https://api.github.com/users/wackxu/events{/privacy}","received_events_url":"https://api.github.com/users/wackxu/received_events","type":"User","site_admin":false},"body":"/assign @xing-yang @jingxu97 @saad-ali @jsafrane for review\r\n\r\nbased on https://github.com/kubernetes-csi/external-snapshotter/pull/7\r\n\r\n","created_at":"2018-08-22T04:12:53Z","updated_at":"2018-08-30T14:09:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3b0a4e57e0796349e7941f1d5a550e05e69a5439","assignee":null,"assignees":[],"requested_reviewers":[{"login":"saad-ali","id":10052848,"node_id":"MDQ6VXNlcjEwMDUyODQ4","avatar_url":"https://avatars1.githubusercontent.com/u/10052848?v=4","gravatar_id":"","url":"https://api.github.com/users/saad-ali","html_url":"https://github.com/saad-ali","followers_url":"https://api.github.com/users/saad-ali/followers","following_url":"https://api.github.com/users/saad-ali/following{/other_user}","gists_url":"https://api.github.com/users/saad-ali/gists{/gist_id}","starred_url":"https://api.github.com/users/saad-ali/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saad-ali/subscriptions","organizations_url":"https://api.github.com/users/saad-ali/orgs","repos_url":"https://api.github.com/users/saad-ali/repos","events_url":"https://api.github.com/users/saad-ali/events{/privacy}","received_events_url":"https://api.github.com/users/saad-ali/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":1024432553,"node_id":"MDU6TGFiZWwxMDI0NDMyNTUz","url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/labels/size/XXL","name":"size/XXL","color":"ee0000","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12/commits","review_comments_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12/comments","review_comment_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/12/comments","statuses_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/statuses/8d2504ad9ce4b5f872e127836759185ec9802826","head":{"label":"wackxu:snapshot_controller","ref":"snapshot_controller","sha":"8d2504ad9ce4b5f872e127836759185ec9802826","user":{"login":"wackxu","id":30396467,"node_id":"MDQ6VXNlcjMwMzk2NDY3","avatar_url":"https://avatars1.githubusercontent.com/u/30396467?v=4","gravatar_id":"","url":"https://api.github.com/users/wackxu","html_url":"https://github.com/wackxu","followers_url":"https://api.github.com/users/wackxu/followers","following_url":"https://api.github.com/users/wackxu/following{/other_user}","gists_url":"https://api.github.com/users/wackxu/gists{/gist_id}","starred_url":"https://api.github.com/users/wackxu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wackxu/subscriptions","organizations_url":"https://api.github.com/users/wackxu/orgs","repos_url":"https://api.github.com/users/wackxu/repos","events_url":"https://api.github.com/users/wackxu/events{/privacy}","received_events_url":"https://api.github.com/users/wackxu/received_events","type":"User","site_admin":false},"repo":{"id":144555016,"node_id":"MDEwOlJlcG9zaXRvcnkxNDQ1NTUwMTY=","name":"external-snapshotter","full_name":"wackxu/external-snapshotter","owner":{"login":"wackxu","id":30396467,"node_id":"MDQ6VXNlcjMwMzk2NDY3","avatar_url":"https://avatars1.githubusercontent.com/u/30396467?v=4","gravatar_id":"","url":"https://api.github.com/users/wackxu","html_url":"https://github.com/wackxu","followers_url":"https://api.github.com/users/wackxu/followers","following_url":"https://api.github.com/users/wackxu/following{/other_user}","gists_url":"https://api.github.com/users/wackxu/gists{/gist_id}","starred_url":"https://api.github.com/users/wackxu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wackxu/subscriptions","organizations_url":"https://api.github.com/users/wackxu/orgs","repos_url":"https://api.github.com/users/wackxu/repos","events_url":"https://api.github.com/users/wackxu/events{/privacy}","received_events_url":"https://api.github.com/users/wackxu/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wackxu/external-snapshotter","description":"Sidecar container that watches Kubernetes Snapshot CRD objects and triggers CreateSnapshot/DeleteSnapshot against a CSI endpoint.","fork":true,"url":"https://api.github.com/repos/wackxu/external-snapshotter","forks_url":"https://api.github.com/repos/wackxu/external-snapshotter/forks","keys_url":"https://api.github.com/repos/wackxu/external-snapshotter/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wackxu/external-snapshotter/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wackxu/external-snapshotter/teams","hooks_url":"https://api.github.com/repos/wackxu/external-snapshotter/hooks","issue_events_url":"https://api.github.com/repos/wackxu/external-snapshotter/issues/events{/number}","events_url":"https://api.github.com/repos/wackxu/external-snapshotter/events","assignees_url":"https://api.github.com/repos/wackxu/external-snapshotter/assignees{/user}","branches_url":"https://api.github.com/repos/wackxu/external-snapshotter/branches{/branch}","tags_url":"https://api.github.com/repos/wackxu/external-snapshotter/tags","blobs_url":"https://api.github.com/repos/wackxu/external-snapshotter/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wackxu/external-snapshotter/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wackxu/external-snapshotter/git/refs{/sha}","trees_url":"https://api.github.com/repos/wackxu/external-snapshotter/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wackxu/external-snapshotter/statuses/{sha}","languages_url":"https://api.github.com/repos/wackxu/external-snapshotter/languages","stargazers_url":"https://api.github.com/repos/wackxu/external-snapshotter/stargazers","contributors_url":"https://api.github.com/repos/wackxu/external-snapshotter/contributors","subscribers_url":"https://api.github.com/repos/wackxu/external-snapshotter/subscribers","subscription_url":"https://api.github.com/repos/wackxu/external-snapshotter/subscription","commits_url":"https://api.github.com/repos/wackxu/external-snapshotter/commits{/sha}","git_commits_url":"https://api.github.com/repos/wackxu/external-snapshotter/git/commits{/sha}","comments_url":"https://api.github.com/repos/wackxu/external-snapshotter/comments{/number}","issue_comment_url":"https://api.github.com/repos/wackxu/external-snapshotter/issues/comments{/number}","contents_url":"https://api.github.com/repos/wackxu/external-snapshotter/contents/{+path}","compare_url":"https://api.github.com/repos/wackxu/external-snapshotter/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wackxu/external-snapshotter/merges","archive_url":"https://api.github.com/repos/wackxu/external-snapshotter/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wackxu/external-snapshotter/downloads","issues_url":"https://api.github.com/repos/wackxu/external-snapshotter/issues{/number}","pulls_url":"https://api.github.com/repos/wackxu/external-snapshotter/pulls{/number}","milestones_url":"https://api.github.com/repos/wackxu/external-snapshotter/milestones{/number}","notifications_url":"https://api.github.com/repos/wackxu/external-snapshotter/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wackxu/external-snapshotter/labels{/name}","releases_url":"https://api.github.com/repos/wackxu/external-snapshotter/releases{/id}","deployments_url":"https://api.github.com/repos/wackxu/external-snapshotter/deployments","created_at":"2018-08-13T09:04:19Z","updated_at":"2018-08-13T09:04:21Z","pushed_at":"2018-08-30T13:33:04Z","git_url":"git://github.com/wackxu/external-snapshotter.git","ssh_url":"git@github.com:wackxu/external-snapshotter.git","clone_url":"https://github.com/wackxu/external-snapshotter.git","svn_url":"https://github.com/wackxu/external-snapshotter","homepage":null,"size":41434,"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":"kubernetes-csi:master","ref":"master","sha":"234c01b3e9ea94ed413f1423b5e8536ebf288078","user":{"login":"kubernetes-csi","id":33050221,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzMDUwMjIx","avatar_url":"https://avatars0.githubusercontent.com/u/33050221?v=4","gravatar_id":"","url":"https://api.github.com/users/kubernetes-csi","html_url":"https://github.com/kubernetes-csi","followers_url":"https://api.github.com/users/kubernetes-csi/followers","following_url":"https://api.github.com/users/kubernetes-csi/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes-csi/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes-csi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes-csi/subscriptions","organizations_url":"https://api.github.com/users/kubernetes-csi/orgs","repos_url":"https://api.github.com/users/kubernetes-csi/repos","events_url":"https://api.github.com/users/kubernetes-csi/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes-csi/received_events","type":"Organization","site_admin":false},"repo":{"id":140244788,"node_id":"MDEwOlJlcG9zaXRvcnkxNDAyNDQ3ODg=","name":"external-snapshotter","full_name":"kubernetes-csi/external-snapshotter","owner":{"login":"kubernetes-csi","id":33050221,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzMDUwMjIx","avatar_url":"https://avatars0.githubusercontent.com/u/33050221?v=4","gravatar_id":"","url":"https://api.github.com/users/kubernetes-csi","html_url":"https://github.com/kubernetes-csi","followers_url":"https://api.github.com/users/kubernetes-csi/followers","following_url":"https://api.github.com/users/kubernetes-csi/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes-csi/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes-csi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes-csi/subscriptions","organizations_url":"https://api.github.com/users/kubernetes-csi/orgs","repos_url":"https://api.github.com/users/kubernetes-csi/repos","events_url":"https://api.github.com/users/kubernetes-csi/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes-csi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes-csi/external-snapshotter","description":"Sidecar container that watches Kubernetes Snapshot CRD objects and triggers CreateSnapshot/DeleteSnapshot against a CSI endpoint.","fork":false,"url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter","forks_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/forks","keys_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/teams","hooks_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/hooks","issue_events_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/events","assignees_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/tags","blobs_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/languages","stargazers_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/stargazers","contributors_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/contributors","subscribers_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/subscribers","subscription_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/subscription","commits_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/merges","archive_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/downloads","issues_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/releases{/id}","deployments_url":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/deployments","created_at":"2018-07-09T07:05:08Z","updated_at":"2018-08-30T06:41:56Z","pushed_at":"2018-08-30T13:33:34Z","git_url":"git://github.com/kubernetes-csi/external-snapshotter.git","ssh_url":"git@github.com:kubernetes-csi/external-snapshotter.git","clone_url":"https://github.com/kubernetes-csi/external-snapshotter.git","svn_url":"https://github.com/kubernetes-csi/external-snapshotter","homepage":null,"size":41248,"stargazers_count":2,"watchers_count":2,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"archived":false,"open_issues_count":3,"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":7,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12"},"html":{"href":"https://github.com/kubernetes-csi/external-snapshotter/pull/12"},"issue":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/12"},"comments":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/issues/12/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/pulls/12/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes-csi/external-snapshotter/statuses/8d2504ad9ce4b5f872e127836759185ec9802826"}},"author_association":"NONE"}}
{"actor":{"display_login":"xing-yang"}}