feat(edge/stack): add stack deployment info struct [EE-5523] (#9042)

pull/9123/head
Oscar Zhou 2023-06-26 18:12:15 +12:00 committed by GitHub
parent 89c1d0e337
commit c96e076871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
"github.com/gofrs/uuid"
portainer "github.com/portainer/portainer/api"
"github.com/rs/zerolog/log"
"io"
"os"
@ -316,6 +317,43 @@ func (service *Service) StoreEdgeStackFileFromBytes(edgeStackIdentifier, fileNam
return service.wrapFileStore(stackStorePath), nil
}
// GetEdgeStackProjectPathByVersion returns the absolute path on the FS for a edge stack based
// on its identifier and version.
// EE only feature
func (service *Service) GetEdgeStackProjectPathByVersion(edgeStackIdentifier string, version int) string {
versionStr := fmt.Sprintf("v%d", version)
return JoinPaths(service.wrapFileStore(EdgeStackStorePath), edgeStackIdentifier, versionStr)
}
// StoreEdgeStackFileFromBytesByVersion creates a subfolder in the EdgeStackStorePath with version and stores a new file from bytes.
// It returns the path to the folder where the file is stored.
// EE only feature
func (service *Service) StoreEdgeStackFileFromBytesByVersion(edgeStackIdentifier, fileName string, version int, data []byte) (string, error) {
versionStr := fmt.Sprintf("v%d", version)
stackStorePath := JoinPaths(EdgeStackStorePath, edgeStackIdentifier, versionStr)
err := service.createDirectoryInStore(stackStorePath)
if err != nil {
return "", err
}
composeFilePath := JoinPaths(stackStorePath, fileName)
r := bytes.NewReader(data)
err = service.createFileInStore(composeFilePath, r)
if err != nil {
return "", err
}
return service.wrapFileStore(stackStorePath), nil
}
// FormProjectPathByVersion returns the absolute path on the FS for a project based with version
func (service *Service) FormProjectPathByVersion(path string, version int) string {
versionStr := fmt.Sprintf("v%d", version)
return JoinPaths(path, versionStr)
}
// StoreRegistryManagementFileFromBytes creates a subfolder in the
// ExtensionRegistryManagementStorePath and stores a new file from bytes.
// It returns the path to the folder where the file is stored.
@ -734,6 +772,56 @@ func FileExists(filePath string) (bool, error) {
return true, nil
}
// SafeCopyDirectory copies a directory from src to dst in a safe way.
func (service *Service) SafeMoveDirectory(originalPath, newPath string) error {
// 1. Backup the source directory to a different folder
backupDir := fmt.Sprintf("%s-%s", filepath.Dir(originalPath), "backup")
err := MoveDirectory(originalPath, backupDir)
if err != nil {
return fmt.Errorf("failed to backup source directory: %w", err)
}
defer func() {
if err != nil {
// If an error occurred, rollback the backup directory
restoreErr := restoreBackup(originalPath, backupDir)
if restoreErr != nil {
log.Warn().Err(restoreErr).Msg("failed to restore backup during creating versioning folder")
}
}
}()
// 2. Copy the backup directory to the destination directory
err = CopyDir(backupDir, newPath, false)
if err != nil {
return fmt.Errorf("failed to copy backup directory to destination directory: %w", err)
}
// 3. Delete the backup directory
err = os.RemoveAll(backupDir)
if err != nil {
return fmt.Errorf("failed to delete backup directory: %w", err)
}
return nil
}
func restoreBackup(src, backupDir string) error {
// Rollback by deleting the original directory and copying the
// backup direcotry back to the source directory, and then deleting
// the backup directory
err := os.RemoveAll(src)
if err != nil {
return fmt.Errorf("failed to delete destination directory: %w", err)
}
err = MoveDirectory(backupDir, src)
if err != nil {
return fmt.Errorf("failed to restore backup directory: %w", err)
}
return nil
}
func MoveDirectory(originalPath, newPath string) error {
if _, err := os.Stat(originalPath); err != nil {
return err

View File

@ -299,6 +299,12 @@ type (
Endpoints []EndpointID `json:"Endpoints"`
}
// StackDeploymentInfo records the information of a deployed stack
StackDeploymentInfo struct {
Version int `json:"Version"`
ConfigHash string `json:"ConfigHash"`
}
//EdgeStack represents an edge stack
EdgeStack struct {
// EdgeStack Identifier
@ -340,6 +346,8 @@ type (
Details EdgeStackStatusDetails `json:"Details"`
Error string `json:"Error"`
EndpointID EndpointID `json:"EndpointID"`
// EE only feature
DeploymentInfo StackDeploymentInfo `json:"DeploymentInfo"`
// Deprecated
Type EdgeStackStatusType `json:"Type"`
@ -1380,6 +1388,10 @@ type (
RollbackStackFile(stackIdentifier, fileName string) error
GetEdgeStackProjectPath(edgeStackIdentifier string) string
StoreEdgeStackFileFromBytes(edgeStackIdentifier, fileName string, data []byte) (string, error)
GetEdgeStackProjectPathByVersion(edgeStackIdentifier string, version int) string
StoreEdgeStackFileFromBytesByVersion(edgeStackIdentifier, fileName string, version int, data []byte) (string, error)
FormProjectPathByVersion(projectIdentifier string, version int) string
SafeMoveDirectory(src, dst string) error
StoreRegistryManagementFileFromBytes(folder, fileName string, data []byte) (string, error)
KeyPairFilesExist() (bool, error)
StoreKeyPair(private, public []byte, privatePEMHeader, publicPEMHeader string) error