Skip to content

Commit

Permalink
High level design for starting kopia server in kanister using kopia S…
Browse files Browse the repository at this point in the history
…DK (#2597)

* HLD for storage wrappers library

Signed-off-by: Amruta Kale <amruta.kale@veeam.com>

* add diagrams for CLI and SDK approach

* address review comments

* cosmetic changes

* address review comments

Signed-off-by: Amruta Kale <amruta.kale@veeam.com>

---------

Signed-off-by: Amruta Kale <amruta.kale@veeam.com>
  • Loading branch information
kale-amruta committed Apr 16, 2024
1 parent e44a7cf commit 6ac3818
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 0 deletions.
Binary file added design/images/kopia-CLI-workflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added design/images/kopia-SDK-workflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions design/kanister-kopia-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
<!-- /toc -->

This document proposes all the high-level changes required within Kanister to
Expand Down Expand Up @@ -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).
164 changes: 164 additions & 0 deletions design/replace-CLI-with-SDK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@

<!-- toc -->
- [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)
<!-- /toc -->


# 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

0 comments on commit 6ac3818

Please sign in to comment.