Skip to main content
This section implements the Create method. We’ll use the async pattern here: Create returns immediately with a RequestID, and the agent polls Status() until completion.

The async pattern

Many infrastructure operations take time. Instead of blocking, plugins can use an async pattern:
  1. Create starts the operation and returns InProgress with a RequestID
  2. Agent polls Status with the RequestID until Success or Failure
  3. On Success, the resource exists and properties are returned

When to use async

The async pattern is optional for Create, Update, and Delete. If your infrastructure operation completes quickly, you can return Success directly without going through the polling cycle. The agent enforces a timeout on plugin calls, so we recommend using the async pattern for any operation that might take longer than 5 seconds. For our SFTP plugin, file uploads could take time for large files, so we implement Create as async. Update and Delete are synchronous since they typically complete quickly.

ProgressResult

All mutating operations (Create, Update, Delete) return their results wrapped in a ProgressResult. This common structure enables the agent to handle async operations uniformly:
The OperationStatus tells the agent what to do next: When an operation fails, set the ErrorCode to help the agent understand the nature of the failure. See 10 - Error handling for the complete list of error codes and when to use each one.

CreateRequest

The agent sends a CreateRequest when provisioning a new resource:

Test

Create sftp_test.go with the Create test:

Test structure

The test follows our testing pattern: We use a separate asyncsftp client in the test to verify results. This keeps the test isolated from Plugin internals.

Implementation

First, add the FileProperties type and update the Plugin struct to hold a client:
Update the Plugin struct to hold a client with lazy initialization:
Now implement Create:

Key points

  1. Parse properties - Extract path, content, permissions from the request
  2. Get client - Lazy initialization reuses the connection
  3. Start async operation - StartUpload returns immediately with an operation ID
  4. Return InProgress - The agent will poll Status() with the RequestID
  5. Set NativeID - The file path uniquely identifies this resource

Status implementation

After Create returns InProgress, the agent polls the Status method to check on the operation’s progress.

StatusRequest

The RequestID links this status check back to the original operation. Your plugin needs to track in-flight operations so it can report their progress.

Implementation

State mapping

The asyncsftp library uses its own state enum, so we need to translate these to the formae SDK’s OperationStatus type. This mapping is straightforward since both represent the same three states: When the operation completes successfully, we also populate ResourceProperties with the current state of the resource. On failure, we set an appropriate ErrorCode. See 10 - Error handling for guidance on choosing the right error code.

Verify

To verify that Create works as expected, run the integration test:
The test output shows the async flow in action. Create returns immediately with a RequestID, then Status polling eventually returns Success:

Summary

You’ve implemented the async Create pattern:
  1. Create parses properties, starts the upload, returns InProgress + RequestID
  2. Status polls the operation and returns InProgress, Success, or Failure
  3. The test verifies the full flow and checks the file exists independently
This async pattern is common in infrastructure plugins where operations may take time (creating VMs, databases, etc.).
Next: 06 - Read