mirror of
https://github.com/kopia/kopia.git
synced 2026-03-12 11:16:25 -04:00
* server: repro for zero-sized snapshot bug As described in https://kopia.discourse.group/t/kopia-0-7-0-not-backing-up-any-files-repro-needed/136/5 * server: fixed zero-sized snapshots after repository is connected via API The root cause was that source manager was inheriting HTTP call context which was immediately closed after the 'connect' RPC returned thus silently killing all uploads.
125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"os"
|
|
"sort"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/internal/serverapi"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/snapshot"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
func (s *Server) handleSourcesList(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
_, multiUser := s.rep.(*repo.DirectRepository)
|
|
|
|
resp := &serverapi.SourcesResponse{
|
|
Sources: []*serverapi.SourceStatus{},
|
|
LocalHost: s.rep.ClientOptions().Hostname,
|
|
LocalUsername: s.rep.ClientOptions().Username,
|
|
MultiUser: multiUser,
|
|
}
|
|
|
|
for _, v := range s.sourceManagers {
|
|
if !sourceMatchesURLFilter(v.src, r.URL.Query()) {
|
|
continue
|
|
}
|
|
|
|
resp.Sources = append(resp.Sources, v.Status())
|
|
}
|
|
|
|
sort.Slice(resp.Sources, func(i, j int) bool {
|
|
return resp.Sources[i].Source.String() < resp.Sources[j].Source.String()
|
|
})
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Server) handleSourcesCreate(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
var req serverapi.CreateSnapshotSourceRequest
|
|
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "malformed request body")
|
|
}
|
|
|
|
if req.Path == "" {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "missing path")
|
|
}
|
|
|
|
_, err := os.Stat(req.Path)
|
|
if os.IsNotExist(err) {
|
|
return nil, requestError(serverapi.ErrorPathNotFound, "path does not exist")
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
sourceInfo := snapshot.SourceInfo{
|
|
UserName: s.rep.ClientOptions().Username,
|
|
Host: s.rep.ClientOptions().Hostname,
|
|
Path: req.Path,
|
|
}
|
|
|
|
resp := &serverapi.CreateSnapshotSourceResponse{}
|
|
|
|
// ensure we have the policy for this source, otherwise it will not show up in the
|
|
// list of sources at all.
|
|
_, err = policy.GetDefinedPolicy(ctx, s.rep, sourceInfo)
|
|
switch err {
|
|
case nil:
|
|
// already have policy, do nothing
|
|
log(ctx).Debugf("policy for %v already exists", sourceInfo)
|
|
|
|
resp.Created = false
|
|
|
|
case policy.ErrPolicyNotFound:
|
|
resp.Created = true
|
|
// don't have policy - create an empty one
|
|
log(ctx).Debugf("policy for %v not found, creating empty one", sourceInfo)
|
|
|
|
if err = policy.SetPolicy(ctx, s.rep, sourceInfo, &req.InitialPolicy); err != nil {
|
|
return nil, internalServerError(errors.Wrap(err, "unable to set initial policy"))
|
|
}
|
|
|
|
if err = s.rep.Flush(ctx); err != nil {
|
|
return nil, internalServerError(errors.Wrap(err, "unable to flush"))
|
|
}
|
|
|
|
default:
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
// upgrade to exclusive lock to ensure we have source manager
|
|
s.mu.RUnlock()
|
|
s.mu.Lock()
|
|
if s.sourceManagers[sourceInfo] == nil {
|
|
log(ctx).Debugf("creating source manager for %v", sourceInfo)
|
|
sm := newSourceManager(sourceInfo, s)
|
|
s.sourceManagers[sourceInfo] = sm
|
|
|
|
go sm.run(ctx)
|
|
}
|
|
s.mu.Unlock()
|
|
s.mu.RLock()
|
|
|
|
manager := s.sourceManagers[sourceInfo]
|
|
if manager == nil {
|
|
return nil, internalServerError(errors.Errorf("could not find source manager that was just created"))
|
|
}
|
|
|
|
if req.CreateSnapshot {
|
|
resp.SnapshotStarted = true
|
|
|
|
log(ctx).Debugf("scheduling snapshot of %v immediately...", sourceInfo)
|
|
manager.scheduleSnapshotNow()
|
|
}
|
|
|
|
return resp, nil
|
|
}
|