{"action":"created","comment":{"url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/comments/172153537","pull_request_review_id":101120492,"id":172153537,"diff_hunk":"@@ -0,0 +1,756 @@\n+/*\n+ * This file is part of the KubeVirt project\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+ * Copyright 2017 Red Hat, Inc.\n+ *\n+ */\n+\n+package watch\n+\n+import (\n+\t\"time\"\n+\n+\t\"k8s.io/apimachinery/pkg/util/wait\"\n+\t\"k8s.io/client-go/tools/cache\"\n+\t\"k8s.io/client-go/tools/record\"\n+\t\"k8s.io/client-go/util/workqueue\"\n+\n+\t\"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\n+\tk8score \"k8s.io/api/core/v1\"\n+\n+\t\"fmt\"\n+\n+\t\"reflect\"\n+\n+\tvirtv1 \"kubevirt.io/kubevirt/pkg/api/v1\"\n+\t\"kubevirt.io/kubevirt/pkg/controller\"\n+\t\"kubevirt.io/kubevirt/pkg/kubecli\"\n+\t\"kubevirt.io/kubevirt/pkg/log\"\n+)\n+\n+func NewOVMController(vmInformer cache.SharedIndexInformer, vmOVMInformer cache.SharedIndexInformer, recorder record.EventRecorder, clientset kubecli.KubevirtClient) *OVMController {\n+\n+\tc := &OVMController{\n+\t\tQueue:         workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),\n+\t\tvmInformer:    vmInformer,\n+\t\tvmOVMInformer: vmOVMInformer,\n+\t\trecorder:      recorder,\n+\t\tclientset:     clientset,\n+\t\texpectations:  controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()),\n+\t}\n+\n+\tc.vmOVMInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc:    c.addOvm,\n+\t\tDeleteFunc: c.deleteOvm,\n+\t\tUpdateFunc: c.updateOvm,\n+\t})\n+\n+\tc.vmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc:    c.addVirtualMachine,\n+\t\tDeleteFunc: c.deleteVirtualMachine,\n+\t\tUpdateFunc: c.updateVirtualMachine,\n+\t})\n+\n+\treturn c\n+}\n+\n+type OVMController struct {\n+\tclientset     kubecli.KubevirtClient\n+\tQueue         workqueue.RateLimitingInterface\n+\tvmInformer    cache.SharedIndexInformer\n+\tvmOVMInformer cache.SharedIndexInformer\n+\trecorder      record.EventRecorder\n+\texpectations  *controller.UIDTrackingControllerExpectations\n+}\n+\n+func (c *OVMController) Run(threadiness int, stopCh chan struct{}) {\n+\tdefer controller.HandlePanic()\n+\tdefer c.Queue.ShutDown()\n+\tlog.Log.Info(\"Starting OfflineVirtualMachine controller.\")\n+\n+\t// Wait for cache sync before we start the controller\n+\tcache.WaitForCacheSync(stopCh, c.vmInformer.HasSynced, c.vmOVMInformer.HasSynced)\n+\n+\t// Start the actual work\n+\tfor i := 0; i < threadiness; i++ {\n+\t\tgo wait.Until(c.runWorker, time.Second, stopCh)\n+\t}\n+\n+\t<-stopCh\n+\tlog.Log.Info(\"Stopping OfflineVirtualMachine controller.\")\n+}\n+\n+func (c *OVMController) runWorker() {\n+\tfor c.Execute() {\n+\t}\n+}\n+\n+func (c *OVMController) Execute() bool {\n+\tkey, quit := c.Queue.Get()\n+\tif quit {\n+\t\treturn false\n+\t}\n+\tdefer c.Queue.Done(key)\n+\tif err := c.execute(key.(string)); err != nil {\n+\t\tlog.Log.Reason(err).Infof(\"re-enqueuing OfflineVirtualMachine %v\", key)\n+\t\tc.Queue.AddRateLimited(key)\n+\t} else {\n+\t\tlog.Log.V(4).Infof(\"processed OfflineVirtualMachine %v\", key)\n+\t\tc.Queue.Forget(key)\n+\t}\n+\treturn true\n+}\n+\n+func (c *OVMController) execute(key string) error {\n+\n+\tobj, exists, err := c.vmOVMInformer.GetStore().GetByKey(key)\n+\tif err != nil {\n+\t\treturn nil\n+\t}\n+\tif !exists {\n+\t\t// nothing we need to do. It should always be possible to re-create this type of controller\n+\t\tc.expectations.DeleteExpectations(key)\n+\t\treturn nil\n+\t}\n+\tOVM := obj.(*virtv1.OfflineVirtualMachine)\n+\n+\tlogger := log.Log.Object(OVM)\n+\n+\tlogger.Info(\"Started processing OVM\")\n+\n+\t//TODO default rs if necessary, the aggregated apiserver will do that in the future\n+\tif OVM.Spec.Template == nil || len(OVM.Spec.Template.ObjectMeta.Labels) == 0 {\n+\t\tlogger.Error(\"Invalid controller spec, will not re-enqueue.\")\n+\t\treturn nil\n+\t}\n+\n+\tneedsSync := c.expectations.SatisfiedExpectations(key)\n+\n+\tovmKey, err := controller.KeyFunc(OVM)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\t// If any adoptions are attempted, we should first recheck for deletion with\n+\t// an uncached quorum read sometime after listing VirtualMachines (see kubernetes/kubernetes#42639).\n+\tcanAdoptFunc := controller.RecheckDeletionTimestamp(func() (v1.Object, error) {\n+\t\tfresh, err := c.clientset.OfflineVirtualMachine(OVM.ObjectMeta.Namespace).Get(OVM.ObjectMeta.Name, &v1.GetOptions{})\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\tif fresh.ObjectMeta.UID != OVM.ObjectMeta.UID {\n+\t\t\treturn nil, fmt.Errorf(\"original OfflineVirtualMachine %v/%v is gone: got uid %v, wanted %v\", OVM.Namespace, OVM.Name, fresh.UID, OVM.UID)\n+\t\t}\n+\t\treturn fresh, nil\n+\t})\n+\tcm := controller.NewVirtualMachineControllerRefManager(controller.RealVirtualMachineControl{Clientset: c.clientset}, OVM, nil, virtv1.OfflineVirtualMachineGroupVersionKind, canAdoptFunc)\n+\n+\tvar vm *virtv1.VirtualMachine\n+\tvmObj, exist, err := c.vmInformer.GetStore().GetByKey(ovmKey)\n+\tif err != nil {\n+\t\tlogger.Reason(err).Error(\"Failed to fetch vm for namespace from cache.\")\n+\t\treturn err\n+\t}\n+\tif !exist {\n+\t\tlogger.Infof(\"VM not found in cache %s\", key)\n+\t\tvm = nil\n+\t} else {\n+\t\tvm = vmObj.(*virtv1.VirtualMachine)\n+\n+\t\tvm, err = cm.ClaimVirtualMachineByName(vm)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t}\n+\n+\tvar createErr, vmError error\n+\n+\t// Scale up or down, if all expected creates and deletes were report by the listener\n+\tif needsSync && OVM.ObjectMeta.DeletionTimestamp == nil {\n+\t\tlogger.Infof(\"Creating or the VM: %t\", OVM.Spec.Running)\n+\t\tcreateErr = c.startStop(OVM, vm)\n+\n+\t\t// restart VM if the VM fails or is final\n+\t\tvmError = c.restartVM(OVM, vm)\n+\t}\n+\n+\t// If the controller is going to be deleted and the orphan finalizer is the next one, release the VMs. Don't update the status\n+\t// TODO: Workaround for https://github.com/kubernetes/kubernetes/issues/56348, remove it once it is fixed\n+\tif OVM.ObjectMeta.DeletionTimestamp != nil && controller.HasFinalizer(OVM, v1.FinalizerOrphanDependents) {\n+\t\treturn c.orphan(cm, vm)\n+\t}\n+\n+\tif createErr != nil {\n+\t\tlogger.Reason(err).Error(\"Scaling the OfflineVirtualMachine failed.\")\n+\t}\n+\n+\terr = c.updateStatus(OVM.DeepCopy(), vm, createErr, vmError)\n+\tif err != nil {\n+\t\tlogger.Reason(err).Error(\"Updating the OfflineVirtualMachine status failed.\")\n+\t}\n+\n+\treturn err\n+}\n+\n+// orphan removes the owner reference of all VMs which are owned by the controller instance.\n+// Workaround for https://github.com/kubernetes/kubernetes/issues/56348 to make no-cascading deletes possible\n+// We don't have to remove the finalizer. This part of the gc is not affected by the mentioned bug\n+// TODO +pkotas unify with replicasets. This function can be the same\n+func (c *OVMController) orphan(cm *controller.VirtualMachineControllerRefManager, vm *virtv1.VirtualMachine) error {\n+\tif vm == nil {\n+\t\treturn nil\n+\t}\n+\n+\terrChan := make(chan error, 1)\n+\n+\tgo func(vm *virtv1.VirtualMachine) {\n+\t\terr := cm.ReleaseVirtualMachine(vm)\n+\t\tif err != nil {\n+\t\t\terrChan <- err\n+\t\t}\n+\t}(vm)\n+\n+\tselect {\n+\tcase err := <-errChan:\n+\t\treturn err\n+\tdefault:\n+\t}\n+\treturn nil\n+}\n+\n+func (c *OVMController) startStop(ovm *virtv1.OfflineVirtualMachine, vm *virtv1.VirtualMachine) error {\n+\tlog.Log.Object(ovm).Infof(\"VM should be running: %t\", ovm.Spec.Running)","path":"pkg/virt-controller/watch/ovm.go","position":235,"original_position":235,"commit_id":"0a8a0dd51d26e65b33c53ea7faeba443ba0e25ba","original_commit_id":"0a8a0dd51d26e65b33c53ea7faeba443ba0e25ba","user":{"login":"rmohr","id":4534621,"avatar_url":"https://avatars3.githubusercontent.com/u/4534621?v=4","gravatar_id":"","url":"https://api.github.com/users/rmohr","html_url":"https://github.com/rmohr","followers_url":"https://api.github.com/users/rmohr/followers","following_url":"https://api.github.com/users/rmohr/following{/other_user}","gists_url":"https://api.github.com/users/rmohr/gists{/gist_id}","starred_url":"https://api.github.com/users/rmohr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmohr/subscriptions","organizations_url":"https://api.github.com/users/rmohr/orgs","repos_url":"https://api.github.com/users/rmohr/repos","events_url":"https://api.github.com/users/rmohr/events{/privacy}","received_events_url":"https://api.github.com/users/rmohr/received_events","type":"User","site_admin":false},"body":"That log message should not be there, or should be reworded and should have a higher verbosity. It would be printed a lot.","created_at":"2018-03-05T11:09:09Z","updated_at":"2018-03-05T11:15:27Z","html_url":"https://github.com/kubevirt/kubevirt/pull/667#discussion_r172153537","pull_request_url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/comments/172153537"},"html":{"href":"https://github.com/kubevirt/kubevirt/pull/667#discussion_r172153537"},"pull_request":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667"}}},"pull_request":{"url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667","id":164130182,"html_url":"https://github.com/kubevirt/kubevirt/pull/667","diff_url":"https://github.com/kubevirt/kubevirt/pull/667.diff","patch_url":"https://github.com/kubevirt/kubevirt/pull/667.patch","issue_url":"https://api.github.com/repos/kubevirt/kubevirt/issues/667","number":667,"state":"open","locked":false,"title":"OfflineVirtualMachine implementation","user":{"login":"petrkotas","id":8687113,"avatar_url":"https://avatars1.githubusercontent.com/u/8687113?v=4","gravatar_id":"","url":"https://api.github.com/users/petrkotas","html_url":"https://github.com/petrkotas","followers_url":"https://api.github.com/users/petrkotas/followers","following_url":"https://api.github.com/users/petrkotas/following{/other_user}","gists_url":"https://api.github.com/users/petrkotas/gists{/gist_id}","starred_url":"https://api.github.com/users/petrkotas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petrkotas/subscriptions","organizations_url":"https://api.github.com/users/petrkotas/orgs","repos_url":"https://api.github.com/users/petrkotas/repos","events_url":"https://api.github.com/users/petrkotas/events{/privacy}","received_events_url":"https://api.github.com/users/petrkotas/received_events","type":"User","site_admin":false},"body":"This PR introduces the OfflineVirtualMachine kind to the kubernetes ecosystem and add its support to the KubeVirt.\r\n\r\nCurrently it is a heavy work in progress and this PR is meant to support discussion.\r\nAll remarks, tips and comments are welcomed.\r\n\r\nFixes #668\r\n\r\n@fabiand @rmohr @davidvossel @mpolednik @michalskrivanek @stu-gott\r\n\r\n<!-- Reviewable:start -->\r\n---\r\nThis change is [<img src=\"https://reviewable.io/review_button.svg\" height=\"34\" align=\"absmiddle\" alt=\"Reviewable\"/>](https://reviewable.io/reviews/kubevirt/kubevirt/667)\r\n<!-- Reviewable:end -->\r\n\r\n\r\n- [x] Basic controller logic\r\n- [x] OfflineVirtualMachine Client\r\n- [x] OnDelete update strategy\r\n- [x] Unit Tests\r\n- Functional Tests\r\n  - [ ] cover restart of guest-side stopped vm (vm in final or failed state)","created_at":"2018-01-20T14:38:57Z","updated_at":"2018-03-05T11:15:27Z","closed_at":null,"merged_at":null,"merge_commit_sha":"30ecd569b8225d2c424f68b2efe54b116b51035a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667/commits","review_comments_url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667/comments","review_comment_url":"https://api.github.com/repos/kubevirt/kubevirt/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubevirt/kubevirt/issues/667/comments","statuses_url":"https://api.github.com/repos/kubevirt/kubevirt/statuses/0a8a0dd51d26e65b33c53ea7faeba443ba0e25ba","head":{"label":"petrkotas:offlinevm-implementation","ref":"offlinevm-implementation","sha":"0a8a0dd51d26e65b33c53ea7faeba443ba0e25ba","user":{"login":"petrkotas","id":8687113,"avatar_url":"https://avatars1.githubusercontent.com/u/8687113?v=4","gravatar_id":"","url":"https://api.github.com/users/petrkotas","html_url":"https://github.com/petrkotas","followers_url":"https://api.github.com/users/petrkotas/followers","following_url":"https://api.github.com/users/petrkotas/following{/other_user}","gists_url":"https://api.github.com/users/petrkotas/gists{/gist_id}","starred_url":"https://api.github.com/users/petrkotas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petrkotas/subscriptions","organizations_url":"https://api.github.com/users/petrkotas/orgs","repos_url":"https://api.github.com/users/petrkotas/repos","events_url":"https://api.github.com/users/petrkotas/events{/privacy}","received_events_url":"https://api.github.com/users/petrkotas/received_events","type":"User","site_admin":false},"repo":{"id":99820257,"name":"kubevirt","full_name":"petrkotas/kubevirt","owner":{"login":"petrkotas","id":8687113,"avatar_url":"https://avatars1.githubusercontent.com/u/8687113?v=4","gravatar_id":"","url":"https://api.github.com/users/petrkotas","html_url":"https://github.com/petrkotas","followers_url":"https://api.github.com/users/petrkotas/followers","following_url":"https://api.github.com/users/petrkotas/following{/other_user}","gists_url":"https://api.github.com/users/petrkotas/gists{/gist_id}","starred_url":"https://api.github.com/users/petrkotas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petrkotas/subscriptions","organizations_url":"https://api.github.com/users/petrkotas/orgs","repos_url":"https://api.github.com/users/petrkotas/repos","events_url":"https://api.github.com/users/petrkotas/events{/privacy}","received_events_url":"https://api.github.com/users/petrkotas/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/petrkotas/kubevirt","description":"KubeVirt is a virtual machine management add-on for Kubernetes.","fork":true,"url":"https://api.github.com/repos/petrkotas/kubevirt","forks_url":"https://api.github.com/repos/petrkotas/kubevirt/forks","keys_url":"https://api.github.com/repos/petrkotas/kubevirt/keys{/key_id}","collaborators_url":"https://api.github.com/repos/petrkotas/kubevirt/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/petrkotas/kubevirt/teams","hooks_url":"https://api.github.com/repos/petrkotas/kubevirt/hooks","issue_events_url":"https://api.github.com/repos/petrkotas/kubevirt/issues/events{/number}","events_url":"https://api.github.com/repos/petrkotas/kubevirt/events","assignees_url":"https://api.github.com/repos/petrkotas/kubevirt/assignees{/user}","branches_url":"https://api.github.com/repos/petrkotas/kubevirt/branches{/branch}","tags_url":"https://api.github.com/repos/petrkotas/kubevirt/tags","blobs_url":"https://api.github.com/repos/petrkotas/kubevirt/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/petrkotas/kubevirt/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/petrkotas/kubevirt/git/refs{/sha}","trees_url":"https://api.github.com/repos/petrkotas/kubevirt/git/trees{/sha}","statuses_url":"https://api.github.com/repos/petrkotas/kubevirt/statuses/{sha}","languages_url":"https://api.github.com/repos/petrkotas/kubevirt/languages","stargazers_url":"https://api.github.com/repos/petrkotas/kubevirt/stargazers","contributors_url":"https://api.github.com/repos/petrkotas/kubevirt/contributors","subscribers_url":"https://api.github.com/repos/petrkotas/kubevirt/subscribers","subscription_url":"https://api.github.com/repos/petrkotas/kubevirt/subscription","commits_url":"https://api.github.com/repos/petrkotas/kubevirt/commits{/sha}","git_commits_url":"https://api.github.com/repos/petrkotas/kubevirt/git/commits{/sha}","comments_url":"https://api.github.com/repos/petrkotas/kubevirt/comments{/number}","issue_comment_url":"https://api.github.com/repos/petrkotas/kubevirt/issues/comments{/number}","contents_url":"https://api.github.com/repos/petrkotas/kubevirt/contents/{+path}","compare_url":"https://api.github.com/repos/petrkotas/kubevirt/compare/{base}...{head}","merges_url":"https://api.github.com/repos/petrkotas/kubevirt/merges","archive_url":"https://api.github.com/repos/petrkotas/kubevirt/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/petrkotas/kubevirt/downloads","issues_url":"https://api.github.com/repos/petrkotas/kubevirt/issues{/number}","pulls_url":"https://api.github.com/repos/petrkotas/kubevirt/pulls{/number}","milestones_url":"https://api.github.com/repos/petrkotas/kubevirt/milestones{/number}","notifications_url":"https://api.github.com/repos/petrkotas/kubevirt/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/petrkotas/kubevirt/labels{/name}","releases_url":"https://api.github.com/repos/petrkotas/kubevirt/releases{/id}","deployments_url":"https://api.github.com/repos/petrkotas/kubevirt/deployments","created_at":"2017-08-09T14:53:19Z","updated_at":"2017-08-09T14:53:21Z","pushed_at":"2018-03-05T09:21:00Z","git_url":"git://github.com/petrkotas/kubevirt.git","ssh_url":"git@github.com:petrkotas/kubevirt.git","clone_url":"https://github.com/petrkotas/kubevirt.git","svn_url":"https://github.com/petrkotas/kubevirt","homepage":"","size":59888,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"kubevirt:master","ref":"master","sha":"9c5d74a3ae6c5df9dff022f282a1e030b4d67e0a","user":{"login":"kubevirt","id":18700703,"avatar_url":"https://avatars1.githubusercontent.com/u/18700703?v=4","gravatar_id":"","url":"https://api.github.com/users/kubevirt","html_url":"https://github.com/kubevirt","followers_url":"https://api.github.com/users/kubevirt/followers","following_url":"https://api.github.com/users/kubevirt/following{/other_user}","gists_url":"https://api.github.com/users/kubevirt/gists{/gist_id}","starred_url":"https://api.github.com/users/kubevirt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubevirt/subscriptions","organizations_url":"https://api.github.com/users/kubevirt/orgs","repos_url":"https://api.github.com/users/kubevirt/repos","events_url":"https://api.github.com/users/kubevirt/events{/privacy}","received_events_url":"https://api.github.com/users/kubevirt/received_events","type":"Organization","site_admin":false},"repo":{"id":76686583,"name":"kubevirt","full_name":"kubevirt/kubevirt","owner":{"login":"kubevirt","id":18700703,"avatar_url":"https://avatars1.githubusercontent.com/u/18700703?v=4","gravatar_id":"","url":"https://api.github.com/users/kubevirt","html_url":"https://github.com/kubevirt","followers_url":"https://api.github.com/users/kubevirt/followers","following_url":"https://api.github.com/users/kubevirt/following{/other_user}","gists_url":"https://api.github.com/users/kubevirt/gists{/gist_id}","starred_url":"https://api.github.com/users/kubevirt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubevirt/subscriptions","organizations_url":"https://api.github.com/users/kubevirt/orgs","repos_url":"https://api.github.com/users/kubevirt/repos","events_url":"https://api.github.com/users/kubevirt/events{/privacy}","received_events_url":"https://api.github.com/users/kubevirt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubevirt/kubevirt","description":"A virtualization API and runtime add-on for Kubernetes in order to define and manage virtual machines.","fork":false,"url":"https://api.github.com/repos/kubevirt/kubevirt","forks_url":"https://api.github.com/repos/kubevirt/kubevirt/forks","keys_url":"https://api.github.com/repos/kubevirt/kubevirt/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubevirt/kubevirt/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubevirt/kubevirt/teams","hooks_url":"https://api.github.com/repos/kubevirt/kubevirt/hooks","issue_events_url":"https://api.github.com/repos/kubevirt/kubevirt/issues/events{/number}","events_url":"https://api.github.com/repos/kubevirt/kubevirt/events","assignees_url":"https://api.github.com/repos/kubevirt/kubevirt/assignees{/user}","branches_url":"https://api.github.com/repos/kubevirt/kubevirt/branches{/branch}","tags_url":"https://api.github.com/repos/kubevirt/kubevirt/tags","blobs_url":"https://api.github.com/repos/kubevirt/kubevirt/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubevirt/kubevirt/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubevirt/kubevirt/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubevirt/kubevirt/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubevirt/kubevirt/statuses/{sha}","languages_url":"https://api.github.com/repos/kubevirt/kubevirt/languages","stargazers_url":"https://api.github.com/repos/kubevirt/kubevirt/stargazers","contributors_url":"https://api.github.com/repos/kubevirt/kubevirt/contributors","subscribers_url":"https://api.github.com/repos/kubevirt/kubevirt/subscribers","subscription_url":"https://api.github.com/repos/kubevirt/kubevirt/subscription","commits_url":"https://api.github.com/repos/kubevirt/kubevirt/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubevirt/kubevirt/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubevirt/kubevirt/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubevirt/kubevirt/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubevirt/kubevirt/contents/{+path}","compare_url":"https://api.github.com/repos/kubevirt/kubevirt/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubevirt/kubevirt/merges","archive_url":"https://api.github.com/repos/kubevirt/kubevirt/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubevirt/kubevirt/downloads","issues_url":"https://api.github.com/repos/kubevirt/kubevirt/issues{/number}","pulls_url":"https://api.github.com/repos/kubevirt/kubevirt/pulls{/number}","milestones_url":"https://api.github.com/repos/kubevirt/kubevirt/milestones{/number}","notifications_url":"https://api.github.com/repos/kubevirt/kubevirt/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubevirt/kubevirt/labels{/name}","releases_url":"https://api.github.com/repos/kubevirt/kubevirt/releases{/id}","deployments_url":"https://api.github.com/repos/kubevirt/kubevirt/deployments","created_at":"2016-12-16T21:24:26Z","updated_at":"2018-03-03T14:02:14Z","pushed_at":"2018-03-05T10:48:51Z","git_url":"git://github.com/kubevirt/kubevirt.git","ssh_url":"git@github.com:kubevirt/kubevirt.git","clone_url":"https://github.com/kubevirt/kubevirt.git","svn_url":"https://github.com/kubevirt/kubevirt","homepage":"","size":51262,"stargazers_count":426,"watchers_count":426,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":107,"mirror_url":null,"archived":false,"open_issues_count":91,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":107,"open_issues":91,"watchers":426,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667"},"html":{"href":"https://github.com/kubevirt/kubevirt/pull/667"},"issue":{"href":"https://api.github.com/repos/kubevirt/kubevirt/issues/667"},"comments":{"href":"https://api.github.com/repos/kubevirt/kubevirt/issues/667/comments"},"review_comments":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667/comments"},"review_comment":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubevirt/kubevirt/pulls/667/commits"},"statuses":{"href":"https://api.github.com/repos/kubevirt/kubevirt/statuses/0a8a0dd51d26e65b33c53ea7faeba443ba0e25ba"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"rmohr"}}