{"action":"created","comment":{"url":"https://api.github.com/repos/containerd/containerd/pulls/comments/220205378","pull_request_review_id":158558204,"id":220205378,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyMDIwNTM3OA==","diff_hunk":"@@ -0,0 +1,159 @@\n+/*\n+   Copyright The containerd 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 containerd\n+\n+import (\n+\t\"context\"\n+\n+\t\"github.com/containerd/containerd/containers\"\n+\t\"github.com/containerd/containerd/content\"\n+\t\"github.com/containerd/containerd/images\"\n+\t\"github.com/containerd/containerd/platforms\"\n+\t\"github.com/gogo/protobuf/proto\"\n+\tptypes \"github.com/gogo/protobuf/types\"\n+\t\"github.com/opencontainers/image-spec/identity\"\n+\timagespec \"github.com/opencontainers/image-spec/specs-go/v1\"\n+\t\"github.com/pkg/errors\"\n+)\n+\n+var (\n+\t// ErrImageNameNotFoundInIndex is returned when the image name is not found in the index\n+\tErrImageNameNotFoundInIndex = errors.New(\"image name not found in index\")\n+\t// ErrRuntimeNameNotFoundInIndex is returned when the runtime name is not found in the index\n+\tErrRuntimeNameNotFoundInIndex = errors.New(\"runtime name not found in index\")\n+)\n+\n+// RestoreOpts are options to manage the restore operation\n+type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) NewContainerOpts\n+\n+// WithRestoreImage restores the image for the container\n+func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {\n+\treturn func(ctx context.Context, client *Client, c *containers.Container) error {\n+\t\tname, ok := index.Annotations[checkpointImageNameLabel]\n+\t\tif !ok || name == \"\" {\n+\t\t\treturn ErrRuntimeNameNotFoundInIndex\n+\t\t}\n+\t\ti, err := client.GetImage(ctx, name)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\n+\t\tc.Image = i.Name()\n+\t\treturn nil\n+\t}\n+}\n+\n+// WithRestoreRuntime restores the runtime for the container\n+func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {\n+\treturn func(ctx context.Context, client *Client, c *containers.Container) error {\n+\t\tname, ok := index.Annotations[checkpointRuntimeNameLabel]\n+\t\tif !ok {\n+\t\t\treturn ErrRuntimeNameNotFoundInIndex\n+\t\t}\n+\n+\t\t// restore options if present\n+\t\tm, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions)\n+\t\tif err != nil {\n+\t\t\tif err != ErrMediaTypeNotFound {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\t\tvar options *ptypes.Any\n+\t\tif m != nil {\n+\t\t\tstore := client.ContentStore()\n+\t\t\tdata, err := content.ReadBlob(ctx, store, *m)\n+\t\t\tif err != nil {\n+\t\t\t\treturn errors.Wrap(err, \"unable to read checkpoint runtime\")\n+\t\t\t}\n+\t\t\tif err := proto.Unmarshal(data, options); err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\n+\t\tc.Runtime = containers.RuntimeInfo{\n+\t\t\tName:    name,\n+\t\t\tOptions: options,\n+\t\t}\n+\t\treturn nil\n+\t}\n+}\n+\n+// WithRestoreSpec restores the spec from the checkpoint for the container\n+func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {\n+\treturn func(ctx context.Context, client *Client, c *containers.Container) error {\n+\t\tm, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\tstore := client.ContentStore()\n+\t\tdata, err := content.ReadBlob(ctx, store, *m)\n+\t\tif err != nil {\n+\t\t\treturn errors.Wrap(err, \"unable to read checkpoint config\")\n+\t\t}\n+\t\tvar any ptypes.Any\n+\t\tif err := proto.Unmarshal(data, &any); err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\tc.Spec = &any\n+\t\treturn nil\n+\t}\n+}\n+\n+// WithRestoreSnapshot restores the snapshot from the checkpoint for the container\n+func WithRestoreSnapshot(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {\n+\treturn func(ctx context.Context, client *Client, c *containers.Container) error {\n+\t\timageName, ok := index.Annotations[checkpointImageNameLabel]\n+\t\tif !ok || imageName == \"\" {\n+\t\t\treturn ErrRuntimeNameNotFoundInIndex\n+\t\t}\n+\t\ti, err := client.GetImage(ctx, imageName)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\tdiffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\tparent := identity.ChainID(diffIDs).String()\n+\t\tif _, err := client.SnapshotService(DefaultSnapshotter).Prepare(ctx, id, parent); err != nil {","path":"container_restore_opts.go","position":132,"original_position":132,"commit_id":"b9ae44a34d11c9d555ca3eeb38d2d9e6d31d5e66","original_commit_id":"b9ae44a34d11c9d555ca3eeb38d2d9e6d31d5e66","user":{"login":"crosbymichael","id":749551,"node_id":"MDQ6VXNlcjc0OTU1MQ==","avatar_url":"https://avatars1.githubusercontent.com/u/749551?v=4","gravatar_id":"","url":"https://api.github.com/users/crosbymichael","html_url":"https://github.com/crosbymichael","followers_url":"https://api.github.com/users/crosbymichael/followers","following_url":"https://api.github.com/users/crosbymichael/following{/other_user}","gists_url":"https://api.github.com/users/crosbymichael/gists{/gist_id}","starred_url":"https://api.github.com/users/crosbymichael/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/crosbymichael/subscriptions","organizations_url":"https://api.github.com/users/crosbymichael/orgs","repos_url":"https://api.github.com/users/crosbymichael/repos","events_url":"https://api.github.com/users/crosbymichael/events{/privacy}","received_events_url":"https://api.github.com/users/crosbymichael/received_events","type":"User","site_admin":false},"body":"we should save the snapshotter used on the original container to the checkpoint so we can restore it from metadata","created_at":"2018-09-25T14:02:25Z","updated_at":"2018-09-25T14:02:25Z","html_url":"https://github.com/containerd/containerd/pull/2632#discussion_r220205378","pull_request_url":"https://api.github.com/repos/containerd/containerd/pulls/2632","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/containerd/containerd/pulls/comments/220205378"},"html":{"href":"https://github.com/containerd/containerd/pull/2632#discussion_r220205378"},"pull_request":{"href":"https://api.github.com/repos/containerd/containerd/pulls/2632"}}},"pull_request":{"url":"https://api.github.com/repos/containerd/containerd/pulls/2632","id":214775220,"node_id":"MDExOlB1bGxSZXF1ZXN0MjE0Nzc1MjIw","html_url":"https://github.com/containerd/containerd/pull/2632","diff_url":"https://github.com/containerd/containerd/pull/2632.diff","patch_url":"https://github.com/containerd/containerd/pull/2632.patch","issue_url":"https://api.github.com/repos/containerd/containerd/issues/2632","number":2632,"state":"open","locked":false,"title":"Refactor checkpoint and restore to client","user":{"login":"ehazlett","id":260642,"node_id":"MDQ6VXNlcjI2MDY0Mg==","avatar_url":"https://avatars0.githubusercontent.com/u/260642?v=4","gravatar_id":"","url":"https://api.github.com/users/ehazlett","html_url":"https://github.com/ehazlett","followers_url":"https://api.github.com/users/ehazlett/followers","following_url":"https://api.github.com/users/ehazlett/following{/other_user}","gists_url":"https://api.github.com/users/ehazlett/gists{/gist_id}","starred_url":"https://api.github.com/users/ehazlett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehazlett/subscriptions","organizations_url":"https://api.github.com/users/ehazlett/orgs","repos_url":"https://api.github.com/users/ehazlett/repos","events_url":"https://api.github.com/users/ehazlett/events{/privacy}","received_events_url":"https://api.github.com/users/ehazlett/received_events","type":"User","site_admin":false},"body":"This refactors the checkpoint and restore to be on the containerd client.  \r\n\r\nToDo\r\n- [x] Tests\r\n\r\nExample\r\n\r\n```\r\n$> ctr run --runtime io.containerd.runc.v1 -d docker.io/library/redis:alpine redis\r\n# checkpoint\r\n$>  ctr c checkpoint --rw --task redis checkpoint/redis:20180911\r\n# restore \r\n$> ctr c restore redis-debug checkpoint/redis:20180911\r\n# restore live\r\n$> ctr c restore --live redis-debug checkpoint/redis:20180911\r\n```\r\n\r\nRefs #2602 \r\n","created_at":"2018-09-11T21:41:25Z","updated_at":"2018-09-25T14:02:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4c142b889aa9b9f02a2d0304958c537166eb510a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/containerd/containerd/pulls/2632/commits","review_comments_url":"https://api.github.com/repos/containerd/containerd/pulls/2632/comments","review_comment_url":"https://api.github.com/repos/containerd/containerd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/containerd/containerd/issues/2632/comments","statuses_url":"https://api.github.com/repos/containerd/containerd/statuses/b9ae44a34d11c9d555ca3eeb38d2d9e6d31d5e66","head":{"label":"ehazlett:checkpoint-restore","ref":"checkpoint-restore","sha":"b9ae44a34d11c9d555ca3eeb38d2d9e6d31d5e66","user":{"login":"ehazlett","id":260642,"node_id":"MDQ6VXNlcjI2MDY0Mg==","avatar_url":"https://avatars0.githubusercontent.com/u/260642?v=4","gravatar_id":"","url":"https://api.github.com/users/ehazlett","html_url":"https://github.com/ehazlett","followers_url":"https://api.github.com/users/ehazlett/followers","following_url":"https://api.github.com/users/ehazlett/following{/other_user}","gists_url":"https://api.github.com/users/ehazlett/gists{/gist_id}","starred_url":"https://api.github.com/users/ehazlett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehazlett/subscriptions","organizations_url":"https://api.github.com/users/ehazlett/orgs","repos_url":"https://api.github.com/users/ehazlett/repos","events_url":"https://api.github.com/users/ehazlett/events{/privacy}","received_events_url":"https://api.github.com/users/ehazlett/received_events","type":"User","site_admin":false},"repo":{"id":87554732,"node_id":"MDEwOlJlcG9zaXRvcnk4NzU1NDczMg==","name":"containerd","full_name":"ehazlett/containerd","private":false,"owner":{"login":"ehazlett","id":260642,"node_id":"MDQ6VXNlcjI2MDY0Mg==","avatar_url":"https://avatars0.githubusercontent.com/u/260642?v=4","gravatar_id":"","url":"https://api.github.com/users/ehazlett","html_url":"https://github.com/ehazlett","followers_url":"https://api.github.com/users/ehazlett/followers","following_url":"https://api.github.com/users/ehazlett/following{/other_user}","gists_url":"https://api.github.com/users/ehazlett/gists{/gist_id}","starred_url":"https://api.github.com/users/ehazlett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehazlett/subscriptions","organizations_url":"https://api.github.com/users/ehazlett/orgs","repos_url":"https://api.github.com/users/ehazlett/repos","events_url":"https://api.github.com/users/ehazlett/events{/privacy}","received_events_url":"https://api.github.com/users/ehazlett/received_events","type":"User","site_admin":false},"html_url":"https://github.com/ehazlett/containerd","description":"An open and reliable container runtime","fork":true,"url":"https://api.github.com/repos/ehazlett/containerd","forks_url":"https://api.github.com/repos/ehazlett/containerd/forks","keys_url":"https://api.github.com/repos/ehazlett/containerd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ehazlett/containerd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ehazlett/containerd/teams","hooks_url":"https://api.github.com/repos/ehazlett/containerd/hooks","issue_events_url":"https://api.github.com/repos/ehazlett/containerd/issues/events{/number}","events_url":"https://api.github.com/repos/ehazlett/containerd/events","assignees_url":"https://api.github.com/repos/ehazlett/containerd/assignees{/user}","branches_url":"https://api.github.com/repos/ehazlett/containerd/branches{/branch}","tags_url":"https://api.github.com/repos/ehazlett/containerd/tags","blobs_url":"https://api.github.com/repos/ehazlett/containerd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ehazlett/containerd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ehazlett/containerd/git/refs{/sha}","trees_url":"https://api.github.com/repos/ehazlett/containerd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ehazlett/containerd/statuses/{sha}","languages_url":"https://api.github.com/repos/ehazlett/containerd/languages","stargazers_url":"https://api.github.com/repos/ehazlett/containerd/stargazers","contributors_url":"https://api.github.com/repos/ehazlett/containerd/contributors","subscribers_url":"https://api.github.com/repos/ehazlett/containerd/subscribers","subscription_url":"https://api.github.com/repos/ehazlett/containerd/subscription","commits_url":"https://api.github.com/repos/ehazlett/containerd/commits{/sha}","git_commits_url":"https://api.github.com/repos/ehazlett/containerd/git/commits{/sha}","comments_url":"https://api.github.com/repos/ehazlett/containerd/comments{/number}","issue_comment_url":"https://api.github.com/repos/ehazlett/containerd/issues/comments{/number}","contents_url":"https://api.github.com/repos/ehazlett/containerd/contents/{+path}","compare_url":"https://api.github.com/repos/ehazlett/containerd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ehazlett/containerd/merges","archive_url":"https://api.github.com/repos/ehazlett/containerd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ehazlett/containerd/downloads","issues_url":"https://api.github.com/repos/ehazlett/containerd/issues{/number}","pulls_url":"https://api.github.com/repos/ehazlett/containerd/pulls{/number}","milestones_url":"https://api.github.com/repos/ehazlett/containerd/milestones{/number}","notifications_url":"https://api.github.com/repos/ehazlett/containerd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ehazlett/containerd/labels{/name}","releases_url":"https://api.github.com/repos/ehazlett/containerd/releases{/id}","deployments_url":"https://api.github.com/repos/ehazlett/containerd/deployments","created_at":"2017-04-07T14:26:51Z","updated_at":"2017-04-07T14:26:53Z","pushed_at":"2018-09-24T18:37:24Z","git_url":"git://github.com/ehazlett/containerd.git","ssh_url":"git@github.com:ehazlett/containerd.git","clone_url":"https://github.com/ehazlett/containerd.git","svn_url":"https://github.com/ehazlett/containerd","homepage":"https://containerd.io","size":44670,"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":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"containerd:master","ref":"master","sha":"87d1118a0f350d019b8259063cf71418e4c2e739","user":{"login":"containerd","id":14037953,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MDM3OTUz","avatar_url":"https://avatars1.githubusercontent.com/u/14037953?v=4","gravatar_id":"","url":"https://api.github.com/users/containerd","html_url":"https://github.com/containerd","followers_url":"https://api.github.com/users/containerd/followers","following_url":"https://api.github.com/users/containerd/following{/other_user}","gists_url":"https://api.github.com/users/containerd/gists{/gist_id}","starred_url":"https://api.github.com/users/containerd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/containerd/subscriptions","organizations_url":"https://api.github.com/users/containerd/orgs","repos_url":"https://api.github.com/users/containerd/repos","events_url":"https://api.github.com/users/containerd/events{/privacy}","received_events_url":"https://api.github.com/users/containerd/received_events","type":"Organization","site_admin":false},"repo":{"id":46089560,"node_id":"MDEwOlJlcG9zaXRvcnk0NjA4OTU2MA==","name":"containerd","full_name":"containerd/containerd","private":false,"owner":{"login":"containerd","id":14037953,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MDM3OTUz","avatar_url":"https://avatars1.githubusercontent.com/u/14037953?v=4","gravatar_id":"","url":"https://api.github.com/users/containerd","html_url":"https://github.com/containerd","followers_url":"https://api.github.com/users/containerd/followers","following_url":"https://api.github.com/users/containerd/following{/other_user}","gists_url":"https://api.github.com/users/containerd/gists{/gist_id}","starred_url":"https://api.github.com/users/containerd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/containerd/subscriptions","organizations_url":"https://api.github.com/users/containerd/orgs","repos_url":"https://api.github.com/users/containerd/repos","events_url":"https://api.github.com/users/containerd/events{/privacy}","received_events_url":"https://api.github.com/users/containerd/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/containerd/containerd","description":"An open and reliable container runtime","fork":false,"url":"https://api.github.com/repos/containerd/containerd","forks_url":"https://api.github.com/repos/containerd/containerd/forks","keys_url":"https://api.github.com/repos/containerd/containerd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/containerd/containerd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/containerd/containerd/teams","hooks_url":"https://api.github.com/repos/containerd/containerd/hooks","issue_events_url":"https://api.github.com/repos/containerd/containerd/issues/events{/number}","events_url":"https://api.github.com/repos/containerd/containerd/events","assignees_url":"https://api.github.com/repos/containerd/containerd/assignees{/user}","branches_url":"https://api.github.com/repos/containerd/containerd/branches{/branch}","tags_url":"https://api.github.com/repos/containerd/containerd/tags","blobs_url":"https://api.github.com/repos/containerd/containerd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/containerd/containerd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/containerd/containerd/git/refs{/sha}","trees_url":"https://api.github.com/repos/containerd/containerd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/containerd/containerd/statuses/{sha}","languages_url":"https://api.github.com/repos/containerd/containerd/languages","stargazers_url":"https://api.github.com/repos/containerd/containerd/stargazers","contributors_url":"https://api.github.com/repos/containerd/containerd/contributors","subscribers_url":"https://api.github.com/repos/containerd/containerd/subscribers","subscription_url":"https://api.github.com/repos/containerd/containerd/subscription","commits_url":"https://api.github.com/repos/containerd/containerd/commits{/sha}","git_commits_url":"https://api.github.com/repos/containerd/containerd/git/commits{/sha}","comments_url":"https://api.github.com/repos/containerd/containerd/comments{/number}","issue_comment_url":"https://api.github.com/repos/containerd/containerd/issues/comments{/number}","contents_url":"https://api.github.com/repos/containerd/containerd/contents/{+path}","compare_url":"https://api.github.com/repos/containerd/containerd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/containerd/containerd/merges","archive_url":"https://api.github.com/repos/containerd/containerd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/containerd/containerd/downloads","issues_url":"https://api.github.com/repos/containerd/containerd/issues{/number}","pulls_url":"https://api.github.com/repos/containerd/containerd/pulls{/number}","milestones_url":"https://api.github.com/repos/containerd/containerd/milestones{/number}","notifications_url":"https://api.github.com/repos/containerd/containerd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/containerd/containerd/labels{/name}","releases_url":"https://api.github.com/repos/containerd/containerd/releases{/id}","deployments_url":"https://api.github.com/repos/containerd/containerd/deployments","created_at":"2015-11-13T00:27:43Z","updated_at":"2018-09-25T13:39:45Z","pushed_at":"2018-09-25T13:39:39Z","git_url":"git://github.com/containerd/containerd.git","ssh_url":"git@github.com:containerd/containerd.git","clone_url":"https://github.com/containerd/containerd.git","svn_url":"https://github.com/containerd/containerd","homepage":"https://containerd.io","size":44678,"stargazers_count":2949,"watchers_count":2949,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":598,"mirror_url":null,"archived":false,"open_issues_count":114,"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":598,"open_issues":114,"watchers":2949,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/containerd/containerd/pulls/2632"},"html":{"href":"https://github.com/containerd/containerd/pull/2632"},"issue":{"href":"https://api.github.com/repos/containerd/containerd/issues/2632"},"comments":{"href":"https://api.github.com/repos/containerd/containerd/issues/2632/comments"},"review_comments":{"href":"https://api.github.com/repos/containerd/containerd/pulls/2632/comments"},"review_comment":{"href":"https://api.github.com/repos/containerd/containerd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/containerd/containerd/pulls/2632/commits"},"statuses":{"href":"https://api.github.com/repos/containerd/containerd/statuses/b9ae44a34d11c9d555ca3eeb38d2d9e6d31d5e66"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"crosbymichael"}}