...

Source file src/github.com/LINBIT/golinstor/client/backup.go

Documentation: github.com/LINBIT/golinstor/client

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  
     9  	"github.com/google/go-querystring/query"
    10  
    11  	"github.com/LINBIT/golinstor/devicelayerkind"
    12  )
    13  
    14  type Backup struct {
    15  	Id                string          `json:"id"`
    16  	StartTime         string          `json:"start_time,omitempty"`
    17  	StartTimestamp    *TimeStampMs    `json:"start_timestamp,omitempty"`
    18  	FinishedTime      string          `json:"finished_time,omitempty"`
    19  	FinishedTimestamp *TimeStampMs    `json:"finished_timestamp,omitempty"`
    20  	OriginRsc         string          `json:"origin_rsc"`
    21  	OriginSnap        string          `json:"origin_snap"`
    22  	OriginNode        string          `json:"origin_node,omitempty"`
    23  	FailMessages      string          `json:"fail_messages,omitempty"`
    24  	Vlms              []BackupVolumes `json:"vlms"`
    25  	Success           bool            `json:"success,omitempty"`
    26  	Shipping          bool            `json:"shipping,omitempty"`
    27  	Restorable        bool            `json:"restorable,omitempty"`
    28  	S3                BackupS3        `json:"s3,omitempty"`
    29  	BasedOnId         string          `json:"based_on_id,omitempty"`
    30  }
    31  
    32  type BackupInfo struct {
    33  	Rsc          string               `json:"rsc"`
    34  	Snap         string               `json:"snap"`
    35  	Full         string               `json:"full"`
    36  	Latest       string               `json:"latest"`
    37  	Count        int32                `json:"count,omitempty"`
    38  	DlSizeKib    int64                `json:"dl_size_kib"`
    39  	AllocSizeKib int64                `json:"alloc_size_kib"`
    40  	Storpools    []BackupInfoStorPool `json:"storpools"`
    41  }
    42  
    43  type BackupInfoRequest struct {
    44  	SrcRscName  string            `json:"src_rsc_name,omitempty"`
    45  	SrcSnapName string            `json:"src_snap_name,omitempty"`
    46  	LastBackup  string            `json:"last_backup,omitempty"`
    47  	StorPoolMap map[string]string `json:"stor_pool_map,omitempty"`
    48  	NodeName    string            `json:"node_name,omitempty"`
    49  }
    50  
    51  type BackupInfoStorPool struct {
    52  	Name              string             `json:"name"`
    53  	ProviderKind      ProviderKind       `json:"provider_kind,omitempty"`
    54  	TargetName        string             `json:"target_name,omitempty"`
    55  	RemainingSpaceKib int64              `json:"remaining_space_kib,omitempty"`
    56  	Vlms              []BackupInfoVolume `json:"vlms"`
    57  }
    58  
    59  type BackupInfoVolume struct {
    60  	Name          string                          `json:"name,omitempty"`
    61  	LayerType     devicelayerkind.DeviceLayerKind `json:"layer_type"`
    62  	DlSizeKib     int64                           `json:"dl_size_kib,omitempty"`
    63  	AllocSizeKib  int64                           `json:"alloc_size_kib"`
    64  	UsableSizeKib int64                           `json:"usable_size_kib,omitempty"`
    65  }
    66  
    67  type BackupList struct {
    68  	// Linstor is a map of all entries found that could be parsed as LINSTOR backups.
    69  	Linstor map[string]Backup `json:"linstor,omitempty"`
    70  	// Other are files that could not be parsed as LINSTOR backups.
    71  	Other BackupOther `json:"other,omitempty"`
    72  }
    73  
    74  type BackupOther struct {
    75  	Files *[]string `json:"files,omitempty"`
    76  }
    77  
    78  type BackupRestoreRequest struct {
    79  	SrcRscName    string            `json:"src_rsc_name,omitempty"`
    80  	SrcSnapName   string            `json:"src_snap_name,omitempty"`
    81  	LastBackup    string            `json:"last_backup,omitempty"`
    82  	StorPoolMap   map[string]string `json:"stor_pool_map,omitempty"`
    83  	TargetRscName string            `json:"target_rsc_name"`
    84  	Passphrase    string            `json:"passphrase,omitempty"`
    85  	NodeName      string            `json:"node_name"`
    86  	DownloadOnly  bool              `json:"download_only,omitempty"`
    87  }
    88  
    89  type BackupS3 struct {
    90  	MetaName string `json:"meta_name,omitempty"`
    91  }
    92  
    93  type BackupAbortRequest struct {
    94  	RscName string `json:"rsc_name"`
    95  	Restore *bool  `json:"restore,omitempty"`
    96  	Create  *bool  `json:"create,omitempty"`
    97  }
    98  
    99  type BackupCreate struct {
   100  	RscName     string `json:"rsc_name"`
   101  	SnapName    string `json:"snap_name,omitempty"`
   102  	NodeName    string `json:"node_name,omitempty"`
   103  	Incremental bool   `json:"incremental,omitempty"`
   104  }
   105  
   106  type BackupShipRequest struct {
   107  	SrcNodeName    string            `json:"src_node_name,omitempty"`
   108  	SrcRscName     string            `json:"src_rsc_name"`
   109  	DstRscName     string            `json:"dst_rsc_name"`
   110  	DstNodeName    string            `json:"dst_node_name,omitempty"`
   111  	DstNetIfName   string            `json:"dst_net_if_name,omitempty"`
   112  	DstStorPool    string            `json:"dst_stor_pool,omitempty"`
   113  	StorPoolRename map[string]string `json:"stor_pool_rename,omitempty"`
   114  	DownloadOnly   *bool             `json:"download_only,omitempty"`
   115  }
   116  
   117  type BackupVolumes struct {
   118  	VlmNr             int64            `json:"vlm_nr"`
   119  	FinishedTime      *string          `json:"finished_time,omitempty"`
   120  	FinishedTimestamp *TimeStampMs     `json:"finished_timestamp,omitempty"`
   121  	S3                *BackupVolumesS3 `json:"s3,omitempty"`
   122  }
   123  
   124  type BackupVolumesS3 struct {
   125  	Key *string `json:"key,omitempty"`
   126  }
   127  
   128  type BackupDeleteOpts struct {
   129  	ID              string       `url:"id,omitempty"`
   130  	IDPrefix        string       `url:"id_prefix,omitempty"`
   131  	Cascading       bool         `url:"cascading,omitempty"`
   132  	Timestamp       *TimeStampMs `url:"timestamp,omitempty"`
   133  	ResourceName    string       `url:"resource_name,omitempty"`
   134  	NodeName        string       `url:"node_name,omitempty"`
   135  	AllLocalCluster bool         `url:"all_local_cluster,omitempty"`
   136  	All             bool         `url:"all,omitempty"`
   137  	S3Key           string       `url:"s3key,omitempty"`
   138  	S3KeyForce      string       `url:"s3key_force,omitempty"`
   139  	DryRun          bool         `url:"dryrun,omitempty"`
   140  }
   141  
   142  type BackupProvider interface {
   143  	// GetAll fetches information on all backups stored at the given remote. Optionally limited to the given
   144  	// resource names.
   145  	GetAll(ctx context.Context, remoteName string, rscName string, snapName string) (*BackupList, error)
   146  	// DeleteAll backups that fit the given criteria.
   147  	DeleteAll(ctx context.Context, remoteName string, filter BackupDeleteOpts) error
   148  	// Create a new backup operation.
   149  	Create(ctx context.Context, remoteName string, request BackupCreate) (string, error)
   150  	// Info retrieves information about a specific backup instance.
   151  	Info(ctx context.Context, remoteName string, request BackupInfoRequest) (*BackupInfo, error)
   152  	// Abort all running backup operations of a resource.
   153  	Abort(ctx context.Context, remoteName string, request BackupAbortRequest) error
   154  	// Ship ships a backup from one LINSTOR cluster to another.
   155  	Ship(ctx context.Context, remoteName string, request BackupShipRequest) (string, error)
   156  	// Restore starts to restore a resource from a backup.
   157  	Restore(ctx context.Context, remoteName string, request BackupRestoreRequest) error
   158  }
   159  
   160  var _ BackupProvider = &BackupService{}
   161  
   162  type BackupService struct {
   163  	client *Client
   164  }
   165  
   166  func (b *BackupService) GetAll(ctx context.Context, remoteName string, rscName string, snapName string) (*BackupList, error) {
   167  	vals, err := query.Values(struct {
   168  		ResourceName string `url:"rsc_name,omitempty"`
   169  		SnapshotName string `url:"snap_name,omitempty"`
   170  	}{ResourceName: rscName, SnapshotName: snapName})
   171  	if err != nil {
   172  		return nil, fmt.Errorf("failed to encode resource names: %w", err)
   173  	}
   174  
   175  	var list BackupList
   176  	_, err = b.client.doGET(ctx, "/v1/remotes/"+remoteName+"/backups?"+vals.Encode(), &list)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	return &list, err
   181  }
   182  
   183  func (b *BackupService) DeleteAll(ctx context.Context, remoteName string, filter BackupDeleteOpts) error {
   184  	vals, err := query.Values(filter)
   185  	if err != nil {
   186  		return fmt.Errorf("failed to encode filter options: %w", err)
   187  	}
   188  
   189  	_, err = b.client.doDELETE(ctx, "/v1/remotes/"+remoteName+"/backups?"+vals.Encode(), nil)
   190  	return err
   191  }
   192  
   193  func (b *BackupService) Create(ctx context.Context, remoteName string, request BackupCreate) (string, error) {
   194  	req, err := b.client.newRequest(http.MethodPost, "/v1/remotes/"+remoteName+"/backups", request)
   195  	if err != nil {
   196  		return "", err
   197  	}
   198  
   199  	var resp []ApiCallRc
   200  	_, err = b.client.do(ctx, req, &resp)
   201  	if err != nil {
   202  		return "", err
   203  	}
   204  
   205  	for _, rc := range resp {
   206  		if s, ok := rc.ObjRefs["Snapshot"]; ok {
   207  			return s, nil
   208  		}
   209  	}
   210  
   211  	return "", errors.New("missing snapshot reference")
   212  }
   213  
   214  func (b *BackupService) Info(ctx context.Context, remoteName string, request BackupInfoRequest) (*BackupInfo, error) {
   215  	req, err := b.client.newRequest(http.MethodPost, "/v1/remotes/"+remoteName+"/backups/info", request)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	var resp BackupInfo
   221  	_, err = b.client.do(ctx, req, &resp)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	return &resp, nil
   227  }
   228  
   229  func (b *BackupService) Abort(ctx context.Context, remoteName string, request BackupAbortRequest) error {
   230  	_, err := b.client.doPOST(ctx, "/v1/remotes/"+remoteName+"/backups/abort", request)
   231  	return err
   232  }
   233  
   234  func (b *BackupService) Ship(ctx context.Context, remoteName string, request BackupShipRequest) (string, error) {
   235  	req, err := b.client.newRequest(http.MethodPost, "/v1/remotes/"+remoteName+"/backups/ship", request)
   236  	if err != nil {
   237  		return "", err
   238  	}
   239  
   240  	var resp []ApiCallRc
   241  	_, err = b.client.do(ctx, req, &resp)
   242  	if err != nil {
   243  		return "", err
   244  	}
   245  
   246  	for _, rc := range resp {
   247  		// LINSTOR will report the name of the created (local) snapshot in one of the messages.
   248  		// There may be multiple such references, but the name of the snapshot stays the same.
   249  		if s, ok := rc.ObjRefs["Snapshot"]; ok {
   250  			return s, nil
   251  		}
   252  	}
   253  
   254  	return "", errors.New("missing snapshot reference")
   255  }
   256  
   257  func (b *BackupService) Restore(ctx context.Context, remoteName string, request BackupRestoreRequest) error {
   258  	_, err := b.client.doPOST(ctx, "/v1/remotes/"+remoteName+"/backups/restore", request)
   259  	return err
   260  }
   261  

View as plain text