2015-01-20 03:30:57 +02:00
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2015-01-24 03:33:49 +02:00
import os
2015-07-22 07:58:28 +03:00
2015-04-27 23:19:17 +03:00
from aiohttp . web import HTTPConflict
2016-05-14 03:00:07 +03:00
from gns3server . web . route import Route
from gns3server . schemas . nio import NIO_SCHEMA
from gns3server . schemas . node import NODE_CAPTURE_SCHEMA
from gns3server . compute . virtualbox import VirtualBox
2017-03-16 20:17:12 +02:00
from gns3server . compute . virtualbox . virtualbox_error import VirtualBoxError
2016-05-14 03:00:07 +03:00
from gns3server . compute . project_manager import ProjectManager
from gns3server . schemas . virtualbox import (
VBOX_CREATE_SCHEMA ,
VBOX_OBJECT_SCHEMA
)
2015-01-20 03:30:57 +02:00
2016-05-18 12:00:35 +03:00
2015-01-20 03:30:57 +02:00
class VirtualBoxHandler :
2015-01-31 23:34:49 +02:00
2015-01-20 03:30:57 +02:00
"""
API entry points for VirtualBox .
"""
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes " ,
2015-02-05 02:13:35 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID "
2015-02-05 02:13:35 +02:00
} ,
2015-01-20 03:30:57 +02:00
status_codes = {
2015-01-24 01:38:46 +02:00
201 : " Instance created " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-20 03:30:57 +02:00
409 : " Conflict "
} ,
description = " Create a new VirtualBox VM instance " ,
input = VBOX_CREATE_SCHEMA ,
output = VBOX_OBJECT_SCHEMA )
def create ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = yield from vbox_manager . create_node ( request . json . pop ( " name " ) ,
request . match_info [ " project_id " ] ,
request . json . get ( " node_id " ) ,
request . json . pop ( " vmname " ) ,
2016-11-17 11:17:23 +02:00
linked_clone = request . json . pop ( " linked_clone " , False ) ,
2016-05-11 20:35:36 +03:00
console = request . json . get ( " console " , None ) ,
2018-03-24 14:11:21 +03:00
console_type = request . json . get ( " console_type " , " telnet " ) ,
2016-05-11 20:35:36 +03:00
adapters = request . json . get ( " adapters " , 0 ) )
2015-01-31 04:36:05 +02:00
2015-03-14 01:13:36 +02:00
if " ram " in request . json :
ram = request . json . pop ( " ram " )
if ram != vm . ram :
yield from vm . set_ram ( ram )
2015-01-31 04:36:05 +02:00
for name , value in request . json . items ( ) :
2016-05-11 20:35:36 +03:00
if name != " node_id " :
2015-04-14 15:24:13 +03:00
if hasattr ( vm , name ) and getattr ( vm , name ) != value :
setattr ( vm , name , value )
2015-01-31 04:36:05 +02:00
2015-01-21 23:01:15 +02:00
response . set_status ( 201 )
2015-01-22 00:21:15 +02:00
response . json ( vm )
2015-01-20 03:30:57 +02:00
2015-01-24 01:38:46 +02:00
@Route.get (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} " ,
2015-01-24 01:38:46 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-24 01:38:46 +02:00
} ,
status_codes = {
200 : " Success " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Get a VirtualBox VM instance " ,
output = VBOX_OBJECT_SCHEMA )
def show ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-24 01:38:46 +02:00
response . json ( vm )
@Route.put (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} " ,
2015-01-24 01:38:46 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-24 01:38:46 +02:00
} ,
status_codes = {
200 : " Instance updated " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist " ,
409 : " Conflict "
} ,
description = " Update a VirtualBox VM instance " ,
2016-07-12 17:22:55 +03:00
input = VBOX_OBJECT_SCHEMA ,
2015-01-24 01:38:46 +02:00
output = VBOX_OBJECT_SCHEMA )
def update ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-24 01:38:46 +02:00
2017-01-31 19:58:43 +02:00
if " name " in request . json :
name = request . json . pop ( " name " )
vmname = request . json . pop ( " vmname " , None )
if name != vm . name :
2017-03-16 20:17:12 +02:00
oldname = vm . name
2017-01-31 19:58:43 +02:00
vm . name = name
if vm . linked_clone :
2017-03-16 20:17:12 +02:00
try :
yield from vm . set_vmname ( vm . name )
except VirtualBoxError as e : # In case of error we rollback (we can't change the name when running)
vm . name = oldname
vm . updated ( )
raise e
2015-03-08 20:32:36 +02:00
2015-03-05 03:24:15 +02:00
if " adapters " in request . json :
adapters = int ( request . json . pop ( " adapters " ) )
if adapters != vm . adapters :
yield from vm . set_adapters ( adapters )
2015-03-14 01:13:36 +02:00
if " ram " in request . json :
ram = request . json . pop ( " ram " )
if ram != vm . ram :
yield from vm . set_ram ( ram )
2018-06-09 17:47:36 +03:00
# update the console first to avoid issue if updating console type
vm . console = request . json . pop ( " console " , vm . console )
2015-01-24 01:38:46 +02:00
for name , value in request . json . items ( ) :
if hasattr ( vm , name ) and getattr ( vm , name ) != value :
setattr ( vm , name , value )
2015-02-07 02:31:13 +02:00
2016-05-18 12:00:35 +03:00
vm . updated ( )
2015-01-24 01:38:46 +02:00
response . json ( vm )
@Route.delete (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} " ,
2015-01-24 01:38:46 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-24 01:38:46 +02:00
} ,
status_codes = {
204 : " Instance deleted " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Delete a VirtualBox VM instance " )
def delete ( request , response ) :
2015-02-05 02:13:35 +02:00
# check the project_id exists
ProjectManager . instance ( ) . get_project ( request . match_info [ " project_id " ] )
2016-05-11 20:35:36 +03:00
yield from VirtualBox . instance ( ) . delete_node ( request . match_info [ " node_id " ] )
2015-01-24 01:38:46 +02:00
response . set_status ( 204 )
2015-01-20 03:30:57 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /start " ,
2015-01-20 03:30:57 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-20 03:30:57 +02:00
} ,
status_codes = {
2015-01-24 01:38:46 +02:00
204 : " Instance started " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
2015-01-20 03:30:57 +02:00
} ,
description = " Start a VirtualBox VM instance " )
2015-01-22 02:41:35 +02:00
def start ( request , response ) :
2015-01-20 03:30:57 +02:00
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-07-27 04:21:30 +03:00
if ( yield from vm . check_hw_virtualization ( ) ) :
2015-07-22 07:58:28 +03:00
pm = ProjectManager . instance ( )
if pm . check_hardware_virtualization ( vm ) is False :
2015-07-27 04:21:30 +03:00
raise HTTPConflict ( text = " Cannot start VM because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or KVM (on Linux) " )
2015-01-22 02:41:35 +02:00
yield from vm . start ( )
2015-01-21 23:01:15 +02:00
response . set_status ( 204 )
2015-01-20 03:30:57 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /stop " ,
2015-01-20 03:30:57 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-20 03:30:57 +02:00
} ,
status_codes = {
2015-01-24 01:38:46 +02:00
204 : " Instance stopped " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
2015-01-20 03:30:57 +02:00
} ,
description = " Stop a VirtualBox VM instance " )
2015-01-22 02:41:35 +02:00
def stop ( request , response ) :
2015-01-20 03:30:57 +02:00
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-22 02:41:35 +02:00
yield from vm . stop ( )
2015-01-21 23:01:15 +02:00
response . set_status ( 204 )
2015-01-22 04:28:52 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /suspend " ,
2015-01-22 04:28:52 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-22 04:28:52 +02:00
} ,
status_codes = {
2015-01-24 01:38:46 +02:00
204 : " Instance suspended " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
2015-01-22 04:28:52 +02:00
} ,
description = " Suspend a VirtualBox VM instance " )
def suspend ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-22 04:28:52 +02:00
yield from vm . suspend ( )
response . set_status ( 204 )
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /resume " ,
2015-01-22 04:28:52 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-22 04:28:52 +02:00
} ,
status_codes = {
2015-01-24 01:38:46 +02:00
204 : " Instance resumed " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
2015-01-22 04:28:52 +02:00
} ,
description = " Resume a suspended VirtualBox VM instance " )
2015-05-01 04:05:37 +03:00
def resume ( request , response ) :
2015-01-22 04:28:52 +02:00
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-22 04:28:52 +02:00
yield from vm . resume ( )
response . set_status ( 204 )
2015-01-23 04:06:17 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /reload " ,
2015-01-23 04:06:17 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID "
2015-01-23 04:06:17 +02:00
} ,
status_codes = {
2015-01-24 01:38:46 +02:00
204 : " Instance reloaded " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
2015-01-23 04:06:17 +02:00
} ,
description = " Reload a VirtualBox VM instance " )
2015-02-05 02:13:35 +02:00
def reload ( request , response ) :
2015-01-23 04:06:17 +02:00
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-01-23 04:06:17 +02:00
yield from vm . reload ( )
response . set_status ( 204 )
2015-01-24 01:38:46 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /adapters/ { adapter_number: \ d+}/ports/ { port_number: \ d+}/nio " ,
2015-01-24 01:38:46 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID " ,
2015-02-14 00:11:14 +02:00
" adapter_number " : " Adapter where the nio should be added " ,
" port_number " : " Port on the adapter (always 0) "
2015-01-24 01:38:46 +02:00
} ,
status_codes = {
201 : " NIO created " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Add a NIO to a VirtualBox VM instance " ,
2015-04-27 23:19:17 +03:00
input = NIO_SCHEMA ,
output = NIO_SCHEMA )
2015-01-24 01:38:46 +02:00
def create_nio ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-04-27 23:19:17 +03:00
nio_type = request . json [ " type " ]
2015-05-07 00:21:39 +03:00
if nio_type not in ( " nio_udp " , " nio_nat " ) :
2015-04-27 23:19:17 +03:00
raise HTTPConflict ( text = " NIO of type {} is not supported " . format ( nio_type ) )
2016-06-25 03:35:39 +03:00
nio = vbox_manager . create_nio ( request . json )
2015-02-14 00:11:14 +02:00
yield from vm . adapter_add_nio_binding ( int ( request . match_info [ " adapter_number " ] ) , nio )
2015-01-24 01:38:46 +02:00
response . set_status ( 201 )
response . json ( nio )
2017-07-18 15:59:47 +03:00
@Route.put (
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /adapters/ { adapter_number: \ d+}/ports/ { port_number: \ d+}/nio " ,
parameters = {
" project_id " : " Project UUID " ,
" node_id " : " Node UUID " ,
" adapter_number " : " Network adapter where the nio is located " ,
" port_number " : " Port from where the nio should be updated "
} ,
status_codes = {
201 : " NIO updated " ,
400 : " Invalid request " ,
404 : " Instance doesn ' t exist "
} ,
input = NIO_SCHEMA ,
output = NIO_SCHEMA ,
description = " Update a NIO from a Virtualbox instance " )
def update_nio ( request , response ) :
virtualbox_manager = VirtualBox . instance ( )
vm = virtualbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
nio = vm . ethernet_adapters [ int ( request . match_info [ " adapter_number " ] ) ]
if " filters " in request . json and nio :
nio . filters = request . json [ " filters " ]
2018-03-19 11:26:12 +02:00
if " suspend " in request . json and nio :
nio . suspend = request . json [ " suspend " ]
2017-07-18 15:59:47 +03:00
yield from vm . adapter_update_nio_binding ( int ( request . match_info [ " adapter_number " ] ) , nio )
response . set_status ( 201 )
response . json ( request . json )
2015-01-24 01:38:46 +02:00
@Route.delete (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /adapters/ { adapter_number: \ d+}/ports/ { port_number: \ d+}/nio " ,
2015-01-24 01:38:46 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID " ,
2015-02-14 00:11:14 +02:00
" adapter_number " : " Adapter from where the nio should be removed " ,
2015-03-07 05:08:00 +02:00
" port_number " : " Port on the adapter (always 0) "
2015-01-24 01:38:46 +02:00
} ,
status_codes = {
204 : " NIO deleted " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 01:38:46 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Remove a NIO from a VirtualBox VM instance " )
def delete_nio ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-02-14 00:11:14 +02:00
yield from vm . adapter_remove_nio_binding ( int ( request . match_info [ " adapter_number " ] ) )
2015-01-24 01:38:46 +02:00
response . set_status ( 204 )
2015-01-24 03:33:49 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /adapters/ { adapter_number: \ d+}/ports/ { port_number: \ d+}/start_capture " ,
2015-01-24 03:33:49 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID " ,
2015-02-14 00:11:14 +02:00
" adapter_number " : " Adapter to start a packet capture " ,
" port_number " : " Port on the adapter (always 0) "
2015-01-24 03:33:49 +02:00
} ,
status_codes = {
200 : " Capture started " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 03:33:49 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Start a packet capture on a VirtualBox VM instance " ,
2016-05-11 20:35:36 +03:00
input = NODE_CAPTURE_SCHEMA )
2015-01-24 03:33:49 +02:00
def start_capture ( request , response ) :
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-02-14 00:11:14 +02:00
adapter_number = int ( request . match_info [ " adapter_number " ] )
2015-02-08 23:44:56 +02:00
pcap_file_path = os . path . join ( vm . project . capture_working_directory ( ) , request . json [ " capture_file_name " ] )
2015-05-27 22:56:27 +03:00
yield from vm . start_capture ( adapter_number , pcap_file_path )
2015-01-31 21:01:23 +02:00
response . json ( { " pcap_file_path " : pcap_file_path } )
2015-01-24 03:33:49 +02:00
@Route.post (
2016-05-11 20:35:36 +03:00
r " /projects/ {project_id} /virtualbox/nodes/ {node_id} /adapters/ { adapter_number: \ d+}/ports/ { port_number: \ d+}/stop_capture " ,
2015-01-24 03:33:49 +02:00
parameters = {
2016-05-14 03:00:07 +03:00
" project_id " : " Project UUID " ,
" node_id " : " Node UUID " ,
2015-02-14 00:11:14 +02:00
" adapter_number " : " Adapter to stop a packet capture " ,
" port_number " : " Port on the adapter (always 0) "
2015-01-24 03:33:49 +02:00
} ,
status_codes = {
204 : " Capture stopped " ,
2015-02-05 02:13:35 +02:00
400 : " Invalid request " ,
2015-01-24 03:33:49 +02:00
404 : " Instance doesn ' t exist "
} ,
description = " Stop a packet capture on a VirtualBox VM instance " )
2015-02-17 01:53:50 +02:00
def stop_capture ( request , response ) :
2015-01-24 03:33:49 +02:00
vbox_manager = VirtualBox . instance ( )
2016-05-11 20:35:36 +03:00
vm = vbox_manager . get_node ( request . match_info [ " node_id " ] , project_id = request . match_info [ " project_id " ] )
2015-02-14 00:11:14 +02:00
vm . stop_capture ( int ( request . match_info [ " adapter_number " ] ) )
2015-01-24 03:33:49 +02:00
response . set_status ( 204 )
2016-05-14 03:00:07 +03:00
@Route.get (
r " /virtualbox/vms " ,
status_codes = {
200 : " Success " ,
} ,
description = " Get all available VirtualBox VMs " )
def get_vms ( request , response ) :
vbox_manager = VirtualBox . instance ( )
vms = yield from vbox_manager . list_vms ( )
response . json ( vms )