@@ -113,14 +113,11 @@ func (r *Rclone) Mount(ctx context.Context, rcloneVolume *RcloneVolume, targetPa
113113 requestBody := bytes .NewBuffer (postBody )
114114 resp , err := http .Post (fmt .Sprintf ("http://localhost:%d/config/create" , r .port ), "application/json" , requestBody )
115115 if err != nil {
116- return fmt .Errorf ("mounting failed: err : %s " , err )
116+ return fmt .Errorf ("mounting failed: couldn't send HTTP request to create config : %w " , err )
117117 }
118- if resp .StatusCode != 200 {
119- body , err := io .ReadAll (resp .Body )
120- if err != nil {
121- return err
122- }
123- return fmt .Errorf ("mounting failed: couldn't create config: %s" , string (body ))
118+ err = checkResponse (resp )
119+ if err != nil {
120+ return fmt .Errorf ("mounting failed: couldn't create config: %w" , err )
124121 }
125122 klog .Infof ("created config: %s" , configName )
126123
@@ -152,19 +149,14 @@ func (r *Rclone) Mount(ctx context.Context, rcloneVolume *RcloneVolume, targetPa
152149 requestBody = bytes .NewBuffer (postBody )
153150 resp , err = http .Post (fmt .Sprintf ("http://localhost:%d/mount/mount" , r .port ), "application/json" , requestBody )
154151 if err != nil {
155- return fmt .Errorf ("mounting failed: err : %s " , err )
152+ return fmt .Errorf ("mounting failed: couldn't send HTTP request to create mount : %w " , err )
156153 }
157- if resp .StatusCode != 200 {
158- body , err := io .ReadAll (resp .Body )
159- if err != nil {
160- return err
161- }
162- return fmt .Errorf ("mounting failed: couldn't create mount: %s" , string (body ))
154+ err = checkResponse (resp )
155+ if err != nil {
156+ return fmt .Errorf ("mounting failed: couldn't create mount: %w" , err )
163157 }
164158 klog .Infof ("created mount: %s" , configName )
165159
166- defer resp .Body .Close ()
167-
168160 return nil
169161}
170162
@@ -212,23 +204,13 @@ func (r Rclone) Unmount(ctx context.Context, volumeId string, targetPath string)
212204 requestBody := bytes .NewBuffer (postBody )
213205 resp , err := http .Post (fmt .Sprintf ("http://localhost:%d/mount/unmount" , r .port ), "application/json" , requestBody )
214206 if err != nil {
215- return fmt .Errorf ("unmounting failed: err : %s " , err )
207+ return fmt .Errorf ("unmounting failed: couldn't send HTTP request : %w " , err )
216208 }
217- body , err := io . ReadAll (resp . Body )
209+ err = checkResponse (resp )
218210 if err != nil {
219- return err
211+ return fmt . Errorf ( "unmounting failed: %w" , err )
220212 }
221- if resp .StatusCode != 200 {
222- var result map [string ]interface {}
223- json .Unmarshal (body , & result )
224- errorMsg , found := result ["error" ]
225- if ! found || errorMsg != "mount not found" {
226- // if the mount errored out, we'd get mount not found and want to continue
227- klog .Errorf ("unmounting failed: couldn't delete mount: %s" , string (body ))
228- }
229- }
230- klog .Infof ("deleted mount: %s" , string (body ))
231- defer resp .Body .Close ()
213+ klog .Infof ("deleted mount with volume ID %s at path %s" , volumeId , targetPath )
232214
233215 configDelete := ConfigDeleteRequest {
234216 Name : rcloneVolume .deploymentName (),
@@ -240,18 +222,15 @@ func (r Rclone) Unmount(ctx context.Context, volumeId string, targetPath string)
240222 requestBody = bytes .NewBuffer (postBody )
241223 resp , err = http .Post (fmt .Sprintf ("http://localhost:%d/config/delete" , r .port ), "application/json" , requestBody )
242224 if err != nil {
243- klog .Errorf ("deleting config failed: err : %s " , err )
225+ klog .Errorf ("deleting config failed: couldn't send HTTP request : %v " , err )
244226 return nil
245227 }
246- body , err = io . ReadAll (resp . Body )
228+ err = checkResponse (resp )
247229 if err != nil {
248- return err
249- }
250- if resp .StatusCode != 200 {
251- //don't error here so storage can be successfully unmounted
252- klog .Errorf ("deleting config failed: couldn't delete mount: %s" , string (body ))
230+ klog .Errorf ("deleting config failed: %v" , err )
231+ return nil
253232 }
254- klog .Infof ("deleted config: %s " , string ( body ) )
233+ klog .Infof ("deleted config for volume ID %s at path %s " , volumeId , targetPath )
255234
256235 return nil
257236}
@@ -312,6 +291,51 @@ func NewRclone(kubeClient *kubernetes.Clientset, port int) Operations {
312291 return rclone
313292}
314293
294+ // Format from https://rclone.org/rc/#error-returns
295+ type serverErrorResponse struct {
296+ Error string `json:"error"`
297+ Path string `json:"path"`
298+ input json.RawMessage // can contain sensitive info in plain text
299+ status int // same as the http status code
300+ }
301+
302+ func (s serverErrorResponse ) String () string {
303+ return fmt .Sprintf (
304+ "{%q: %q, %q: %q, %q: %q, %q: %d}" ,
305+ "error" ,
306+ s .Error ,
307+ "path" ,
308+ s .Path ,
309+ "input" ,
310+ "<redacted>" ,
311+ "status" ,
312+ s .status ,
313+ )
314+ }
315+
316+ func checkResponse (resp * http.Response ) error {
317+ if resp .StatusCode >= 200 && resp .StatusCode < 300 {
318+ // everything is ok with the response, there should be no error
319+ return nil
320+ }
321+ body , err := io .ReadAll (resp .Body )
322+ defer resp .Body .Close ()
323+ if err != nil {
324+ // NOTE: do not wrap the error in case it contains sensitive information from the body
325+ return fmt .Errorf ("could not read the error response body from the rclone server" )
326+ }
327+ var result serverErrorResponse
328+ err = json .Unmarshal (body , & result )
329+ if err != nil {
330+ // NOTE: do not wrap the error in case it contains sensitive information from the body
331+ return fmt .Errorf ("could not unmarshal the error response from the rclone server" )
332+ }
333+ if result .Error == "" {
334+ return fmt .Errorf ("unmarshalled the response from the server but it had nothing in the error field" )
335+ }
336+ return fmt .Errorf ("received error from the rclone server: %s" , result .String ())
337+ }
338+
315339func (r * Rclone ) start_daemon () error {
316340 f , err := os .CreateTemp ("" , "rclone.conf" )
317341 if err != nil {
0 commit comments