flamenco/pkg/shaman/checkout/checkout.go
Sybren A. Stüvel f413a40f4e Store Shaman checkout ID when submitting a job
If Shaman is used to submit the job files, store the job's checkout ID
(i.e. the path relative to the checkout root) in the database. This will
make it possible in the future to remove the Shaman checkout along with
the job itself.
2023-01-04 01:18:21 +01:00

75 lines
2.2 KiB
Go

package checkout
// SPDX-License-Identifier: GPL-3.0-or-later
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"git.blender.org/flamenco/pkg/api"
"git.blender.org/flamenco/pkg/shaman/filestore"
"github.com/rs/zerolog"
)
var (
ErrMissingFiles = errors.New("unknown files requested in checkout")
validCheckoutRegexp = regexp.MustCompile(`^[^/?*:;{}\\][^?*:;{}\\]*$`)
)
// Checkout symlinks the requested files into the checkout directory.
// Returns the actually-used checkout directory, relative to the configured checkout root.
func (m *Manager) Checkout(ctx context.Context, checkout api.ShamanCheckout) (string, error) {
logger := (*zerolog.Ctx(ctx))
logger.Debug().
Str("checkoutPath", checkout.CheckoutPath).
Msg("shaman: user requested checkout creation")
// Actually create the checkout.
resolvedCheckoutInfo, err := m.PrepareCheckout(checkout.CheckoutPath)
if err != nil {
return "", err
}
logger = logger.With().Str("checkoutPath", resolvedCheckoutInfo.RelativePath).Logger()
// The checkout directory was created, so if anything fails now, it should be erased.
var checkoutOK bool
defer func() {
if !checkoutOK {
err := m.EraseCheckout(checkout.CheckoutPath)
if err != nil {
logger.Error().Err(err).Msg("shaman: error erasing checkout directory")
}
}
}()
for _, fileSpec := range checkout.Files {
blobPath, status := m.fileStore.ResolveFile(fileSpec.Sha, int64(fileSpec.Size), filestore.ResolveStoredOnly)
if status != filestore.StatusStored {
// Caller should upload this file before we can create the checkout.
return "", ErrMissingFiles
}
if err := m.SymlinkToCheckout(blobPath, resolvedCheckoutInfo.absolutePath, fileSpec.Path); err != nil {
return "", fmt.Errorf("symlinking %q to checkout: %w", fileSpec.Path, err)
}
}
checkoutOK = true // Prevent the checkout directory from being erased again.
logger.Info().Msg("shaman: checkout created")
return resolvedCheckoutInfo.RelativePath, nil
}
func isValidCheckoutPath(checkoutPath string) bool {
if !validCheckoutRegexp.MatchString(checkoutPath) {
return false
}
if strings.Contains(checkoutPath, "../") || strings.Contains(checkoutPath, "/..") {
return false
}
return true
}