github.com/weaviate/weaviate@v1.24.6/adapters/clients/cluster_backups.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package clients
    13  
    14  import (
    15  	"bytes"
    16  	"context"
    17  	"encoding/json"
    18  	"fmt"
    19  	"io"
    20  	"net/http"
    21  	"net/url"
    22  
    23  	"github.com/weaviate/weaviate/usecases/backup"
    24  )
    25  
    26  const (
    27  	pathCanCommit = "/backups/can-commit"
    28  	pathCommit    = "/backups/commit"
    29  	pathStatus    = "/backups/status"
    30  	pathAbort     = "/backups/abort"
    31  )
    32  
    33  type ClusterBackups struct {
    34  	client *http.Client
    35  }
    36  
    37  func NewClusterBackups(client *http.Client) *ClusterBackups {
    38  	return &ClusterBackups{client: client}
    39  }
    40  
    41  func (c *ClusterBackups) CanCommit(ctx context.Context,
    42  	host string, req *backup.Request,
    43  ) (*backup.CanCommitResponse, error) {
    44  	url := url.URL{Scheme: "http", Host: host, Path: pathCanCommit}
    45  
    46  	b, err := json.Marshal(req)
    47  	if err != nil {
    48  		return nil, fmt.Errorf("marshal can-commit request: %w", err)
    49  	}
    50  
    51  	httpReq, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(b))
    52  	if err != nil {
    53  		return nil, fmt.Errorf("new can-commit request: %w", err)
    54  	}
    55  
    56  	respBody, statusCode, err := c.do(httpReq)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("can-commit request: %w", err)
    59  	}
    60  
    61  	if statusCode != http.StatusOK {
    62  		return nil, fmt.Errorf("unexpected status code %d (%s)",
    63  			statusCode, respBody)
    64  	}
    65  
    66  	var resp backup.CanCommitResponse
    67  	err = json.Unmarshal(respBody, &resp)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("unmarshal can-commit response: %w", err)
    70  	}
    71  
    72  	return &resp, nil
    73  }
    74  
    75  func (c *ClusterBackups) Commit(ctx context.Context,
    76  	host string, req *backup.StatusRequest,
    77  ) error {
    78  	url := url.URL{Scheme: "http", Host: host, Path: pathCommit}
    79  
    80  	b, err := json.Marshal(req)
    81  	if err != nil {
    82  		return fmt.Errorf("marshal commit request: %w", err)
    83  	}
    84  
    85  	httpReq, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(b))
    86  	if err != nil {
    87  		return fmt.Errorf("new commit request: %w", err)
    88  	}
    89  
    90  	respBody, statusCode, err := c.do(httpReq)
    91  	if err != nil {
    92  		return fmt.Errorf("commit request: %w", err)
    93  	}
    94  
    95  	if statusCode != http.StatusCreated {
    96  		return fmt.Errorf("unexpected status code %d (%s)",
    97  			statusCode, respBody)
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  func (c *ClusterBackups) Status(ctx context.Context,
   104  	host string, req *backup.StatusRequest,
   105  ) (*backup.StatusResponse, error) {
   106  	url := url.URL{Scheme: "http", Host: host, Path: pathStatus}
   107  
   108  	b, err := json.Marshal(req)
   109  	if err != nil {
   110  		return nil, fmt.Errorf("marshal status request: %w", err)
   111  	}
   112  
   113  	httpReq, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(b))
   114  	if err != nil {
   115  		return nil, fmt.Errorf("new status request: %w", err)
   116  	}
   117  
   118  	respBody, statusCode, err := c.do(httpReq)
   119  	if err != nil {
   120  		return nil, fmt.Errorf("status request: %w", err)
   121  	}
   122  
   123  	if statusCode != http.StatusOK {
   124  		return nil, fmt.Errorf("unexpected status code %d (%s)",
   125  			statusCode, respBody)
   126  	}
   127  
   128  	var resp backup.StatusResponse
   129  	err = json.Unmarshal(respBody, &resp)
   130  	if err != nil {
   131  		return nil, fmt.Errorf("unmarshal status response: %w", err)
   132  	}
   133  
   134  	return &resp, nil
   135  }
   136  
   137  func (c *ClusterBackups) Abort(_ context.Context,
   138  	host string, req *backup.AbortRequest,
   139  ) error {
   140  	url := url.URL{Scheme: "http", Host: host, Path: pathAbort}
   141  
   142  	b, err := json.Marshal(req)
   143  	if err != nil {
   144  		return fmt.Errorf("marshal abort request: %w", err)
   145  	}
   146  
   147  	httpReq, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(b))
   148  	if err != nil {
   149  		return fmt.Errorf("new abort request: %w", err)
   150  	}
   151  
   152  	respBody, statusCode, err := c.do(httpReq)
   153  	if err != nil {
   154  		return fmt.Errorf("abort request: %w", err)
   155  	}
   156  
   157  	if statusCode != http.StatusNoContent {
   158  		return fmt.Errorf("unexpected status code %d (%s)",
   159  			statusCode, respBody)
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func (c *ClusterBackups) do(req *http.Request) (body []byte, statusCode int, err error) {
   166  	httpResp, err := c.client.Do(req)
   167  	if err != nil {
   168  		return nil, 0, fmt.Errorf("make request: %w", err)
   169  	}
   170  
   171  	body, err = io.ReadAll(httpResp.Body)
   172  	if err != nil {
   173  		return nil, httpResp.StatusCode, fmt.Errorf("read response: %w", err)
   174  	}
   175  	defer httpResp.Body.Close()
   176  
   177  	return body, httpResp.StatusCode, nil
   178  }