@@ -2,35 +2,147 @@ package system
2
2
3
3
import (
4
4
"fmt"
5
+ log "github.com/sirupsen/logrus"
5
6
6
7
xfs "github.com/saitho/golang-extended-fs/v2"
7
8
)
8
9
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 )
11
20
}
12
21
13
- func RollbackResourceOperation (resource Resource , ignoreBackup bool ) (bool , error ) {
22
+ func RollbackResourceOperation (resource * Resource , ignoreBackup bool ) (bool , error ) {
14
23
if resource .Operation == OperationCreate {
15
24
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
17
36
}
18
37
return true , fmt .Errorf (fmt .Sprintf ("unupported rollback for operation %s" , resource .Operation ))
19
38
}
20
39
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
+ }
22
104
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
23
138
switch resource .Type {
24
139
case TypeFile :
25
140
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 {
28
142
return true , fmt .Errorf ("unable to create file at %s: %s" , resource .Name , err )
29
143
}
30
144
} 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 {
34
146
if err .Error () == "file does not exist" {
35
147
return true , nil
36
148
}
@@ -40,13 +152,11 @@ func PerformOperation(resource Resource, ignoreBackup bool) (bool, error) {
40
152
return true , nil
41
153
case TypeFolder :
42
154
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 {
45
156
return true , fmt .Errorf ("unable to create folder at %s: %s" , resource .Name , err )
46
157
}
47
158
} 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 {
50
160
return true , fmt .Errorf ("unable to remove folder at %s: %s" , resource .Name , err )
51
161
}
52
162
}
@@ -61,14 +171,14 @@ func PerformOperation(resource Resource, ignoreBackup bool) (bool, error) {
61
171
return true , fmt .Errorf ("Unable to symlink " + resource .LinkSource + " -> " + resourceFilePath + ": " + err .Error ())
62
172
}
63
173
} 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 {
66
175
if err .Error () == "file does not exist" {
67
176
return true , nil
68
177
}
69
178
return true , fmt .Errorf ("unable to remove symlink at %s: %s" , resource .Name , err )
70
179
}
71
180
}
181
+ return true , nil
72
182
}
73
183
// CONTAINER via ResourceGroup (see StackHead container module)
74
184
return false , nil
0 commit comments