> Main > Sdk
Version developers branch

SDK

This guide explains how to implement a Plakar Integration (Source, Destination, or Storage) in Go, and how to use the provided SDK to run it.

📌 What is a Plakar Plugin?

A Plakar Plugin is an external binary that implements one of the Plakar interfaces:

  • Storage: Provides the implementation of a storage for backups
  • Importer: Provides an implementation to import from a source into plakar
  • Exporter: Provides an implementation to export from plakar to a destination

✅ Step 1 — Implement the Interface

Each plugin must implement the right interface from the Plakar source tree.


Store Interface

 1type Store interface {
 2	Create(ctx context.Context, config []byte) error
 3	Open(ctx context.Context) ([]byte, error)
 4	Location() string
 5	Mode() Mode
 6	Size() int64
 7
 8	GetStates() ([]objects.MAC, error)
 9	PutState(mac objects.MAC, rd io.Reader) (int64, error)
10	GetState(mac objects.MAC) (io.Reader, error)
11	DeleteState(mac objects.MAC) error
12
13	GetPackfiles() ([]objects.MAC, error)
14	PutPackfile(mac objects.MAC, rd io.Reader) (int64, error)
15	GetPackfile(mac objects.MAC) (io.Reader, error)
16	GetPackfileBlob(mac objects.MAC, offset uint64, length uint32) (io.Reader, error)
17	DeletePackfile(mac objects.MAC) error
18
19	GetLocks() ([]objects.MAC, error)
20	PutLock(lockID objects.MAC, rd io.Reader) (int64, error)
21	GetLock(lockID objects.MAC) (io.Reader, error)
22	DeleteLock(lockID objects.MAC) error
23
24	Close() error
25}

By implementing the Store interface, an integration can provide access to a new data source for fetching and creating backups.

Create method creates a new storage backend with the provided configuration.

Open method opens an existing storage backend and returns its configuration.

Location method returns the storage location (e.g., file path, URL).

Mode method returns the storage mode (e.g., read, write).

Size method returns the size of the storage backend.

For managing states, packfiles, and locks, the following methods are defined:

  • GetXs: Retrieves all Xs from the storage.
  • PutX: Stores a X in the storage, returning the size of the stored data.
  • GetX: Retrieves a specific X from the storage.
  • DeleteX: Deletes a specific X from the storage.

GetPackfileBlob: Retrieves a specific blob from a packfile, given an offset and length.

Close method is called to clean up resources after the storage operation is complete.


Importer Interface

 1type Importer interface {
 2	Origin() string
 3	Type() string
 4	Root() string
 5	Scan() (<-chan *ScanResult, error)
 6	Close() error
 7}
 8
 9type ScanResult struct {
10	Record *ScanRecord
11	Error  *ScanError
12}
13
14type ScanRecord struct {
15	Reader io.ReadCloser
16	Pathname           string
17	Target             string
18	FileInfo           objects.FileInfo
19	ExtendedAttributes []string
20	FileAttributes     uint32
21	IsXattr            bool
22	XattrName          string
23	XattrType          objects.Attribute
24}
25
26type ScanError struct {
27	Pathname string
28	Err      error
29}

By implementing the Importer interface, an integration can provide storage of backups on any backend that supports listing, storing and fetching byte streams.

Interface: plakarkorp/kloset/snapshot/importer/importer.go

Scan method returns a channel of *ScanResult, which contains the results of the scan operation.

If the ScanResult contains a Record, it means the scan was successful for that file. Record includes the file’s metadata and a reader to access its content (Reader).

If it contains an Error, it indicates a problem encountered during the scan.

Origin method returns the host or source of the data being imported.

Type method returns the name of the importer type (e.g., “fs”, “s3”, “notion”).

Root method returns the root directory of the data being imported.

close method returns called to clean up resources after the import operation is complete.


1type Exporter interface {
2	Root() string
3	CreateDirectory(pathname string) error
4	StoreFile(pathname string, fp io.Reader, size int64) error
5	SetPermissions(pathname string, fileinfo *objects.FileInfo) error
6	Close() error
7}

Exporter Interface

Path: plakarkorp/kloset/snapshot/exporter/exporter.go

Root method returns the root directory where files will be stored.

CreateDirectory method creates a directory at the specified pathname.

StoreFile method stores a file at the specified pathname, reading from the provided io.Reader.

SetPermissions method sets the file permissions based on the provided FileInfo.

Close method is called to clean up resources after the export operation is complete.

🛠️ Step 2 — Write Your Implementation

Example: Implementing an Exporter:

 1package myexporter
 2
 3import (
 4	"io"
 5	"os"
 6	"path/filepath"
 7
 8	"github.com/PlakarKorp/kloset/objects"
 9)
10
11struct MyExporter struct {
12    rootDir string
13}
14
15func NewMyExporter(ctx context.Context, opts *exporter.Options, name string, config map[string]string) (exporter.Exporter, error) {
16	return &MyExporter{
17		rootDir: config["location"], // Location where files will be restored
18	}, nil
19}
20
21type MyExporter struct {
22	root string
23}
24
25func (l *MyExporter) Root() string {
26	return l.root
27}
28
29func (l *MyExporter) CreateDirectory(pathname string) error {
30	return os.MkdirAll(filepath.Join(l.root, pathname), 0755)
31}
32
33func (l *MyExporter) StoreFile(pathname string, fp io.Reader, size int64) error {
34	f, err := os.Create(filepath.Join(l.root, pathname))
35	if err != nil {
36		return err
37	}
38	defer f.Close()
39
40	_, err = io.CopyN(f, fp, size)
41	return err
42}
43
44func (l *MyExporter) SetPermissions(pathname string, fileinfo *objects.FileInfo) error {
45	return os.Chmod(filepath.Join(l.root, pathname), fileinfo.Mode())
46}
47
48func (l *MyExporter) Close() error {
49	return nil
50}

🚀 Step 3 — Make a main function

For the plugin to be executable, you need a main function that uses the SDK to run your plugin.

 1package main
 2
 3import (
 4	"context"
 5	
 6	"github.com/PlakarKorp/go-kloset-sdk"
 7
 8    // Import your implementation package based on the plugin type
 9	"myexporter"
10    // or
11    "myimporter"
12    // or
13    "mystorage"
14)
15
16func main() {
17    // Use the correct SDK function based on your plugin type
18    // For Exporter: sdk.RunExporter()
19    // For Importer: sdk.RunImporter()
20    // For Storage: sdk.RunStorage()
21
22    // Example for Exporter
23	if err := sdk.RunExporter(myexporter.NewMyExporter); err != nil {
24		panic(err)
25	}
26}

🧪 Step 4 — Create a Makefile

To being integrate your plugin in the Plakar system, you need to create a Makefile that builds your plugin binary. Add the following rules in your Makefile but only the ones that you have implemented (Exporter, Importer, and/or Storage):

 1all: exporter importer storage
 2
 3importer:
 4    go build -o myimporter -v ./importer
 5
 6exporter:
 7    go build -o myexporter -v ./exporter
 8
 9storage:
10    go build -o mystorage -v ./storage

🏗️ Step 5 — Add a Manifest.yaml

To integrate your plugin with Plakar, you need to create a Manifest.yaml file in the root of your plugin directory. This file describes your plugin and its capabilities.

 1name: my-plugin-name
 2description: A brief description of your plugin
 3version: 1.0.0
 4connectors:
 5  - type: importer
 6    executable: myimporter
 7    protocols: [my-plugin]
 8 - type: exporter
 9    executable: myexporter
10    protocols: [my-plugin]
11  - type: storage
12    executable: mystorage
13    protocols: [my-plugin]

The protocols field specifies the protocols your plugin supports (e.g., notion, fs, s3). It will be used by Plakar cli to determine which plugins to use for specific operations.

🏁 Step 6 — Create the plugin pkg

To create the plugin package, you need to run the following command in the root of your plugin directory:

Your Manifest.yaml file should be in the same directory as your Makefile.

1./plakar pkg create <path-to-your-manifest.yaml>

From this line, an ptar file will be created in the current directory.

📦 Step 7 — Install the ptar file

To install your plugin, you can use the Plakar CLI:

1plakar pkg install <path-to-your-plugin.ptar>

You can check if your plugin is well installed by running:

1plakar version

If your plugin is installed correctly, you should see it listed in the output.

Now you can use your plugin with Plakar commands, such as a classical plakar connector, if you don’t how to use it, you can check the Plakar documentation for more information on how to use connectors.