Skip to main content

Other Software

VIKTOR comes with a list of specific integrations, but also enables you to integrate with other software packages not listed. This is possible using

  • Generic worker
  • Generic OAuth 2.0 integration.

A general introduction on OAuth 2.0 and a comparison with other integration types can be found here here.

Generic worker

VIKTOR offers a Generic worker, which can be used to integrate with any software package that supports command-line interaction. The GenericAnalysis class is used for this, which requires one or multiple input files. Furthermore, you need to specify an executable_key to instruct the worker to call a specific task as defined in the configuration file (config.yaml).

from viktor.external.generic import GenericAnalysis

# Generate the input file(s)
files = [
('input1.txt', file1),
('input2.txt', file2)
]

# Run the analysis and obtain the output file.
generic_analysis = GenericAnalysis(files=files, executable_key="some_executable", output_filenames=["output.txt"])
generic_analysis.execute(timeout=60)
output_file = generic_analysis.get_output_file("output.txt")

The executable_key in the example above refers to the "some_executable" command. This command should also be specified in the configuration file on the server, located in the same directory as the worker:

config.yaml

executables:
some_executable:
path: 'C:\path\to\executable.exe'
arguments:
- '-arg1'
- '-arg2'
- '-arg3'
workingDirectoryPath: 'C:\path\to\script'
maxParallelProcesses: 1 # must be 1 if any of the above workingDirectoryPath is not '' (stateful path)
note

If a fixed workingDirectoryPath is defined in the configuration file the maximum number of parallel processes should be 1. When the workingDirectoryPath is not specified a temporary directory will be created to run each job. This allows for a maxParallelProcesses > 1.

note

The worker reads the config file once during startup. So when you change the config file, you will need to restart the worker for your changes to take effect.

With this setup, we can basically run any third-party software which supports command-line execution.

Testing

New in v13.5.0

mock_GenericAnalysis decorator for easier testing of GenericAnalysis

GenericAnalysis.execute needs to be mocked within the context of (automated) testing.

The viktor.testing module provides the mock_GenericAnalysis decorator that facilitate mocking of workers:

import unittest

import viktor as vkt

from viktor.testing import mock_GenericAnalysis

from app.my_entity_type.controller import MyEntityTypeController


class TestMyEntityTypeController(unittest.TestCase):
@mock_GenericAnalysis(get_output_file={
'result.xml': vkt.File.from_path('test_file.xml'), # <name>: <File>
'result.json': vkt.File.from_path('test_file.json'),
...
})
def test_analysis(self):
MyEntityTypeController().analysis()

For the decorator's input parameters the following holds:

  • If a Sequence type is provided, the next entry is returned for each corresponding method call. When a call is performed on a depleted iterable, an Exception is raised.
  • If a single object is provided, the object is returned each time the corresponding method is called (endlessly).
  • If None is provided (default), a default File/BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly).

Generic OAuth 2.0 integration

VIKTOR offers a generic OAuth 2.0 integration, enabling you to connect to any software which supports the OAuth 2.0 protocol.

Creating a generic OAuth 2.0 integration (admin)

First a generic OAuth 2.0 integration needs be setup by one of the VIKTOR admins. This needs to be done in the third-party software and VIKTOR.

  1. Navigate to the "Integrations" tab in the Administrator panel

  2. Select the "OAuth 2.0 integrations" tab

  3. Click "Add OAuth 2.0 integration"

  4. Follow the steps provided in the modal

    1. Select "Generic"
    2. Fill in the basic information of the integration, including the app that the integration should be available to
    3. Fill in the credentials needed to establish a connection. These credentials can found in your third-party software app.
  5. Consult the vendor's documentation on how to set up an "OAuth 2.0" application. In general, the steps are:

    1. Create an OAuth 2.0 application within the relevant software.
    2. Make sure you gather Client ID and Client Secret
      • Most vendors use the terminology Public App or Non-Confidential App for creating OAuth 2.0 applications for public usage (lacking a Client Secret). Since VIKTOR Platform does not support public applications, make sure not to enable public usage for the relevant application.
    3. Make sure you allow <your-viktor-environment-url>/api/integrations/oauth2/callback/ within redirect urls (e.g. https://acme.viktor.ai/api/integrations/oauth2/callback/)
    4. Determine the relevant scopes for your integration.
    5. Some example integration documentation you can refer to:
Security Best Practices
  • Use minimum scope for your application(s) to function when creating integration on VIKTOR. This would limit the impact when there is misuse of integrated software.
  • Use a short Time-to-Live for your Access Tokens when configuring the OAuth 2.0 application on the integration provider.

Implementing the integration in an app (developer)

With the integration name, the developer can start the implementation. First the integration is added in the config file. This is used by the platform to know that this app needs an integration and to trigger a login button for the user.

viktor.config.toml

oauth2_integrations = [
"my-integration-1"
]

Secondly the logic that uses the integration can be implemented in the app. Often external software will provide examples and/or a Python SDK, making it easier to implement. In order to obtain the necessary token for authentication, you instantiate the OAuth2Integration class with the integration name and call the method get_access_token.

integration = vkt.OAuth2Integration('my-integration-1')
access_token = integration.get_access_token()

# code using the token inside your Python code to integrate