Add new disks via API

Add an additional disk to a running VM via the vmpooler API.

````
$ curl -X POST -H X-AUTH-TOKEN:a9znth9dn01t416hrguu56ze37t790bl --url vmpooler.company.com/api/v1/vm/fq6qlpjlsskycq6/disk/8
````
````json
{
  "ok": true,
  "fq6qlpjlsskycq6": {
    "disk": "+8mb"
  }
}
````

Provisioning and attaching disks can take a moment, but once the task completes it will be reflected in a `GET /vm/<hostname>` query:

````
$ curl --url vmpooler.company.com/api/v1/vm/fq6qlpjlsskycq6
````
````json
{
  "ok": true,
  "fq6qlpjlsskycq6": {
    "template": "debian-7-x86_64",
    "lifetime": 2,
    "running": 0.08,
    "state": "running",
    "disk": [
      "+8mb"
    ],
    "domain": "delivery.puppetlabs.net"
  }
}
This commit is contained in:
Scott Schneider 2016-01-12 22:23:09 -08:00
parent 7d0f7254ae
commit 48a1a8d621
4 changed files with 146 additions and 1 deletions

40
API.md
View file

@ -226,6 +226,46 @@ $ curl -X DELETE --url vmpooler.company.com/api/v1/vm/fq6qlpjlsskycq6
}
```
#### Adding additional disk(s)
##### POST /vm/&lt;hostname&gt;/disk/&lt;size&gt;
Add an additional disk to a running VM.
````
$ curl -X POST -H X-AUTH-TOKEN:a9znth9dn01t416hrguu56ze37t790bl --url vmpooler.company.com/api/v1/vm/fq6qlpjlsskycq6/disk/8
````
````json
{
"ok": true,
"fq6qlpjlsskycq6": {
"disk": "+8gb"
}
}
````
Provisioning and attaching disks can take a moment, but once the task completes it will be reflected in a `GET /vm/<hostname>` query:
````
$ curl --url vmpooler.company.com/api/v1/vm/fq6qlpjlsskycq6
````
````json
{
"ok": true,
"fq6qlpjlsskycq6": {
"template": "debian-7-x86_64",
"lifetime": 2,
"running": 0.08,
"state": "running",
"disk": [
"+8gb"
],
"domain": "delivery.puppetlabs.net"
}
}
````
#### VM snapshots
##### POST /vm/&lt;hostname&gt;/snapshot

View file

@ -62,6 +62,10 @@ module Vmpooler
post '/vm/:hostname/snapshot/:snapshot/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:hostname]}/snapshot/#{params[:snapshot]}")
end
put '/vm/:hostname/disk/:size/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:hostname]}/disk/#{params[:size]}")
end
end
end
end

View file

@ -455,6 +455,10 @@ module Vmpooler
end
end
if rdata['disk']
result[params[:hostname]]['disk'] = rdata['disk'].split(':')
end
if config['domain']
result[params[:hostname]]['domain'] = config['domain']
end
@ -552,6 +556,29 @@ module Vmpooler
JSON.pretty_generate(result)
end
post "#{api_prefix}/vm/:hostname/disk/:size/?" do
content_type :json
need_token! if Vmpooler::API.settings.config[:auth]
status 404
result = { 'ok' => false }
params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
if ((params[:size].to_i > 0 )and (backend.exists('vmpooler__vm__' + params[:hostname])))
result[params[:hostname]] = {}
result[params[:hostname]]['disk'] = "+#{params[:size]}gb"
backend.sadd('vmpooler__tasks__disk', params[:hostname] + ':' + params[:size])
status 202
result['ok'] = true
end
JSON.pretty_generate(result)
end
post "#{api_prefix}/vm/:hostname/snapshot/?" do
content_type :json

View file

@ -299,6 +299,47 @@ module Vmpooler
end
end
def create_vm_disk(vm, disk_size)
Thread.new do
_create_vm_disk(vm, disk_size)
end
end
def _create_vm_disk(vm, disk_size)
host = $vsphere['disk_manager'].find_vm(vm) ||
$vsphere['disk_manager'].find_vm_heavy(vm)[vm]
if (host) && ((! disk_size.nil?) && (! disk_size.empty?) && (disk_size.to_i > 0))
$logger.log('s', "[ ] [disk_manager] '#{vm}' is attaching a #{disk_size}gb disk")
start = Time.now
template = $redis.hget('vmpooler__vm__' + vm, 'template')
datastore = nil
$config[:pools].each do |pool|
if pool['name'] == template
datastore = pool['datastore']
end
end
if ((! datastore.nil?) && (! datastore.empty?))
$vsphere['disk_manager'].add_disk(host, disk_size, datastore)
rdisks = $redis.hget('vmpooler__vm__' + vm, 'disk')
disks = rdisks ? rdisks.split(':') : []
disks.push("+#{disk_size}gb")
$redis.hset('vmpooler__vm__' + vm, 'disk', disks.join(':'))
finish = '%.2f' % (Time.now - start)
$logger.log('s', "[+] [disk_manager] '#{vm}' attached #{disk_size}gb disk in #{finish} seconds")
else
$logger.log('s', "[+] [disk_manager] '#{vm}' failed to attach disk")
end
end
end
def create_vm_snapshot(vm, snapshot_name)
Thread.new do
_create_vm_snapshot(vm, snapshot_name)
@ -309,7 +350,7 @@ module Vmpooler
host = $vsphere['snapshot_manager'].find_vm(vm) ||
$vsphere['snapshot_manager'].find_vm_heavy(vm)[vm]
if (host) && ((! snapshot_name.nil?) || (! snapshot_name.empty?))
if (host) && ((! snapshot_name.nil?) && (! snapshot_name.empty?))
$logger.log('s', "[ ] [snapshot_manager] '#{vm}' is being snapshotted")
start = Time.now
@ -356,6 +397,32 @@ module Vmpooler
end
end
def check_disk_queue
$logger.log('d', "[*] [disk_manager] starting worker thread")
$vsphere['disk_manager'] ||= Vmpooler::VsphereHelper.new
$threads['disk_manager'] = Thread.new do
loop do
_check_disk_queue
sleep(5)
end
end
end
def _check_disk_queue
vm = $redis.spop('vmpooler__tasks__disk')
unless vm.nil?
begin
vm_name, disk_size = vm.split(':')
create_vm_disk(vm_name, disk_size)
rescue
$logger.log('s', "[!] [disk_manager] disk creation appears to have failed")
end
end
end
def check_snapshot_queue
$logger.log('d', "[*] [snapshot_manager] starting worker thread")
@ -544,6 +611,13 @@ module Vmpooler
$redis.set('vmpooler__tasks__clone', 0)
loop do
if ! $threads['disk_manager']
check_disk_queue
elsif ! $threads['disk_manager'].alive?
$logger.log('d', "[!] [disk_manager] worker thread died, restarting")
check_disk_queue
end
if ! $threads['snapshot_manager']
check_snapshot_queue
elsif ! $threads['snapshot_manager'].alive?