diff --git a/design/images/kopia-CLI-workflow.png b/design/images/kopia-CLI-workflow.png new file mode 100644 index 0000000000..497764e3e3 Binary files /dev/null and b/design/images/kopia-CLI-workflow.png differ diff --git a/design/images/kopia-SDK-workflow.png b/design/images/kopia-SDK-workflow.png new file mode 100644 index 0000000000..df1eff1e3b Binary files /dev/null and b/design/images/kopia-SDK-workflow.png differ diff --git a/design/kanister-kopia-integration.md b/design/kanister-kopia-integration.md index 0efc01e499..00f022045d 100644 --- a/design/kanister-kopia-integration.md +++ b/design/kanister-kopia-integration.md @@ -15,6 +15,7 @@ - [Client-side Setup](#client-side-setup) - [Server Access Users Management](#server-access-users-management) - [Secrets Management](#secrets-management) + - [Replace Kopia CLI with SDK](#replace-kopia-CLI-with-SDK) This document proposes all the high-level changes required within Kanister to @@ -599,3 +600,17 @@ credentials. This model ensures Kanister remains free from a hard dependency on any crypto packages, and vault-like functionalities. If misplaced, Kanister will not be able to recover these credentials. + + +### Replace Kopia CLI with SDK + +Currently, we are using Kopia CLI to perform the repository and kopia repository server operations in Kanister. +The repository controller creates a pod, executes commands through `kube.exec` on the pod to perform +repository operations. The commands include: +- repo connect +- start server +- add users +- refresh server + +Kopia provides an SDK to perform repository operations which can be used instead of CLI. The detailed design is explained in the document +[Replace Kopia CLI with Kopia SDK](https://github.com/kanisterio/kanister/blob/master/design/replace-CLI-with-SDK.md). diff --git a/design/replace-CLI-with-SDK.md b/design/replace-CLI-with-SDK.md new file mode 100644 index 0000000000..9e8ba359bd --- /dev/null +++ b/design/replace-CLI-with-SDK.md @@ -0,0 +1,164 @@ + + +- [Motivation](#motivation) +- [Scope](#scope) +- [High Level Design](#high-level-design) + - [Kopia SDK wrappers](#kopia-sdk-wrappers) + - [Storage pkg](#storage-pkg) + - [Repository pkg](#repository-pkg) + - [Repository server controller changes](#repository-server-controller-changes) + - [Kopia CLI Approach](#kopia-cli-approach) + - [Kopia SDK Approach](#kopia-sdk-approach) + + + +# Motivation + +Kanister uses a Kubernetes custom controller that makes use of Kopia as a primary backup and restore tool. +The detailed design of the customer controller can be found [here](https://github.com/kanisterio/kanister/blob/master/design/kanister-kopia-integration.md) + +The custom controller called as repository server controller currently uses Kopia CLI to perform the Kopia operations. All the +operations are executed inside a pod using the `kubectl exec` function. + +We can get following benefits if we start using Kopia SDK instead of CLI: +- Better error handling +- Dependency management + +The goal over here is to start the Kopia server by executing a pre-built binary. The binary would execute most of the +operations to start the server using kopia SDK and reduce the dependency on Kopia CLI and gain more flexibility over the operations + +## Scope +1. Implement a library that wraps the SDK functions provided by Kopia to connect to underlying storage providers - S3, Azure, GCP, Filestore +2. Build another library on top of the library implemented in #1 that can be used to perform repository operations +3. Modify the repository server controller to run a pod that executes a custom image. The binary would take all the +necessary steps to make the Kopia server ready using Kopia SDK and Kopia CLI. + +## High Level Design + +### Kopia SDK Wrappers + +#### Storage pkg + +```go + +package storage + +import ( + "context" + + "github.com/kopia/kopia/repo/blob" +) + +type StorageType string + +const ( + TypeS3 StorageType = "S3" + TypeAzure StorageType = "Azure" + TypeFileStore StorageType = "FileStore" + TypeGCP StorageType = "GCP" +) + +type Storage interface { + Connect() (blob.Storage, error) + SetOptions(context.Context, map[string]string) + WithCreate(bool) +} + +func New(storageType StorageType) Storage { + switch storageType { + case TypeS3: + return &s3Storage{} + case TypeFileStore: + return &fileSystem{} + case TypeAzure: + return &azureStorage{} + case TypeGCP: + return &gcpStorage{} + default: + return nil + } +} + +``` + +#### Repository pkg + +This pkg would be a wrapper over the `storage pkg` built above and the Kopia repositoy pkg `github.com/kopia/kopia/repo` +provided by Kopia SDK + +```go + +package repository + +type Repository struct { + st storage.Storage + password string + configFile string + storageType storage.StorageType +} + +// Create repository using Kopia SDK +func (r *Repository) Create(opts *repo.NewRepositoryOptions) (err error) { + storage, err := r.st.Connect() + if err != nil { + return err + } + return repo.Initialize(context.Background(), storage, opts, r.password) +} + +// Connect to the repository using Kopia SDK +func (r *Repository) Connect(opts *repo.ConnectOptions) (err error) { + storage, err := r.st.Connect() + if err != nil { + return err + } + return repo.Connect(context.Background(), r.configFile, storage, r.password, opts) +} + +// Connect to the repository by providing a config file +func (r *Repository) ConnectUsingFile() error { + repoConfig := repositoryConfigFileName(r.configFile) + if _, err := os.Stat(repoConfig); os.IsNotExist(err) { + return errors.New("failed find kopia configuration file") + } + + _, err := repo.Open(context.Background(), repoConfig, r.password, &repo.Options{}) + return err +} + + +func repositoryConfigFileName(configFile string) string { + if configFile != "" { + return configFile + } + return filepath.Join(os.Getenv("HOME"), ".config", "kopia", "repository.config") +} + +``` + +### Repository server controller changes + +#### Kopia CLI Approach + +![Alt text](images/kopia-CLI-workflow.png?raw=true "Kanister Kopia Integration using Kopia CLI") + +Above diagram explains the current workflow repository server controller +uses to start the Kopia repository server. All the commands are executed from the controller pod inside +the respoitory server pod using `kube.exec`. The repository server pod that is created by controller +uses `kanister-tools` image + + +#### Kopia SDK Approach + +![Alt text](images/kopia-SDK-workflow.png?raw=true "Kanister Kopia Integration using Kopia SDK") + + +As shown in the figure we will be building a custom image which is going have this workflow: +1. Start the Kopia repository server in `--async-repo-connect` mode that means the server would be started without +connecting to the repository in an async mode. Existing approach starts the server only after the connection to Kopia repository +is successful. Kopia SDK currently does not have an exported function to start the Kopia server. So we would still be using Kopia +CLI to start the server +2. Check Kopia server status using Kopia SDK wrappers explained in section [Kopia SDK wrappers](#kopia-sdk-wrappers) +2. Connect to Kopia repository using Kopia SDK wrappers +3. Add or Update server users using Kopia SDK wrappers +4. Refresh server using Kopia SDK wrappers \ No newline at end of file