Skip to content

Commit 2a5c766

Browse files
authored
Merge pull request #72 from amberxu25/FMEFLOWCLI-75
implement backup cmd for v4
2 parents b83db21 + b360bb5 commit 2a5c766

4 files changed

Lines changed: 375 additions & 93 deletions

File tree

cmd/backup.go

Lines changed: 186 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1729
type 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

2740
type BackupResource struct {
2841
Id int `json:"id"`
2942
}
3043

44+
var backupV4BuildThreshold = 25208
45+
3146
// backupCmd represents the backup command
3247
func 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

Comments
 (0)