Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

Avalon Worker Application Development Tutorial

This tutorial describes how to build a trusted workload application. We begin by copying template files to a new directory. Then we show how to modify the files to create a workload application.

The example we create will be a workload application that takes a name as input and echos back "Hello name".

Under directory hello_world/ are the desired results of modifying the template files, hello_world/stage_1 and, with further modifications, hello_world/stage_2

The directory structure for this tutorial is as follows:

Prerequisites

Before beginning this tutorial, review the following items:

  • Review the base class WorkloadProcessor, which any workload class inherits, at $TCF_HOME/common/sgx_workload/workload_processor.h

    Observe the following:

    • Each workload must implement method ProcessWorkOrder() (see file templates/plug-in.cpp)
    • Each workload class definition must include the macro IMPL_WORKLOAD_PROCESSOR_CLONE(). This macro clones an instance of class WorkloadProcessor for a worker (see file templates/plug-in.h)
    • Each workload class implementation must include the macro REGISTER_WORKLOAD_PROCESSOR(). This macro registers a workload processor for a specific application. It associates a string with a workload. This is the same string that is passed in the work order request JSON payload (see file templates/plug-in.cpp)
  • Review the generic command line client at $TCF_HOME/examples/apps/generic_client/

    • This component is optional, but it can be useful because it allows early testing of the workload without first creating a custom requester application
    • The client application accepts only strings as input parameters and assumes that all outputs are also provided as strings. If other data types are needed (numbers, binaries), then create a custom test application (potentially by modifying this application)
    • The Workload ID (hello-world) and input parameters (a name string) sent by the client must match the workload requirements for this worker
  • Review how to build Avalon at $TCF_HOME/BUILD.md

As a best practice, this tutorial separates the actual workload-specific logic from the Avalon plumbing required to link the workload to the Avalon framework into separate files.

Tutorial

This tutorial creates a workload application in two phases:

  1. Create generic plug-in logic
  2. Incrementally add workload-specific logic

Phase 1: Avalon Plug-in Code

For the first phase copy and modify template code to create the plug-in code. This code contains Avalon framework code to invoke worker-specific logic that will be created next in Phase 2.

  • From the top-level Avalon source repository directory, $TCF_HOME, create a new workload directory and change into it:

    cd $TCF_HOME
    mkdir -p examples/apps/hello_world/workload
    cd examples/apps/hello_world/workload
  • Copy five template files to the newly-created directory:

    cp ../../../../docs/workload-tutorial/templates/* .
  • Change placeholders $NameSpace$ (two locations) in file plug-in.h to an appropriate workload class name, HelloWorld

  • Change placeholder $WorkloadId$ (one location) in file plug-in.h to an appropriate workload ID, hello-world (note the dash, -)

  • Change placeholder $WORKLOAD_STATIC_NAME$ in file CMakeLists.txt to an appropriate name, hello_world (note the underscore, _)

  • To include the new workload into the build, add this line to the end of $TCF_HOME/examples/apps/CMakeLists.txt :

    ADD_SUBDIRECTORY(hello_world/workload)
    
  • To link the new workload library into the build, add these lines to the end of $TCF_HOME/tc/sgx/trusted_worker_manager/enclave/CMakeLists.txt :

    # Add $WORKLOAD_STATIC_NAME$ workload
    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-L,${TCF_TOP_DIR}/examples/apps/build/$WORKLOAD_STATIC_NAME$/workload")
    TARGET_LINK_LIBRARIES(${PROJECT_NAME} -Wl,--whole-archive -l$WORKLOAD_STATIC_NAME$ -Wl,--no-whole-archive)

    Replace $WORKLOAD_STATIC_NAME$ with hello_world so it becomes:

    # Add hello_world workload
    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-L,${TCF_TOP_DIR}/examples/apps/build/hello_world/workload")
    TARGET_LINK_LIBRARIES(${PROJECT_NAME} -Wl,--whole-archive -lhello_world -Wl,--no-whole-archive)
  • Change to the top-level Avalon source repository directory, $TCF_HOME, and rebuild the framework (see $TCF_HOME/BUILD.md). It should now include the new workload

  • From the $TCF_HOME directory, load the framework and use the generic command line utility to test the newly-added workload:

    examples/apps/generic_client/generic_client.py \
        --workload_id "hello-world" --in_data "Jane" "Dan"

    NOTE: If you are running Avalon in a container you can shell into the container like this: bash docker exec -it tcf bash

  • The Hello World worker should return the string Error: under construction as the result (hard-coded placeholder string in plug-in.cpp):

    [17:35:06 INFO    utility.utility]
    Decryption result at client - Error: under construction
    [17:35:06 INFO    __main__]
    Decrypted response:
     [{'index': 0, 'dataHash':
       '60AEBCFC13614F392352DC5683486C05F5519C927FA35DC254204CA0E5045348',
       'data': 'Error: under construction', 'encryptedDataEncryptionKey': '',
       'iv': ''}]
    

To see what the updated source files should look like, refer to the files in directory $TCF_HOME/docs/workload-tutorial/hello_world/stage_1/.

Phase 2: Worker-specific Code

Now that we have Avalon plug-in framework code, we incrementally add worker-specific logic and call it from the plug-in code. As a best practice, we separate worker-specific logic from the Avalon framework code that calls it into separate files. In this example we name the worker-specific function ProcessHelloWorld().

  • Change back into the "Hello World" workload directory:

    cd $TCF_HOME/examples/apps/hello_world/workload
  • Add the ProcessHelloWorld() function definition to logic.h:

    extern std::string ProcessHelloWorld(std::string in_str);
  • Add the ProcessHelloWorld() function implementation to logic.cpp

    std::string ProcessHelloWorld(std::string in_str) {
        return "Hello " + in_str;
    }

    For this example, the worker-specific logic is trivial. Usually the logic is much more complex so it is in a separate file to separate it from Avalon-specific plug-in code

  • Modify the ProcessWorkOrder() method in plug-in.cpp to call ProcessHelloWorld(). That is, change:

    // Replace the dummy implementation below with invocation of
    // actual logic defined in logic.h and implemented in logic.cpp.
    std::string result_str("Error: under construction");
    ByteArray ba(result_str.begin(), result_str.end());
    AddOutput(0, out_work_order_data, ba);

    to

    for (auto wo_data : in_work_order_data) {
       // Process the input data
       std::string result_str =
               ProcessHelloWorld(ByteArrayToString(wo_data.decrypted_data));
    
       ByteArray ba(result_str.begin(), result_str.end());
       AddOutput(wo_data.index, out_work_order_data, ba);
    }
    

    After these changes, the workload will prepend "Hello " to each input data item and will return each resulting string as a separate output data item.

  • Change to the top-level Avalon source repository directory, $TCF_HOME, and rebuild the framework (see $TCF_HOME/BUILD.md). It should now include the new workload

  • Load the framework and use the generic command line utility to test the newly-added workload:

    examples/apps/generic_client/generic_client.py
        --uri "http://localhost:1947" --workload_id "hello-world" --in_data "Dan"
  • The Hello World worker should return a string Hello name where name is the string sent in the first input parameter

    [17:47:48 INFO    utility.utility] Decryption result at client - Hello Dan
    [17:47:48 INFO    __main__]
    Decrypted response:
    [{'index': 0, 'dataHash':
      '02D0D64CA3F5BC43B29304DA25AE9D240A48DE0374C3296A564CE55FB63E0B8C',
      'data': 'Hello Dan', 'encryptedDataEncryptionKey': '', 'iv': ''}]
    

To see what the updated source files should look like, refer to the files in directory $TCF_HOME/docs/workload-tutorial/hello_world/stage_2/.