mirror of https://github.com/portainer/portainer
feat(edge/stack): add stack deployment info struct [EE-5523] (#9042)
parent
89c1d0e337
commit
c96e076871
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -316,6 +317,43 @@ func (service *Service) StoreEdgeStackFileFromBytes(edgeStackIdentifier, fileNam
|
||||||
return service.wrapFileStore(stackStorePath), nil
|
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
|
// StoreRegistryManagementFileFromBytes creates a subfolder in the
|
||||||
// ExtensionRegistryManagementStorePath and stores a new file from bytes.
|
// ExtensionRegistryManagementStorePath and stores a new file from bytes.
|
||||||
// It returns the path to the folder where the file is stored.
|
// 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
|
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 {
|
func MoveDirectory(originalPath, newPath string) error {
|
||||||
if _, err := os.Stat(originalPath); err != nil {
|
if _, err := os.Stat(originalPath); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -299,6 +299,12 @@ type (
|
||||||
Endpoints []EndpointID `json:"Endpoints"`
|
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 represents an edge stack
|
||||||
EdgeStack struct {
|
EdgeStack struct {
|
||||||
// EdgeStack Identifier
|
// EdgeStack Identifier
|
||||||
|
@ -340,6 +346,8 @@ type (
|
||||||
Details EdgeStackStatusDetails `json:"Details"`
|
Details EdgeStackStatusDetails `json:"Details"`
|
||||||
Error string `json:"Error"`
|
Error string `json:"Error"`
|
||||||
EndpointID EndpointID `json:"EndpointID"`
|
EndpointID EndpointID `json:"EndpointID"`
|
||||||
|
// EE only feature
|
||||||
|
DeploymentInfo StackDeploymentInfo `json:"DeploymentInfo"`
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
Type EdgeStackStatusType `json:"Type"`
|
Type EdgeStackStatusType `json:"Type"`
|
||||||
|
@ -1380,6 +1388,10 @@ type (
|
||||||
RollbackStackFile(stackIdentifier, fileName string) error
|
RollbackStackFile(stackIdentifier, fileName string) error
|
||||||
GetEdgeStackProjectPath(edgeStackIdentifier string) string
|
GetEdgeStackProjectPath(edgeStackIdentifier string) string
|
||||||
StoreEdgeStackFileFromBytes(edgeStackIdentifier, fileName string, data []byte) (string, error)
|
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)
|
StoreRegistryManagementFileFromBytes(folder, fileName string, data []byte) (string, error)
|
||||||
KeyPairFilesExist() (bool, error)
|
KeyPairFilesExist() (bool, error)
|
||||||
StoreKeyPair(private, public []byte, privatePEMHeader, publicPEMHeader string) error
|
StoreKeyPair(private, public []byte, privatePEMHeader, publicPEMHeader string) error
|
||||||
|
|
Loading…
Reference in New Issue