@@ -2,35 +2,147 @@ package system
22
33import (
44 "fmt"
5+ log "github.com/sirupsen/logrus"
56
67 xfs "github.com/saitho/golang-extended-fs/v2"
78)
89
9- func ApplyResourceOperation (resource Resource , ignoreBackup bool ) (bool , error ) {
10- return PerformOperation (resource , ignoreBackup )
10+ func ApplyResourceOperation (resource * Resource , ignoreBackup bool ) (bool , error ) {
11+ if ! ignoreBackup {
12+ // Backup existing file
13+ backupPath , err := backupResource (resource )
14+ if err != nil {
15+ return true , err
16+ }
17+ fmt .Println (backupPath )
18+ }
19+ return PerformOperation (resource )
1120}
1221
13- func RollbackResourceOperation (resource Resource , ignoreBackup bool ) (bool , error ) {
22+ func RollbackResourceOperation (resource * Resource , ignoreBackup bool ) (bool , error ) {
1423 if resource .Operation == OperationCreate {
1524 resource .Operation = OperationDelete
16- return PerformOperation (resource , ignoreBackup )
25+ found , err := PerformOperation (resource )
26+ if err != nil {
27+ return found , err
28+ }
29+ if ! ignoreBackup {
30+ // Restore backup
31+ if err = restoreBackup (resource ); err != nil {
32+ return found , err
33+ }
34+ }
35+ return found , err
1736 }
1837 return true , fmt .Errorf (fmt .Sprintf ("unupported rollback for operation %s" , resource .Operation ))
1938}
2039
21- func PerformOperation (resource Resource , ignoreBackup bool ) (bool , error ) {
40+ func backupResource (resource * Resource ) (string , error ) {
41+ // && resource.Type != TypeLink todo: make it available for symlinks again
42+ // issue with symlinks: cannot stat symlink: permission denied
43+ if resource .Type != TypeFile && resource .Type != TypeFolder {
44+ return "" , nil
45+ }
46+ if ! resource .ExternalResource {
47+ return "" , nil
48+ }
49+ resourceFilePath , err := Context .CurrentDeployment .GetResourcePath (resource )
50+ if err != nil {
51+ return "" , err
52+ }
53+ log .Info ("Creating backup of resource " + resourceFilePath )
54+ backupFilePath := resourceFilePath + ".bak"
55+ xfsFilePath := "ssh://" + resourceFilePath
56+ switch resource .Type {
57+ case TypeFile :
58+ hasFile , err := xfs .HasFile (xfsFilePath )
59+ if err != nil {
60+ return "" , fmt .Errorf ("unable to check status of file %s: %s" , resourceFilePath , err )
61+ }
62+ if ! hasFile {
63+ return "" , nil
64+ }
65+ if _ , err = SimpleRemoteRun ("cp" , RemoteRunOpts {Args : []string {resourceFilePath , backupFilePath }}); err != nil {
66+ return backupFilePath , fmt .Errorf ("unable to backup file %s: %s" , resourceFilePath , err )
67+ }
68+ return backupFilePath , nil
69+ case TypeLink :
70+ hasFile , err := xfs .HasLink (xfsFilePath )
71+ if err != nil {
72+ return "" , fmt .Errorf ("unable to check status of link %s: %s" , resourceFilePath , err )
73+ }
74+ if ! hasFile {
75+ return "" , nil
76+ }
77+ if _ , err = SimpleRemoteRun ("cp" , RemoteRunOpts {Args : []string {resourceFilePath , backupFilePath }}); err != nil {
78+ return backupFilePath , fmt .Errorf ("unable to backup link %s: %s" , resourceFilePath , err )
79+ }
80+ return backupFilePath , nil
81+ case TypeFolder :
82+ hasFolder , err := xfs .HasFolder (xfsFilePath )
83+ if err != nil {
84+ return "" , fmt .Errorf ("unable to check status of folder %s: %s" , resourceFilePath , err )
85+ }
86+ if ! hasFolder {
87+ return "" , nil
88+ }
89+ if _ , err = SimpleRemoteRun ("cp" , RemoteRunOpts {Args : []string {"-R" , resourceFilePath , backupFilePath }}); err != nil {
90+ return backupFilePath , fmt .Errorf ("unable to backup folder %s: %s" , resourceFilePath , err )
91+ }
92+ return backupFilePath , nil
93+ }
94+ return "" , fmt .Errorf ("unknown backup handler for resource type %s" , resource .Type )
95+ }
96+
97+ func restoreBackup (resource * Resource ) error {
98+ if resource .Type != TypeFile && resource .Type != TypeFolder && resource .Type != TypeLink {
99+ return nil
100+ }
101+ if resource .BackupFilePath == "" {
102+ return nil
103+ }
22104 resourceFilePath , _ := Context .CurrentDeployment .GetResourcePath (resource )
105+ xfsBackupFilePath := "ssh://" + resource .BackupFilePath
106+ log .Info ("Restoring backup of resource " + resourceFilePath )
107+
108+ switch resource .Type {
109+ case TypeFile , TypeLink :
110+ hasFile , err := xfs .HasFile (xfsBackupFilePath )
111+ if err != nil {
112+ return err
113+ }
114+ if ! hasFile {
115+ return fmt .Errorf ("backup not found for " + resource .Name )
116+ }
117+ return xfs .CopyFile (xfsBackupFilePath , "ssh://" + resourceFilePath )
118+ case TypeFolder :
119+ backupFileName := "ssh://" + resourceFilePath + ".bak"
120+ hasFolder , err := xfs .HasFolder (backupFileName )
121+ if err != nil {
122+ return err
123+ }
124+ if ! hasFolder {
125+ return fmt .Errorf ("backup not found for " + resource .Name )
126+ }
127+ if _ , err = SimpleRemoteRun ("cp" , RemoteRunOpts {Args : []string {"-R" , backupFileName , resourceFilePath }}); err != nil {
128+ return err
129+ }
130+ return nil
131+ }
132+ return fmt .Errorf ("unknown restore backup handler for resource type %s" , resource .Type )
133+ }
134+
135+ func PerformOperation (resource * Resource ) (bool , error ) {
136+ resourceFilePath , _ := Context .CurrentDeployment .GetResourcePath (resource )
137+ xfsResourceFilePath := "ssh://" + resourceFilePath
23138 switch resource .Type {
24139 case TypeFile :
25140 if resource .Operation == OperationCreate {
26- // TODO: backup if file exists
27- if err := xfs .WriteFile ("ssh://" + resourceFilePath , resource .Content ); err != nil {
141+ if err := xfs .WriteFile (xfsResourceFilePath , resource .Content ); err != nil {
28142 return true , fmt .Errorf ("unable to create file at %s: %s" , resource .Name , err )
29143 }
30144 } else if resource .Operation == OperationDelete {
31- // TODO: restore backup if file exists
32- resourcePath , _ := Context .CurrentDeployment .GetResourcePath (resource )
33- if err := xfs .DeleteFile ("ssh://" + resourcePath ); err != nil {
145+ if err := xfs .DeleteFile (xfsResourceFilePath ); err != nil {
34146 if err .Error () == "file does not exist" {
35147 return true , nil
36148 }
@@ -40,13 +152,11 @@ func PerformOperation(resource Resource, ignoreBackup bool) (bool, error) {
40152 return true , nil
41153 case TypeFolder :
42154 if resource .Operation == OperationCreate {
43- // TODO: backup if file exists
44- if err := xfs .CreateFolder ("ssh://" + resourceFilePath ); err != nil {
155+ if err := xfs .CreateFolder (xfsResourceFilePath ); err != nil {
45156 return true , fmt .Errorf ("unable to create folder at %s: %s" , resource .Name , err )
46157 }
47158 } else if resource .Operation == OperationDelete {
48- // TODO: restore backup if file exists
49- if err := xfs .DeleteFolder ("ssh://" + resourceFilePath , true ); err != nil {
159+ if err := xfs .DeleteFolder (xfsResourceFilePath , true ); err != nil {
50160 return true , fmt .Errorf ("unable to remove folder at %s: %s" , resource .Name , err )
51161 }
52162 }
@@ -61,14 +171,14 @@ func PerformOperation(resource Resource, ignoreBackup bool) (bool, error) {
61171 return true , fmt .Errorf ("Unable to symlink " + resource .LinkSource + " -> " + resourceFilePath + ": " + err .Error ())
62172 }
63173 } else if resource .Operation == OperationDelete {
64- // TODO: restore backup if file exists
65- if err := xfs .DeleteFile ("ssh://" + resourceFilePath ); err != nil {
174+ if err := xfs .DeleteFile (xfsResourceFilePath ); err != nil {
66175 if err .Error () == "file does not exist" {
67176 return true , nil
68177 }
69178 return true , fmt .Errorf ("unable to remove symlink at %s: %s" , resource .Name , err )
70179 }
71180 }
181+ return true , nil
72182 }
73183 // CONTAINER via ResourceGroup (see StackHead container module)
74184 return false , nil
0 commit comments