In Mac OS X an application can be extended by adding services. This feature can be used to add new functionality to GNS3.
GNS3 Services

The easiest way is doing that with the help of Automator. In the following a command line application will be integrated.

First open the Automator application and add a new service. Set “Service receives” to “no input” and the application to GNS3. Then drag “Run AppleScript” from the left into the workflow area.

Automator workflow

I’m using AppleScript, because it’s a fine glue language and it’s easy to create GUI dialogs with it. To integrate a command line application, we start it with “do shell script” and on error an alert box can be displayed.

A simple script, satisfying these requirements:

on run {input, parameters}

	try
		do shell script "cd; PATH=/usr/local/bin:$PATH; " & "GNS3/scripts/close_project"
	on error errStr
		display alert "Close project" & return & return & errStr as critical giving up after 10
	end try

	return input
end run

The cd; PATH=/usr/local/bin:$PATH; part sets the current directory to your home directory and adds /usr/local/bin to the PATH. Then the script starts the application, in this case GNS3/scripts/close_project. If an error occurs, an alert box will show the error message.

Insert the script, then click the hammer symbol. The AppleScript will be parsed for syntax errors and reformatted. If everything goes well, save it and give it a descriptive name. This name will show up in the service menu. The file is stored in the Library/Services directory.

You can even add a shortcut to this service. Open <any application> / Services / Services Preferences, scroll down to the buttom of the list, where you should find the newly created service. Then click on the shortcut definition on the right of it (initially its “none”) and assign a shortcut.

Well, that integrates a command line application. But now we actually need that application. Normally it’s the other way round. You have written an application, tested it and then want to integrate it.

My demo application closes an open project. It uses the GNS3 API to get a list of projects. If only one is open, it closes it. If started from the CLI, you can specify the project name as a parameter.

Here’s the application, save it and make it executable (chmod +x). It uses Python (that’s included in OS X), but it will run with Python 3 as well.

#!/usr/bin/python
#
# close_project - close GNS3 project
#
# Usage: close_project [project]
#

import sys
import gns3api

def die(*msg_list):
    """ abort program with error message """
    error_msg = ' '.join(str(x) for x in msg_list)
    sys.exit(error_msg.rstrip("\n\r"))


# get command line parameter
if len(sys.argv) <= 1:
    proj_name = None
elif len(sys.argv) == 2:
    proj_name = sys.argv[1]
else:
    die("Usage: close_project [project]")

# connect to GNS3 controller
try:
    api = gns3api.GNS3Api()
except (Exception) as err:
    die("Can't connect to GNS3 controller:", err)

# search for the project
project = None
if proj_name is None:		# search for the only open project
    for proj in api.request('GET', '/v2/projects'):
        if proj['status'] == 'opened':
            if project is None:
                project = proj
            else:
                die("Multiple projects active, set project as first param")
    if project is None:
        die("No project is open")
else:				# search for proj_name
    for proj in api.request('GET', '/v2/projects'):
        if proj['name'] == proj_name:
            if proj['status'] != 'opened':
                die("Project '{}' not open".format(proj_name))
            project = proj
            break
    else:
        die("Project '{}' not found".format(proj_name))

print("Closing {}...".format(project['name']))
api.request("POST", ("/v2/projects", project['project_id'], "close"))

But that results in another issue (I should have warned you, that this is advanced stuff):

I’m using a Python library to ease the access to the GNS3 API. I’ve created a very simple python module named gns3api, see https://github.com/ehlers/gns3api. You have to download gns3api.py and store it in the same directory as the python script.

Maarten van der Woord has created another python module, that interfaces to the GNS3 API: PyGNS3 (https://github.com/mvdwoord/PyGNS3). I haven’t tried that, but it looks very promising. My demo program would need some adaptions to use this module, especially it requires Python 3 (what’s a good idea to install, anyway).