Compare commits

...

46 Commits
v1.2 ... v1.2.1

Author SHA1 Message Date
Jeremy
197db35c80 Disable cloud. 2014-12-04 12:50:50 -07:00
Jeremy
8771e1ace7 Bump version to 1.2.1 2014-12-04 12:49:40 -07:00
Jeremy
e6e1275ad2 Fixes missing options. 2014-12-04 12:35:36 -07:00
Jeremy
417dc0859b Use bundled Qemu on Windows and OSX by default and checks if remote server are registered. 2014-12-04 12:25:49 -07:00
Jeremy
806e1f29bb Bump version to 1.2.1.dev2 2014-12-02 18:52:28 -07:00
Jeremy
9724f5769d Support for CPU throttling and process priority for Qemu. 2014-12-02 18:12:37 -07:00
Jeremy
5a0c8914c4 Rename IOSv symbols + improve support for ASA on Windows. 2014-12-02 14:49:04 -07:00
Jeremy
c2e0a30da8 Merge pull request #157. 2014-12-02 12:37:21 -07:00
Jeremy
45ae4f20a0 Merge remote-tracking branch 'origin/master' 2014-12-02 12:34:06 -07:00
Jeremy
398826d7ef IOSv and IOSv-L2 integration. 2014-12-02 12:33:49 -07:00
grossmj
14e5f3bf74 Merge remote-tracking branch 'origin/master' 2014-12-02 11:51:32 -07:00
grossmj
57b1cbf41b Fixes SecureCRT command line. 2014-12-02 11:51:17 -07:00
Julien Duponchelle
51a0d88b9b Revert "Add start instructions for MacOSX"
This reverts commit 16d4d7d1ea.
2014-12-01 22:57:17 +01:00
Julien Duponchelle
16d4d7d1ea Add start instructions for MacOSX 2014-12-01 21:26:16 +01:00
grossmj
023c5fb99a Install scripts for Mac OS X. 2014-11-30 19:37:15 -07:00
grossmj
329ed371f9 Adds default path for VBoxManage on Mac OS X. 2014-11-29 16:42:57 -07:00
grossmj
0577bfbde3 Support for older Qemu versions like the 0.11.0 on Windows. 2014-11-29 14:11:51 -07:00
grossmj
3ce5c35143 Use PROGRAMFILES and PROGRAMFILES(X86) environment variables for console command lines on Windows. 2014-11-28 17:57:54 -07:00
grossmj
6b2da1ec97 Fixes port sorting issues. 2014-11-27 11:34:01 -07:00
Jeremy Grossmann
6aa1b515c7 Merge pull request #154 from dlintott/master
Validate the Idle-PC value and display an error if invalid
2014-11-25 13:55:16 -07:00
Daniel Lintott
5d64ec1c8f Validate the Idle-PC value and display an error if invalid 2014-11-25 20:34:43 +00:00
Jeremy
e1b81fb931 Fixes PyQt module usage. 2014-11-25 11:54:35 -07:00
Jeremy Grossmann
c91752598c Merge pull request #153 from planctechnologies/dev
Remove image access server references
2014-11-25 11:51:07 -07:00
grossmj
708515925f Do not put space in VirtualBox linked VM names. 2014-11-24 20:11:34 -07:00
Jeremy
a61745f868 Fixes C7200 IO cards insert/remove issues and makes C7200-IO-FE the default. 2014-11-24 17:02:00 -07:00
Jeremy
2ca7af34df Load project from command line. Fixes #151. 2014-11-24 14:21:51 -07:00
jseutter
bd7e6f4e3e Merge pull request #47 from planctechnologies/gns-136
Gns 136 gui won't exit when telnet session open to device
2014-11-24 10:49:51 -07:00
jseutter
32e86d461e Merge pull request #46 from planctechnologies/gns-132
Gns 132 Remove IAS (Image Access Server) code
2014-11-24 10:23:37 -07:00
Massimiliano Pippi
66ea5ad979 close cloud server connections when gns3 exits 2014-11-24 12:47:56 +01:00
Massimiliano Pippi
ebfa80d444 return the list of cloud servers as a property 2014-11-24 12:47:06 +01:00
Massimiliano Pippi
4247cc819d removed references to the IAS server 2014-11-24 12:18:42 +01:00
Massimiliano Pippi
1f9f5bd734 hardcode Ubuntu image in cloud preferences 2014-11-24 12:11:36 +01:00
Jeremy
426d791eea Fixes #48, #152. 2014-11-23 19:26:37 -07:00
grossmj
30d99b812c Merge remote-tracking branch 'origin/master' 2014-11-23 19:04:35 -07:00
grossmj
981e55bc4d Use the Qt binding abstraction layer. 2014-11-23 19:04:11 -07:00
Jeremy
bab1090a25 Use SubprocessError to catch Subprocess exceptions. 2014-11-22 17:45:04 -07:00
Jeremy
84b5181fd8 Support for full screen mode (View -> Fullscreen). 2014-11-21 16:52:06 -07:00
Jeremy
222ebb58c0 Bump to version 1.2.1.dev1 and fixes vboxmanage lookup on Windows. 2014-11-20 19:01:00 -07:00
Jerry Seutter
f5ad3a6a2e Merge branch 'master' into dev 2014-11-18 16:21:39 -07:00
Jerry Seutter
422af60827 Enabling cloud functionality 2014-11-18 16:21:17 -07:00
Jerry Seutter
9127321540 Merge branch 'master' into dev 2014-11-18 16:18:16 -07:00
jseutter
dcae059480 Merge pull request #44 from planctechnologies/gns-130
Gns 130: QThreads missing a parent QObject
2014-11-17 09:24:53 -07:00
jseutter
6d6603e013 Merge pull request #45 from planctechnologies/gns-131
Fix bug where new instances would not build.
2014-11-17 09:24:35 -07:00
Massimiliano Pippi
90fe8078c3 fixed transitions for custom instance states, fixes gns-131 2014-11-17 16:47:56 +01:00
Massimiliano Pippi
367fb32114 instance QThreads passing a parent 2014-11-17 14:24:03 +01:00
Massimiliano Pippi
b2b82afd71 fixed super() call, propagate parent 2014-11-17 14:23:52 +01:00
47 changed files with 3531 additions and 712 deletions

View File

@@ -42,11 +42,9 @@ class RackspaceCtrl(BaseCloudCtrl):
""" Controller class for interacting with Rackspace API. """
def __init__(self, username, api_key, gns3_ias_url):
def __init__(self, username, api_key, *args, **kwargs):
super(RackspaceCtrl, self).__init__(username, api_key)
self.gns3_ias_url = gns3_ias_url
# set this up so it can be swapped out with a mock for testing
self.post_fn = requests.post
self.driver_cls = get_driver(Provider.RACKSPACE)
@@ -225,55 +223,6 @@ class RackspaceCtrl(BaseCloudCtrl):
self.region = region
return True
def _get_shared_images(self, username, region, gns3_version):
"""
Given a GNS3 version, ask gns3-ias to share compatible images
Response:
[{"created_at": "", "schema": "", "status": "", "member_id": "", "image_id": "", "updated_at": ""},]
or, if access was already asked
[{"image_id": "", "member_id": "", "status": "ALREADYREQUESTED"},]
"""
endpoint = self.gns3_ias_url+"/images/grant_access"
params = {
"user_id": username,
"user_region": region.upper(),
"gns3_version": gns3_version,
}
try:
response = requests.get(endpoint, params=params)
except requests.ConnectionError:
raise ApiError("Unable to connect to IAS")
status = response.status_code
if status == 200:
return response.json()
elif status == 404:
raise ItemNotFound()
else:
raise ApiError("IAS status code: %d" % status)
def list_images(self):
"""
Return a dictionary containing RackSpace server images
retrieved from gns3-ias server
"""
if not (self.tenant_id and self.region):
return {}
try:
shared_images = self._get_shared_images(self.tenant_id, self.region, __version__)
images = {}
for i in shared_images:
images[i['image_id']] = i['image_name']
return images
except ItemNotFound:
return {}
except ApiError as e:
log.error('Error while retrieving image list: %s' % e)
return {}
def get_image(self, image_id):
return self.driver.get_image(image_id)
@@ -290,12 +239,11 @@ def get_provider(cloud_settings):
username = cloud_settings['cloud_user_name']
apikey = cloud_settings['cloud_api_key']
region = cloud_settings['cloud_region']
ias_url = cloud_settings['gns3_ias_url']
except KeyError as e:
log.error("Unable to create cloud provider: {}".format(e))
return
provider = RackspaceCtrl(username, apikey, ias_url)
provider = RackspaceCtrl(username, apikey)
if not provider.authenticate():
log.error("Authentication failed for cloud provider")

View File

@@ -4,16 +4,14 @@ import json
from socket import error as socket_error
import logging
import os
import select
import tempfile
import time
import zipfile
from PyQt4.QtCore import QThread
from PyQt4.QtCore import pyqtSignal
from ..qt import QtCore
from .exceptions import KeyPairExists
from .rackspace_ctrl import RackspaceCtrl, get_provider
from .rackspace_ctrl import get_provider
from ..topology import Topology
from ..servers import Servers
@@ -54,15 +52,15 @@ def ssh_client(host, key_string):
client.close()
class ListInstancesThread(QThread):
class ListInstancesThread(QtCore.QThread):
"""
Helper class to retrieve data from the provider in a separate thread,
avoid freezing the gui
"""
instancesReady = pyqtSignal(object)
instancesReady = QtCore.pyqtSignal(object)
def __init__(self, parent, provider):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._provider = provider
def run(self):
@@ -74,14 +72,14 @@ class ListInstancesThread(QThread):
log.info('list_instances error: {}'.format(e))
class CreateInstanceThread(QThread):
class CreateInstanceThread(QtCore.QThread):
"""
Helper class to create instances in a separate thread
"""
instanceCreated = pyqtSignal(object, object)
instanceCreated = QtCore.pyqtSignal(object, object)
def __init__(self, parent, provider, name, flavor_id, image_id):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._provider = provider
self._name = name
self._flavor_id = flavor_id
@@ -104,14 +102,14 @@ class CreateInstanceThread(QThread):
self.instanceCreated.emit(i, k)
class DeleteInstanceThread(QThread):
class DeleteInstanceThread(QtCore.QThread):
"""
Helper class to remove an instance in a separate thread
"""
instanceDeleted = pyqtSignal(object)
instanceDeleted = QtCore.pyqtSignal(object)
def __init__(self, parent, provider, instance):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._provider = provider
self._instance = instance
@@ -120,12 +118,12 @@ class DeleteInstanceThread(QThread):
self.instanceDeleted.emit(self._instance)
class StartGNS3ServerThread(QThread):
class StartGNS3ServerThread(QtCore.QThread):
"""
Perform an SSH connection to the instances in a separate thread,
outside the GUI event loop, and start GNS3 server
"""
gns3server_started = pyqtSignal(str, str, str)
gns3server_started = QtCore.pyqtSignal(str, str, str)
# This is for testing without pushing to github
# commands = '''
@@ -170,7 +168,7 @@ killall python3 gns3server gns3dms
'''
def __init__(self, parent, host, private_key_string, server_id, username, api_key, region, dead_time):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._host = host
self._private_key_string = private_key_string
self._server_id = server_id
@@ -240,16 +238,16 @@ killall python3 gns3server gns3dms
self.gns3server_started.emit(str(self._server_id), str(self._host), str(response))
class WSConnectThread(QThread):
class WSConnectThread(QtCore.QThread):
"""
Establish a websocket connection with the remote gns3server
instance. Run outside the GUI event loop.
"""
established = pyqtSignal(str)
established = QtCore.pyqtSignal(str)
def __init__(self, parent, provider, server_id, host, port, ca_file,
auth_user, auth_password, ssh_pkey, instance_id):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._provider = provider
self._server_id = server_id
self._host = host
@@ -278,18 +276,18 @@ class WSConnectThread(QThread):
self.established.emit(self._server_id)
class UploadProjectThread(QThread):
class UploadProjectThread(QtCore.QThread):
"""
Zip and Upload project to the cloud
"""
# signals to update the progress dialog.
error = pyqtSignal(str, bool)
completed = pyqtSignal()
update = pyqtSignal(int)
error = QtCore.pyqtSignal(str, bool)
completed = QtCore.pyqtSignal()
update = QtCore.pyqtSignal(int)
def __init__(self, cloud_settings, project_path, images_path):
super().__init__()
def __init__(self, parent, cloud_settings, project_path, images_path):
super(QtCore.QThread, self).__init__(parent)
self.cloud_settings = cloud_settings
self.project_path = project_path
self.images_path = images_path
@@ -353,17 +351,17 @@ class UploadProjectThread(QThread):
self.quit()
class UploadFilesThread(QThread):
class UploadFilesThread(QtCore.QThread):
"""
Upload multiple files to cloud files
uploads - A list of 2-tuples of (local_src_path, remote_dst_path)
"""
completed = pyqtSignal()
completed = QtCore.pyqtSignal()
def __init__(self, parent, cloud_settings, uploads):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._cloud_settings = cloud_settings
self._uploads = uploads
@@ -376,18 +374,18 @@ class UploadFilesThread(QThread):
self.completed.emit()
class DownloadProjectThread(QThread):
class DownloadProjectThread(QtCore.QThread):
"""
Downloads project from cloud storage
"""
# signals to update the progress dialog.
error = pyqtSignal(str, bool)
completed = pyqtSignal()
update = pyqtSignal(int)
error = QtCore.pyqtSignal(str, bool)
completed = QtCore.pyqtSignal()
update = QtCore.pyqtSignal(int)
def __init__(self, cloud_project_file_name, project_dest_path, images_dest_path, cloud_settings):
super().__init__()
def __init__(self, parent, cloud_project_file_name, project_dest_path, images_dest_path, cloud_settings):
super(QtCore.QThread, self).__init__(parent)
self.project_name = cloud_project_file_name
self.project_dest_path = project_dest_path
self.images_dest_path = images_dest_path
@@ -433,18 +431,18 @@ class DownloadProjectThread(QThread):
self.quit()
class DeleteProjectThread(QThread):
class DeleteProjectThread(QtCore.QThread):
"""
Deletes project from cloud storage
"""
# signals to update the progress dialog.
error = pyqtSignal(str, bool)
completed = pyqtSignal()
update = pyqtSignal(int)
error = QtCore.pyqtSignal(str, bool)
completed = QtCore.pyqtSignal()
update = QtCore.pyqtSignal(int)
def __init__(self, project_file_name, cloud_settings):
super().__init__()
def __init__(self, parent, project_file_name, cloud_settings):
super(QtCore.QThread, self).__init__(parent)
self.project_file_name = project_file_name
self.cloud_settings = cloud_settings

View File

@@ -2,17 +2,8 @@
import ast
import logging
import os
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QIcon
from PyQt4.QtGui import QMenu
from PyQt4.QtGui import QAction
from PyQt4.QtGui import QInputDialog
from PyQt4.QtCore import QAbstractTableModel
from PyQt4.QtCore import QModelIndex
from PyQt4.QtCore import QTimer
from PyQt4.QtCore import pyqtSignal
from PyQt4.Qt import Qt
from .qt import QtCore, QtGui
from .cloud.utils import (ListInstancesThread, CreateInstanceThread, DeleteInstanceThread,
StartGNS3ServerThread, WSConnectThread)
from libcloud.compute.types import NodeState
@@ -31,12 +22,12 @@ class RunningInstanceState(NodeState):
"""
GNS3 states for running instances
"""
GNS3SERVER_STARTING = 10
GNS3SERVER_STARTED = 11
WS_CONNECTED = 12
GNS3SERVER_STARTING = -1
GNS3SERVER_STARTED = -2
WS_CONNECTED = -3
class InstanceTableModel(QAbstractTableModel):
class InstanceTableModel(QtCore.QAbstractTableModel):
"""
A custom table model storing data of cloud instances
"""
@@ -80,12 +71,12 @@ class InstanceTableModel(QAbstractTableModel):
instance = self._instances.get(self._ids[index.row()])
col = index.column()
if role == Qt.DecorationRole:
if role == QtCore.Qt.DecorationRole:
if col == 1:
# status
return QIcon(self._get_status_icon_path(instance))
return QtGui.QIcon(self._get_status_icon_path(instance))
elif role == Qt.DisplayRole:
elif role == QtCore.Qt.DisplayRole:
if col == 0:
# name
return instance.name
@@ -112,7 +103,7 @@ class InstanceTableModel(QAbstractTableModel):
return None
def headerData(self, section, orientation, role=None):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
try:
return self._header_data[section]
except IndexError:
@@ -120,9 +111,9 @@ class InstanceTableModel(QAbstractTableModel):
return super(InstanceTableModel, self).headerData(section, orientation, role)
def addInstance(self, instance):
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
if not len(self._instances):
self.beginInsertColumns(QModelIndex(), 0, self._width-1)
self.beginInsertColumns(QtCore.QModelIndex(), 0, self._width-1)
self.endInsertColumns()
self._ids.append(instance.id)
self._instances[instance.id] = instance
@@ -143,7 +134,7 @@ class InstanceTableModel(QAbstractTableModel):
def removeInstanceById(self, instance_id):
try:
index = self._ids.index(instance_id)
self.beginRemoveRows(QModelIndex(), index, index)
self.beginRemoveRows(QtCore.QModelIndex(), index, index)
del self._instances[instance_id]
del self._ids[index]
self.endRemoveRows()
@@ -169,7 +160,7 @@ class InstanceTableModel(QAbstractTableModel):
return self._instances.get(instance_id, None)
class CloudInspectorView(QWidget, Ui_CloudInspectorView):
class CloudInspectorView(QtGui.QWidget, Ui_CloudInspectorView):
"""
Table view showing data coming from InstanceTableModel
@@ -177,10 +168,10 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
instanceSelected(int) Emitted when users click and select an instance on the inspector.
Param int is the ID of the instance
"""
instanceSelected = pyqtSignal(str)
instanceSelected = QtCore.pyqtSignal(str)
def __init__(self, parent):
super(QWidget, self).__init__(parent)
super(QtGui.QWidget, self).__init__(parent)
self.setupUi(self)
self._provider = None
@@ -191,14 +182,14 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
self._model = InstanceTableModel() # shortcut for self.uiInstancesTableView.model()
self.uiInstancesTableView.setModel(self._model)
self.uiInstancesTableView.verticalHeader().hide()
self.uiInstancesTableView.setContextMenuPolicy(Qt.CustomContextMenu)
self.uiInstancesTableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.uiInstancesTableView.horizontalHeader().setStretchLastSection(True)
# connections
self.uiInstancesTableView.customContextMenuRequested.connect(self._contextMenu)
self.uiInstancesTableView.clicked.connect(self._rowChanged)
self.uiCreateInstanceButton.clicked.connect(self._create_new_instance)
self._pollingTimer = QTimer(self)
self._pollingTimer = QtCore.QTimer(self)
self._pollingTimer.timeout.connect(self._polling_slot)
# map flavor ids to combobox indexes
@@ -253,10 +244,10 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
def _contextMenu(self, pos):
# create actions
delete_action = QAction("Delete", self)
delete_action = QtGui.QAction("Delete", self)
delete_action.triggered.connect(self._deleteSelectedInstance)
# create context menu and add actions
menu = QMenu(self.uiInstancesTableView)
menu = QtGui.QMenu(self.uiInstancesTableView)
menu.addAction(delete_action)
# show the menu
menu.popup(self.uiInstancesTableView.viewport().mapToGlobal(pos))
@@ -382,9 +373,6 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
# filter instances to only those in the current project
project_instances = [i for i in instances if i.id in self._project_instances_id]
for i in project_instances:
if i.state != RunningInstanceState.RUNNING:
self._model.updateInstanceFields(i, ['state'])
# cleanup removed instances
real = set(i.id for i in project_instances)
@@ -393,12 +381,17 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
self._model.removeInstanceById(i)
self.uiInstancesTableView.resizeColumnsToContents()
# start gns3server if needed
for i in project_instances:
# get the real instance state from self._model
# get the customized instance state from self._model
model_instance = self._model.getInstanceById(i.id)
if model_instance.state == RunningInstanceState.RUNNING:
# update model instance state if needed
if i.state != RunningInstanceState.RUNNING:
self._model.updateInstanceFields(i, ['state'])
# start gns3server if needed
if i.state == RunningInstanceState.RUNNING and (
model_instance.state >= RunningInstanceState.RUNNING):
# instance state transition: RUNNING --> GNS3SERVER_STARTING
model_instance.state = RunningInstanceState.GNS3SERVER_STARTING
self._model.updateInstanceFields(model_instance, ['state'])
@@ -428,10 +421,10 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
flavor_id = self.flavor_index_id[idx]
image_id = self._settings['default_image']
name, ok = QInputDialog.getText(self,
"New instance",
"Choose a name for the instance and press Ok,\n"
"then wait for the instance to appear in the inspector.")
name, ok = QtGui.QInputDialog.getText(self,
"New instance",
"Choose a name for the instance and press Ok,\n"
"then wait for the instance to appear in the inspector.")
if ok:
if not name.endswith("-gns3"):

View File

@@ -34,6 +34,7 @@ class ImportCloudProjectDialog(QtGui.QDialog, Ui_ImportCloudProjectDialog):
project_file_name = self.projects[self.listWidget.currentItem().text()]
download_thread = DownloadProjectThread(
self,
project_file_name,
self.project_dest_path,
self.images_dest_path,
@@ -59,7 +60,7 @@ class ImportCloudProjectDialog(QtGui.QDialog, Ui_ImportCloudProjectDialog):
)
if button_clicked == QtGui.QMessageBox.Yes:
delete_project_thread = DeleteProjectThread(project_file_name, self.cloud_settings)
delete_project_thread = DeleteProjectThread(self, project_file_name, self.cloud_settings)
progress_dialog = ProgressDialog(delete_project_thread, "Deleting project", "Deleting project files...",
"Cancel", parent=self)
progress_dialog.show()

View File

@@ -1151,6 +1151,10 @@ class GraphicsView(QtGui.QGraphicsView):
except ValueError:
raise ModuleError("Wrong format for server: '{}', please recreate the node in preferences".format(node_data["server"]))
server = Servers.instance().getRemoteServer(host, port)
if server is None:
return
if not server.connected() and ConnectToServer(self, server) is False:
return

View File

@@ -341,29 +341,33 @@ class NodeItem(QtSvg.QGraphicsSvgItem):
QtGui.QMessageBox.critical(self.scene().parent(), "Link", "No port available, please configure this device")
return None
# sort by port name
port_names = {}
# sort the ports
ports_dict = {}
for port in ports:
port_names[port.name()] = port
if port.slotNumber() is not None:
# multiply the slot number by 16 to make the port number unique.
ports_dict[(port.slotNumber() * 16) + port.portNumber()] = port
elif port.portNumber()is not None:
ports_dict[port.portNumber()] = port
else:
ports_dict[port.name()] = port
try:
# try a numeric sort first
ports = sorted(port_names.keys(), key=int)
ports = sorted(ports_dict.keys(), key=int)
except ValueError:
# fall back to a classic sort
ports = sorted(port_names.keys())
ports = sorted(ports_dict.keys())
# show a contextual menu for the user to choose a port
for port in ports:
port_object = port_names[port]
port_object = ports_dict[port]
if port in unavailable_ports:
# this port cannot be chosen by the user (grayed out)
action = menu.addAction(QtGui.QIcon(':/icons/led_green.svg'), port)
action = menu.addAction(QtGui.QIcon(':/icons/led_green.svg'), port_object.name())
action.setDisabled(True)
elif port_object.isFree():
menu.addAction(QtGui.QIcon(':/icons/led_red.svg'), port)
menu.addAction(QtGui.QIcon(':/icons/led_red.svg'), port_object.name())
else:
menu.addAction(QtGui.QIcon(':/icons/led_green.svg'), port)
menu.addAction(QtGui.QIcon(':/icons/led_green.svg'), port_object.name())
menu.triggered.connect(self.selectedPortSlot)
menu.exec_(QtGui.QCursor.pos())

View File

@@ -82,11 +82,15 @@ def main():
"""
parser = argparse.ArgumentParser()
parser.add_argument('--version', help="show the version", action='version', version=__version__)
parser.add_argument('--debug', help="print out debug messages", action='store_true', default=False)
parser.add_argument("project", help="load a GNS3 project (.gns3)", metavar="path", nargs="?")
parser.add_argument("--version", help="show the version", action="version", version=__version__)
parser.add_argument("--debug", help="print out debug messages", action="store_true", default=False)
options = parser.parse_args()
exception_file_path = "exception.log"
if options.project and hasattr(sys, "frozen"):
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
def exceptionHook(exception, value, tb):
if exception == KeyboardInterrupt:
@@ -156,7 +160,7 @@ def main():
if sys.platform.startswith('win') or sys.platform.startswith('darwin'):
QtCore.QSettings.setDefaultFormat(QtCore.QSettings.IniFormat)
if sys.platform.startswith('win'):
if sys.platform.startswith('win') and hasattr(sys, "frozen"):
try:
import win32console
import win32con
@@ -165,7 +169,7 @@ def main():
raise RuntimeError("Python for Windows extensions must be installed.")
try:
win32console.AllocConsole()
# hide the console
console_window = win32console.GetConsoleWindow()
win32gui.ShowWindow(console_window, win32con.SW_HIDE)
except win32console.error as e:
@@ -214,7 +218,7 @@ def main():
# update the exception file path to have it in the same directory as the settings file.
exception_file_path = os.path.join(os.path.dirname(QtCore.QSettings().fileName()), exception_file_path)
mainwindow = MainWindow.instance()
mainwindow = MainWindow(options.project)
mainwindow.show()
exit_code = app.exec_()
delattr(MainWindow, "_instance")

View File

@@ -87,12 +87,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# signal to tell a new project was created
project_new_signal = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
def __init__(self, project, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
MainWindow._instance = self
self._settings = {}
self._project_from_cmdline = project
self._cloud_settings = {}
self._loadSettings()
self._connections()
@@ -283,6 +285,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.uiPreferencesAction.triggered.connect(self._preferencesActionSlot)
# view menu connections
self.uiActionFullscreen.triggered.connect(self._fullScreenActionSlot)
self.uiZoomInAction.triggered.connect(self._zoomInActionSlot)
self.uiZoomOutAction.triggered.connect(self._zoomOutActionSlot)
self.uiZoomResetAction.triggered.connect(self._zoomResetActionSlot)
@@ -581,6 +584,18 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
for item in scene.items():
item.setSelected(False)
def _fullScreenActionSlot(self):
"""
Slot to switch to full screen.
"""
if not self.windowState() & QtCore.Qt.WindowFullScreen:
# switch to full screen
self.setWindowState(self.windowState() | QtCore.Qt.WindowFullScreen)
else:
# switch back to normal
self.setWindowState(self.windowState() & ~QtCore.Qt.WindowFullScreen)
def _zoomInActionSlot(self):
"""
Slot called to scale in the view.
@@ -980,6 +995,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
servers = Servers.instance()
servers.stopLocalServer(wait=True)
for cs in servers.cloud_servers.values():
cs.close_connection()
time_spent = "{:.0f}".format(time.time() - self._start_time)
AnalyticsClient().send_event("GNS3", "Close", "Version {} on {}".format(__version__, platform.system()), time_spent)
else:
@@ -1090,7 +1108,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
error=e))
self._createTemporaryProject()
if self._settings["auto_launch_project_dialog"]:
if self._project_from_cmdline:
time.sleep(0.5) # give so time to the server to initialize
self.loadProject(self._project_from_cmdline)
elif self._settings["auto_launch_project_dialog"]:
project_dialog = NewProjectDialog(self, showed_from_startup=True)
project_dialog.show()
create_new_project = project_dialog.exec_()
@@ -1108,8 +1129,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self._settings["last_check_for_update"] = current_epoch
self.setSettings(self._settings)
AnalyticsClient().send_event("GNS3", "Open", "Version {} on {}".format(__version__, platform.system()))
def saveProjectAs(self):
"""
Saves a project to another location/name.
@@ -1308,8 +1327,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
project_files_dir = path[:-4]
self._project_settings["project_files_dir"] = project_files_dir + "-files"
if not os.path.isdir(self._project_settings["project_files_dir"]):
try:
os.makedirs(self._project_settings["project_files_dir"])
except FileExistsError:
pass
except OSError as e:
QtGui.QMessageBox.critical(self, "Load project", "Could not create project sub-directory {}: {}".format(self._project_settings["project_files_dir"], e))
return
self.uiGraphicsView.updateProjectFilesDir(self._project_settings["project_files_dir"])
# if we're opening a cloud project, fire up instances
@@ -1341,7 +1366,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if need_to_save:
self.saveProject(path)
except OSError as e:
QtGui.QMessageBox.critical(self, "Load", "Could not load project from {}: {}".format(path, e))
QtGui.QMessageBox.critical(self, "Load", "Could not load project {}: {}".format(os.path.basename(path), e))
#log.error("exception {type}".format(type=type(e)), exc_info=1)
return False
except ValueError as e:
@@ -1616,6 +1641,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
return
upload_thread = UploadProjectThread(
self,
self._cloud_settings,
self._project_settings['project_path'],
self._settings['images_path']
@@ -1798,4 +1824,4 @@ QComboBox {selection-color: black; selection-background-color: #dedede}
icon.addPixmap(QtGui.QPixmap(":/charcoal_icons/add-link-1.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon.addPixmap(QtGui.QPixmap(":/charcoal_icons/add-link-1-hover.svg"), QtGui.QIcon.Active, QtGui.QIcon.Off)
icon.addPixmap(QtGui.QPixmap(":/charcoal_icons/add-link-1-cancel.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On)
self.uiAddLinkAction.setIcon(icon)
self.uiAddLinkAction.setIcon(icon)

View File

@@ -41,7 +41,7 @@ class Host(Cloud):
self._name_id = Host._name_instance_count
Host._name_instance_count += 1
name = "Host {}".format(self._name_id)
name = "Host{}".format(self._name_id)
self._settings["name"] = name
self.created_signal.connect(self._autoConfigure)

View File

@@ -77,6 +77,14 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
self.uiPlatformComboBox.currentIndexChanged[str].connect(self._platformChangedSlot)
self.uiPlatformComboBox.addItems(list(PLATFORMS_DEFAULT_RAM.keys()))
# Validate the Idle PC value
self._idle_valid = False
idle_pc_rgx = QtCore.QRegExp("^(0x[0-9a-fA-F]+)?$")
validator = QtGui.QRegExpValidator(idle_pc_rgx)
self.uiIdlepcLineEdit.setValidator(validator)
self.uiIdlepcLineEdit.textChanged.connect(self._idlePCValidateSlot)
self.uiIdlepcLineEdit.textChanged.emit(self.uiIdlepcLineEdit.text())
#FIXME: hide because of issue on Windows.
self.uiTestIOSImagePushButton.hide()
@@ -162,6 +170,24 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
except OSError as e:
QtGui.QMessageBox.critical(self, "IOS image", "Could not test the IOS image: {}".format(e))
def _idlePCValidateSlot(self):
"""
Slot to validate the entered Idle-PC Value
"""
sender = self.sender()
validator = sender.validator()
state = validator.validate(sender.text(), 0)[0]
if state == QtGui.QValidator.Acceptable:
color = '#A2C964' # green
self._idle_valid = True
elif state == QtGui.QValidator.Intermediate:
color = '#fff79a' # yellow
self._idle_valid = False
else:
color = '#f6989d' # red
self._idle_valid = False
sender.setStyleSheet('QLineEdit { background-color: %s }' % color)
def _idlePCFinderSlot(self):
"""
Slot for the idle-PC finder.
@@ -326,7 +352,7 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
def validateCurrentPage(self):
"""
Validates the IOS name.
Validates the IOS name and checks validation state for Idle-PC value
"""
if self.currentPage() == self.uiNamePlatformWizardPage:
@@ -335,6 +361,15 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
if ios_router["name"] == name:
QtGui.QMessageBox.critical(self, "Name", "{} is already used, please choose another name".format(name))
return False
if self.currentPage() == self.uiIdlePCWizardPage:
if not self._idle_valid:
idle_pc = self.uiIdlepcLineEdit.text()
QtGui.QMessageBox.critical(self, "Idle-PC", "{} is not a valid Idle-PC value ".format(idle_pc))
return False
if self.currentPage() == self.uiServerWizardPage and self.uiRemoteRadioButton.isChecked():
if not Servers.instance().remoteServers():
QtGui.QMessageBox.critical(self, "Remote server", "There is no remote server registered in Dynamips preferences")
return False
return True
@@ -365,9 +400,6 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
elif self.uiRemoteRadioButton.isChecked():
if self.uiLoadBalanceCheckBox.isChecked():
server = next(iter(Servers.instance()))
if not server:
QtGui.QMessageBox.critical(self, "IOS router", "No remote server available!")
return
server = "{}:{}".format(server.host, server.port)
else:
server = self.uiRemoteServersComboBox.currentText()

View File

@@ -47,7 +47,7 @@ class C7200(Router):
if npe == "npe-g2":
self._platform_settings["slot0"] = "C7200-IO-GE-E"
else:
self._platform_settings["slot0"] = "C7200-IO-2FE"
self._platform_settings["slot0"] = "C7200-IO-FE"
# merge platform settings with the generic ones
self._settings.update(self._platform_settings)

View File

@@ -24,7 +24,7 @@ import re
import sys
import pkg_resources
from gns3.qt import QtGui
from gns3.qt import QtCore, QtGui
from gns3.dialogs.node_configurator_dialog import ConfigurationError
from ..ui.ios_router_configuration_page_ui import Ui_iosRouterConfigPageWidget
from ..settings import CHASSIS, ADAPTER_MATRIX, WIC_MATRIX
@@ -56,6 +56,31 @@ class IOSRouterConfigurationPage(QtGui.QWidget, Ui_iosRouterConfigPageWidget):
self.uiPrivateConfigToolButton.clicked.connect(self._privateConfigBrowserSlot)
self.uiIOSImageToolButton.clicked.connect(self._iosImageBrowserSlot)
self._idle_valid = False
idle_pc_rgx = QtCore.QRegExp("^(0x[0-9a-fA-F]+)?$")
validator = QtGui.QRegExpValidator(idle_pc_rgx)
self.uiIdlepcLineEdit.setValidator(validator)
self.uiIdlepcLineEdit.textChanged.connect(self._idlePCValidateSlot)
self.uiIdlepcLineEdit.textChanged.emit(self.uiIdlepcLineEdit.text())
def _idlePCValidateSlot(self):
"""
Slot to validate the entered Idle-PC Value
"""
sender = self.sender()
validator = sender.validator()
state = validator.validate(sender.text(), 0)[0]
if state == QtGui.QValidator.Acceptable:
color = '#A2C964' # green
self._idle_valid = True
elif state == QtGui.QValidator.Intermediate:
color = '#fff79a' # yellow
self._idle_valid = False
else:
color = '#f6989d' # red
self._idle_valid = False
sender.setStyleSheet('QLineEdit { background-color: %s }' % color)
def _iosImageBrowserSlot(self):
"""
Slot to open a file browser and select an IOU image.
@@ -154,13 +179,14 @@ class IOSRouterConfigurationPage(QtGui.QWidget, Ui_iosRouterConfigPageWidget):
if type(slot_adapters) == str:
# only one default adapter for this slot.
self._widget_slots[slot_number].addItem(slot_adapters)
# elif platform == "c7200" and slot_number == 0 and settings["slot0"] != None:
# # special case
# self._widget_slots[slot_number].addItem(settings["slot0"])
else:
# list of adapters
module_list = list(slot_adapters)
self._widget_slots[slot_number].addItems([""] + module_list)
if platform == "c7200" and slot_number == 0:
# special case
self._widget_slots[slot_number].addItems(module_list)
else:
self._widget_slots[slot_number].addItems([""] + module_list)
# set the combox box to the correct slot adapter if configured.
if settings["slot" + str(slot_number)]:
@@ -420,6 +446,12 @@ class IOSRouterConfigurationPage(QtGui.QWidget, Ui_iosRouterConfigPageWidget):
if not group:
# Check if the Idle-PC value has been validated okay
if not self._idle_valid:
idle_pc = self.uiIdlepcLineEdit.text()
QtGui.QMessageBox.critical(self, "Idle-PC", "{} is not a valid Idle-PC value ".format(idle_pc))
raise ConfigurationError()
# set the device name
name = self.uiNameLineEdit.text()
if not name:

View File

@@ -154,6 +154,10 @@ class IOUDeviceWizard(QtGui.QWizard, Ui_IOUDeviceWizard):
if iou_device["name"] == name:
QtGui.QMessageBox.critical(self, "Name", "{} is already used, please choose another name".format(name))
return False
if self.currentPage() == self.uiServerWizardPage and self.uiRemoteRadioButton.isChecked():
if not Servers.instance().remoteServers():
QtGui.QMessageBox.critical(self, "Remote server", "There is no remote server registered in IOS on UNIX preferences")
return False
return True
def getSettings(self):
@@ -193,9 +197,6 @@ class IOUDeviceWizard(QtGui.QWizard, Ui_IOUDeviceWizard):
elif self.uiRemoteRadioButton.isChecked():
if self.uiLoadBalanceCheckBox.isChecked():
server = next(iter(Servers.instance()))
if not server:
QtGui.QMessageBox.critical(self, "IOU device", "No remote server available!")
return
server = "{}:{}".format(server.host, server.port)
else:
server = self.uiRemoteServersComboBox.currentText()

View File

@@ -335,6 +335,7 @@ class Qemu(Module):
"adapters": self._qemu_vms[vm]["adapters"],
"adapter_type": self._qemu_vms[vm]["adapter_type"]}
#FIXME: this is ugly...
if self._qemu_vms[vm]["hda_disk_image"]:
settings["hda_disk_image"] = self._qemu_vms[vm]["hda_disk_image"]
@@ -350,6 +351,14 @@ class Qemu(Module):
if self._qemu_vms[vm]["kernel_command_line"]:
settings["kernel_command_line"] = self._qemu_vms[vm]["kernel_command_line"]
if self._qemu_vms[vm]["legacy_networking"]:
settings["legacy_networking"] = self._qemu_vms[vm]["legacy_networking"]
settings["cpu_throttling"] = self._qemu_vms[vm]["cpu_throttling"]
if self._qemu_vms[vm]["process_priority"]:
settings["process_priority"] = self._qemu_vms[vm]["process_priority"]
if self._qemu_vms[vm]["options"]:
settings["options"] = self._qemu_vms[vm]["options"]

View File

@@ -61,7 +61,7 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
self.uiTypeComboBox.currentIndexChanged[str].connect(self._typeChangedSlot)
# Available types
self.uiTypeComboBox.addItems(["Default", "ASA 8.4(2)", "IDS"])
self.uiTypeComboBox.addItems(["Default", "IOSv", "IOSv-L2", "ASA 8.4(2)", "IDS"])
# Mandatory fields
self.uiNameTypeWizardPage.registerField("vm_name*", self.uiNameLineEdit)
@@ -101,12 +101,25 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
:param vm_type: type of VM
"""
if vm_type == "ASA 8.4(2)":
if vm_type == "IOSv":
self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/symbols/iosv_virl.normal.svg"))
self.uiNameLineEdit.setText("vIOS")
self.uiHdaDiskImageLabel.setText("IOSv VDMK file:")
elif vm_type == "IOSv-L2":
self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/symbols/iosv_l2_virl.normal.svg"))
self.uiNameLineEdit.setText("vIOS-L2")
self.uiHdaDiskImageLabel.setText("IOSv-L2 VDMK file:")
elif vm_type == "ASA 8.4(2)":
self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/symbols/asa.normal.svg"))
self.uiNameLineEdit.setText("ASA")
elif vm_type == "IDS":
self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/symbols/ids.normal.svg"))
self.uiNameLineEdit.setText("IDS")
self.uiHdaDiskImageLabel.setText("Disk image (hda):")
else:
self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/icons/qemu.svg"))
self.uiHdaDiskImageLabel.setText("Disk image (hda):")
self.uiNameLineEdit.setText("")
def _getDiskImage(self):
@@ -198,6 +211,9 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
if Qemu.instance().settings()["use_local_server"] or self.uiLocalRadioButton.isChecked():
server = Servers.instance().localServer()
elif self.uiRemoteRadioButton.isChecked():
if not Servers.instance().remoteServers():
QtGui.QMessageBox.critical(self, "Remote server", "There is no remote server registered in QEMU preferences")
return False
server = self.uiRemoteServersComboBox.itemData(self.uiRemoteServersComboBox.currentIndex())
if not server.connected() and ConnectToServer(self, server) is False:
return False
@@ -266,12 +282,16 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
is_64bit = sys.maxsize > 2**32
if sys.platform.startswith("win"):
if is_64bit:
# default is qemu-system-x86_64w.exe on Windows 64-bit
if Qemu.instance().settings()["use_local_server"] or self.uiLocalRadioButton.isChecked():
search_string = "qemu.exe"
elif is_64bit:
# default is qemu-system-x86_64w.exe on Windows 64-bit with a remote server
search_string = "x86_64w.exe"
else:
# default is qemu-system-i386w.exe on Windows 32-bit
# default is qemu-system-i386w.exe on Windows 32-bit with a remote server
search_string = "i386w.exe"
elif sys.platform.startswith("darwin") and hasattr(sys, "frozen") and Qemu.instance().settings()["use_local_server"] or self.uiLocalRadioButton.isChecked():
search_string = "GNS3.app/Contents/Resources/qemu/bin/qemu-system-x86_64"
elif is_64bit:
# default is qemu-system-x86_64 on other 64-bit platforms
search_string = "x86_64"
@@ -306,12 +326,27 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
"server": server,
}
if self.uiTypeComboBox.currentText() == "ASA 8.4(2)":
settings["adapters"] = 6
if self.uiTypeComboBox.currentText() == "IOSv":
settings["adapters"] = 8
settings["hda_disk_image"] = self.uiHdaDiskImageLineEdit.text()
settings["default_symbol"] = ":/symbols/iosv_virl.normal.svg"
settings["hover_symbol"] = ":/symbols/iosv_virl.selected.svg"
settings["category"] = Node.routers
elif self.uiTypeComboBox.currentText() == "IOSv-L2":
settings["adapters"] = 8
settings["hda_disk_image"] = self.uiHdaDiskImageLineEdit.text()
settings["default_symbol"] = ":/symbols/iosv_l2_virl.normal.svg"
settings["hover_symbol"] = ":/symbols/iosv_l2_virl.selected.svg"
settings["category"] = Node.switches
elif self.uiTypeComboBox.currentText() == "ASA 8.4(2)":
settings["adapters"] = 4
settings["initrd"] = self.uiInitrdLineEdit.text()
settings["kernel_image"] = self.uiKernelImageLineEdit.text()
settings["kernel_command_line"] = "ide_generic.probe_mask=0x01 ide_core.chs=0.0:980,16,32 auto nousb console=ttyS0,9600 bigphysarea=65536 ide1=noprobe no-hlt"
settings["options"] = "-nographic -cpu coreduo -icount auto -hdachs 980,16,32"
settings["options"] = "-icount auto -hdachs 980,16,32"
if not sys.platform.startswith("darwin"):
settings["cpu_throttling"] = 65
settings["process_priority"] = "low"
settings["default_symbol"] = ":/symbols/asa.normal.svg"
settings["hover_symbol"] = ":/symbols/asa.selected.svg"
settings["category"] = Node.security_devices
@@ -327,6 +362,16 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
settings["hda_disk_image"] = self.uiHdaDiskImageLineEdit.text()
settings["category"] = Node.end_devices
if self.uiTypeComboBox.currentText() != "Default":
if not "options" in settings:
settings["options"] = ""
if server == "local" and (sys.platform.startswith("win") and qemu_path.endswith("qemu.exe")) or (sys.platform.startswith("darwin") and "GNS3.app" in qemu_path):
settings["options"] += " -vga none -vnc none"
settings["legacy_networking"] = True
else:
settings["options"] += " -nographic"
settings["options"] = settings["options"].strip()
return settings
def nextId(self):
@@ -337,7 +382,9 @@ class QemuVMWizard(QtGui.QWizard, Ui_QemuVMWizard):
current_id = self.currentId()
if self.page(current_id) == self.uiNameTypeWizardPage:
if self.uiTypeComboBox.currentText() != "Default":
if self.uiTypeComboBox.currentText().startswith("IOSv"):
self.uiRamSpinBox.setValue(384)
elif self.uiTypeComboBox.currentText() != "Default":
self.uiRamSpinBox.setValue(1024)
elif self.page(current_id) == self.uiBinaryMemoryWizardPage:

View File

@@ -48,6 +48,7 @@ class QemuVMConfigurationPage(QtGui.QWidget, Ui_QemuVMConfigPageWidget):
self.uiHdbDiskImageToolButton.clicked.connect(self._hdbDiskImageBrowserSlot)
self.uiInitrdToolButton.clicked.connect(self._initrdBrowserSlot)
self.uiKernelImageToolButton.clicked.connect(self._kernelImageBrowserSlot)
self.uiActivateCPUThrottlingCheckBox.stateChanged.connect(self._cpuThrottlingChangedSlot)
self.uiAdapterTypesComboBox.clear()
self.uiAdapterTypesComboBox.addItems(["ne2k_pci",
@@ -168,6 +169,16 @@ class QemuVMConfigurationPage(QtGui.QWidget, Ui_QemuVMConfigPageWidget):
QtGui.QMessageBox.critical(self, "Qemu", "Could not find {} in the Qemu binaries list".format(qemu_path))
self.uiQemuListComboBox.clear()
def _cpuThrottlingChangedSlot(self, state):
"""
Slot to enable or not CPU throttling.
"""
if state:
self.uiCPUThrottlingSpinBox.setEnabled(True)
else:
self.uiCPUThrottlingSpinBox.setEnabled(False)
def loadSettings(self, settings, node=None, group=False):
"""
Loads the QEMU VM settings.
@@ -239,8 +250,18 @@ class QemuVMConfigurationPage(QtGui.QWidget, Ui_QemuVMConfigPageWidget):
index = self.uiAdapterTypesComboBox.findText(settings["adapter_type"])
if index != -1:
self.uiAdapterTypesComboBox.setCurrentIndex(index)
self.uiLegacyNetworkingCheckBox.setChecked(settings["legacy_networking"])
self.uiRamSpinBox.setValue(settings["ram"])
if settings["cpu_throttling"]:
self.uiActivateCPUThrottlingCheckBox.setChecked(True)
self.uiCPUThrottlingSpinBox.setValue(settings["cpu_throttling"])
else:
self.uiActivateCPUThrottlingCheckBox.setChecked(False)
index = self.uiProcessPriorityComboBox.findText(settings["process_priority"], QtCore.Qt.MatchFixedString)
if index != -1:
self.uiProcessPriorityComboBox.setCurrentIndex(index)
self.uiQemuOptionsLineEdit.setText(settings["options"])
def saveSettings(self, settings, node=None, group=False):
@@ -295,5 +316,11 @@ class QemuVMConfigurationPage(QtGui.QWidget, Ui_QemuVMConfigPageWidget):
raise ConfigurationError()
settings["adapters"] = adapters
settings["legacy_networking"] = self.uiLegacyNetworkingCheckBox.isChecked()
settings["ram"] = self.uiRamSpinBox.value()
if self.uiActivateCPUThrottlingCheckBox.isChecked():
settings["cpu_throttling"] = self.uiCPUThrottlingSpinBox.value()
else:
settings["cpu_throttling"] = 0
settings["process_priority"] = self.uiProcessPriorityComboBox.currentText().lower()
settings["options"] = self.uiQemuOptionsLineEdit.text()

View File

@@ -101,6 +101,14 @@ class QemuVMPreferencesPage(QtGui.QWidget, Ui_QemuVMPreferencesPageWidget):
if qemu_vm["kernel_command_line"]:
QtGui.QTreeWidgetItem(section_item, ["Kernel command line:", qemu_vm["kernel_command_line"]])
# performance section
section_item = self._createSectionItem("Optimizations")
if qemu_vm["cpu_throttling"]:
QtGui.QTreeWidgetItem(section_item, ["CPU throttling:", "{}%".format(qemu_vm["cpu_throttling"])])
else:
QtGui.QTreeWidgetItem(section_item, ["CPU throttling:", "disabled"])
QtGui.QTreeWidgetItem(section_item, ["Process priority:", qemu_vm["process_priority"]])
# fill out the Additional options section
if qemu_vm["options"]:
section_item = self._createSectionItem("Additional options")

View File

@@ -57,6 +57,9 @@ class QemuVM(Node):
"console": None,
"adapters": QEMU_VM_SETTINGS["adapters"],
"adapter_type": QEMU_VM_SETTINGS["adapter_type"],
"legacy_networking": QEMU_VM_SETTINGS["legacy_networking"],
"cpu_throttling": QEMU_VM_SETTINGS["cpu_throttling"],
"process_priority": QEMU_VM_SETTINGS["process_priority"],
"initrd": "",
"kernel_image": "",
"kernel_command_line": ""}
@@ -89,7 +92,7 @@ class QemuVM(Node):
# let's create a unique name if none has been chosen
if not name:
name = self.allocateName(base_name)
name = self.allocateName(base_name + "-")
if not name:
self.error_signal.emit(self.id(), "could not allocate a name for this QEMU VM")

View File

@@ -48,6 +48,9 @@ QEMU_VM_SETTINGS = {
"ram": 256,
"adapters": 1,
"adapter_type": "e1000",
"legacy_networking": False,
"cpu_throttling": 0,
"process_priority": "normal",
"options": "",
"initrd": "",
"kernel_image": "",
@@ -66,6 +69,9 @@ QEMU_VM_SETTING_TYPES = {
"ram": int,
"adapters": int,
"adapter_type": str,
"legacy_networking": bool,
"cpu_throttling": int,
"process_priority": str,
"options": str,
"initrd": str,
"kernel_image": str,

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>492</width>
<height>399</height>
<width>486</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
@@ -175,7 +175,7 @@
<attribute name="title">
<string>Network</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="uiAdaptersLabel">
<property name="text">
@@ -206,7 +206,7 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<item row="1" column="1">
<widget class="QComboBox" name="uiAdapterTypesComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -216,7 +216,14 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="uiLegacyNetworkingCheckBox">
<property name="text">
<string>Use the legacy networking mode</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -235,8 +242,8 @@
<attribute name="title">
<string>Advanced settings</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="uiLinuxBootGroupBox">
<property name="title">
<string>Linux boot specific settings</string>
@@ -295,7 +302,99 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<item>
<widget class="QGroupBox" name="uiOptimizationGroupBox">
<property name="title">
<string>Optimizations</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="uiActivateCPUThrottlingCheckBox">
<property name="text">
<string>Activate CPU throttling</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="uiCPUThrottlingLabel">
<property name="text">
<string>Percentage of CPU allowed:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="uiCPUThrottlingSpinBox">
<property name="suffix">
<string> %</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>800</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uiProcessPriorityLabel">
<property name="text">
<string>Process priority:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="uiProcessPriorityComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>Realtime</string>
</property>
</item>
<item>
<property name="text">
<string>Very high</string>
</property>
</item>
<item>
<property name="text">
<string>High</string>
</property>
</item>
<item>
<property name="text">
<string>Normal</string>
</property>
</item>
<item>
<property name="text">
<string>Low</string>
</property>
</item>
<item>
<property name="text">
<string>Very low</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Aditional settings</string>
@@ -316,7 +415,7 @@
<zorder>uiQemuOptionsLabel</zorder>
</widget>
</item>
<item row="2" column="0">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/qemu/ui/qemu_vm_configuration_page.ui'
#
# Created: Sun Nov 9 16:27:45 2014
# Created: Tue Dec 2 15:47:26 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -26,7 +26,7 @@ except AttributeError:
class Ui_QemuVMConfigPageWidget(object):
def setupUi(self, QemuVMConfigPageWidget):
QemuVMConfigPageWidget.setObjectName(_fromUtf8("QemuVMConfigPageWidget"))
QemuVMConfigPageWidget.resize(492, 399)
QemuVMConfigPageWidget.resize(486, 407)
self.verticalLayout = QtGui.QVBoxLayout(QemuVMConfigPageWidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.uiQemutabWidget = QtGui.QTabWidget(QemuVMConfigPageWidget)
@@ -106,11 +106,11 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiQemutabWidget.addTab(self.tab_3, _fromUtf8(""))
self.tab_7 = QtGui.QWidget()
self.tab_7.setObjectName(_fromUtf8("tab_7"))
self.gridLayout_8 = QtGui.QGridLayout(self.tab_7)
self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8"))
self.gridLayout_5 = QtGui.QGridLayout(self.tab_7)
self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
self.uiAdaptersLabel = QtGui.QLabel(self.tab_7)
self.uiAdaptersLabel.setObjectName(_fromUtf8("uiAdaptersLabel"))
self.gridLayout_8.addWidget(self.uiAdaptersLabel, 0, 0, 1, 1)
self.gridLayout_5.addWidget(self.uiAdaptersLabel, 0, 0, 1, 1)
self.uiAdaptersSpinBox = QtGui.QSpinBox(self.tab_7)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -120,10 +120,10 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiAdaptersSpinBox.setMinimum(0)
self.uiAdaptersSpinBox.setMaximum(8)
self.uiAdaptersSpinBox.setObjectName(_fromUtf8("uiAdaptersSpinBox"))
self.gridLayout_8.addWidget(self.uiAdaptersSpinBox, 0, 1, 1, 1)
self.gridLayout_5.addWidget(self.uiAdaptersSpinBox, 0, 1, 1, 1)
self.uiAdapterTypesLabel = QtGui.QLabel(self.tab_7)
self.uiAdapterTypesLabel.setObjectName(_fromUtf8("uiAdapterTypesLabel"))
self.gridLayout_8.addWidget(self.uiAdapterTypesLabel, 1, 0, 1, 1)
self.gridLayout_5.addWidget(self.uiAdapterTypesLabel, 1, 0, 1, 1)
self.uiAdapterTypesComboBox = QtGui.QComboBox(self.tab_7)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -131,14 +131,17 @@ class Ui_QemuVMConfigPageWidget(object):
sizePolicy.setHeightForWidth(self.uiAdapterTypesComboBox.sizePolicy().hasHeightForWidth())
self.uiAdapterTypesComboBox.setSizePolicy(sizePolicy)
self.uiAdapterTypesComboBox.setObjectName(_fromUtf8("uiAdapterTypesComboBox"))
self.gridLayout_8.addWidget(self.uiAdapterTypesComboBox, 1, 1, 1, 2)
self.gridLayout_5.addWidget(self.uiAdapterTypesComboBox, 1, 1, 1, 1)
self.uiLegacyNetworkingCheckBox = QtGui.QCheckBox(self.tab_7)
self.uiLegacyNetworkingCheckBox.setObjectName(_fromUtf8("uiLegacyNetworkingCheckBox"))
self.gridLayout_5.addWidget(self.uiLegacyNetworkingCheckBox, 2, 0, 1, 2)
spacerItem2 = QtGui.QSpacerItem(20, 261, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_8.addItem(spacerItem2, 2, 1, 1, 1)
self.gridLayout_5.addItem(spacerItem2, 3, 1, 1, 1)
self.uiQemutabWidget.addTab(self.tab_7, _fromUtf8(""))
self.tab_2 = QtGui.QWidget()
self.tab_2.setObjectName(_fromUtf8("tab_2"))
self.gridLayout = QtGui.QGridLayout(self.tab_2)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.verticalLayout_2 = QtGui.QVBoxLayout(self.tab_2)
self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
self.uiLinuxBootGroupBox = QtGui.QGroupBox(self.tab_2)
self.uiLinuxBootGroupBox.setObjectName(_fromUtf8("uiLinuxBootGroupBox"))
self.gridLayout_2 = QtGui.QGridLayout(self.uiLinuxBootGroupBox)
@@ -169,7 +172,42 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiKernelCommandLineEdit = QtGui.QLineEdit(self.uiLinuxBootGroupBox)
self.uiKernelCommandLineEdit.setObjectName(_fromUtf8("uiKernelCommandLineEdit"))
self.gridLayout_2.addWidget(self.uiKernelCommandLineEdit, 2, 1, 1, 2)
self.gridLayout.addWidget(self.uiLinuxBootGroupBox, 0, 0, 1, 1)
self.verticalLayout_2.addWidget(self.uiLinuxBootGroupBox)
self.groupBox_2 = QtGui.QGroupBox(self.tab_2)
self.groupBox_2.setObjectName(_fromUtf8("groupBox_2"))
self.gridLayout = QtGui.QGridLayout(self.groupBox_2)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.uiActivateCPUThrottlingCheckBox = QtGui.QCheckBox(self.groupBox_2)
self.uiActivateCPUThrottlingCheckBox.setChecked(True)
self.uiActivateCPUThrottlingCheckBox.setObjectName(_fromUtf8("uiActivateCPUThrottlingCheckBox"))
self.gridLayout.addWidget(self.uiActivateCPUThrottlingCheckBox, 0, 0, 1, 2)
self.uiCPUThrottlingLabel = QtGui.QLabel(self.groupBox_2)
self.uiCPUThrottlingLabel.setObjectName(_fromUtf8("uiCPUThrottlingLabel"))
self.gridLayout.addWidget(self.uiCPUThrottlingLabel, 1, 0, 1, 1)
self.uiCPUThrottlingSpinBox = QtGui.QSpinBox(self.groupBox_2)
self.uiCPUThrottlingSpinBox.setMinimum(1)
self.uiCPUThrottlingSpinBox.setMaximum(800)
self.uiCPUThrottlingSpinBox.setProperty("value", 100)
self.uiCPUThrottlingSpinBox.setObjectName(_fromUtf8("uiCPUThrottlingSpinBox"))
self.gridLayout.addWidget(self.uiCPUThrottlingSpinBox, 1, 1, 1, 1)
self.uiProcessPriorityLabel = QtGui.QLabel(self.groupBox_2)
self.uiProcessPriorityLabel.setObjectName(_fromUtf8("uiProcessPriorityLabel"))
self.gridLayout.addWidget(self.uiProcessPriorityLabel, 2, 0, 1, 1)
self.uiProcessPriorityComboBox = QtGui.QComboBox(self.groupBox_2)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.uiProcessPriorityComboBox.sizePolicy().hasHeightForWidth())
self.uiProcessPriorityComboBox.setSizePolicy(sizePolicy)
self.uiProcessPriorityComboBox.setObjectName(_fromUtf8("uiProcessPriorityComboBox"))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.uiProcessPriorityComboBox.addItem(_fromUtf8(""))
self.gridLayout.addWidget(self.uiProcessPriorityComboBox, 2, 1, 1, 1)
self.verticalLayout_2.addWidget(self.groupBox_2)
self.groupBox = QtGui.QGroupBox(self.tab_2)
self.groupBox.setObjectName(_fromUtf8("groupBox"))
self.gridLayout_3 = QtGui.QGridLayout(self.groupBox)
@@ -180,14 +218,15 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiQemuOptionsLineEdit = QtGui.QLineEdit(self.groupBox)
self.uiQemuOptionsLineEdit.setObjectName(_fromUtf8("uiQemuOptionsLineEdit"))
self.gridLayout_3.addWidget(self.uiQemuOptionsLineEdit, 0, 2, 1, 1)
self.gridLayout.addWidget(self.groupBox, 1, 0, 1, 1)
self.verticalLayout_2.addWidget(self.groupBox)
spacerItem3 = QtGui.QSpacerItem(20, 90, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem3, 2, 0, 1, 1)
self.verticalLayout_2.addItem(spacerItem3)
self.uiQemutabWidget.addTab(self.tab_2, _fromUtf8(""))
self.verticalLayout.addWidget(self.uiQemutabWidget)
self.retranslateUi(QemuVMConfigPageWidget)
self.uiQemutabWidget.setCurrentIndex(0)
self.uiProcessPriorityComboBox.setCurrentIndex(3)
QtCore.QMetaObject.connectSlotsByName(QemuVMConfigPageWidget)
def retranslateUi(self, QemuVMConfigPageWidget):
@@ -205,6 +244,7 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.tab_3), _translate("QemuVMConfigPageWidget", "HDD", None))
self.uiAdaptersLabel.setText(_translate("QemuVMConfigPageWidget", "Adapters:", None))
self.uiAdapterTypesLabel.setText(_translate("QemuVMConfigPageWidget", "Type:", None))
self.uiLegacyNetworkingCheckBox.setText(_translate("QemuVMConfigPageWidget", "Use the legacy networking mode", None))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.tab_7), _translate("QemuVMConfigPageWidget", "Network", None))
self.uiLinuxBootGroupBox.setTitle(_translate("QemuVMConfigPageWidget", "Linux boot specific settings", None))
self.uiKernelCommandLineLabel.setText(_translate("QemuVMConfigPageWidget", "Kernel command line:", None))
@@ -212,6 +252,17 @@ class Ui_QemuVMConfigPageWidget(object):
self.uiKernelImageLabel.setText(_translate("QemuVMConfigPageWidget", "Kernel image:", None))
self.uiInitrdToolButton.setText(_translate("QemuVMConfigPageWidget", "&Browse...", None))
self.uiKernelImageToolButton.setText(_translate("QemuVMConfigPageWidget", "&Browse...", None))
self.groupBox_2.setTitle(_translate("QemuVMConfigPageWidget", "Performance", None))
self.uiActivateCPUThrottlingCheckBox.setText(_translate("QemuVMConfigPageWidget", "Activate CPU throttling", None))
self.uiCPUThrottlingLabel.setText(_translate("QemuVMConfigPageWidget", "Percentage of CPU allowed:", None))
self.uiCPUThrottlingSpinBox.setSuffix(_translate("QemuVMConfigPageWidget", " %", None))
self.uiProcessPriorityLabel.setText(_translate("QemuVMConfigPageWidget", "Process priority:", None))
self.uiProcessPriorityComboBox.setItemText(0, _translate("QemuVMConfigPageWidget", "Realtime", None))
self.uiProcessPriorityComboBox.setItemText(1, _translate("QemuVMConfigPageWidget", "Very high", None))
self.uiProcessPriorityComboBox.setItemText(2, _translate("QemuVMConfigPageWidget", "High", None))
self.uiProcessPriorityComboBox.setItemText(3, _translate("QemuVMConfigPageWidget", "Normal", None))
self.uiProcessPriorityComboBox.setItemText(4, _translate("QemuVMConfigPageWidget", "Low", None))
self.uiProcessPriorityComboBox.setItemText(5, _translate("QemuVMConfigPageWidget", "Very low", None))
self.groupBox.setTitle(_translate("QemuVMConfigPageWidget", "Aditional settings", None))
self.uiQemuOptionsLabel.setText(_translate("QemuVMConfigPageWidget", "Options:", None))
self.uiQemutabWidget.setTabText(self.uiQemutabWidget.indexOf(self.tab_2), _translate("QemuVMConfigPageWidget", "Advanced settings", None))

View File

@@ -113,6 +113,9 @@ class VirtualBoxVMWizard(QtGui.QWizard, Ui_VirtualBoxVMWizard):
if VirtualBox.instance().settings()["use_local_server"] or self.uiLocalRadioButton.isChecked():
server = Servers.instance().localServer()
else:
if not Servers.instance().remoteServers():
QtGui.QMessageBox.critical(self, "Remote server", "There is no remote server registered in VirtualBox preferences")
return False
server = self.uiRemoteServersComboBox.itemData(self.uiRemoteServersComboBox.currentIndex())
if not server.connected() and ConnectToServer(self, server) is False:
return False

View File

@@ -25,8 +25,15 @@ import sys
import os
# default path to VirtualBox vboxmanage executable
if sys.platform.startswith("win") and "VBOX_INSTALL_PATH" in os.environ:
DEFAULT_VBOXMANAGE_PATH = os.path.join(os.environ["VBOX_INSTALL_PATH"], "VBoxManage.exe")
if sys.platform.startswith("win"):
if "VBOX_INSTALL_PATH" in os.environ:
DEFAULT_VBOXMANAGE_PATH = os.path.join(os.environ["VBOX_INSTALL_PATH"], "VBoxManage.exe")
elif "VBOX_MSI_INSTALL_PATH" in os.environ:
DEFAULT_VBOXMANAGE_PATH = os.path.join(os.environ["VBOX_MSI_INSTALL_PATH"], "VBoxManage.exe")
else:
DEFAULT_VBOXMANAGE_PATH = "VBoxManage.exe"
elif sys.platform.startswith("darwin"):
DEFAULT_VBOXMANAGE_PATH = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
else:
paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
# look for vboxmanage in the current working directory and $PATH

View File

@@ -88,7 +88,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>Use as a linked base VM</string>
<string>Use as a linked base VM (experimental)</string>
</property>
</widget>
</item>

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/virtualbox/ui/virtualbox_vm_configuration_page.ui'
#
# Created: Sat Nov 15 15:33:17 2014
# Created: Tue Dec 2 14:17:34 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -121,7 +121,7 @@ class Ui_virtualBoxVMConfigPageWidget(object):
self.uiConsolePortLabel.setText(_translate("virtualBoxVMConfigPageWidget", "Console port:", None))
self.uiEnableConsoleCheckBox.setText(_translate("virtualBoxVMConfigPageWidget", "Enable remote console", None))
self.uiHeadlessModeCheckBox.setText(_translate("virtualBoxVMConfigPageWidget", "Start VM in headless mode", None))
self.uiBaseVMCheckBox.setText(_translate("virtualBoxVMConfigPageWidget", "Use as a linked base VM", None))
self.uiBaseVMCheckBox.setText(_translate("virtualBoxVMConfigPageWidget", "Use as a linked base VM (experimental)", None))
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.tab), _translate("virtualBoxVMConfigPageWidget", "General settings", None))
self.uiAdaptersLabel.setText(_translate("virtualBoxVMConfigPageWidget", "Adapters:", None))
self.uiAdapterStartIndexLabel.setText(_translate("virtualBoxVMConfigPageWidget", "Start at:", None))

View File

@@ -132,7 +132,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>Use as a linked base VM</string>
<string>Use as a linked base VM (experimental)</string>
</property>
</widget>
</item>

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/virtualbox/ui/virtualbox_vm_wizard.ui'
#
# Created: Sat Nov 15 15:29:07 2014
# Created: Tue Dec 2 14:17:34 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -104,5 +104,5 @@ class Ui_VirtualBoxVMWizard(object):
self.uiVirtualBoxWizardPage.setTitle(_translate("VirtualBoxVMWizard", "VirtualBox Virtual Machine", None))
self.uiVirtualBoxWizardPage.setSubTitle(_translate("VirtualBoxVMWizard", "Please choose a VirtualBox virtual machine from the list.", None))
self.uiVMListLabel.setText(_translate("VirtualBoxVMWizard", "VM list:", None))
self.uiBaseVMCheckBox.setText(_translate("VirtualBoxVMWizard", "Use as a linked base VM", None))
self.uiBaseVMCheckBox.setText(_translate("VirtualBoxVMWizard", "Use as a linked base VM (experimental)", None))

View File

@@ -91,7 +91,7 @@ class VirtualBoxVM(Node):
# let's create a unique name if none has been chosen
if not name:
if linked_clone:
name = self.allocateName(vmname + " ")
name = self.allocateName(vmname + "-")
else:
name = vmname
self.setName(name)

View File

@@ -36,6 +36,7 @@ class NewsDockWidget(QtGui.QDockWidget, Ui_NewsDockWidget):
QtGui.QDockWidget.__init__(self, parent)
self.setupUi(self)
self._visible = True
self.visibilityChanged.connect(self._visibilityChangedSlot)
self.uiWebView.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
self.uiWebView.linkClicked.connect(self._urlClickedSlot)

View File

@@ -3,8 +3,7 @@ from ..ui.cloud_preferences_page_ui import Ui_CloudPreferencesPageWidget
from ..settings import CLOUD_PROVIDERS
from ..utils import import_from_string
from PyQt4 import QtGui
from PyQt4 import Qt
from ..qt import QtCore, QtGui
class CloudPreferencesPage(QtGui.QWidget, Ui_CloudPreferencesPageWidget):
@@ -58,7 +57,7 @@ class CloudPreferencesPage(QtGui.QWidget, Ui_CloudPreferencesPageWidget):
return self.uiRememberAPIKeyRadioButton.isChecked()
def _terms_accepted(self):
return self.uiTermsCheckBox.checkState() == Qt.Qt.Checked
return self.uiTermsCheckBox.checkState() == QtCore.Qt.Qt.Checked
def _validate(self):
"""
@@ -105,11 +104,10 @@ class CloudPreferencesPage(QtGui.QWidget, Ui_CloudPreferencesPageWidget):
default_image = self.settings['default_image']
default_flavor = self.settings['default_flavor']
new_instance_flavor = self.settings['new_instance_flavor']
gns3_ias_url = self.settings['gns3_ias_url']
# instance a provider controller and try to use it
try:
provider = self.provider_controllers[provider_id](username, apikey, gns3_ias_url)
provider = self.provider_controllers[provider_id](username, apikey)
if provider.authenticate():
provider.set_region(region)
# fill region combo box
@@ -121,11 +119,9 @@ class CloudPreferencesPage(QtGui.QWidget, Ui_CloudPreferencesPageWidget):
self.uiRegionComboBox.addItem(api_region_names[0])
self.region_index_id.append(api_libcloud_names[0])
# fill image template list
self.image_index_id = [""]
self.uiImageTemplateComboBox.addItem("Select default template...")
for image_id, image_name in provider.list_images().items():
self.uiImageTemplateComboBox.addItem(image_name)
self.image_index_id.append(image_id)
self.image_index_id = ["cc6e0096-84f9-4beb-a21e-d80a11a769d8"]
self.uiImageTemplateComboBox.addItem("Ubuntu 14.04")
self.uiImageTemplateComboBox.setCurrentIndex(0)
# fill flavor comboboxes
for id, name in provider.list_flavors().items():
self.uiInstanceFlavorComboBox.addItem(name)

View File

@@ -63,6 +63,6 @@ def serialConsole(vmname):
# use arguments on other platforms
args = shlex.split(command)
subprocess.Popen(args)
except (OSError, ValueError) as e:
except subprocess.SubprocessError as e:
log.warning('could not start serial console "{}": {}'.format(command, e))
raise

View File

@@ -194,7 +194,7 @@ class Servers(QtCore.QObject):
# use arguments on other platforms
args = shlex.split(command)
self._local_server_proccess = subprocess.Popen(args)
except OSError as e:
except subprocess.SubprocessError as e:
log.warning('could not start local server "{}": {}'.format(command, e))
return False
@@ -370,6 +370,28 @@ class Servers(QtCore.QObject):
return value
return None
def cloudServerById(self, instance_id):
"""
Return the server with the specified instance id, or None.
"""
for cs in self.cloud_servers.values():
if cs.instance_id == instance_id:
return cs
return None
def removeCloudServer(self, server):
try:
cs = self.cloud_servers[server.host]
cs.close_connection()
del self.cloud_servers[server.host]
return True
except KeyError:
return False
@property
def cloud_servers(self):
return self._cloud_servers
def __iter__(self):
"""
Creates a round-robin system to pick up a remote server.

View File

@@ -54,32 +54,23 @@ DEFAULT_LOCAL_SERVER_HOST = "127.0.0.1"
DEFAULT_LOCAL_SERVER_PORT = 8000
# Pre-configured Telnet console commands on various OSes
if sys.platform.startswith("win") and "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
# windows 64-bit
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (included with GNS3)': 'putty.exe -telnet %h %p -wt "%d" -gns3 5 -skin 4',
'SuperPutty': 'SuperPutty.exe -telnet "%h -P %p -wt \"%d\" -gns3 5 -skin 4"',
'SecureCRT': '"C:\Program Files\\VanDyke Software\\SecureCRT\\SecureCRT.EXE" /SCRIPT securecrt.vbs /ARG %d /T /TELNET %h %p',
'TeraTerm Pro (64-bit)': r'"C:\Program Files (x86)\teraterm\ttermpro.exe" /W="%d" /M="C:\Program Files\GNS3\ttstart.macro" /T=1 %h %p',
'TeraTerm Pro (32-bit)': r'"C:\Program Files\teraterm\ttermpro.exe" /W="%d" /M="C:\Program Files\GNS3\ttstart.macro" /T=1 %h %p"',
'Telnet': 'telnet %h %p',
'Xshell 4': 'C:\Program Files (x86)\\NetSarang\\Xshell 4\\xshell.exe -url telnet://%h:%p'}
# default Windows 64-bit Telnet console command
if os.path.exists(os.getcwd() + os.sep + "SuperPutty.exe"):
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["SuperPutty"]
if sys.platform.startswith("win"):
if "PROGRAMFILES(X86)" in os.environ:
# windows 64-bit
program_files = os.environ["PROGRAMFILES(X86)"]
else:
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Putty (included with GNS3)"]
# windows 32-bit
program_files = os.environ["PROGRAMFILES"]
elif sys.platform.startswith("win"):
# windows 32-bit
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (included with GNS3)': 'putty.exe -telnet %h %p -wt "%d" -gns3 5 -skin 4',
'SuperPutty': 'SuperPutty.exe -telnet "%h -P %p -wt \"%d\" -gns3 5 -skin 4"',
'SecureCRT': '"C:\Program Files\\VanDyke Software\\SecureCRT\\SecureCRT.EXE" /SCRIPT securecrt.vbs /ARG %d /T /TELNET %h %p',
'TeraTerm Pro': r'"C:\Program Files\teraterm\ttermpro.exe" /W="%d" /M="C:\Program Files\GNS3\ttstart.macro" /T=1 %h %p"',
'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /SCRIPT securecrt.vbs /ARG "%d" /T /TELNET %h %p'.format(program_files),
'TeraTerm Pro': r'"{}\teraterm\ttermpro.exe" /W="%d" /M="ttstart.macro" /T=1 %h %p'.format(program_files),
'Telnet': 'telnet %h %p',
'Xshell 4': 'C:\Program Files\\NetSarang\\Xshell 4\\xshell.exe -url telnet://%h:%p'}
'Xshell 4': r'"{}\NetSarang\Xshell 4\xshell.exe" -url telnet://%h:%p'.format(program_files),
'ZOC 6': r'"{}\ZOC6\zoc.exe" "/TELNET:%h:%p" /TABBED "/TITLE:%d"'.format(program_files)}
# default Windows 32-bit Telnet console command
# default on Windows
if os.path.exists(os.getcwd() + os.sep + "SuperPutty.exe"):
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["SuperPutty"]
else:
@@ -114,7 +105,8 @@ elif sys.platform.startswith("darwin"):
" -e ' end tell'"
" -e 'end tell'"
" -e 'end tell'",
'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /ARG %d /T /TELNET %h %p'
'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /ARG "%d" /T /TELNET %h %p',
'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:%h:%p" /TABBED "/TITLE:%d"'
}
# default Mac OS X Telnet console command
@@ -175,8 +167,8 @@ WIRESHARK_NORMAL_CAPTURE = "Wireshark Traditional Capture"
WIRESHARK_LIVE_TRAFFIC_CAPTURE = "Wireshark Live Traffic Capture"
if sys.platform.startswith("win"):
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "C:\Program Files\Wireshark\wireshark.exe %c",
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail.exe -f -c +0b %c | "C:\Program Files\Wireshark\wireshark.exe" -k -i -'}
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "{}\Wireshark\wireshark.exe %c".format(os.environ["PROGRAMFILES"]),
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail.exe -f -c +0b %c | "{}\Wireshark\wireshark.exe" -k -i -'.format(os.environ["PROGRAMFILES"])}
elif sys.platform.startswith("darwin"):
# Mac OS X
@@ -194,9 +186,9 @@ else:
DEFAULT_PACKET_CAPTURE_READER_COMMAND = PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS[WIRESHARK_LIVE_TRAFFIC_CAPTURE]
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = ""
if sys.platform.startswith("win") and "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
if sys.platform.startswith("win") and "PROGRAMFILES(X86)" in os.environ:
# Windows 64-bit
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"C:\Program Files (x86)\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" %c'
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"{}\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" %c'.format(os.environ["PROGRAMFILES(X86)"])
STYLES = ["Charcoal (default)", "Classic", "Legacy"]
@@ -282,7 +274,6 @@ CLOUD_SETTINGS = {
"accepted_terms": False,
"instance_timeout": 30,
"default_image": "",
"gns3_ias_url": "http://ias.gns3.net:8888",
}
CLOUD_SETTINGS_TYPES = {
@@ -298,7 +289,6 @@ CLOUD_SETTINGS_TYPES = {
"accepted_terms": bool,
"instance_timeout": int,
"default_image": str,
"gns3_ias_url": str,
}
# TODO proof of concept, needs review

View File

@@ -18,7 +18,8 @@
"""
Functions to start external console terminals.
"""
from PyQt4.QtCore import QThread, pyqtSignal
from .qt import QtCore
import sys
import shlex
@@ -29,14 +30,14 @@ import logging
log = logging.getLogger(__name__)
class ConsoleThread(QThread):
class ConsoleThread(QtCore.QThread):
"""
"""
consoleDone = pyqtSignal(str, str, int)
consoleDone = QtCore.pyqtSignal(str, str, int)
def __init__(self, parent, command, name, host, port):
super(QThread, self).__init__(parent)
super(QtCore.QThread, self).__init__(parent)
self._command = command
self._name = name
self._host = host
@@ -55,7 +56,7 @@ class ConsoleThread(QThread):
# emit signal upon completion
self.consoleDone.emit(self._name, self._host, self._port)
except (OSError, ValueError) as e:
except subprocess.SubprocessError as e:
log.warning('could not start Telnet console "{}": {}'.format(self._command, e))
raise

View File

@@ -251,6 +251,12 @@ class Topology(object):
for instance in self._instances:
if instance.id == id:
# remove all the nodes running on the instance
for node in self._nodes:
if node._server.instance_id == id:
self.removeNode(node)
node.delete()
# remove the instance itself
self._instances.remove(instance)
break

View File

@@ -114,6 +114,8 @@ background-none;
<string>Docks</string>
</property>
</widget>
<addaction name="uiActionFullscreen"/>
<addaction name="separator"/>
<addaction name="uiZoomInAction"/>
<addaction name="uiZoomOutAction"/>
<addaction name="uiZoomResetAction"/>
@@ -274,7 +276,7 @@ background-none;
<enum>LeftToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>true</bool>
<bool>false</bool>
</attribute>
<addaction name="uiBrowseRoutersAction"/>
<addaction name="separator"/>
@@ -1120,6 +1122,14 @@ background-none;
<string>Dark Style</string>
</property>
</action>
<action name="uiActionFullscreen">
<property name="text">
<string>Fullscreen</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/main_window.ui'
#
# Created: Wed Nov 19 14:45:32 2014
# Created: Fri Nov 21 14:57:39 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -124,7 +124,6 @@ class Ui_MainWindow(object):
self.uiBrowsersToolBar.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
self.uiBrowsersToolBar.setObjectName(_fromUtf8("uiBrowsersToolBar"))
MainWindow.addToolBar(QtCore.Qt.LeftToolBarArea, self.uiBrowsersToolBar)
MainWindow.insertToolBarBreak(self.uiBrowsersToolBar)
self.uiControlToolBar = QtGui.QToolBar(MainWindow)
self.uiControlToolBar.setIconSize(QtCore.QSize(32, 32))
self.uiControlToolBar.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
@@ -408,6 +407,8 @@ class Ui_MainWindow(object):
self.uiImportProjectAction.setObjectName(_fromUtf8("uiImportProjectAction"))
self.uiDarkStyleAction = QtGui.QAction(MainWindow)
self.uiDarkStyleAction.setObjectName(_fromUtf8("uiDarkStyleAction"))
self.uiActionFullscreen = QtGui.QAction(MainWindow)
self.uiActionFullscreen.setObjectName(_fromUtf8("uiActionFullscreen"))
self.uiEditMenu.addAction(self.uiSelectAllAction)
self.uiEditMenu.addAction(self.uiSelectNoneAction)
self.uiEditMenu.addSeparator()
@@ -430,6 +431,8 @@ class Ui_MainWindow(object):
self.uiHelpMenu.addAction(self.uiLabInstructionsAction)
self.uiHelpMenu.addAction(self.uiAboutQtAction)
self.uiHelpMenu.addAction(self.uiAboutAction)
self.uiViewMenu.addAction(self.uiActionFullscreen)
self.uiViewMenu.addSeparator()
self.uiViewMenu.addAction(self.uiZoomInAction)
self.uiViewMenu.addAction(self.uiZoomOutAction)
self.uiViewMenu.addAction(self.uiZoomResetAction)
@@ -647,6 +650,8 @@ class Ui_MainWindow(object):
self.uiExportProjectAction.setText(_translate("MainWindow", "Export project", None))
self.uiImportProjectAction.setText(_translate("MainWindow", "Import project", None))
self.uiDarkStyleAction.setText(_translate("MainWindow", "Dark Style", None))
self.uiActionFullscreen.setText(_translate("MainWindow", "Fullscreen", None))
self.uiActionFullscreen.setShortcut(_translate("MainWindow", "Ctrl+F", None))
from ..cloud_inspector_view import CloudInspectorView
from ..console_view import ConsoleView

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from PyQt4.QtGui import QSpinBox
from ..qt import QtGui
class ChoicesSpinBox(QSpinBox):
class ChoicesSpinBox(QtGui.QSpinBox):
"""
A custom QSpinBox that shows only values contained in `choices` iterable
"""

View File

@@ -25,5 +25,5 @@ or negative for a release candidate or beta (after the base version
number has been incremented)
"""
__version__ = "1.2"
__version_info__ = (1, 2, 0, 0)
__version__ = "1.2.1"
__version_info__ = (1, 2, 1, 0)

View File

@@ -4,6 +4,8 @@
<file>symbols/router.selected.svg</file>
<file>symbols/gateway.normal.svg</file>
<file>symbols/gateway.selected.svg</file>
<file>symbols/iosv_virl.normal.svg</file>
<file>symbols/iosv_virl.selected.svg</file>
<file>symbols/label_switch_router.normal.svg</file>
<file>symbols/label_switch_router.selected.svg</file>
<file>symbols/optical_router.normal.svg</file>
@@ -52,6 +54,8 @@
<file>symbols/route_switch_processor.selected.svg</file>
<file>symbols/multilayer_switch.normal.svg</file>
<file>symbols/multilayer_switch.selected.svg</file>
<file>symbols/iosv_l2_virl.normal.svg</file>
<file>symbols/iosv_l2_virl.selected.svg</file>
<file>symbols/lightweight_ap.normal.svg</file>
<file>symbols/lightweight_ap.selected.svg</file>
<file>symbols/wlan_controller.normal.svg</file>

View File

@@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg1998"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
width="51.358818"
height="47.630692"
version="1.0"
sodipodi:docname="vios_l2.normal.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:modified="true">
<metadata
id="metadata2003">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Multilayer switch</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jeremy Grossmann</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>GNS-3</dc:title>
</cc:Agent>
</dc:publisher>
<dc:description>Created for the GNS-3 project (www.gns3.net)</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs2001">
<linearGradient
id="linearGradient8331">
<stop
style="stop-color:#6e8caa;stop-opacity:1;"
offset="0"
id="stop8333" />
<stop
style="stop-color:#cfd8e9;stop-opacity:1;"
offset="1"
id="stop8335" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6603">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6605" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6607" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6587">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6589" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6591" />
</linearGradient>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path11918"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
id="path11921"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path11936"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6587"
id="linearGradient6593"
x1="3.95626"
y1="0.64267641"
x2="-1.2664427"
y2="0.62730032"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942481e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6603"
id="linearGradient6609"
x1="2.2801981"
y1="1.4519272"
x2="-0.41311559"
y2="1.4649135"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942482e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8331"
id="linearGradient8337"
x1="2.1178279"
y1="0.30649999"
x2="-0.4954865"
y2="0.30649999"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.117962,0,0,1.035008,-4.0973e-2,-6.788682e-3)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8331"
id="linearGradient9199"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(24.666332,1.3331909e-2,-1.2883406e-2,23.708747,-8.6563136,-4.6316275)"
x1="2.1178279"
y1="0.30649999"
x2="-0.4954865"
y2="0.30649999" />
<path
transform="scale(10,-10) translate(26,-26)"
id="p"
d="M 2.8117,-1.046 A 3 3 0 0 1 .5,2.958 V 4.5119 A 10.5 10.5 0 0 1 2,25.3078 V 25.8661 A 15 15 0 0 0 14.7975,8.5433 15 15 0 0 0 23.4007,-11.201 L 22.9172,-10.9218 A 10.5 10.5 0 0 1 4.1574,-1.8229 z M 6.2265,7.825 A 10 10 0 0 1 -6.2265,7.825 9.5 9.5 0 0 0 -8.4021,10.5667 13.5 13.5 0 0 0 8.4021,10.5667 10 10 0 0 0 6.2265,7.825 z" />
</defs>
<sodipodi:namedview
inkscape:window-height="631"
inkscape:window-width="710"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="5.6568542"
inkscape:cx="45.594763"
inkscape:cy="27.091102"
inkscape:window-x="1129"
inkscape:window-y="285"
inkscape:current-layer="svg1998"
showgrid="false"
inkscape:window-maximized="0" />
<path
id="path11907"
d="M 1.8402723,44.565612 L 1.8402723,47.615693 L 44.293781,47.615693 L 44.293781,44.565612 L 1.8402723,44.565612"
style="fill:#000000;fill-opacity:0.39215686;stroke:none;stroke-width:0.001" />
<path
id="path11020"
d="M 44.370594,6.1851672 L 51.194316,1.0980117 L 51.358819,41.344844 L 44.266438,47.63069 L 44.370594,6.1851672"
style="fill:#000000;fill-opacity:0.39215686;stroke:none;stroke-width:0.001"
sodipodi:nodetypes="ccccc" />
<path
id="path2037"
d="m -0.02588799,5.0439492 0,41.2829658 44.25563999,0 0,-41.2829658 -44.25563999,0"
style="fill:#6e8caa;fill-opacity:1;stroke:none"
inkscape:connector-curvature="0" />
<path
id="path2041"
d="M -0.028418806,5.1647552 L 5.5982489,0.11782966 L 50.022311,0.14184042 L 44.346312,5.1887393 L -0.028418806,5.1647552"
style="fill:url(#linearGradient9199);fill-opacity:1;stroke:none;stroke-width:0.001" />
<path
id="path2045"
d="m 44.228586,5.2655031 5.747583,-4.96041157 0,41.22032047 -5.747583,4.960412 0,-41.2203209"
style="fill:#6e8296;fill-opacity:1;stroke:none"
inkscape:connector-curvature="0" />
<g
transform="matrix(0.11988204,0,0,0.11988204,-17.597288,73.349552)"
id="biohazard-5">
<use
style="fill:#000000"
transform="matrix(0.59107234,0,0,0.59107234,184.79656,-531.9575)"
xlink:href="#p"
id="use3175"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3341-4"
xlink:href="#p"
transform="matrix(0.59107234,0,0,0.59107234,178.54041,-531.9575)"
style="fill:#ffffff" />
<use
style="fill:#000000"
xlink:href="#p"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,548.40456,-434.52903)"
id="use3177"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3343-1"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,542.14838,-434.52903)"
xlink:href="#p"
style="fill:#ffffff" />
<use
style="fill:#000000"
xlink:href="#p"
transform="matrix(-0.29400183,-0.50773227,0.5092261,-0.29313937,279.18389,-169.44999)"
id="use3179"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3345-1"
transform="matrix(-0.28939879,-0.51188366,0.5012534,-0.29553617,274.12647,-168.34953)"
xlink:href="#p"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg1998"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
width="51.358818"
height="47.630692"
version="1.0"
sodipodi:docname="vios_l2.selected.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<metadata
id="metadata2003">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Multilayer switch</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jeremy Grossmann</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>GNS-3</dc:title>
</cc:Agent>
</dc:publisher>
<dc:description>Created for the GNS-3 project (www.gns3.net)</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs2001">
<linearGradient
id="linearGradient8331">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop8333" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop8335" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6603">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6605" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6607" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6587">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6589" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6591" />
</linearGradient>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path11918"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
id="path11921"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path11936"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6587"
id="linearGradient6593"
x1="3.95626"
y1="0.64267641"
x2="-1.2664427"
y2="0.62730032"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942481e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6603"
id="linearGradient6609"
x1="2.2801981"
y1="1.4519272"
x2="-0.41311559"
y2="1.4649135"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942482e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8331"
id="linearGradient8337"
x1="2.1178279"
y1="0.30649999"
x2="-0.4954865"
y2="0.30649999"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.117962,0,0,1.035008,-4.0973e-2,-6.788682e-3)" />
<path
d="M 2.8117,-1.046 A 3 3 0 0 1 .5,2.958 V 4.5119 A 10.5 10.5 0 0 1 2,25.3078 V 25.8661 A 15 15 0 0 0 14.7975,8.5433 15 15 0 0 0 23.4007,-11.201 L 22.9172,-10.9218 A 10.5 10.5 0 0 1 4.1574,-1.8229 z M 6.2265,7.825 A 10 10 0 0 1 -6.2265,7.825 9.5 9.5 0 0 0 -8.4021,10.5667 13.5 13.5 0 0 0 8.4021,10.5667 10 10 0 0 0 6.2265,7.825 z"
id="p"
transform="scale(10,-10) translate(26,-26)" />
<linearGradient
y2="0.30649999"
x2="-0.4954865"
y1="0.30649999"
x1="2.1178279"
gradientTransform="matrix(24.666332,0.01333191,-0.01288341,23.708747,-8.6563136,-4.6316275)"
gradientUnits="userSpaceOnUse"
id="linearGradient9199"
xlink:href="#linearGradient8331-0"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.117962,0,0,1.035008,-4.0973e-2,-6.788682e-3)"
gradientUnits="userSpaceOnUse"
y2="0.30649999"
x2="-0.4954865"
y1="0.30649999"
x1="2.1178279"
id="linearGradient8337-2"
xlink:href="#linearGradient8331-0"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942482e-3,-0.356572)"
gradientUnits="userSpaceOnUse"
y2="1.4649135"
x2="-0.41311559"
y1="1.4519272"
x1="2.2801981"
id="linearGradient6609-5"
xlink:href="#linearGradient6603-5"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942481e-3,-0.356572)"
gradientUnits="userSpaceOnUse"
y2="0.62730032"
x2="-1.2664427"
y1="0.64267641"
x1="3.95626"
id="linearGradient6593-5"
xlink:href="#linearGradient6587-2"
inkscape:collect="always" />
<marker
style="overflow:visible"
id="Arrow1Lstart-4"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11936-5" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11921-2" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Lstart-2"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lstart">
<path
transform="matrix(1.1,0,0,1.1,1.1,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
id="path11918-3" />
</marker>
<linearGradient
id="linearGradient6587-2"
inkscape:collect="always">
<stop
id="stop6589-1"
offset="0"
style="stop-color:#506eaa;stop-opacity:1;" />
<stop
id="stop6591-3"
offset="1"
style="stop-color:#506eaa;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient6603-5"
inkscape:collect="always">
<stop
id="stop6605-3"
offset="0"
style="stop-color:#506eaa;stop-opacity:1;" />
<stop
id="stop6607-2"
offset="1"
style="stop-color:#506eaa;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient8331-0">
<stop
id="stop8333-5"
offset="0"
style="stop-color:#6e8caa;stop-opacity:1;" />
<stop
id="stop8335-7"
offset="1"
style="stop-color:#cfd8e9;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:window-height="940"
inkscape:window-width="1602"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="3.9479168"
inkscape:cx="84.420406"
inkscape:cy="-29.401656"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:current-layer="svg1998"
showgrid="false"
inkscape:window-maximized="0" />
<path
id="path11907"
d="M 1.8402723,44.565612 L 1.8402723,47.615693 L 44.293781,47.615693 L 44.293781,44.565612 L 1.8402723,44.565612"
style="fill:#000000;fill-opacity:0.55686275;stroke:none;stroke-width:0.001" />
<path
id="path11020"
d="M 44.370594,6.1851672 L 51.194316,1.0980117 L 51.358819,41.344844 L 44.266438,47.63069 L 44.370594,6.1851672"
style="fill:#000000;fill-opacity:0.55686275;stroke:none;stroke-width:0.001"
sodipodi:nodetypes="ccccc" />
<path
id="path2037"
d="M 0.062500355,4.8648404 L 0.062500355,46.326915 L 44.31814,46.326915 L 44.31814,4.8648404 L 0.062500355,4.8648404"
style="fill:#49659d;fill-opacity:1;stroke:none;stroke-width:0.001" />
<path
id="path2041"
d="M 0.017723106,4.957238 L 5.6315849,0.057895699 L 49.976168,0.057895699 L 44.313061,4.957238 L 0.017723106,4.957238"
style="fill:#4f6eab;fill-opacity:1;stroke:none;stroke-width:0.001" />
<path
id="path2045"
d="M 44.181009,4.9736333 L 49.978969,-0.0060167968 L 49.978969,41.374173 L 44.181009,46.353824 L 44.181009,4.9736333"
style="fill:#495b89;fill-opacity:1;stroke:none;stroke-width:0.001" />
<g
transform="matrix(0.11988204,0,0,0.11988204,-17.597288,73.349552)"
id="biohazard-5">
<use
style="fill:#000000"
transform="matrix(0.59107234,0,0,0.59107234,184.79656,-531.9575)"
xlink:href="#p"
id="use3175"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3341-4"
xlink:href="#p"
transform="matrix(0.59107234,0,0,0.59107234,178.54041,-531.9575)"
style="fill:#ffffff" />
<use
style="fill:#000000"
xlink:href="#p"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,548.40456,-434.52903)"
id="use3177"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3343-1"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,542.14838,-434.52903)"
xlink:href="#p"
style="fill:#ffffff" />
<use
style="fill:#000000"
xlink:href="#p"
transform="matrix(-0.29400183,-0.50773227,0.5092261,-0.29313937,279.18389,-169.44999)"
id="use3179"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3345-1"
transform="matrix(-0.28939879,-0.51188366,0.5012534,-0.29553617,274.12647,-168.34953)"
xlink:href="#p"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,394 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg1998"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
width="65.937935"
height="55.615818"
version="1.0"
sodipodi:docname="vios.normal.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<metadata
id="metadata2003">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Router</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jeremy Grossmann</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>GNS-3</dc:title>
</cc:Agent>
</dc:publisher>
<dc:description>Created for the GNS-3 project (www.gns3.net)</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs2001">
<linearGradient
id="linearGradient9312">
<stop
style="stop-color:#3c8c8c;stop-opacity:1;"
offset="0"
id="stop9314" />
<stop
style="stop-color:#ffffff;stop-opacity:0.94117647;"
offset="1"
id="stop9316" />
</linearGradient>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path11918"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
id="path11921"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path11936"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient9312"
id="linearGradient2216"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(15.252829,0,0,14.082619,53.467529,3.4188377)"
x1="-1.0929121"
y1="0.63145506"
x2="-4.5832458"
y2="0.070047863" />
<path
d="M 2.8117,-1.046 A 3 3 0 0 1 .5,2.958 V 4.5119 A 10.5 10.5 0 0 1 2,25.3078 V 25.8661 A 15 15 0 0 0 14.7975,8.5433 15 15 0 0 0 23.4007,-11.201 L 22.9172,-10.9218 A 10.5 10.5 0 0 1 4.1574,-1.8229 z M 6.2265,7.825 A 10 10 0 0 1 -6.2265,7.825 9.5 9.5 0 0 0 -8.4021,10.5667 13.5 13.5 0 0 0 8.4021,10.5667 10 10 0 0 0 6.2265,7.825 z"
id="p"
transform="scale(10,-10) translate(26,-26)" />
<linearGradient
y2="0.30649999"
x2="-0.4954865"
y1="0.30649999"
x1="2.1178279"
gradientTransform="matrix(24.666332,1.3331909e-2,-1.2883406e-2,23.708747,-8.6563136,-4.6316275)"
gradientUnits="userSpaceOnUse"
id="linearGradient9199"
xlink:href="#linearGradient8331"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.117962,0,0,1.035008,-4.0973e-2,-6.788682e-3)"
gradientUnits="userSpaceOnUse"
y2="0.30649999"
x2="-0.4954865"
y1="0.30649999"
x1="2.1178279"
id="linearGradient8337"
xlink:href="#linearGradient8331"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942482e-3,-0.356572)"
gradientUnits="userSpaceOnUse"
y2="1.4649135"
x2="-0.41311559"
y1="1.4519272"
x1="2.2801981"
id="linearGradient6609"
xlink:href="#linearGradient6603"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942481e-3,-0.356572)"
gradientUnits="userSpaceOnUse"
y2="0.62730032"
x2="-1.2664427"
y1="0.64267641"
x1="3.95626"
id="linearGradient6593"
xlink:href="#linearGradient6587"
inkscape:collect="always" />
<marker
style="overflow:visible"
id="Arrow1Lstart-0"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11936-1" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send-4"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11921-5" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Lstart-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lstart">
<path
transform="matrix(1.1,0,0,1.1,1.1,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
id="path11918-3" />
</marker>
<linearGradient
id="linearGradient6587"
inkscape:collect="always">
<stop
id="stop6589"
offset="0"
style="stop-color:#506eaa;stop-opacity:1;" />
<stop
id="stop6591"
offset="1"
style="stop-color:#506eaa;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient6603"
inkscape:collect="always">
<stop
id="stop6605"
offset="0"
style="stop-color:#506eaa;stop-opacity:1;" />
<stop
id="stop6607"
offset="1"
style="stop-color:#506eaa;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient8331">
<stop
id="stop8333"
offset="0"
style="stop-color:#6e8caa;stop-opacity:1;" />
<stop
id="stop8335"
offset="1"
style="stop-color:#cfd8e9;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:window-height="979"
inkscape:window-width="1400"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="11.166395"
inkscape:cx="27.334225"
inkscape:cy="20.948248"
inkscape:window-x="124"
inkscape:window-y="51"
inkscape:current-layer="svg1998"
showgrid="false"
inkscape:window-maximized="0" />
<rect
style="opacity:1;fill:#000000;fill-opacity:0.39215686;fill-rule:evenodd;stroke:none;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4558"
width="64.553001"
height="54.450546"
x="1.3854325"
y="1.1652724"
ry="15.247324"
rx="32.213169"
inkscape:transform-center-x="8.4568758" />
<rect
style="opacity:1;fill:#3c8c8c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.015;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect9971"
width="64.499474"
height="52.040936"
x="0"
y="0.91024613"
ry="11.802391"
rx="32.249737"
inkscape:transform-center-x="8.2952569" />
<g
id="g3579"
transform="matrix(1.0000067,0,0,0.9900067,40.759311,2.327137)">
<path
id="path3581"
d="M 23.677527,9.7502028 L 23.620489,9.1645488 L 23.506407,8.5788958 L 23.316272,8.0127658 L 23.03107,7.4271138 L 22.650803,6.8609828 L 22.213492,6.2948508 L 21.681115,5.7482428 L 21.072684,5.2211558 L 20.3882,4.6940668 L 19.627661,4.1865018 L 18.810084,3.6789348 L 17.916451,3.1908918 L 16.946765,2.7028468 L 15.920038,2.2733688 L 14.817258,1.8438898 L 13.657439,1.4144108 L 12.45959,1.0239748 L 11.18569,0.6725838 L 9.8737612,0.3211921 L 8.5047922,0.0088434012 L 7.0977972,-0.2839824 L 5.6527742,-0.5572882 L 4.1697252,-0.7915484 L 2.6676622,-1.0258099 L 1.1275722,-1.2015057 L -0.45054482,-1.3576797 L -2.0476748,-1.4943326 L -3.6448038,-1.5919412 L -5.2609448,-1.6700286 L -6.8961048,-1.7285939 L -8.5122458,-1.7285939 L -8.5122458,-1.7285939 L -10.147406,-1.7285939 L -11.78256,-1.6700286 L -13.379691,-1.5919412 L -14.995836,-1.4943326 L -16.592965,-1.3576797 L -18.152069,-1.2015057 L -19.711169,-1.0258099 L -21.213234,-0.7915484 L -22.696283,-0.5572882 L -24.141307,-0.2839824 L -25.548301,0.0088434012 L -26.917268,0.3211921 L -28.229199,0.6725838 L -29.503099,1.0239748 L -30.700949,1.4144108 L -31.860772,1.8438898 L -32.963548,2.2733688 L -33.990275,2.7028468 L -34.959963,3.1908918 L -35.853593,3.6789348 L -36.671173,4.1865018 L -37.431708,4.6940668 L -38.116197,5.2211558 L -38.705611,5.7482428 L -39.257001,6.2948508 L -39.694309,6.8609828 L -40.074582,7.4271138 L -40.359781,8.0127658 L -40.568933,8.5788958 L -40.683011,9.1645488 L -40.721038,9.7502028 L -40.721038,9.7502028 L -40.683011,10.335856 L -40.568933,10.901987 L -40.359781,11.48764 L -40.074582,12.03425 L -39.694309,12.619902 L -39.257001,13.166511 L -38.705611,13.732642 L -38.116197,14.279254 L -37.431708,14.806341 L -36.671173,15.294385 L -35.853593,15.801949 L -34.959963,16.309514 L -33.990275,16.758515 L -32.963548,17.207517 L -31.860772,17.656519 L -30.700949,18.066477 L -29.503099,18.456913 L -28.229199,18.808302 L -26.917268,19.159693 L -25.548301,19.472041 L -24.141307,19.784392 L -22.696283,20.038171 L -21.213234,20.291955 L -19.711169,20.506693 L -18.152069,20.682391 L -16.592965,20.838567 L -14.995836,20.975218 L -13.379691,21.072827 L -11.78256,21.150915 L -10.147406,21.20948 L -8.5122458,21.20948 L -8.5122458,21.20948 L -6.8961048,21.20948 L -5.2609448,21.150915 L -3.6448038,21.072827 L -2.0476748,20.975218 L -0.45054482,20.838567 L 1.1275722,20.682391 L 2.6676622,20.506693 L 4.1697252,20.291955 L 5.6527742,20.038171 L 7.0977972,19.784392 L 8.5047922,19.472041 L 9.8737612,19.159693 L 11.18569,18.808302 L 12.45959,18.456913 L 13.657439,18.066477 L 14.817258,17.656519 L 15.920038,17.207517 L 16.946765,16.758515 L 17.916451,16.309514 L 18.810084,15.801949 L 19.627661,15.294385 L 20.3882,14.806341 L 21.072684,14.279254 L 21.681115,13.732642 L 22.213492,13.166511 L 22.650803,12.619902 L 23.03107,12.03425 L 23.316272,11.48764 L 23.506407,10.901987 L 23.620489,10.335856 L 23.677527,9.7502028"
style="fill:#3c8c8c;fill-opacity:1;stroke:none;stroke-width:0.01928605;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g4160"
transform="matrix(1.0000067,0,0,0.9900067,-7.7865845e-2,0.5539581)">
<path
id="path4815"
d="M 64.514069,11.541297 L 64.457031,10.955643 L 64.342949,10.36999 L 64.152814,9.8038604 L 63.867612,9.2182077 L 63.487345,8.6520765 L 63.050034,8.0859452 L 62.517657,7.5393369 L 61.909226,7.0122499 L 61.224742,6.4851607 L 60.464203,5.9775955 L 59.646626,5.4700289 L 58.752993,4.9819859 L 57.783307,4.4939413 L 56.75658,4.0644625 L 55.6538,3.6349838 L 54.493981,3.2055052 L 53.296132,2.8150692 L 52.022232,2.4636777 L 50.710303,2.1122862 L 49.341334,1.7999375 L 47.934339,1.5071117 L 46.489316,1.2338059 L 45.006267,0.99954576 L 43.504204,0.76528425 L 41.964114,0.58958842 L 40.385997,0.43341443 L 38.788867,0.29676153 L 37.191738,0.19915292 L 35.575597,0.12106555 L 33.940437,0.06250017 L 32.324296,0.06250017 L 32.324296,0.06250017 L 30.689136,0.06250017 L 29.053981,0.12106555 L 27.45685,0.19915292 L 25.840705,0.29676153 L 24.243576,0.43341443 L 22.684472,0.58958842 L 21.125372,0.76528425 L 19.623307,0.99954576 L 18.140258,1.2338059 L 16.695234,1.5071117 L 15.28824,1.7999375 L 13.919273,2.1122862 L 12.607342,2.4636777 L 11.333442,2.8150692 L 10.135592,3.2055052 L 8.9757693,3.6349838 L 7.8729941,4.0644625 L 6.8462664,4.4939413 L 5.8765785,4.9819859 L 4.9829488,5.4700289 L 4.1653682,5.9775955 L 3.4048335,6.4851607 L 2.7203448,7.0122499 L 2.1309311,7.5393369 L 1.5795405,8.0859452 L 1.1422325,8.6520765 L 0.76195982,9.2182077 L 0.47676065,9.8038604 L 0.26760898,10.36999 L 0.15353084,10.955643 L 0.11550327,11.541297 L 0.11550327,11.541297 L 0.15353084,12.12695 L 0.26760898,12.693081 L 0.47676065,13.278734 L 0.76195982,13.825344 L 1.1422325,14.410996 L 1.5795405,14.957605 L 2.1309311,15.523736 L 2.7203448,16.070348 L 3.4048335,16.597435 L 4.1653682,17.085479 L 4.9829488,17.593043 L 5.8765785,18.100608 L 6.8462664,18.549609 L 7.8729941,18.998611 L 8.9757693,19.447613 L 10.135592,19.857571 L 11.333442,20.248007 L 12.607342,20.599396 L 13.919273,20.950787 L 15.28824,21.263135 L 16.695234,21.575486 L 18.140258,21.829265 L 19.623307,22.083049 L 21.125372,22.297787 L 22.684472,22.473485 L 24.243576,22.629661 L 25.840705,22.766312 L 27.45685,22.863921 L 29.053981,22.942009 L 30.689136,23.000574 L 32.324296,23.000574 L 32.324296,23.000574 L 33.940437,23.000574 L 35.575597,22.942009 L 37.191738,22.863921 L 38.788867,22.766312 L 40.385997,22.629661 L 41.964114,22.473485 L 43.504204,22.297787 L 45.006267,22.083049 L 46.489316,21.829265 L 47.934339,21.575486 L 49.341334,21.263135 L 50.710303,20.950787 L 52.022232,20.599396 L 53.296132,20.248007 L 54.493981,19.857571 L 55.6538,19.447613 L 56.75658,18.998611 L 57.783307,18.549609 L 58.752993,18.100608 L 59.646626,17.593043 L 60.464203,17.085479 L 61.224742,16.597435 L 61.909226,16.070348 L 62.517657,15.523736 L 63.050034,14.957605 L 63.487345,14.410996 L 63.867612,13.825344 L 64.152814,13.278734 L 64.342949,12.693081 L 64.457031,12.12695 L 64.514069,11.541297"
style="fill:url(#linearGradient2216);fill-opacity:1;stroke:none;stroke-width:0.01928605;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path4819"
d="M 33.023738,8.6936939 L 37.664889,10.327433 L 48.909313,5.4458969 L 53.946665,7.0599533 L 51.229891,3.0248142 L 38.061087,3.0248142 L 43.475766,4.225514 L 33.023738,8.6936939"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4821"
d="M 31.08049,13.161874 L 26.439334,11.528132 L 15.591104,16.429352 L 10.176425,14.775929 L 12.874332,19.244109 L 26.439334,19.244109 L 20.628458,17.630052 L 31.08049,13.161874"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4823"
d="M 11.327278,4.225514 L 15.968435,2.611458 L 27.212859,7.0599533 L 32.25021,5.8592533 L 29.552303,9.8943939 L 16.364632,9.8943939 L 21.779313,8.6936939 L 11.327278,4.225514"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4825"
d="M 53.154272,18.023723 L 48.513117,19.657467 L 37.664889,14.775929 L 32.25021,16.429352 L 34.966985,12.33516 L 48.513117,12.33516 L 42.70224,13.555544 L 53.154272,18.023723"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4827"
d="M 33.419936,9.1070493 L 38.061087,10.721105 L 49.286643,5.8592533 L 54.323994,7.4929926 L 51.60722,3.4184854 L 38.438415,3.4184854 L 43.871962,4.6191872 L 33.419936,9.1070493"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4829"
d="M 31.476681,13.555544 L 26.816665,11.941487 L 15.968435,16.803341 L 10.553753,15.189284 L 13.25166,19.657467 L 26.816665,19.657467 L 21.005786,18.023723 L 31.476681,13.555544"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4831"
d="M 11.723476,4.6191872 L 16.364632,3.0248142 L 27.609055,7.4929926 L 32.627541,6.2529266 L 29.929634,10.327433 L 16.741963,10.327433 L 22.175509,9.1070493 L 11.723476,4.6191872"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4833"
d="M 53.531602,18.43708 L 48.909313,20.070823 L 38.061087,15.189284 L 32.627541,16.803341 L 35.344315,12.7682 L 48.909313,12.7682 L 43.098437,13.9689 L 53.531602,18.43708"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
</g>
<g
id="g3377"
transform="translate(27.261461,25.114531)">
<g
id="biohazard-5"
transform="matrix(0.08208805,0,0,0.08208805,-22.699733,44.974166)">
<use
height="1"
width="1"
y="0"
x="0"
id="use3175"
xlink:href="#p"
transform="matrix(0.59107234,0,0,0.59107234,184.79656,-531.9575)"
style="fill:#000000" />
<use
style="fill:#ffffff"
transform="matrix(0.59107234,0,0,0.59107234,178.54041,-531.9575)"
xlink:href="#p"
id="use3341-4"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3177"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,548.40456,-434.52903)"
xlink:href="#p"
style="fill:#000000" />
<use
style="fill:#ffffff"
xlink:href="#p"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,542.14838,-434.52903)"
id="use3343-1"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3179"
transform="matrix(-0.29400183,-0.50773227,0.5092261,-0.29313937,279.18389,-169.44999)"
xlink:href="#p"
style="fill:#000000" />
<use
style="fill:#ffffff"
xlink:href="#p"
transform="matrix(-0.28939879,-0.51188366,0.5012534,-0.29553617,274.12647,-168.34953)"
id="use3345-1"
x="0"
y="0"
width="1"
height="1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,432 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg1998"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
width="65.937935"
height="55.615818"
version="1.0"
sodipodi:docname="vios.selected.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<metadata
id="metadata2003">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Router</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jeremy Grossmann</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>GNS-3</dc:title>
</cc:Agent>
</dc:publisher>
<dc:description>Created for the GNS-3 project (www.gns3.net)</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs2001">
<linearGradient
id="linearGradient9312">
<stop
style="stop-color:#3c8c8c;stop-opacity:1;"
offset="0"
id="stop9314" />
<stop
style="stop-color:#ffffff;stop-opacity:0.94117647;"
offset="1"
id="stop9316" />
</linearGradient>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path11918"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
id="path11921"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path11936"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<linearGradient
id="linearGradient8331">
<stop
style="stop-color:#6e8caa;stop-opacity:1;"
offset="0"
id="stop8333" />
<stop
style="stop-color:#cfd8e9;stop-opacity:1;"
offset="1"
id="stop8335" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6603">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6605" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6607" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6587">
<stop
style="stop-color:#506eaa;stop-opacity:1;"
offset="0"
id="stop6589" />
<stop
style="stop-color:#506eaa;stop-opacity:0;"
offset="1"
id="stop6591" />
</linearGradient>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart-1"
style="overflow:visible">
<path
id="path11918-3"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-4"
style="overflow:visible">
<path
id="path11921-5"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart-0"
style="overflow:visible">
<path
id="path11936-1"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6587"
id="linearGradient6593"
x1="3.95626"
y1="0.64267641"
x2="-1.2664427"
y2="0.62730032"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942481e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6603"
id="linearGradient6609"
x1="2.2801981"
y1="1.4519272"
x2="-0.41311559"
y2="1.4649135"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.060042,0,0,1.074658,-3.942482e-3,-0.356572)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8331"
id="linearGradient8337"
x1="2.1178279"
y1="0.30649999"
x2="-0.4954865"
y2="0.30649999"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.117962,0,0,1.035008,-4.0973e-2,-6.788682e-3)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8331"
id="linearGradient9199"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(24.666332,1.3331909e-2,-1.2883406e-2,23.708747,-8.6563136,-4.6316275)"
x1="2.1178279"
y1="0.30649999"
x2="-0.4954865"
y2="0.30649999" />
<path
transform="scale(10,-10) translate(26,-26)"
id="p"
d="M 2.8117,-1.046 A 3 3 0 0 1 .5,2.958 V 4.5119 A 10.5 10.5 0 0 1 2,25.3078 V 25.8661 A 15 15 0 0 0 14.7975,8.5433 15 15 0 0 0 23.4007,-11.201 L 22.9172,-10.9218 A 10.5 10.5 0 0 1 4.1574,-1.8229 z M 6.2265,7.825 A 10 10 0 0 1 -6.2265,7.825 9.5 9.5 0 0 0 -8.4021,10.5667 13.5 13.5 0 0 0 8.4021,10.5667 10 10 0 0 0 6.2265,7.825 z" />
<linearGradient
y2="0.070047863"
x2="-4.5832458"
y1="0.63145506"
x1="-1.0929121"
gradientTransform="matrix(15.252829,0,0,14.082619,53.467529,3.4188377)"
gradientUnits="userSpaceOnUse"
id="linearGradient2216"
xlink:href="#linearGradient9312-3"
inkscape:collect="always" />
<marker
style="overflow:visible"
id="Arrow1Lstart-05"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11936-0" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
id="path11921-8" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Lstart-12"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lstart">
<path
transform="matrix(1.1,0,0,1.1,1.1,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
id="path11918-0" />
</marker>
<linearGradient
id="linearGradient9312-3">
<stop
id="stop9314-1"
offset="0"
style="stop-color:#3c8c8c;stop-opacity:1;" />
<stop
id="stop9316-6"
offset="1"
style="stop-color:#ffffff;stop-opacity:0.94117647;" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:window-height="979"
inkscape:window-width="1400"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="1.9739584"
inkscape:cx="62.349773"
inkscape:cy="63.631513"
inkscape:window-x="579"
inkscape:window-y="51"
inkscape:current-layer="svg1998"
showgrid="false"
inkscape:window-maximized="0" />
<rect
style="opacity:1;fill:#000000;fill-opacity:0.39215686;fill-rule:evenodd;stroke:none;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4558"
width="64.552505"
height="54.743599"
x="1.3854325"
y="0.87222236"
ry="15.329384"
rx="32.212925"
inkscape:transform-center-x="8.4568136" />
<rect
style="opacity:1;fill:#194b4b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.015;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect9971"
width="64.499474"
height="52.321018"
x="0"
y="0.61582047"
ry="11.865911"
rx="32.249737"
inkscape:transform-center-x="8.2952569" />
<g
id="g4160"
transform="matrix(1.0000067,0,0,0.995335,-7.7865845e-2,0.2576149)">
<path
id="path4819"
d="M 33.023738,8.6936939 L 37.664889,10.327433 L 48.909313,5.4458969 L 53.946665,7.0599533 L 51.229891,3.0248142 L 38.061087,3.0248142 L 43.475766,4.225514 L 33.023738,8.6936939"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4821"
d="M 31.08049,13.161874 L 26.439334,11.528132 L 15.591104,16.429352 L 10.176425,14.775929 L 12.874332,19.244109 L 26.439334,19.244109 L 20.628458,17.630052 L 31.08049,13.161874"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4823"
d="M 11.327278,4.225514 L 15.968435,2.611458 L 27.212859,7.0599533 L 32.25021,5.8592533 L 29.552303,9.8943939 L 16.364632,9.8943939 L 21.779313,8.6936939 L 11.327278,4.225514"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4825"
d="M 53.154272,18.023723 L 48.513117,19.657467 L 37.664889,14.775929 L 32.25021,16.429352 L 34.966985,12.33516 L 48.513117,12.33516 L 42.70224,13.555544 L 53.154272,18.023723"
style="fill:#000000;stroke:none;stroke-width:0.001" />
<path
id="path4827"
d="M 33.419936,9.1070493 L 38.061087,10.721105 L 49.286643,5.8592533 L 54.323994,7.4929926 L 51.60722,3.4184854 L 38.438415,3.4184854 L 43.871962,4.6191872 L 33.419936,9.1070493"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4829"
d="M 31.476681,13.555544 L 26.816665,11.941487 L 15.968435,16.803341 L 10.553753,15.189284 L 13.25166,19.657467 L 26.816665,19.657467 L 21.005786,18.023723 L 31.476681,13.555544"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4831"
d="M 11.723476,4.6191872 L 16.364632,3.0248142 L 27.609055,7.4929926 L 32.627541,6.2529266 L 29.929634,10.327433 L 16.741963,10.327433 L 22.175509,9.1070493 L 11.723476,4.6191872"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
<path
id="path4833"
d="M 53.531602,18.43708 L 48.909313,20.070823 L 38.061087,15.189284 L 32.627541,16.803341 L 35.344315,12.7682 L 48.909313,12.7682 L 43.098437,13.9689 L 53.531602,18.43708"
style="fill:#ffffff;stroke:none;stroke-width:0.001" />
</g>
<g
id="g3377"
transform="translate(27.261461,25.114531)">
<g
id="biohazard-5"
transform="matrix(0.08208805,0,0,0.08208805,-22.699733,44.974166)">
<use
height="1"
width="1"
y="0"
x="0"
id="use3175"
xlink:href="#p"
transform="matrix(0.59107234,0,0,0.59107234,184.79656,-531.9575)"
style="fill:#000000" />
<use
style="fill:#ffffff"
transform="matrix(0.59107234,0,0,0.59107234,178.54041,-531.9575)"
xlink:href="#p"
id="use3341-4"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3177"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,548.40456,-434.52903)"
xlink:href="#p"
style="fill:#000000" />
<use
style="fill:#ffffff"
xlink:href="#p"
transform="matrix(-0.29553617,0.51188366,-0.51188366,-0.29553617,542.14838,-434.52903)"
id="use3343-1"
x="0"
y="0"
width="1"
height="1" />
<use
height="1"
width="1"
y="0"
x="0"
id="use3179"
transform="matrix(-0.29400183,-0.50773227,0.5092261,-0.29313937,279.18389,-169.44999)"
xlink:href="#p"
style="fill:#000000" />
<use
style="fill:#ffffff"
xlink:href="#p"
transform="matrix(-0.28939879,-0.51188366,0.5012534,-0.29553617,274.12647,-168.34953)"
id="use3345-1"
x="0"
y="0"
width="1"
height="1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,21 @@
#!/bin/sh
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install python3
brew install qt
brew install sip --without-python --with-python3
brew install pyqt --without-python --with-python3
sudo pip3 install netifaces
sudo pip3 install gns3-gui
sudo pip3 install gns3-server
echo "Installing Dynamips 0.2.12"
curl -Lo dynamips http://sourceforge.net/projects/gns-3/files/Dynamips/0.2.12/dynamips-0.2.12-OSX.intel64.bin/download
chmod +x dynamips
sudo mv dynamips /usr/local/bin
echo "Installing VPCS 0.6"
curl -Lo vpcs http://sourceforge.net/projects/vpcs/files/0.6/vpcs_0.6_OSX64/download
chmod +x vpcs
sudo mv vpcs /usr/local/bin

View File

@@ -0,0 +1,32 @@
#!/bin/sh
if [ ! -f /usr/bin/clang ]; then
echo "Please install Xcode Command Line Developer Tools"
xcode-select --install
exit
fi
if [ ! -f /opt/local/bin/port ]; then
echo "Please install MacPorts: https://www.macports.org/install.php"
exit
fi
source $HOME/.profile
sudo port -v install py34-pyqt4 py34-zmq py34-pip
sudo pip-3.4 install netifaces
sudo pip-3.4 install gns3-gui
sudo pip-3.4 install gns3-server
echo "PATH=/opt/local/bin:/opt/local/sbin:/opt/local/Library/Frameworks/Python.framework/Versions/3.4/bin:$PATH" >> $HOME/.profile
source $HOME/.profile
echo "Installing Dynamips 0.2.12"
curl -Lo dynamips http://sourceforge.net/projects/gns-3/files/Dynamips/0.2.12/dynamips-0.2.12-OSX.intel64.bin/download
chmod +x dynamips
sudo mv dynamips /opt/local/bin
echo "Installing VPCS 0.6"
curl -Lo vpcs http://sourceforge.net/projects/vpcs/files/0.6/vpcs_0.6_OSX64/download
chmod +x vpcs
sudo mv vpcs /opt/local/bin