Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(QENG-2636) Host snapshots #117

Merged
merged 5 commits into from
Jul 27, 2015
Merged

Conversation

sschneid
Copy link
Contributor

This PR introduces host (VM) snapshotting support. Example workflow:

  1. Request a VM
$ curl -d '{"debian-7-x86_64":"1"}' --url vmpooler-dev/vm
{
  "ok": true,
  "debian-7-x86_64": {
    "ok": true,
    "hostname": "cxd6n45t1pd5s4j"
  },
  "domain": "delivery.puppetlabs.net"
}
  1. Take a snapshot
This command will return a snapshot ID ("fjgd9l9okym8647gmjnznky5sklji0r3")

$ curl -d --url vmpooler-dev/vm/cxd6n45t1pd5s4j/snapshot
{
  "ok": true,
  "cxd6n45t1pd5s4j": {
    "snapshot": "fjgd9l9okym8647gmjnznky5sklji0r3"
  }
}
  1. The vmpooler pooler_manager component sees the snapshot-creation task, and snapshots the VM in the background
[2015-05-01 12:35:02] [ ] [snapshot_manager] 'cxd6n45t1pd5s4j' is being snapshotted
[2015-05-01 12:39:04] [+] [snapshot_manager] 'cxd6n45t1pd5s4j' snapshot created in 242.77 seconds
  1. You can query the VM itself; the GET /vm/:hostname endpoint will show a snapshot once pool_manager has finished the snapshotting task
$ curl --url vmpooler-dev/vm/cxd6n45t1pd5s4j
{
  "ok": true,
  "cxd6n45t1pd5s4j": {
    "template": "debian-7-x86_64",
    "lifetime": 1,
    "running": 0.08,
    "snapshots": [
      "fjgd9l9okym8647gmjnznky5sklji0r3"
    ],
    "domain": "delivery.puppetlabs.net"
  }
}
  1. Change something on the VM
$ ssh root@cxd6n45t1pd5s4j
root@cxd6n45t1pd5s4j's password:
Linux debian-7-64 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1 x86_64 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. 

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Mar 31 08:33:05 2015
root@cxd6n45t1pd5s4j:~# echo "This VM has been modified." >/etc/motd
root@cxd6n45t1pd5s4j:~# cat /etc/motd
This VM has been modified.
  1. Revert the VM back to the snapshot we took earlier
$ curl -d --url vmpooler-dev/vm/cxd6n45t1pd5s4j/snapshot/fjgd9l9okym8647gmjnznky5sklji0r3
{
  "ok": true
}
  1. pool_manager reverts the VM
[2015-05-01 12:41:52] [ ] [snapshot_manager] 'cxd6n45t1pd5s4j' is being reverted to snapshot 'fjgd9l9okym8647gmjnznky5sklji0r3'
[2015-05-01 12:41:58] [<] [snapshot_manager] 'cxd6n45t1pd5s4j' reverted to snapshot in 6.86 seconds
  1. Verify that the changes in step 4 do not persist
$ ssh root@cxd6n45t1pd5s4j
root@cxd6n45t1pd5s4j's password:
Linux debian-7-64 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1 x86_64 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. 

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Mar 31 08:33:05 2015
root@cxd6n45t1pd5s4j:~# cat /etc/motd 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright. 

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

@colinPL
Copy link
Contributor

colinPL commented Jul 14, 2015

How many snapshots can a VM have at one time?

result[params[:hostname]] = {}

o = [('a'..'z'), ('0'..'9')].map(&:to_a).flatten
result[params[:hostname]]['snapshot'] = o[rand(25)] + (0...31).map { o[rand(o.length)] }.join
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't a random name method available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't a random name method available?

Not currently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would definitely say this pair of lines is a candidate for extracting to a method with an intention-revealing name.

  def random_snapshot_name
    o = [('a'..'z'), ('0'..'9')].map(&:to_a).flatten
    o[rand(25)] + (0...31).map { o[rand(o.length)] }.join
  end

  # ...

    post "#{api_prefix}/vm/:hostname/snapshot/?" do
      content_type :json

      status 404
      result = { 'ok' => false }

      hostname = params[:hostname] = hostname_shorten(params[:hostname], config['domain'])

      if backend.exists("vmpooler__vm__#{hostname}")
        result[hostname] = {}
        result[hostname]['snapshot'] = random_snapshot_name
        backend.sadd('vmpooler__tasks__snapshot', hostname + ':' + result[hostname]['snapshot'])

        status 202
        result['ok'] = true
      end

      JSON.pretty_generate(result)
    end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the usefulness of a create_a_random_string_of_N_characters method. Currenlty both pool_manager and api/v1 have randomization code in them, and unfortunately there isn't currently a helper library which is shared throughout the app. I can certainly refactor some code to accomplish this, but am unsure if it's out of the scope of the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would ticket the creation of the method and work on it separately. It is out-of-scope of this PR, IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, defer for separate work.

@sschneid
Copy link
Contributor Author

How many snapshots can a VM have at one time?

No limit defined by either vmpooler or vSphere.

end
end

def _create_vm_snapshot(vm, snapshot_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should do some scrutiny of snapshot_name. Or is that left to CreateSnapshot_Task?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What sort of scrutiny do you have in mind? As-is the only method calling create_vm_snapshot is the API, which is generating the snapshot_name var right before calling this method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly a check that it is not nil or empty?.

@stahnma
Copy link

stahnma commented Jul 15, 2015

Random Question, will you have to be auth'ed to use snap shotting?

@sschneid
Copy link
Contributor Author

Random Question, will you have to be auth'ed to use snap shotting?

That's actually something I started thinking about yesterday. This PR doesn't require auth at the moment, but as snapshotting is a relatively "expensive" vSphere task, I think it probably should.

@sschneid
Copy link
Contributor Author

This is ready for re-review. Addressed applicable comments above and included an additional commit to support requiring authentication tokens when using snapshots.

@sschneid
Copy link
Contributor Author

I've deployed this branch to vmpooler-dev for manual testing as well.

@sschneid
Copy link
Contributor Author

Some UX things I haven't figured out how to solve yet:

  • no way for user to tell when snapshotting is complete other than to check /api/v1/vm/:vm until a snapshots section appears in the JSON response
  • no way for user to tell when a snapshot revert task has completed

@@ -413,6 +413,11 @@ def need_token!
result[params[:hostname]]['tags'] ||= {}
result[params[:hostname]]['tags'][$1] = rdata[key]
end

if key.match('^snapshot\:(.+?)$')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be an elsif for the above if.

colinPL added a commit that referenced this pull request Jul 27, 2015
@colinPL colinPL merged commit 7fddaf8 into puppetlabs:master Jul 27, 2015
@sschneid sschneid deleted the host_snapshots branch July 28, 2015 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants