Skip to content

ResourcePlugin Interface

The ResourcePlugin interface is the core contract between your plugin and the formae agent. This page documents all methods, their parameters, return types, and behavioral contracts.

Interface Definition

type ResourcePlugin interface {
    // Configuration
    RateLimit() RateLimitConfig
    DiscoveryFilters() []MatchFilter
    LabelConfig() LabelConfig

    // CRUD Operations
    Create(ctx context.Context, req *resource.CreateRequest) (*resource.CreateResult, error)
    Read(ctx context.Context, req *resource.ReadRequest) (*resource.ReadResult, error)
    Update(ctx context.Context, req *resource.UpdateRequest) (*resource.UpdateResult, error)
    Delete(ctx context.Context, req *resource.DeleteRequest) (*resource.DeleteResult, error)
    Status(ctx context.Context, req *resource.StatusRequest) (*resource.StatusResult, error)
    List(ctx context.Context, req *resource.ListRequest) (*resource.ListResult, error)
}

Configuration Methods

RateLimit

Returns rate limiting configuration for your plugin.

func (p *Plugin) RateLimit() plugin.RateLimitConfig

Returns:

type RateLimitConfig struct {
    Scope                            RateLimitScope
    MaxRequestsPerSecondForNamespace int
}

type RateLimitScope string

const (
    RateLimitScopeNamespace RateLimitScope = "Namespace"
)
Field Description
Scope Currently only RateLimitScopeNamespace is supported
MaxRequestsPerSecondForNamespace Maximum requests per second across all resource types in this plugin

Example:

func (p *Plugin) RateLimit() plugin.RateLimitConfig {
    return plugin.RateLimitConfig{
        Scope:                            plugin.RateLimitScopeNamespace,
        MaxRequestsPerSecondForNamespace: 10,
    }
}

DiscoveryFilters

Returns filters to exclude resources from discovery.

func (p *Plugin) DiscoveryFilters() []plugin.MatchFilter

Returns:

type MatchFilter struct {
    ResourceTypes []string
    Conditions    []FilterCondition
}

type FilterCondition struct {
    PropertyPath  string  // JSONPath expression
    PropertyValue string  // Expected value (empty = existence check)
}

Resources matching all conditions in a filter are excluded from discovery.

Example:

func (p *Plugin) DiscoveryFilters() []plugin.MatchFilter {
    return []plugin.MatchFilter{
        {
            ResourceTypes: []string{"MYCLOUD::Compute::Instance"},
            Conditions: []plugin.FilterCondition{
                {
                    PropertyPath:  "$.Tags[?(@.Key=='formae:skip')].Value",
                    PropertyValue: "true",
                },
            },
        },
    }
}

Return nil to discover all resources.


LabelConfig

Returns configuration for extracting human-readable labels from discovered resources.

func (p *Plugin) LabelConfig() plugin.LabelConfig

Returns:

type LabelConfig struct {
    DefaultQuery      string
    ResourceOverrides map[string]string
}
Field Description
DefaultQuery JSONPath expression applied to all resources
ResourceOverrides Per-resource-type JSONPath overrides

Example:

func (p *Plugin) LabelConfig() plugin.LabelConfig {
    return plugin.LabelConfig{
        DefaultQuery: "$.Tags[?(@.Key=='Name')].Value",
        ResourceOverrides: map[string]string{
            "MYCLOUD::IAM::Policy": "$.PolicyName",
            "MYCLOUD::IAM::Role":   "$.RoleName",
        },
    }
}

CRUD Methods

Create

Provisions a new resource.

func (p *Plugin) Create(ctx context.Context, req *resource.CreateRequest) (*resource.CreateResult, error)

Request:

type CreateRequest struct {
    ResourceType string          // e.g., "MYCLOUD::Compute::Instance"
    Properties   json.RawMessage // Desired resource configuration
    TargetConfig json.RawMessage // Credentials and endpoint config
}

Result:

type CreateResult struct {
    ProgressResult *ProgressResult
}

Contract:

  • On success: Set OperationStatus to Success, provide NativeID and ResourceProperties
  • On async: Set OperationStatus to InProgress, provide RequestID for polling
  • On failure: Set OperationStatus to Failure, provide ErrorCode and StatusMessage
  • Return Go error only for unexpected/unrecoverable errors

Read

Fetches current state of an existing resource.

func (p *Plugin) Read(ctx context.Context, req *resource.ReadRequest) (*resource.ReadResult, error)

Request:

type ReadRequest struct {
    ResourceType string
    NativeID     string
    TargetConfig json.RawMessage
}

Result:

type ReadResult struct {
    ResourceType       string
    NativeID           string
    ResourceProperties json.RawMessage
    ErrorCode          OperationErrorCode
}

Contract:

  • On success: Provide ResourceProperties with current state
  • If not found: Set ErrorCode to OperationErrorCodeNotFound
  • Never return Go error for "not found"

Update

Modifies an existing resource.

func (p *Plugin) Update(ctx context.Context, req *resource.UpdateRequest) (*resource.UpdateResult, error)

Request:

type UpdateRequest struct {
    ResourceType      string
    NativeID          string
    PriorProperties   json.RawMessage // State before update
    DesiredProperties json.RawMessage // Requested new state
    PatchDocument     json.RawMessage // JSON Patch of changes
    TargetConfig      json.RawMessage
}

Result:

type UpdateResult struct {
    ProgressResult *ProgressResult
}

Contract:

  • Use DesiredProperties for full replacement or PatchDocument for partial update
  • On success: Provide updated ResourceProperties
  • On async: Return InProgress with RequestID

Delete

Removes a resource.

func (p *Plugin) Delete(ctx context.Context, req *resource.DeleteRequest) (*resource.DeleteResult, error)

Request:

type DeleteRequest struct {
    ResourceType string
    NativeID     string
    TargetConfig json.RawMessage
}

Result:

type DeleteResult struct {
    ProgressResult *ProgressResult
}

Contract:

  • Must be idempotent—deleting a non-existent resource should succeed
  • On success: Set OperationStatus to Success
  • On async: Return InProgress with RequestID

Status

Polls for completion of an async operation.

func (p *Plugin) Status(ctx context.Context, req *resource.StatusRequest) (*resource.StatusResult, error)

Request:

type StatusRequest struct {
    ResourceType string
    RequestID    string // From the original InProgress response
    TargetConfig json.RawMessage
}

Result:

type StatusResult struct {
    ProgressResult *ProgressResult
}

Contract:

  • Called when Create/Update/Delete returns InProgress
  • Return InProgress to continue polling
  • Return Success or Failure when complete
  • Provide NativeID and ResourceProperties on success

List

Returns all resource identifiers of a given type for discovery.

func (p *Plugin) List(ctx context.Context, req *resource.ListRequest) (*resource.ListResult, error)

Request:

type ListRequest struct {
    ResourceType string
    TargetConfig json.RawMessage
    PageToken    *string // For pagination
    PageSize     int     // Suggested page size
}

Result:

type ListResult struct {
    NativeIDs     []string
    NextPageToken *string
}

Contract:

  • Return all native IDs for resources of the given type
  • Use pagination for large result sets
  • Set NextPageToken if more pages available

ProgressResult

Common result structure for operations:

type ProgressResult struct {
    Operation          Operation
    OperationStatus    OperationStatus
    RequestID          string
    NativeID           string
    ResourceProperties json.RawMessage
    ErrorCode          OperationErrorCode
    StatusMessage      string
}

Operation

type Operation string

const (
    OperationCreate      Operation = "CREATE"
    OperationRead        Operation = "READ"
    OperationUpdate      Operation = "UPDATE"
    OperationDelete      Operation = "DELETE"
    OperationCheckStatus Operation = "CHECK_STATUS"
)

OperationStatus

type OperationStatus string

const (
    OperationStatusSuccess    OperationStatus = "SUCCESS"
    OperationStatusFailure    OperationStatus = "FAILURE"
    OperationStatusInProgress OperationStatus = "IN_PROGRESS"
    OperationStatusPending    OperationStatus = "PENDING"
)

OperationErrorCode

type OperationErrorCode string

const (
    OperationErrorCodeNotFound           OperationErrorCode = "NOT_FOUND"
    OperationErrorCodeAlreadyExists      OperationErrorCode = "ALREADY_EXISTS"
    OperationErrorCodeInvalidRequest     OperationErrorCode = "INVALID_REQUEST"
    OperationErrorCodeAccessDenied       OperationErrorCode = "ACCESS_DENIED"
    OperationErrorCodeThrottling         OperationErrorCode = "THROTTLING"
    OperationErrorCodeServiceUnavailable OperationErrorCode = "SERVICE_UNAVAILABLE"
    OperationErrorCodeInternalFailure    OperationErrorCode = "INTERNAL_FAILURE"
    OperationErrorCodeNotStabilized      OperationErrorCode = "NOT_STABILIZED"
)
Error Code Retriable Description
NOT_FOUND No Resource does not exist
ALREADY_EXISTS No Resource already exists (Create)
INVALID_REQUEST No Invalid parameters
ACCESS_DENIED No Permission denied
THROTTLING Yes Rate limited by provider
SERVICE_UNAVAILABLE Yes Temporary provider outage
INTERNAL_FAILURE Maybe Unexpected error
NOT_STABILIZED Yes Resource not yet ready

See Also