@@ -12,8 +12,20 @@ import (
1212 "strings"
1313
1414 "github.com/spf13/cobra"
15+ "github.com/spf13/viper"
1516)
1617
18+ type backupDownloadV4 struct {
19+ PackageName string `json:"packageName"`
20+ }
21+
22+ type backupResourceV4 struct {
23+ ResourceName string `json:"resourceName"`
24+ PackagePath string `json:"packagePath"`
25+ SuccessTopic string `json:"successTopic"`
26+ FailureTopic string `json:"failureTopic"`
27+ }
28+
1729type backupFlags struct {
1830 outputBackupFile string
1931 backupResourceName string
@@ -22,12 +34,15 @@ type backupFlags struct {
2234 backupSuccessTopic string
2335 backupResource bool
2436 suppressFileRename bool
37+ apiVersion apiVersionFlag
2538}
2639
2740type BackupResource struct {
2841 Id int `json:"id"`
2942}
3043
44+ var backupV4BuildThreshold = 25208
45+
3146// backupCmd represents the backup command
3247func newBackupCmd () * cobra.Command {
3348 f := backupFlags {}
@@ -52,9 +67,10 @@ func newBackupCmd() *cobra.Command {
5267 cmd .Flags ().BoolVar (& f .backupResource , "resource" , false , "Backup to a shared resource instead of downloading." )
5368 cmd .Flags ().StringVar (& f .backupResourceName , "resource-name" , "FME_SHAREDRESOURCE_BACKUP" , "Shared Resource Name where the exported package is saved." )
5469 cmd .Flags ().StringVar (& f .backupExportPackage , "export-package" , "ServerConfigPackage.fsconfig" , "Path and name of the export package." )
55- cmd .Flags ().StringVar (& f .backupFailureTopic , "failure-topic" , "" , "Topic to notify on failure of the backup. Default is MIGRATION_ASYNC_JOB_FAILURE" )
56- cmd .Flags ().StringVar (& f .backupSuccessTopic , "success-topic" , "" , "Topic to notify on success of the backup. Default is MIGRATION_ASYNC_JOB_SUCCESS" )
70+ cmd .Flags ().StringVar (& f .backupFailureTopic , "failure-topic" , "" , "Topic to notify on failure of the backup. In V3, default is MIGRATION_ASYNC_JOB_FAILURE" )
71+ cmd .Flags ().StringVar (& f .backupSuccessTopic , "success-topic" , "" , "Topic to notify on success of the backup. In V3, default is MIGRATION_ASYNC_JOB_SUCCESS" )
5772 cmd .Flags ().BoolVar (& f .suppressFileRename , "suppress-file-rename" , false , "Specify this flag to not add .fsconfig to the output file automatically" )
73+ cmd .Flags ().Var (& f .apiVersion , "api-version" , "The api version to use when contacting FME Server. Must be one of v3 or v4" )
5874 cmd .MarkFlagsMutuallyExclusive ("file" , "resource" )
5975 cmd .MarkFlagsMutuallyExclusive ("file" , "resource-name" )
6076 cmd .MarkFlagsMutuallyExclusive ("file" , "export-package" )
@@ -77,91 +93,194 @@ func backupRun(f *backupFlags) func(cmd *cobra.Command, args []string) error {
7793 }
7894 }
7995
80- if ! f . backupResource {
81-
82- // add mandatory values
83- data := url. Values {
84- "exportPackageName" : { f . outputBackupFile },
96+ if f . apiVersion == "" {
97+ if viper . GetInt ( "build" ) < backupV4BuildThreshold {
98+ f . apiVersion = apiVersionFlagV3
99+ } else {
100+ f . apiVersion = apiVersionFlagV4
85101 }
102+ }
86103
87- request , err := buildFmeFlowRequest ("/fmerest/v3/migration/backup/download" , "POST" , strings .NewReader (data .Encode ()))
88- if err != nil {
89- return err
90- }
104+ if f .apiVersion == apiVersionFlagV4 {
91105
92- request .Header .Add ("Content-Type" , "application/x-www-form-urlencoded" )
93- request .Header .Add ("Accept" , "application/octet-stream" )
106+ if ! f .backupResource {
107+ var backupRequest backupDownloadV4
108+ backupRequest .PackageName = f .outputBackupFile
94109
95- fmt .Fprintln (cmd .OutOrStdout (), "Downloading backup file..." )
110+ requestBody , err := json .Marshal (backupRequest )
111+ if err != nil {
112+ return err
113+ }
96114
97- response , err := client .Do (& request )
98- if err != nil {
99- return err
100- } else if response .StatusCode != 200 {
101- return errors .New (response .Status )
102- }
103- defer response .Body .Close ()
115+ request , err := buildFmeFlowRequest ("/fmeapiv4/migrations/backup/download" , "POST" , strings .NewReader (string (requestBody )))
116+ if err != nil {
117+ return err
118+ }
104119
105- // Create the output file
106- out , err := os .Create (f .outputBackupFile )
107- if err != nil {
108- return err
109- }
110- defer out .Close ()
120+ request .Header .Add ("Content-Type" , "application/json" )
111121
112- // use Copy so that it doesn't store the entire file in memory
113- _ , err = io .Copy (out , response .Body )
114- if err != nil {
115- return err
116- }
122+ fmt .Fprintln (cmd .OutOrStdout (), "Downloading backup file..." )
123+ response , err := client .Do (& request )
124+ if err != nil {
125+ return err
126+ } else if response .StatusCode != 200 {
127+ return errors .New (response .Status )
128+ }
129+ defer response .Body .Close ()
117130
118- fmt .Fprintln (cmd .OutOrStdout (), "FME Server backed up to " + f .outputBackupFile )
119- } else {
120- // backup to a resource
121- // add mandatory values
122- data := url.Values {
123- "exportPackage" : {f .backupExportPackage },
124- "resourceName" : {f .backupResourceName },
125- }
131+ // Create the output file
132+ out , err := os .Create (f .outputBackupFile )
133+ if err != nil {
134+ return err
135+ }
136+ defer out .Close ()
126137
127- // add optional values
128- if f .backupSuccessTopic != "" {
129- data .Add ("successTopic" , f .backupSuccessTopic )
130- }
131- if f .backupFailureTopic != "" {
132- data .Add ("failureTopic" , f .backupFailureTopic )
133- }
138+ // use Copy so that it doesn't store the entire file in memory
139+ _ , err = io .Copy (out , response .Body )
140+ if err != nil {
141+ return err
142+ }
134143
135- request , err := buildFmeFlowRequest ("/fmerest/v3/migration/backup/resource" , "POST" , strings .NewReader (data .Encode ()))
136- if err != nil {
137- return err
138- }
144+ fmt .Fprintln (cmd .OutOrStdout (), "FME Server backed up to " + f .outputBackupFile )
139145
140- request .Header .Add ("Content-Type" , "application/x-www-form-urlencoded" )
146+ } else {
147+ // backup to a resource
148+ var backupRequest backupResourceV4
149+ backupRequest .PackagePath = f .backupExportPackage
150+ backupRequest .ResourceName = f .backupResourceName
151+ if f .backupSuccessTopic != "" {
152+ backupRequest .SuccessTopic = f .backupSuccessTopic
153+ }
154+ if f .backupFailureTopic != "" {
155+ backupRequest .FailureTopic = f .backupFailureTopic
156+ }
157+ requestBody , err := json .Marshal (backupRequest )
158+ if err != nil {
159+ return err
160+ }
161+ request , err := buildFmeFlowRequest ("/fmeapiv4/migrations/backup/resource" , "POST" , strings .NewReader (string (requestBody )))
162+ if err != nil {
163+ return err
164+ }
141165
142- response , err := client .Do (& request )
143- if err != nil {
144- return err
145- } else if response .StatusCode != http .StatusAccepted {
146- return errors .New (response .Status )
147- }
166+ request .Header .Add ("Content-Type" , "application/json" )
167+
168+ response , err := client .Do (& request )
169+ if err != nil {
170+ return err
171+ } else if response .StatusCode != 202 && response .StatusCode != 200 {
172+ if response .StatusCode == 401 {
173+ return errors .New ("failed to login" )
174+ } else {
175+ return errors .New (response .Status )
176+ }
177+ }
178+ responseData , err := io .ReadAll (response .Body )
179+ if err != nil {
180+ return err
181+ }
182+
183+ var result BackupResource
184+ if err := json .Unmarshal (responseData , & result ); err != nil {
185+ return err
186+ } else {
187+ if ! jsonOutput {
188+ fmt .Fprintln (cmd .OutOrStdout (), "Backup task submitted with id: " + strconv .Itoa (result .Id ))
189+ } else {
190+ fmt .Fprintln (cmd .OutOrStdout (), string (responseData ))
191+ }
192+ }
148193
149- responseData , err := io .ReadAll (response .Body )
150- if err != nil {
151- return err
152194 }
153195
154- var result BackupResource
155- if err := json .Unmarshal (responseData , & result ); err != nil {
156- return err
196+ } else if f .apiVersion == apiVersionFlagV3 {
197+ if ! f .backupResource {
198+
199+ // add mandatory values
200+ data := url.Values {
201+ "exportPackageName" : {f .outputBackupFile },
202+ }
203+
204+ request , err := buildFmeFlowRequest ("/fmerest/v3/migration/backup/download" , "POST" , strings .NewReader (data .Encode ()))
205+ if err != nil {
206+ return err
207+ }
208+
209+ request .Header .Add ("Content-Type" , "application/x-www-form-urlencoded" )
210+ request .Header .Add ("Accept" , "application/octet-stream" )
211+
212+ fmt .Fprintln (cmd .OutOrStdout (), "Downloading backup file..." )
213+
214+ response , err := client .Do (& request )
215+ if err != nil {
216+ return err
217+ } else if response .StatusCode != 200 {
218+ return errors .New (response .Status )
219+ }
220+ defer response .Body .Close ()
221+
222+ // Create the output file
223+ out , err := os .Create (f .outputBackupFile )
224+ if err != nil {
225+ return err
226+ }
227+ defer out .Close ()
228+
229+ // use Copy so that it doesn't store the entire file in memory
230+ _ , err = io .Copy (out , response .Body )
231+ if err != nil {
232+ return err
233+ }
234+
235+ fmt .Fprintln (cmd .OutOrStdout (), "FME Server backed up to " + f .outputBackupFile )
157236 } else {
158- if ! jsonOutput {
159- fmt .Fprintln (cmd .OutOrStdout (), "Backup task submitted with id: " + strconv .Itoa (result .Id ))
237+ // backup to a resource
238+ // add mandatory values
239+ data := url.Values {
240+ "exportPackage" : {f .backupExportPackage },
241+ "resourceName" : {f .backupResourceName },
242+ }
243+
244+ // add optional values
245+ if f .backupSuccessTopic != "" {
246+ data .Add ("successTopic" , f .backupSuccessTopic )
247+ }
248+ if f .backupFailureTopic != "" {
249+ data .Add ("failureTopic" , f .backupFailureTopic )
250+ }
251+
252+ request , err := buildFmeFlowRequest ("/fmerest/v3/migration/backup/resource" , "POST" , strings .NewReader (data .Encode ()))
253+ if err != nil {
254+ return err
255+ }
256+
257+ request .Header .Add ("Content-Type" , "application/x-www-form-urlencoded" )
258+
259+ response , err := client .Do (& request )
260+ if err != nil {
261+ return err
262+ } else if response .StatusCode != http .StatusAccepted {
263+ return errors .New (response .Status )
264+ }
265+
266+ responseData , err := io .ReadAll (response .Body )
267+ if err != nil {
268+ return err
269+ }
270+
271+ var result BackupResource
272+ if err := json .Unmarshal (responseData , & result ); err != nil {
273+ return err
160274 } else {
161- fmt .Fprintln (cmd .OutOrStdout (), string (responseData ))
275+ if ! jsonOutput {
276+ fmt .Fprintln (cmd .OutOrStdout (), "Backup task submitted with id: " + strconv .Itoa (result .Id ))
277+ } else {
278+ fmt .Fprintln (cmd .OutOrStdout (), string (responseData ))
279+ }
162280 }
163281 }
164282 }
283+
165284 return nil
166285 }
167286}
0 commit comments