2015-05-01 04:05:37 +03:00
#
2015-09-05 23:38:11 +03:00
# Copyright (C) 2015 GNS3 Technologies Inc.
2015-05-01 04:05:37 +03:00
#
# 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/>.
"""
VMware VM instance .
"""
import sys
import os
import asyncio
2015-05-28 06:06:18 +03:00
import tempfile
2021-06-08 05:26:33 +03:00
import platform
2015-05-01 04:05:37 +03:00
2016-11-07 12:16:51 +02:00
from gns3server . utils . asyncio . telnet_server import AsyncioTelnetServer
from gns3server . utils . asyncio . serial import asyncio_open_serial
2021-06-08 05:26:33 +03:00
from gns3server . utils import parse_version
2018-08-25 10:10:47 +03:00
from gns3server . utils . asyncio import locking
2015-05-22 06:48:59 +03:00
from collections import OrderedDict
2015-05-01 04:05:37 +03:00
from . vmware_error import VMwareError
from . . nios . nio_udp import NIOUDP
2015-05-15 05:11:57 +03:00
from . . adapters . ethernet_adapter import EthernetAdapter
2016-05-11 20:35:36 +03:00
from . . base_node import BaseNode
2015-05-01 04:05:37 +03:00
2015-05-21 04:05:26 +03:00
2015-05-01 04:05:37 +03:00
import logging
2021-04-13 12:16:50 +03:00
2015-05-01 04:05:37 +03:00
log = logging . getLogger ( __name__ )
2015-05-21 04:05:26 +03:00
2016-05-11 20:35:36 +03:00
class VMwareVM ( BaseNode ) :
2015-05-01 04:05:37 +03:00
"""
VMware VM implementation .
"""
2021-04-13 12:16:50 +03:00
def __init__ (
self , name , node_id , project , manager , vmx_path , linked_clone = False , console = None , console_type = " telnet "
) :
2015-05-01 04:05:37 +03:00
2021-04-13 12:16:50 +03:00
super ( ) . __init__ (
name , node_id , project , manager , console = console , console_type = console_type , linked_clone = linked_clone
)
2015-05-01 04:05:37 +03:00
2015-05-22 06:48:59 +03:00
self . _vmx_pairs = OrderedDict ( )
2016-11-07 12:16:51 +02:00
self . _telnet_server = None
2015-05-22 06:48:59 +03:00
self . _vmnets = [ ]
self . _maximum_adapters = 10
2015-05-28 06:06:18 +03:00
self . _started = False
2015-05-01 04:05:37 +03:00
self . _closed = False
# VMware VM settings
self . _headless = False
self . _vmx_path = vmx_path
2018-03-30 17:18:44 +03:00
self . _on_close = " power_off "
2015-05-15 05:11:57 +03:00
self . _adapters = 0
self . _ethernet_adapters = { }
self . _adapter_type = " e1000 "
2015-05-22 06:48:59 +03:00
self . _use_any_adapter = False
2015-05-15 05:11:57 +03:00
if not os . path . exists ( vmx_path ) :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' VMware VM " { name } " [ { node_id } ]: could not find VMX file " { vmx_path } " ' )
2015-05-01 04:05:37 +03:00
2017-07-18 19:04:03 +03:00
@property
def ethernet_adapters ( self ) :
return self . _ethernet_adapters
2021-04-17 17:04:28 +03:00
def asdict ( self ) :
2015-05-01 04:05:37 +03:00
2021-04-13 12:16:50 +03:00
json = {
" name " : self . name ,
" usage " : self . usage ,
" node_id " : self . id ,
" console " : self . console ,
" console_type " : self . console_type ,
" project_id " : self . project . id ,
" vmx_path " : self . vmx_path ,
" headless " : self . headless ,
" on_close " : self . on_close ,
" adapters " : self . _adapters ,
" adapter_type " : self . adapter_type ,
" use_any_adapter " : self . use_any_adapter ,
" status " : self . status ,
" node_directory " : self . working_path ,
" linked_clone " : self . linked_clone ,
}
2015-06-26 18:09:19 +03:00
return json
2015-05-22 06:48:59 +03:00
@property
def vmnets ( self ) :
return self . _vmnets
2015-05-01 04:05:37 +03:00
2018-08-25 10:10:47 +03:00
@locking
2018-10-15 13:05:49 +03:00
async def _control_vm ( self , subcommand , * additional_args ) :
2015-05-01 04:05:37 +03:00
args = [ self . _vmx_path ]
args . extend ( additional_args )
2018-10-15 13:05:49 +03:00
result = await self . manager . execute ( subcommand , args )
2021-04-13 12:07:58 +03:00
log . debug ( f " Control VM ' { subcommand } ' result: { result } " )
2015-05-01 04:05:37 +03:00
return result
2015-09-05 23:38:11 +03:00
def _read_vmx_file ( self ) :
"""
Reads from the VMware VMX file corresponding to this VM .
"""
try :
self . _vmx_pairs = self . manager . parse_vmware_file ( self . _vmx_path )
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' Could not read VMware VMX file " { self . _vmx_path } " : { e } ' )
2015-09-05 23:38:11 +03:00
def _write_vmx_file ( self ) :
"""
Writes pairs to the VMware VMX file corresponding to this VM .
"""
try :
self . manager . write_vmx_file ( self . _vmx_path , self . _vmx_pairs )
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' Could not write VMware VMX file " { self . _vmx_path } " : { e } ' )
2015-09-05 23:38:11 +03:00
2018-10-15 13:05:49 +03:00
async def is_running ( self ) :
2015-10-12 01:41:55 +03:00
2018-10-15 13:05:49 +03:00
result = await self . manager . execute ( " list " , [ ] )
2015-10-12 01:41:55 +03:00
if self . _vmx_path in result :
return True
return False
2018-10-15 13:05:49 +03:00
async def _check_duplicate_linked_clone ( self ) :
2016-11-17 13:21:38 +02:00
"""
Without linked clone two VM using the same image can ' t run
at the same time .
To avoid issue like false detection when a project close
and another open we try multiple times .
"""
trial = 0
while True :
found = False
for node in self . manager . nodes :
if node != self and node . vmx_path == self . _vmx_path :
found = True
if node . project != self . project :
if trial > = 30 :
2021-04-13 12:16:50 +03:00
raise VMwareError (
f " Sorry a node without the linked clone setting enabled can only be used once on your server. \n { self . vmx_path } is already used by { node . name } in project { self . project . name } "
)
2016-11-17 13:21:38 +02:00
else :
if trial > = 5 :
2021-04-13 12:16:50 +03:00
raise VMwareError (
f " Sorry a node without the linked clone setting enabled can only be used once on your server. \n { self . vmx_path } is already used by { node . name } in this project "
)
2016-11-17 13:21:38 +02:00
if not found :
return
trial + = 1
2018-10-15 13:05:49 +03:00
await asyncio . sleep ( 1 )
2016-11-17 13:21:38 +02:00
2018-10-15 13:05:49 +03:00
async def create ( self ) :
2015-06-18 02:36:52 +03:00
"""
Creates this VM and handle linked clones .
"""
2016-11-17 13:21:38 +02:00
if not self . linked_clone :
2018-10-15 13:05:49 +03:00
await self . _check_duplicate_linked_clone ( )
2015-05-31 05:26:38 +03:00
2018-10-15 13:05:49 +03:00
await self . manager . check_vmrun_version ( )
2016-10-24 22:39:35 +03:00
if self . linked_clone and not os . path . exists ( os . path . join ( self . working_dir , os . path . basename ( self . _vmx_path ) ) ) :
2016-04-04 21:10:48 +03:00
if self . manager . host_type == " player " :
raise VMwareError ( " Linked clones are not supported by VMware Player " )
2015-05-31 05:26:38 +03:00
# create the base snapshot for linked clones
base_snapshot_name = " GNS3 Linked Base for clones "
vmsd_path = os . path . splitext ( self . _vmx_path ) [ 0 ] + " .vmsd "
if not os . path . exists ( vmsd_path ) :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " { vmsd_path } doesn ' t not exist " )
2015-05-31 05:26:38 +03:00
try :
vmsd_pairs = self . manager . parse_vmware_file ( vmsd_path )
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' Could not read VMware VMSD file " { vmsd_path } " : { e } ' )
2015-05-31 05:26:38 +03:00
gns3_snapshot_exists = False
for value in vmsd_pairs . values ( ) :
if value == base_snapshot_name :
gns3_snapshot_exists = True
break
if not gns3_snapshot_exists :
2021-04-13 12:07:58 +03:00
log . info ( f " Creating snapshot ' { base_snapshot_name } ' " )
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " snapshot " , base_snapshot_name )
2015-05-31 05:26:38 +03:00
# create the linked clone based on the base snapshot
new_vmx_path = os . path . join ( self . working_dir , self . name + " .vmx " )
2021-04-13 12:16:50 +03:00
await self . _control_vm (
" clone " , new_vmx_path , " linked " , f " -snapshot= { base_snapshot_name } " , f " -cloneName= { self . name } "
)
2015-05-31 05:26:38 +03:00
try :
vmsd_pairs = self . manager . parse_vmware_file ( vmsd_path )
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' Could not read VMware VMSD file " { vmsd_path } " : { e } ' )
2015-05-31 05:26:38 +03:00
snapshot_name = None
for name , value in vmsd_pairs . items ( ) :
if value == base_snapshot_name :
snapshot_name = name . split ( " . " , 1 ) [ 0 ]
break
if snapshot_name is None :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " Could not find the linked base snapshot in { vmsd_path } " )
2015-05-31 05:26:38 +03:00
2021-04-13 12:07:58 +03:00
num_clones_entry = f " { snapshot_name } .numClones "
2015-05-31 05:26:38 +03:00
if num_clones_entry in vmsd_pairs :
try :
nb_of_clones = int ( vmsd_pairs [ num_clones_entry ] )
except ValueError :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " Value of { num_clones_entry } in { vmsd_path } is not a number " )
2015-05-31 05:26:38 +03:00
vmsd_pairs [ num_clones_entry ] = str ( nb_of_clones - 1 )
for clone_nb in range ( 0 , nb_of_clones ) :
2021-04-13 12:07:58 +03:00
clone_entry = f " { snapshot_name } .clone { clone_nb } "
2015-05-31 05:26:38 +03:00
if clone_entry in vmsd_pairs :
del vmsd_pairs [ clone_entry ]
try :
self . manager . write_vmware_file ( vmsd_path , vmsd_pairs )
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' Could not write VMware VMSD file " { vmsd_path } " : { e } ' )
2015-05-31 05:26:38 +03:00
# update the VMX file path
self . _vmx_path = new_vmx_path
2015-05-22 06:48:59 +03:00
def _get_vmx_setting ( self , name , value = None ) :
2015-05-21 04:05:26 +03:00
2015-05-22 06:48:59 +03:00
if name in self . _vmx_pairs :
if value is not None :
if self . _vmx_pairs [ name ] == value :
return value
else :
return self . _vmx_pairs [ name ]
return None
2015-05-21 04:05:26 +03:00
2015-05-15 05:11:57 +03:00
def _set_network_options ( self ) :
2015-06-18 02:36:52 +03:00
"""
Set up VMware networking .
"""
2015-05-15 05:11:57 +03:00
2015-09-05 23:38:11 +03:00
# first some sanity checks
2015-05-21 04:05:26 +03:00
for adapter_number in range ( 0 , self . _adapters ) :
2015-09-05 23:38:11 +03:00
# we want the vmnet interface to be connected when starting the VM
2021-04-13 12:07:58 +03:00
connected = f " ethernet { adapter_number } .startConnected "
2015-05-22 06:48:59 +03:00
if self . _get_vmx_setting ( connected ) :
del self . _vmx_pairs [ connected ]
2021-06-08 05:26:33 +03:00
use_ubridge = True
# use alternative method to find vmnet interfaces on macOS >= 11.0 (BigSur)
# because "bridge" interfaces are used instead and they are only created on the VM starts
if sys . platform . startswith ( " darwin " ) and parse_version ( platform . mac_ver ( ) [ 0 ] ) > = parse_version ( " 11.0.0 " ) :
use_ubridge = False
self . manager . refresh_vmnet_list ( ubridge = use_ubridge )
2015-09-05 23:38:11 +03:00
# then configure VMware network adapters
2015-05-22 06:48:59 +03:00
for adapter_number in range ( 0 , self . _adapters ) :
2015-09-05 23:38:11 +03:00
2018-04-02 18:27:12 +03:00
custom_adapter = self . _get_custom_adapter_settings ( adapter_number )
adapter_type = custom_adapter . get ( " adapter_type " , self . _adapter_type )
2015-09-05 23:38:11 +03:00
# add/update the interface
2018-04-02 18:27:12 +03:00
if adapter_type == " default " :
2016-05-23 23:14:42 +03:00
# force default to e1000 because some guest OS don't detect the adapter (i.e. Windows 2012 server)
# when 'virtualdev' is not set in the VMX file.
2018-04-02 18:27:12 +03:00
vmware_adapter_type = " e1000 "
2016-05-23 23:14:42 +03:00
else :
2018-04-02 18:27:12 +03:00
vmware_adapter_type = adapter_type
2021-04-13 12:16:50 +03:00
ethernet_adapter = {
f " ethernet { adapter_number } .present " : " TRUE " ,
f " ethernet { adapter_number } .addresstype " : " generated " ,
f " ethernet { adapter_number } .generatedaddressoffset " : " 0 " ,
f " ethernet { adapter_number } .virtualdev " : vmware_adapter_type ,
}
2015-05-22 06:48:59 +03:00
self . _vmx_pairs . update ( ethernet_adapter )
2021-04-13 12:07:58 +03:00
connection_type = f " ethernet { adapter_number } .connectiontype "
2021-04-13 12:16:50 +03:00
if (
not self . _use_any_adapter
and connection_type in self . _vmx_pairs
and self . _vmx_pairs [ connection_type ] in ( " nat " , " bridged " , " hostonly " )
) :
2015-05-22 06:48:59 +03:00
continue
2015-09-05 23:38:11 +03:00
2021-04-13 12:07:58 +03:00
self . _vmx_pairs [ f " ethernet { adapter_number } .connectiontype " ] = " custom "
2018-04-17 06:47:25 +03:00
2016-06-01 04:16:55 +03:00
# make sure we have a vmnet per adapter if we use uBridge
allocate_vmnet = False
2015-09-05 23:38:11 +03:00
2016-06-01 04:16:55 +03:00
# first check if a vmnet is already assigned to the adapter
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2016-06-01 04:16:55 +03:00
if vnet in self . _vmx_pairs :
vmnet = os . path . basename ( self . _vmx_pairs [ vnet ] )
if self . manager . is_managed_vmnet ( vmnet ) or vmnet in ( " vmnet0 " , " vmnet1 " , " vmnet8 " ) :
2018-04-17 06:47:25 +03:00
# vmnet already managed or a special vmnet, try to allocate a new one
2015-09-05 23:38:11 +03:00
allocate_vmnet = True
2015-09-13 23:52:25 +03:00
else :
2016-06-01 04:16:55 +03:00
# otherwise allocate a new one
allocate_vmnet = True
if allocate_vmnet :
try :
vmnet = self . manager . allocate_vmnet ( )
2017-07-18 19:04:03 +03:00
except BaseException :
2016-06-01 04:16:55 +03:00
# clear everything up in case of error (e.g. no enough vmnets)
self . _vmnets . clear ( )
raise
2018-04-17 06:47:25 +03:00
# mark the vmnet as managed by us
2016-06-01 04:16:55 +03:00
if vmnet not in self . _vmnets :
self . _vmnets . append ( vmnet )
2021-04-13 12:07:58 +03:00
self . _vmx_pairs [ f " ethernet { adapter_number } .vnet " ] = vmnet
2015-05-22 06:48:59 +03:00
# disable remaining network adapters
for adapter_number in range ( self . _adapters , self . _maximum_adapters ) :
2021-04-13 12:07:58 +03:00
if self . _get_vmx_setting ( f " ethernet { adapter_number } .present " , " TRUE " ) :
log . debug ( f " disabling remaining adapter { adapter_number } " )
self . _vmx_pairs [ f " ethernet { adapter_number } .startconnected " ] = " FALSE "
2015-05-21 04:05:26 +03:00
2017-07-18 19:04:03 +03:00
def _get_vnet ( self , adapter_number ) :
"""
Return the vnet will use in ubridge
"""
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2017-07-18 19:04:03 +03:00
if vnet not in self . _vmx_pairs :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " vnet { vnet } not in VMX file " )
2017-07-18 19:04:03 +03:00
return vnet
2018-10-15 13:05:49 +03:00
async def _add_ubridge_connection ( self , nio , adapter_number ) :
2015-07-20 07:55:10 +03:00
"""
Creates a connection in uBridge .
2015-05-21 04:05:26 +03:00
2015-07-20 07:55:10 +03:00
: param nio : NIO instance
: param adapter_number : adapter number
2015-05-21 04:05:26 +03:00
"""
2015-07-20 07:55:10 +03:00
2017-07-18 19:04:03 +03:00
vnet = self . _get_vnet ( adapter_number )
2021-04-13 12:07:58 +03:00
await self . _ubridge_send ( f " bridge create { vnet } " )
2015-07-20 07:55:10 +03:00
vmnet_interface = os . path . basename ( self . _vmx_pairs [ vnet ] )
2016-03-15 02:27:51 +02:00
2016-11-13 11:28:14 +02:00
if sys . platform . startswith ( " darwin " ) :
2021-06-08 05:26:33 +03:00
if parse_version ( platform . mac_ver ( ) [ 0 ] ) > = parse_version ( " 11.0.0 " ) :
# a bridge interface (bridge100, bridge101 etc.) is used instead of a vmnet interface
# on macOS >= 11.0 (Big Sur)
vmnet_interface = self . manager . find_bridge_interface ( vmnet_interface )
if not vmnet_interface :
2021-06-12 08:06:32 +03:00
raise VMwareError ( f " Could not find bridge interface linked with { vmnet_interface } " )
2021-06-08 05:26:33 +03:00
block_host_traffic = self . manager . config . get_section_config ( " VMware " ) . getboolean ( " block_host_traffic " , False )
await self . _add_ubridge_ethernet_connection ( vnet , vmnet_interface , block_host_traffic )
else :
# special case on macOS, we cannot bind VMnet interfaces using the libpcap
await self . _ubridge_send ( ' bridge add_nio_fusion_vmnet {name} " {interface} " ' . format ( name = vnet , interface = vmnet_interface ) )
2015-07-20 07:55:10 +03:00
else :
2021-04-12 10:32:23 +03:00
block_host_traffic = self . manager . config . VMware . block_host_traffic
2018-10-15 13:05:49 +03:00
await self . _add_ubridge_ethernet_connection ( vnet , vmnet_interface , block_host_traffic )
2015-07-20 07:55:10 +03:00
if isinstance ( nio , NIOUDP ) :
2021-04-13 12:16:50 +03:00
await self . _ubridge_send (
" bridge add_nio_udp {name} {lport} {rhost} {rport} " . format (
name = vnet , lport = nio . lport , rhost = nio . rhost , rport = nio . rport
)
)
2015-07-20 07:55:10 +03:00
if nio . capturing :
2021-04-13 12:07:58 +03:00
await self . _ubridge_send ( f ' bridge start_capture { vnet } " { nio . pcap_output_file } " ' )
2015-07-20 07:55:10 +03:00
2021-04-13 12:16:50 +03:00
await self . _ubridge_send ( f " bridge start { vnet } " )
2018-10-15 13:05:49 +03:00
await self . _ubridge_apply_filters ( vnet , nio . filters )
2017-07-18 19:04:03 +03:00
2018-10-15 13:05:49 +03:00
async def _update_ubridge_connection ( self , adapter_number , nio ) :
2017-07-18 19:04:03 +03:00
"""
Update a connection in uBridge .
: param nio : NIO instance
: param adapter_number : adapter number
"""
try :
bridge_name = self . _get_vnet ( adapter_number )
except VMwareError :
return # vnet not yet available
2018-10-15 13:05:49 +03:00
await self . _ubridge_apply_filters ( bridge_name , nio . filters )
2016-03-15 02:27:51 +02:00
2018-10-15 13:05:49 +03:00
async def _delete_ubridge_connection ( self , adapter_number ) :
2015-05-21 04:05:26 +03:00
"""
2015-07-20 07:55:10 +03:00
Deletes a connection in uBridge .
2015-05-15 05:11:57 +03:00
2015-07-20 07:55:10 +03:00
: param adapter_number : adapter number
"""
2015-05-21 04:05:26 +03:00
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2015-07-20 07:55:10 +03:00
if vnet not in self . _vmx_pairs :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " vnet { vnet } not in VMX file " )
await self . _ubridge_send ( f " bridge delete { vnet } " )
2015-05-21 04:05:26 +03:00
2018-10-15 13:05:49 +03:00
async def _start_ubridge_capture ( self , adapter_number , output_file ) :
2015-09-13 18:40:09 +03:00
"""
Start a packet capture in uBridge .
: param adapter_number : adapter number
: param output_file : PCAP destination file for the capture
"""
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2015-09-13 18:40:09 +03:00
if vnet not in self . _vmx_pairs :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " vnet { vnet } not in VMX file " )
2016-01-26 23:45:55 +02:00
if not self . _ubridge_hypervisor :
raise VMwareError ( " Cannot start the packet capture: uBridge is not running " )
2021-04-13 12:16:50 +03:00
await self . _ubridge_send (
' bridge start_capture {name} " {output_file} " ' . format ( name = vnet , output_file = output_file )
)
2015-09-13 18:40:09 +03:00
2018-10-15 13:05:49 +03:00
async def _stop_ubridge_capture ( self , adapter_number ) :
2015-09-13 18:40:09 +03:00
"""
Stop a packet capture in uBridge .
: param adapter_number : adapter number
"""
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2015-09-13 18:40:09 +03:00
if vnet not in self . _vmx_pairs :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " vnet { vnet } not in VMX file " )
2016-01-26 23:45:55 +02:00
if not self . _ubridge_hypervisor :
raise VMwareError ( " Cannot stop the packet capture: uBridge is not running " )
2021-04-13 12:07:58 +03:00
await self . _ubridge_send ( f " bridge stop_capture { vnet } " )
2015-09-13 18:40:09 +03:00
2015-07-27 04:21:30 +03:00
def check_hw_virtualization ( self ) :
"""
Returns either hardware virtualization is activated or not .
: returns : boolean
"""
2015-09-05 23:38:11 +03:00
self . _read_vmx_file ( )
2015-07-27 04:21:30 +03:00
if self . _get_vmx_setting ( " vhv.enable " , " TRUE " ) :
return True
return False
2018-10-15 13:05:49 +03:00
async def start ( self ) :
2015-05-01 04:05:37 +03:00
"""
Starts this VMware VM .
"""
2016-11-17 11:38:29 +02:00
if self . status == " started " :
return
2021-04-13 12:16:50 +03:00
if await self . is_running ( ) :
2015-10-12 01:41:55 +03:00
raise VMwareError ( " The VM is already running in VMware " )
2015-05-26 00:49:28 +03:00
2015-05-21 04:05:26 +03:00
ubridge_path = self . ubridge_path
if not ubridge_path or not os . path . isfile ( ubridge_path ) :
raise VMwareError ( " ubridge is necessary to start a VMware VM " )
2018-11-19 19:22:16 +02:00
await self . _start_ubridge ( require_privileged_access = True )
2015-09-05 23:38:11 +03:00
self . _read_vmx_file ( )
2015-10-13 00:57:37 +03:00
# check if there is enough RAM to run
if " memsize " in self . _vmx_pairs :
self . check_available_ram ( int ( self . _vmx_pairs [ " memsize " ] ) )
2015-05-15 05:11:57 +03:00
self . _set_network_options ( )
2015-05-28 06:06:18 +03:00
self . _set_serial_console ( )
2015-09-05 23:38:11 +03:00
self . _write_vmx_file ( )
2015-05-21 04:05:26 +03:00
2015-05-01 04:05:37 +03:00
if self . _headless :
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " start " , " nogui " )
2015-05-01 04:05:37 +03:00
else :
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " start " )
2015-05-28 06:06:18 +03:00
2016-03-23 18:54:45 +02:00
try :
2016-06-01 04:16:55 +03:00
if self . _ubridge_hypervisor :
2016-03-23 18:54:45 +02:00
for adapter_number in range ( 0 , self . _adapters ) :
nio = self . _ethernet_adapters [ adapter_number ] . get_nio ( 0 )
if nio :
2018-10-15 13:05:49 +03:00
await self . _add_ubridge_connection ( nio , adapter_number )
2015-07-20 07:55:10 +03:00
2018-10-15 13:05:49 +03:00
await self . _start_console ( )
2016-03-23 18:54:45 +02:00
except VMwareError :
2018-10-15 13:05:49 +03:00
await self . stop ( )
2016-03-23 18:54:45 +02:00
raise
2015-05-28 06:06:18 +03:00
2015-07-22 07:58:28 +03:00
if self . _get_vmx_setting ( " vhv.enable " , " TRUE " ) :
self . _hw_virtualization = True
2015-05-28 06:06:18 +03:00
self . _started = True
2016-05-14 05:41:58 +03:00
self . status = " started "
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] started " )
2015-05-01 04:05:37 +03:00
2018-10-15 13:05:49 +03:00
async def stop ( self ) :
2015-05-01 04:05:37 +03:00
"""
Stops this VMware VM .
"""
2015-07-22 07:58:28 +03:00
self . _hw_virtualization = False
2018-10-15 13:05:49 +03:00
await self . _stop_remote_console ( )
await self . _stop_ubridge ( )
2015-05-21 04:05:26 +03:00
2015-05-22 06:48:59 +03:00
try :
2021-04-13 12:16:50 +03:00
if await self . is_running ( ) :
2018-03-30 17:18:44 +03:00
if self . on_close == " save_vm_state " :
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " suspend " )
2018-03-30 17:18:44 +03:00
elif self . on_close == " shutdown_signal " :
2016-03-19 20:08:44 +02:00
# use ACPI to shutdown the VM
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " stop " , " soft " )
2016-03-19 20:08:44 +02:00
else :
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " stop " )
2015-05-22 06:48:59 +03:00
finally :
2015-05-28 06:06:18 +03:00
self . _started = False
2016-05-14 05:41:58 +03:00
self . status = " stopped "
2015-05-22 06:48:59 +03:00
2015-09-05 23:38:11 +03:00
self . _read_vmx_file ( )
2016-06-01 04:16:55 +03:00
self . _vmnets . clear ( )
# remove the adapters managed by GNS3
for adapter_number in range ( 0 , self . _adapters ) :
2021-04-13 12:07:58 +03:00
vnet = f " ethernet { adapter_number } .vnet "
2021-04-13 12:16:50 +03:00
if (
self . _get_vmx_setting ( vnet )
or self . _get_vmx_setting ( f " ethernet { adapter_number } .connectiontype " ) is None
) :
2016-06-01 04:16:55 +03:00
if vnet in self . _vmx_pairs :
vmnet = os . path . basename ( self . _vmx_pairs [ vnet ] )
if not self . manager . is_managed_vmnet ( vmnet ) :
continue
2021-04-13 12:07:58 +03:00
log . debug ( f " removing adapter { adapter_number } " )
2016-06-01 04:16:55 +03:00
self . _vmx_pairs [ vnet ] = " vmnet1 "
2021-04-13 12:07:58 +03:00
self . _vmx_pairs [ f " ethernet { adapter_number } .connectiontype " ] = " custom "
2015-05-22 06:48:59 +03:00
# re-enable any remaining network adapters
for adapter_number in range ( self . _adapters , self . _maximum_adapters ) :
2021-04-13 12:07:58 +03:00
if self . _get_vmx_setting ( f " ethernet { adapter_number } .present " , " TRUE " ) :
log . debug ( f " enabling remaining adapter { adapter_number } " )
self . _vmx_pairs [ f " ethernet { adapter_number } .startconnected " ] = " TRUE "
2015-09-05 23:38:11 +03:00
self . _write_vmx_file ( )
2015-05-22 06:48:59 +03:00
2018-10-15 13:05:49 +03:00
await super ( ) . stop ( )
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] stopped " )
2015-05-01 04:05:37 +03:00
2018-10-15 13:05:49 +03:00
async def suspend ( self ) :
2015-05-01 04:05:37 +03:00
"""
Suspends this VMware VM .
"""
2015-05-16 04:09:48 +03:00
if self . manager . host_type != " ws " :
raise VMwareError ( " Pausing a VM is only supported by VMware Workstation " )
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " pause " )
2016-05-14 05:41:58 +03:00
self . status = " suspended "
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] paused " )
2015-05-01 04:05:37 +03:00
2018-10-15 13:05:49 +03:00
async def resume ( self ) :
2015-05-01 04:05:37 +03:00
"""
Resumes this VMware VM .
"""
2015-05-16 04:09:48 +03:00
if self . manager . host_type != " ws " :
raise VMwareError ( " Unpausing a VM is only supported by VMware Workstation " )
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " unpause " )
2016-05-14 05:41:58 +03:00
self . status = " started "
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] resumed " )
2015-05-01 04:05:37 +03:00
2018-10-15 13:05:49 +03:00
async def reload ( self ) :
2015-05-01 04:05:37 +03:00
"""
Reloads this VMware VM .
"""
2018-10-15 13:05:49 +03:00
await self . _control_vm ( " reset " )
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] reloaded " )
2015-05-01 04:05:37 +03:00
2018-10-15 13:05:49 +03:00
async def close ( self ) :
2015-05-01 04:05:37 +03:00
"""
2015-09-05 23:38:11 +03:00
Closes this VMware VM .
2015-05-01 04:05:37 +03:00
"""
2018-10-15 13:05:49 +03:00
if not ( await super ( ) . close ( ) ) :
2016-02-29 11:38:30 +02:00
return False
2015-05-01 04:05:37 +03:00
2015-05-21 04:05:26 +03:00
for adapter in self . _ethernet_adapters . values ( ) :
if adapter is not None :
for nio in adapter . ports . values ( ) :
if nio and isinstance ( nio , NIOUDP ) :
self . manager . port_manager . release_udp_port ( nio . lport , self . _project )
2015-05-02 03:47:46 +03:00
try :
2018-03-30 17:18:44 +03:00
self . on_close = " power_off "
2018-10-15 13:05:49 +03:00
await self . stop ( )
2015-05-02 03:47:46 +03:00
except VMwareError :
pass
2015-05-01 04:05:37 +03:00
2016-10-24 22:39:35 +03:00
if self . linked_clone :
2018-10-15 13:05:49 +03:00
await self . manager . remove_from_vmware_inventory ( self . _vmx_path )
2015-05-31 05:26:38 +03:00
2015-05-01 04:05:37 +03:00
@property
def headless ( self ) :
"""
Returns either the VM will start in headless mode
: returns : boolean
"""
return self . _headless
@headless.setter
def headless ( self , headless ) :
"""
Sets either the VM will start in headless mode
: param headless : boolean
"""
if headless :
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] has enabled the headless mode " )
2015-05-01 04:05:37 +03:00
else :
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] has disabled the headless mode " )
2015-05-01 04:05:37 +03:00
self . _headless = headless
2015-06-19 00:02:31 +03:00
@property
2018-03-30 17:18:44 +03:00
def on_close ( self ) :
2015-06-19 00:02:31 +03:00
"""
2018-03-30 17:18:44 +03:00
Returns the action to execute when the VM is stopped / closed
2015-06-19 00:02:31 +03:00
2018-03-30 17:18:44 +03:00
: returns : string
2015-06-19 00:02:31 +03:00
"""
2018-03-30 17:18:44 +03:00
return self . _on_close
2015-06-19 00:02:31 +03:00
2018-03-30 17:18:44 +03:00
@on_close.setter
def on_close ( self , on_close ) :
2015-06-19 00:02:31 +03:00
"""
2018-03-30 17:18:44 +03:00
Sets the action to execute when the VM is stopped / closed
2015-06-19 00:02:31 +03:00
2018-03-30 17:18:44 +03:00
: param on_close : string
2015-06-19 00:02:31 +03:00
"""
2021-04-13 12:07:58 +03:00
log . info ( f ' VMware VM " { self . _name } " [ { self . _id } ] set the close action to " { on_close } " ' )
2018-03-30 17:18:44 +03:00
self . _on_close = on_close
2015-06-19 00:02:31 +03:00
2015-05-01 04:05:37 +03:00
@property
def vmx_path ( self ) :
"""
Returns the path to the vmx file .
: returns : VMware vmx file
"""
return self . _vmx_path
@vmx_path.setter
def vmx_path ( self , vmx_path ) :
"""
Sets the path to the vmx file .
: param vmx_path : VMware vmx file
"""
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] has set the vmx file path to ' { vmx_path } ' " )
2015-05-01 04:05:37 +03:00
self . _vmx_path = vmx_path
2015-05-15 05:11:57 +03:00
@property
def adapters ( self ) :
"""
Returns the number of adapters configured for this VMware VM .
: returns : number of adapters
"""
return self . _adapters
@adapters.setter
def adapters ( self , adapters ) :
"""
Sets the number of Ethernet adapters for this VMware VM instance .
: param adapters : number of adapters
"""
2015-07-20 07:55:10 +03:00
# VMware VMs are limited to 10 adapters
2015-05-15 05:11:57 +03:00
if adapters > 10 :
raise VMwareError ( " Number of adapters above the maximum supported of 10 " )
self . _ethernet_adapters . clear ( )
for adapter_number in range ( 0 , adapters ) :
self . _ethernet_adapters [ adapter_number ] = EthernetAdapter ( )
self . _adapters = len ( self . _ethernet_adapters )
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ] has changed the number of Ethernet adapters to {adapters} " . format (
name = self . name , id = self . id , adapters = adapters
)
)
2015-05-15 05:11:57 +03:00
@property
def adapter_type ( self ) :
"""
Returns the adapter type for this VMware VM instance .
: returns : adapter type ( string )
"""
return self . _adapter_type
@adapter_type.setter
def adapter_type ( self , adapter_type ) :
"""
Sets the adapter type for this VMware VM instance .
: param adapter_type : adapter type ( string )
"""
self . _adapter_type = adapter_type
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ]: adapter type changed to {adapter_type} " . format (
name = self . name , id = self . id , adapter_type = adapter_type
)
)
2015-05-16 04:09:48 +03:00
2015-05-22 06:48:59 +03:00
@property
def use_any_adapter ( self ) :
"""
Returns either GNS3 can use any VMware adapter on this instance .
: returns : boolean
"""
return self . _use_any_adapter
@use_any_adapter.setter
def use_any_adapter ( self , use_any_adapter ) :
"""
Allows GNS3 to use any VMware adapter on this instance .
: param use_any_adapter : boolean
"""
if use_any_adapter :
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] is allowed to use any adapter " )
2015-05-22 06:48:59 +03:00
else :
2021-04-13 12:07:58 +03:00
log . info ( f " VMware VM ' { self . name } ' [ { self . id } ] is not allowed to use any adapter " )
2015-05-22 06:48:59 +03:00
self . _use_any_adapter = use_any_adapter
2018-10-15 13:05:49 +03:00
async def adapter_add_nio_binding ( self , adapter_number , nio ) :
2015-05-16 04:09:48 +03:00
"""
Adds an adapter NIO binding .
: param adapter_number : adapter number
: param nio : NIO instance to add to the slot / port
"""
try :
adapter = self . _ethernet_adapters [ adapter_number ]
except IndexError :
2021-04-13 12:16:50 +03:00
raise VMwareError (
" Adapter {adapter_number} doesn ' t exist on VMware VM ' {name} ' " . format (
name = self . name , adapter_number = adapter_number
)
)
2015-05-16 04:09:48 +03:00
2015-09-05 23:38:11 +03:00
self . _read_vmx_file ( )
2016-06-01 04:06:48 +03:00
# check if trying to connect to a nat, bridged or host-only adapter
2021-04-13 12:07:58 +03:00
if self . _get_vmx_setting ( f " ethernet { adapter_number } .present " , " TRUE " ) :
2016-06-01 04:06:48 +03:00
# check for the connection type
2021-04-13 12:07:58 +03:00
connection_type = f " ethernet { adapter_number } .connectiontype "
2021-04-13 12:16:50 +03:00
if (
not self . _use_any_adapter
and connection_type in self . _vmx_pairs
and self . _vmx_pairs [ connection_type ] in ( " nat " , " bridged " , " hostonly " )
) :
if await self . is_running ( ) :
raise VMwareError (
" Attachment ' {attachment} ' is configured on network adapter {adapter_number} . "
" Please stop VMware VM ' {name} ' to link to this adapter and allow GNS3 to change the attachment type. " . format (
attachment = self . _vmx_pairs [ connection_type ] , adapter_number = adapter_number , name = self . name
)
)
2018-04-17 06:47:25 +03:00
else :
2021-04-13 12:16:50 +03:00
raise VMwareError (
" Attachment ' {attachment} ' is already configured on network adapter {adapter_number} . "
" Please remove it or allow VMware VM ' {name} ' to use any adapter. " . format (
attachment = self . _vmx_pairs [ connection_type ] , adapter_number = adapter_number , name = self . name
)
)
2016-06-01 04:06:48 +03:00
adapter . add_nio ( 0 , nio )
2016-06-01 04:16:55 +03:00
if self . _started and self . _ubridge_hypervisor :
2018-10-15 13:05:49 +03:00
await self . _add_ubridge_connection ( nio , adapter_number )
2015-07-20 07:55:10 +03:00
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ]: {nio} added to adapter {adapter_number} " . format (
name = self . name , id = self . id , nio = nio , adapter_number = adapter_number
)
)
2015-05-16 04:09:48 +03:00
2018-10-15 13:05:49 +03:00
async def adapter_update_nio_binding ( self , adapter_number , nio ) :
2017-07-18 19:04:03 +03:00
"""
2018-10-27 10:47:17 +03:00
Updates an adapter NIO binding .
2017-07-18 19:04:03 +03:00
: param adapter_number : adapter number
2018-10-27 10:47:17 +03:00
: param nio : NIO instance to update on the adapter
2017-07-18 19:04:03 +03:00
"""
if self . _ubridge_hypervisor :
try :
2018-10-15 13:05:49 +03:00
await self . _update_ubridge_connection ( adapter_number , nio )
2017-07-18 19:04:03 +03:00
except IndexError :
2021-04-13 12:16:50 +03:00
raise VMwareError (
' Adapter {adapter_number} does not exist on VMware VM " {name} " ' . format (
name = self . _name , adapter_number = adapter_number
)
)
2017-07-18 19:04:03 +03:00
2018-10-15 13:05:49 +03:00
async def adapter_remove_nio_binding ( self , adapter_number ) :
2015-05-16 04:09:48 +03:00
"""
Removes an adapter NIO binding .
: param adapter_number : adapter number
: returns : NIO instance
"""
try :
adapter = self . _ethernet_adapters [ adapter_number ]
except IndexError :
2021-04-13 12:16:50 +03:00
raise VMwareError (
" Adapter {adapter_number} doesn ' t exist on VMware VM ' {name} ' " . format (
name = self . name , adapter_number = adapter_number
)
)
2015-05-16 04:09:48 +03:00
2019-04-01 15:47:31 +03:00
await self . stop_capture ( adapter_number )
2015-05-16 04:09:48 +03:00
nio = adapter . get_nio ( 0 )
if isinstance ( nio , NIOUDP ) :
self . manager . port_manager . release_udp_port ( nio . lport , self . _project )
adapter . remove_nio ( 0 )
2016-06-01 04:16:55 +03:00
if self . _started and self . _ubridge_hypervisor :
2018-10-15 13:05:49 +03:00
await self . _delete_ubridge_connection ( adapter_number )
2015-05-16 04:09:48 +03:00
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ]: {nio} removed from adapter {adapter_number} " . format (
name = self . name , id = self . id , nio = nio , adapter_number = adapter_number
)
)
2015-06-18 02:36:52 +03:00
2015-05-16 04:09:48 +03:00
return nio
2015-05-28 06:06:18 +03:00
2018-10-27 10:47:17 +03:00
def get_nio ( self , adapter_number ) :
"""
Gets an adapter NIO binding .
: param adapter_number : adapter number
: returns : NIO instance
"""
try :
adapter = self . ethernet_adapters [ adapter_number ]
except KeyError :
2021-04-13 12:16:50 +03:00
raise VMwareError (
" Adapter {adapter_number} doesn ' t exist on VMware VM ' {name} ' " . format (
name = self . name , adapter_number = adapter_number
)
)
2018-10-27 10:47:17 +03:00
nio = adapter . get_nio ( 0 )
if not nio :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " Adapter { adapter_number } is not connected " )
2018-10-27 10:47:17 +03:00
return nio
2015-05-28 06:06:18 +03:00
def _get_pipe_name ( self ) :
"""
Returns the pipe name to create a serial connection .
: returns : pipe path ( string )
"""
2022-01-19 13:58:36 +02:00
pipe_name = os . path . join ( tempfile . gettempdir ( ) , " gns3_vmware " , f " { self . id } " )
try :
os . makedirs ( os . path . dirname ( pipe_name ) , exist_ok = True )
except OSError as e :
raise VMwareError ( f " Could not create the VMware pipe directory: { e } " )
2015-05-28 06:06:18 +03:00
return pipe_name
def _set_serial_console ( self ) :
"""
Configures the first serial port to allow a serial console connection .
"""
pipe_name = self . _get_pipe_name ( )
2021-04-13 12:16:50 +03:00
serial_port = {
" serial0.present " : " TRUE " ,
" serial0.filetype " : " pipe " ,
" serial0.filename " : pipe_name ,
" serial0.pipe.endpoint " : " server " ,
" serial0.startconnected " : " TRUE " ,
}
2015-05-28 06:06:18 +03:00
self . _vmx_pairs . update ( serial_port )
2018-10-15 13:05:49 +03:00
async def _start_console ( self ) :
2015-05-28 06:06:18 +03:00
"""
Starts remote console support for this VM .
"""
2018-03-24 14:11:21 +03:00
if self . console and self . console_type == " telnet " :
2018-10-04 16:44:13 +03:00
pipe_name = self . _get_pipe_name ( )
try :
2018-10-15 13:05:49 +03:00
self . _remote_pipe = await asyncio_open_serial ( self . _get_pipe_name ( ) )
2018-10-04 16:44:13 +03:00
except OSError as e :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " Could not open serial pipe ' { pipe_name } ' : { e } " )
2021-04-13 12:16:50 +03:00
server = AsyncioTelnetServer ( reader = self . _remote_pipe , writer = self . _remote_pipe , binary = True , echo = True )
2018-04-18 12:08:42 +03:00
try :
2021-04-13 12:16:50 +03:00
self . _telnet_server = await asyncio . start_server (
server . run , self . _manager . port_manager . console_host , self . console
)
2018-04-18 12:08:42 +03:00
except OSError as e :
2021-04-13 12:16:50 +03:00
self . project . emit (
" log.warning " ,
{
" message " : f " Could not start Telnet server on socket { self . _manager . port_manager . console_host } : { self . console } : { e } "
} ,
)
2015-05-28 06:06:18 +03:00
2018-10-15 13:05:49 +03:00
async def _stop_remote_console ( self ) :
2015-05-28 06:06:18 +03:00
"""
Stops remote console support for this VM .
"""
2016-11-07 12:16:51 +02:00
if self . _telnet_server :
self . _telnet_server . close ( )
2018-10-15 13:05:49 +03:00
await self . _telnet_server . wait_closed ( )
2016-11-18 12:27:50 +02:00
self . _remote_pipe . close ( )
self . _telnet_server = None
2015-09-13 18:40:09 +03:00
2020-07-26 11:57:18 +03:00
async def reset_console ( self ) :
"""
Reset the console .
"""
await self . _stop_remote_console ( )
await self . _start_console ( )
2018-03-24 14:11:21 +03:00
@BaseNode.console_type.setter
def console_type ( self , new_console_type ) :
"""
Sets the console type for this VMware VM .
: param new_console_type : console type ( string )
"""
if self . _started and self . console_type != new_console_type :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f ' " { self . _name } " must be stopped to change the console type to { new_console_type } ' )
2018-03-24 14:11:21 +03:00
super ( VMwareVM , VMwareVM ) . console_type . __set__ ( self , new_console_type )
2018-10-15 13:05:49 +03:00
async def start_capture ( self , adapter_number , output_file ) :
2015-09-13 18:40:09 +03:00
"""
Starts a packet capture .
: param adapter_number : adapter number
: param output_file : PCAP destination file for the capture
"""
2018-10-27 10:47:17 +03:00
nio = self . get_nio ( adapter_number )
2015-09-13 18:40:09 +03:00
if nio . capturing :
2021-04-13 12:07:58 +03:00
raise VMwareError ( f " Packet capture is already activated on adapter { adapter_number } " )
2015-09-13 18:40:09 +03:00
2019-04-01 16:58:18 +03:00
nio . start_packet_capture ( output_file )
2015-09-13 18:40:09 +03:00
if self . _started :
2018-10-15 13:05:49 +03:00
await self . _start_ubridge_capture ( adapter_number , output_file )
2015-09-13 18:40:09 +03:00
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ]: starting packet capture on adapter {adapter_number} " . format (
name = self . name , id = self . id , adapter_number = adapter_number
)
)
2015-09-13 18:40:09 +03:00
2018-10-15 13:05:49 +03:00
async def stop_capture ( self , adapter_number ) :
2015-09-13 18:40:09 +03:00
"""
Stops a packet capture .
: param adapter_number : adapter number
"""
2018-10-27 10:47:17 +03:00
nio = self . get_nio ( adapter_number )
2019-04-01 15:47:31 +03:00
if not nio . capturing :
return
2015-09-13 18:40:09 +03:00
2019-04-01 16:58:18 +03:00
nio . stop_packet_capture ( )
2015-09-13 18:40:09 +03:00
if self . _started :
2018-10-15 13:05:49 +03:00
await self . _stop_ubridge_capture ( adapter_number )
2015-09-13 18:40:09 +03:00
2021-04-13 12:16:50 +03:00
log . info (
" VMware VM ' {name} ' [ {id} ]: stopping packet capture on adapter {adapter_number} " . format (
name = self . name , id = self . id , adapter_number = adapter_number
)
)