2020-10-02 06:37:50 +00:00
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 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/>.
"""
API endpoints for VMware nodes .
"""
import os
2020-10-14 00:19:29 +00:00
from fastapi import APIRouter , Depends , status
2020-10-02 06:37:50 +00:00
from fastapi . encoders import jsonable_encoder
from fastapi . responses import StreamingResponse
from uuid import UUID
from gns3server . endpoints import schemas
from gns3server . compute . vmware import VMware
from gns3server . compute . project_manager import ProjectManager
2020-10-14 00:19:29 +00:00
from gns3server . compute . vmware . vmware_vm import VMwareVM
2020-10-02 06:37:50 +00:00
router = APIRouter ( )
2020-10-14 00:19:29 +00:00
responses = {
404 : { " model " : schemas . ErrorMessage , " description " : " Could not find project or VMware node " }
}
def dep_node ( project_id : UUID , node_id : UUID ) :
"""
Dependency to retrieve a node .
"""
vmware_manager = VMware . instance ( )
node = vmware_manager . get_node ( str ( node_id ) , project_id = str ( project_id ) )
return node
2020-10-02 06:37:50 +00:00
@router.post ( " / " ,
response_model = schemas . VMware ,
status_code = status . HTTP_201_CREATED ,
responses = { 409 : { " model " : schemas . ErrorMessage , " description " : " Could not create VMware node " } } )
async def create_vmware_node ( project_id : UUID , node_data : schemas . VMwareCreate ) :
"""
Create a new VMware node .
"""
vmware_manager = VMware . instance ( )
node_data = jsonable_encoder ( node_data , exclude_unset = True )
vm = await vmware_manager . create_node ( node_data . pop ( " name " ) ,
str ( project_id ) ,
node_data . get ( " node_id " ) ,
node_data . pop ( " vmx_path " ) ,
linked_clone = node_data . pop ( " linked_clone " ) ,
console = node_data . get ( " console " , None ) ,
console_type = node_data . get ( " console_type " , " telnet " ) )
for name , value in node_data . items ( ) :
if name != " node_id " :
if hasattr ( vm , name ) and getattr ( vm , name ) != value :
setattr ( vm , name , value )
return vm . __json__ ( )
@router.get ( " / {node_id} " ,
response_model = schemas . VMware ,
2020-10-14 00:19:29 +00:00
responses = responses )
def get_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Return a VMware node .
"""
2020-10-14 00:19:29 +00:00
return node . __json__ ( )
2020-10-02 06:37:50 +00:00
@router.put ( " / {node_id} " ,
response_model = schemas . VMware ,
2020-10-14 00:19:29 +00:00
responses = responses )
def update_vmware_node ( node_data : schemas . VMwareUpdate , node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Update a VMware node .
"""
node_data = jsonable_encoder ( node_data , exclude_unset = True )
# update the console first to avoid issue if updating console type
2020-10-14 00:19:29 +00:00
node . console = node_data . pop ( " console " , node . console )
2020-10-02 06:37:50 +00:00
for name , value in node_data . items ( ) :
2020-10-14 00:19:29 +00:00
if hasattr ( node , name ) and getattr ( node , name ) != value :
setattr ( node , name , value )
2020-10-02 06:37:50 +00:00
2020-10-14 00:19:29 +00:00
node . updated ( )
return node . __json__ ( )
2020-10-02 06:37:50 +00:00
@router.delete ( " / {node_id} " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def delete_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Delete a VMware node .
"""
2020-10-14 00:19:29 +00:00
await VMware . instance ( ) . delete_node ( node . id )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /start " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def start_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Start a VMware node .
"""
2020-10-14 00:19:29 +00:00
if node . check_hw_virtualization ( ) :
2020-10-02 06:37:50 +00:00
pm = ProjectManager . instance ( )
2020-10-14 00:19:29 +00:00
if pm . check_hardware_virtualization ( node ) is False :
2020-10-02 06:37:50 +00:00
pass # FIXME: check this
#raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
2020-10-14 00:19:29 +00:00
await node . start ( )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /stop " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def stop_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Stop a VMware node .
"""
2020-10-14 00:19:29 +00:00
await node . stop ( )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /suspend " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def suspend_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Suspend a VMware node .
"""
2020-10-14 00:19:29 +00:00
await node . suspend ( )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /resume " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def resume_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Resume a VMware node .
"""
2020-10-14 00:19:29 +00:00
await node . resume ( )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /reload " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def reload_vmware_node ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Reload a VMware node .
"""
2020-10-14 00:19:29 +00:00
await node . reload ( )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /nio " ,
status_code = status . HTTP_201_CREATED ,
response_model = schemas . UDPNIO ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def create_nio ( adapter_number : int ,
port_number : int ,
nio_data : schemas . UDPNIO ,
node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Add a NIO ( Network Input / Output ) to the node .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
nio = VMware . instance ( ) . create_nio ( jsonable_encoder ( nio_data , exclude_unset = True ) )
await node . adapter_add_nio_binding ( adapter_number , nio )
2020-10-02 06:37:50 +00:00
return nio . __json__ ( )
@router.put ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /nio " ,
status_code = status . HTTP_201_CREATED ,
response_model = schemas . UDPNIO ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def update_nio ( adapter_number : int ,
port_number : int ,
nio_data : schemas . UDPNIO , node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Update a NIO ( Network Input / Output ) on the node .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
nio = node . get_nio ( adapter_number )
2020-10-02 06:37:50 +00:00
if nio_data . filters :
nio . filters = nio_data . filters
2020-10-14 00:19:29 +00:00
await node . adapter_update_nio_binding ( adapter_number , nio )
2020-10-02 06:37:50 +00:00
return nio . __json__ ( )
@router.delete ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /nio " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def delete_nio ( adapter_number : int , port_number : int , node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Delete a NIO ( Network Input / Output ) from the node .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
await node . adapter_remove_nio_binding ( adapter_number )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /start_capture " ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def start_capture ( adapter_number : int ,
port_number : int ,
node_capture_data : schemas . NodeCapture ,
node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Start a packet capture on the node .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
pcap_file_path = os . path . join ( node . project . capture_working_directory ( ) , node_capture_data . capture_file_name )
await node . start_capture ( adapter_number , pcap_file_path )
2020-10-02 06:37:50 +00:00
return { " pcap_file_path " : pcap_file_path }
@router.post ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /stop_capture " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def stop_capture ( adapter_number : int , port_number : int , node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Stop a packet capture on the node .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
await node . stop_capture ( adapter_number )
2020-10-02 06:37:50 +00:00
@router.post ( " / {node_id} /console/reset " ,
status_code = status . HTTP_204_NO_CONTENT ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def reset_console ( node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
2020-10-14 00:19:29 +00:00
await node . reset_console ( )
2020-10-02 06:37:50 +00:00
@router.get ( " / {node_id} /adapters/ {adapter_number} /ports/ {port_number} /pcap " ,
2020-10-14 00:19:29 +00:00
responses = responses )
async def stream_pcap_file ( adapter_number : int , port_number : int , node : VMwareVM = Depends ( dep_node ) ) :
2020-10-02 06:37:50 +00:00
"""
Stream the pcap capture file .
The port number on the VMware node is always 0.
"""
2020-10-14 00:19:29 +00:00
nio = node . get_nio ( adapter_number )
stream = VMware . instance ( ) . stream_pcap_file ( nio , node . project . id )
2020-10-02 06:37:50 +00:00
return StreamingResponse ( stream , media_type = " application/vnd.tcpdump.pcap " )
@router.post ( " / {node_id} /interfaces/vmnet " ,
status_code = status . HTTP_201_CREATED ,
2020-10-14 00:19:29 +00:00
responses = responses )
def allocate_vmnet ( node : VMwareVM = Depends ( dep_node ) ) - > dict :
2020-10-02 06:37:50 +00:00
"""
Allocate a VMware VMnet interface on the server .
"""
vmware_manager = VMware . instance ( )
vmware_manager . refresh_vmnet_list ( ubridge = False )
vmnet = vmware_manager . allocate_vmnet ( )
2020-10-14 00:19:29 +00:00
node . vmnets . append ( vmnet )
2020-10-02 06:37:50 +00:00
return { " vmnet " : vmnet }
# @Route.get(
# r"/projects/{project_id}/vmware/nodes/{node_id}/console/ws",
# description="WebSocket for console",
# parameters={
# "project_id": "Project UUID",
# "node_id": "Node UUID",
# })
# async def console_ws(request, response):
#
# vmware_manager = VMware.instance()
# vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
# return await vm.start_websocket_console(request)
#