Path Management with DataReferences
In Flyte, managing data locations across different cloud providers (AWS S3, Google GCS, Azure Blob Storage) and local filesystems requires a consistent way to build and parse URIs. Flyte uses the DataReference type and the ReferenceConstructor interface to ensure that paths are constructed safely without manual string manipulation that often leads to errors with trailing slashes or scheme-specific nuances.
In this tutorial, you will learn how to initialize a storage provider, build nested data paths, and parse existing references into their constituent parts.
Prerequisites
To follow this tutorial, you need the following packages from Flyte:
github.com/flyteorg/flyte/v2/flytestdlib/storagegithub.com/flyteorg/flyte/v2/flytestdlib/promutils
1. Initialize the DataStore
The DataStore is the primary entry point for all storage operations in Flyte. It embeds a ReferenceConstructor, which provides the logic for building paths.
import (
"context"
"github.com/flyteorg/flyte/v2/flytestdlib/promutils"
"github.com/flyteorg/flyte/v2/flytestdlib/storage"
)
func main() {
ctx := context.Background()
testScope := promutils.NewTestScope()
// Configure a local storage backend for this example
cfg := &storage.Config{
Type: storage.TypeLocal,
InitContainer: "my-bucket",
}
// NewDataStore returns a DataStore which includes a ReferenceConstructor
store, err := storage.NewDataStore(cfg, testScope.NewSubScope("tutorial"))
if err != nil {
panic(err)
}
}
The DataStore uses a URLPathConstructor by default for most storage types, which treats paths as URL-compatible strings.
2. Construct Nested References
Instead of using fmt.Sprintf or manual string joining, use the ConstructReference method. This method ensures that separators are handled correctly, regardless of whether your base path or nested keys have leading or trailing slashes.
// Define a base reference
baseRef := storage.DataReference("s3://my-bucket/metadata")
// Construct a nested path: s3://my-bucket/metadata/workflows/execution_1/inputs.pb
nestedRef, err := store.ConstructReference(ctx, baseRef, "workflows", "execution_1/", "/inputs.pb")
if err != nil {
panic(err)
}
fmt.Println(nestedRef.String())
// Output: s3://my-bucket/metadata/workflows/execution_1/inputs.pb
The URLPathConstructor implementation in flytestdlib/storage/url_path.go uses url.ResolveReference internally. It ensures the base reference ends with a / before resolving, preventing common bugs where the last segment of a base path is accidentally replaced.
3. Parse a DataReference
When you receive a DataReference (which is a type alias for string), you often need to extract the bucket (container) or the specific key. The Split() method handles this, including special logic for cloud providers like Azure.
ref := storage.DataReference("s3://my-bucket/path/to/data")
scheme, container, key, err := ref.Split()
if err != nil {
panic(err)
}
fmt.Printf("Scheme: %s, Bucket: %s, Key: %s\n", scheme, container, key)
// Output: Scheme: s3, Bucket: my-bucket, Key: path/to/data
Handling Azure ADLS Gen2
Flyte's Split() implementation in flytestdlib/storage/storage.go contains specific logic for Azure abfs and abfss schemes. In Azure, the filesystem is often encoded in the userinfo position (e.g., abfs://container@account.dfs.core.windows.net/path). Flyte correctly identifies the container from the username field in these cases.
4. Enable Multi-Container Access
By default, Flyte may restrict operations to the InitContainer defined in your configuration. If you need to build and access references across different buckets, you must enable MultiContainerEnabled in your storage.Config.
cfg := &storage.Config{
Type: storage.TypeS3,
InitContainer: "default-bucket",
MultiContainerEnabled: true, // Allows references to any bucket
}
If this is set to false, the storage layer will reject requests to references that do not belong to the InitContainer.
Summary
You have now built a safe path management flow using Flyte's storage utilities:
- Initialized a
DataStoreto gain access to path construction logic. - Constructed nested paths using
ConstructReferenceto avoid slash-related errors. - Parsed URIs using
Split()to extract metadata safely across different cloud schemes. - Configured the system to allow cross-bucket data references.
For next steps, explore the RawStore interface within the DataStore to perform ReadRaw and WriteRaw operations using the references you've constructed.