instructure / canvas-lms

The open LMS by Instructure, Inc.
https://github.com/instructure/canvas-lms/wiki
GNU Affero General Public License v3.0
5.62k stars 2.48k forks source link

No such file or directory error #621

Closed redconfetti closed 9 years ago

redconfetti commented 9 years ago

Disclaimer: This is not a bug report, but just documenting a possible issue others may run into so they might find this in search results.

In my local Canvas instance that I've been running for quite a while I recently started to get this error when our LTI application would attempt to perform an SIS Import of a single user into Canvas via the SIS Import API.

 No such file or directory @ rb_sysopen - /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv
 /Users/jasonmiller/Projects/canvas-lms/app/models/attachments/local_storage.rb:51:in `initialize''
 /Users/jasonmiller/Projects/canvas-lms/app/models/attachments/local_storage.rb:51:in `open''
 /Users/jasonmiller/Projects/canvas-lms/app/models/attachments/local_storage.rb:51:in `open''

It would successfully import the course and section SIS Import files, but it would fail when our course creation LTI tool attempts to import a single user (the instructor officially associated with the course). I took the same file, renamed it 'users.csv' and put it in a ZIP file, then used the web based SIS Import interface to import the same file, and it worked fine. But still during the automated process using the SIS Import API it would fail with this error.

I traced the issue down to the Attachment model, which uses the customized Attachment_Fu gem. The AttachmentFu#uploaded_data= method is responsible for obtaining the temporary file path for the attachment depending on the type of object passed to the method. In our case we're dealing with an ActionDispatch::Http::UploadedFile object. This method applies the contents of the temporary file to a Digest::MD5 object so that it can generate the MD5 hash that represents the contents of the file. It then looks for existing files that use the same MD5 hash.

This is very clever as it cuts down on unnecessary file duplication. If an existing attachment with the same MD5 hash is found, it associates the duplicate attachment with the current attachment. This results in the after_save callback that is called when the Attachment is saved to NOT copy the temporary file to the local file storage area, but instead expect the system to rely on the root attachment object to point to a file with the same contents.

I'm not sure why this is, but in my case, it turns out that the root attachment it associated with was providing a full file path that points to a directory and file that does not exist. This duplicate attachment was from an SIS Import I performed back on December 16, 2014.

> attachment = Attachment.find(472)
> root_attachment = attachment.root_attachment
> root_attachment.full_filename
=> "/Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv"
> attachment.full_filename
=> "/Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv"

> sis_batch = SisBatch.where(:attachment_id => 164).first
=> #<SisBatch id: 136, account_id: 1, ended_at: "2014-12-16 00:21:33", errored_attempts: nil, workflow_state: "imported", data: {:import_type=>"instructure_csv", :supplied_batches=>[:user], :counts=>{:accounts=>0, :terms=>0, :abstract_courses=>0, :courses=>0, :sections=>0, :xlists=>0, :users=>1, :enrollments=>0, :groups=>0, :group_memberships=>0, :grade_publishing_results=>0}}, created_at: "2014-12-16 00:21:33", updated_at: "2015-04-25 00:10:10", attachment_id: 164, progress: 100, processing_errors: [], processing_warnings: [], batch_mode: nil, batch_mode_term_id: nil, options: {}, user_id: 2, started_at: nil, diffing_data_set_identifier: nil, diffing_remaster: nil, generated_diff_id: nil>
$ cat /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv
cat: /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv: No such file or directory
$ cd /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/
cd: no such file or directory: /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/

I recommend adding a check within the 'if existing_attachment' conditional block that assigns the root_attachment to the object IF the file is actually present for the root attachment that was found. This would make for a better failover, and avoid this circumstance should SIS Batch import attachments become missing / lost from S3 or the local filesystem in the future for whatever reason.

redconfetti commented 9 years ago

As a solution to this issue, should anyone else stumble upon it, I recommend simply creating the directory and file that it intends to find. This example is of course for those using a local filesystem:

$ mkdir -p /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/
$ cp tmp/canvas/user_provision-2015-04-24-1a813bd36c82617d-users.csv /Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0164/user_provision-2014-12-15-ae0da1cee526fdc4-users.csv
redconfetti commented 9 years ago

Just to lend some history regarding my setup, in the interest of finding out if this is a false positive, I see only directories that were created/exist shortly AFTER December 16th.

$ pwd
/Users/jasonmiller/Projects/canvas-lms/tmp/files/0000
$ ls -go
total 0
drwxr-xr-x  3   102 Apr 24 17:54 0164
drwxr-xr-x  3   102 Dec 17 23:10 0166
drwxr-xr-x  3   102 Dec 17 23:56 0167
drwxr-xr-x  3   102 Dec 18 00:02 0168
drwxr-xr-x  3   102 Dec 18 00:05 0169
drwxr-xr-x  3   102 Dec 18 00:28 0170
drwxr-xr-x  3   102 Dec 18 00:35 0171
drwxr-xr-x  3   102 Dec 18 00:35 0172
drwxr-xr-x  3   102 Dec 18 10:26 0174
drwxr-xr-x  3   102 Dec 18 10:26 0175
drwxr-xr-x  3   102 Dec 18 10:36 0177
drwxr-xr-x  3   102 Dec 18 10:45 0179
drwxr-xr-x  3   102 Dec 18 10:46 0180
drwxr-xr-x  3   102 Dec 18 10:54 0182
drwxr-xr-x  3   102 Dec 18 11:22 0183
drwxr-xr-x  3   102 Dec 18 11:39 0184
drwxr-xr-x  3   102 Dec 18 11:40 0185
drwxr-xr-x  3   102 Dec 18 11:47 0186
drwxr-xr-x  3   102 Dec 18 11:49 0187
drwxr-xr-x  3   102 Dec 18 11:58 0188
drwxr-xr-x  3   102 Dec 18 11:59 0189
drwxr-xr-x  3   102 Dec 18 12:03 0190
drwxr-xr-x  3   102 Dec 18 12:04 0191
drwxr-xr-x  3   102 Dec 18 12:09 0192
drwxr-xr-x  3   102 Dec 18 12:14 0193
drwxr-xr-x  3   102 Dec 18 12:14 0194
drwxr-xr-x  3   102 Dec 18 12:16 0195
drwxr-xr-x  3   102 Dec 18 12:17 0196
drwxr-xr-x  3   102 Dec 18 12:20 0197
drwxr-xr-x  3   102 Dec 18 12:49 0198
drwxr-xr-x  3   102 Dec 18 12:53 0199
drwxr-xr-x  3   102 Dec 18 12:58 0200
drwxr-xr-x  3   102 Dec 18 12:58 0201
drwxr-xr-x  3   102 Dec 18 12:59 0202
drwxr-xr-x  3   102 Dec 18 13:08 0203
drwxr-xr-x  3   102 Dec 18 13:09 0204
drwxr-xr-x  3   102 Dec 19 10:33 0205
drwxr-xr-x  3   102 Dec 19 10:40 0208
drwxr-xr-x  3   102 Dec 19 10:40 0209
drwxr-xr-x  3   102 Dec 19 12:15 0210
drwxr-xr-x  3   102 Dec 19 12:18 0212
drwxr-xr-x  3   102 Dec 19 12:28 0213
drwxr-xr-x  3   102 Dec 19 12:30 0214
drwxr-xr-x  3   102 Dec 19 12:31 0215
drwxr-xr-x  3   102 Dec 19 12:40 0216
drwxr-xr-x  3   102 Dec 19 12:40 0217
drwxr-xr-x  3   102 Dec 19 13:05 0219
drwxr-xr-x  4   136 Dec 20 18:26 0220
drwxr-xr-x  3   102 Dec 22 16:38 0221
drwxr-xr-x  3   102 Jan 12 18:31 0222
drwxr-xr-x  3   102 Jan 13 11:39 0223
drwxr-xr-x  3   102 Jan 13 11:55 0224
drwxr-xr-x  3   102 Feb  9 15:16 0225
drwxr-xr-x  3   102 Feb 12 13:28 0257
drwxr-xr-x  3   102 Feb 12 13:29 0258
drwxr-xr-x  3   102 Feb 13 13:00 0263
drwxr-xr-x  3   102 Feb 23 12:39 0269
drwxr-xr-x  3   102 Feb 23 12:39 0270
drwxr-xr-x  4   136 Feb 23 12:42 0272
drwxr-xr-x  3   102 Feb 23 12:44 0273
drwxr-xr-x  3   102 Feb 24 15:24 0275
drwxr-xr-x  3   102 Feb 24 15:25 0276
drwxr-xr-x  3   102 Feb 25 10:05 0278
drwxr-xr-x  3   102 Feb 25 10:06 0279
drwxr-xr-x  3   102 Feb 25 10:06 0280
drwxr-xr-x  3   102 Feb 25 10:06 0281
drwxr-xr-x  3   102 Feb 25 10:11 0282
drwxr-xr-x  3   102 Feb 25 10:11 0283
drwxr-xr-x  3   102 Feb 25 10:15 0313
drwxr-xr-x  3   102 Mar  3 11:37 0314
drwxr-xr-x  3   102 Mar  3 11:37 0315
drwxr-xr-x  3   102 Mar  3 11:38 0317
drwxr-xr-x  3   102 Mar  4 10:32 0318
drwxr-xr-x  3   102 Mar  4 10:32 0319
drwxr-xr-x  3   102 Mar  4 10:33 0320
drwxr-xr-x  3   102 Mar  4 10:34 0321
drwxr-xr-x  3   102 Mar  4 10:41 0322
drwxr-xr-x  3   102 Mar  4 10:41 0323
drwxr-xr-x  3   102 Mar  4 10:42 0324
drwxr-xr-x  3   102 Mar  4 10:42 0325
drwxr-xr-x  3   102 Mar  4 10:44 0326
drwxr-xr-x  3   102 Mar  4 10:44 0327
drwxr-xr-x  3   102 Mar  4 10:45 0328
drwxr-xr-x  3   102 Mar  4 10:45 0329
drwxr-xr-x  3   102 Mar  4 11:27 0330
drwxr-xr-x  3   102 Mar  4 11:27 0331
drwxr-xr-x  3   102 Mar  4 15:31 0332
drwxr-xr-x  3   102 Mar  4 15:31 0333
drwxr-xr-x  3   102 Mar  4 15:51 0334
drwxr-xr-x  3   102 Mar  4 15:51 0335
drwxr-xr-x  3   102 Mar  4 16:12 0336
drwxr-xr-x  3   102 Mar  4 16:12 0337
drwxr-xr-x  3   102 Mar  4 16:14 0338
drwxr-xr-x  3   102 Mar  4 16:14 0339
drwxr-xr-x  3   102 Mar  4 16:15 0340
drwxr-xr-x  3   102 Mar  4 16:15 0341
drwxr-xr-x  3   102 Mar  4 16:18 0342
drwxr-xr-x  3   102 Mar  4 16:18 0343
drwxr-xr-x  3   102 Mar  5 13:50 0348
drwxr-xr-x  3   102 Mar  5 13:50 0349
drwxr-xr-x  3   102 Mar  5 13:55 0351
drwxr-xr-x  3   102 Mar  5 13:56 0352
drwxr-xr-x  3   102 Mar  5 13:59 0353
drwxr-xr-x  3   102 Mar  5 13:59 0354
drwxr-xr-x  3   102 Mar  5 14:02 0355
drwxr-xr-x  3   102 Mar  5 14:02 0356
drwxr-xr-x  3   102 Mar  5 14:09 0357
drwxr-xr-x  3   102 Mar  5 14:09 0358
drwxr-xr-x  3   102 Mar  5 14:09 0360
drwxr-xr-x  3   102 Mar  5 14:11 0361
drwxr-xr-x  3   102 Mar  5 14:11 0362
drwxr-xr-x  3   102 Mar  5 14:52 0363
drwxr-xr-x  3   102 Mar  5 14:52 0364
drwxr-xr-x  3   102 Mar  5 14:55 0365
drwxr-xr-x  3   102 Mar  5 14:55 0366
drwxr-xr-x  3   102 Mar  5 14:56 0368
drwxr-xr-x  3   102 Mar  5 15:23 0369
drwxr-xr-x  3   102 Mar  5 15:23 0370
drwxr-xr-x  3   102 Mar  5 15:23 0371
drwxr-xr-x  3   102 Mar  5 15:24 0372
drwxr-xr-x  3   102 Mar  9 11:47 0373
drwxr-xr-x  3   102 Mar  9 11:48 0374
drwxr-xr-x  3   102 Mar  9 12:18 0376
drwxr-xr-x  3   102 Mar  9 12:18 0377
drwxr-xr-x  3   102 Mar  9 12:18 0378
drwxr-xr-x  3   102 Mar  9 12:19 0381
drwxr-xr-x  3   102 Mar  9 12:22 0382
drwxr-xr-x  3   102 Mar  9 12:22 0383
drwxr-xr-x  3   102 Mar 10 10:59 0384
drwxr-xr-x  3   102 Mar 10 10:59 0385
drwxr-xr-x  3   102 Mar 10 11:01 0386
drwxr-xr-x  3   102 Mar 10 11:01 0387
drwxr-xr-x  3   102 Mar 10 11:02 0388
drwxr-xr-x  3   102 Mar 12 12:26 0389
drwxr-xr-x  3   102 Mar 12 12:26 0390
drwxr-xr-x  3   102 Mar 12 12:27 0391
drwxr-xr-x  3   102 Mar 16 18:14 0392
drwxr-xr-x  3   102 Mar 16 18:14 0393
drwxr-xr-x  3   102 Mar 16 18:22 0394
drwxr-xr-x  3   102 Mar 16 18:23 0395
drwxr-xr-x  3   102 Mar 17 16:45 0396
drwxr-xr-x  3   102 Mar 17 16:45 0397
drwxr-xr-x  3   102 Mar 17 16:58 0398
drwxr-xr-x  3   102 Mar 17 16:59 0399
drwxr-xr-x  3   102 Mar 17 17:08 0400
drwxr-xr-x  3   102 Mar 17 17:08 0401
drwxr-xr-x  3   102 Mar 17 17:14 0402
drwxr-xr-x  3   102 Mar 17 17:14 0403
drwxr-xr-x  3   102 Mar 17 17:30 0404
drwxr-xr-x  3   102 Mar 17 17:30 0405
drwxr-xr-x  3   102 Mar 17 17:42 0406
drwxr-xr-x  3   102 Mar 17 17:43 0407
drwxr-xr-x  3   102 Mar 19 13:49 0408
drwxr-xr-x  3   102 Mar 19 13:49 0409
drwxr-xr-x  3   102 Mar 19 13:55 0410
drwxr-xr-x  3   102 Mar 19 13:57 0411
drwxr-xr-x  3   102 Mar 19 13:57 0412
drwxr-xr-x  3   102 Mar 19 13:57 0413
drwxr-xr-x  3   102 Mar 19 13:57 0414
drwxr-xr-x  3   102 Mar 19 15:24 0416
drwxr-xr-x  3   102 Mar 19 15:24 0417
drwxr-xr-x  3   102 Mar 19 15:25 0419
drwxr-xr-x  3   102 Mar 19 17:02 0420
drwxr-xr-x  3   102 Mar 19 17:03 0421
drwxr-xr-x  3   102 Mar 19 17:16 0423
drwxr-xr-x  3   102 Mar 19 17:16 0424
drwxr-xr-x  3   102 Mar 19 17:56 0426
drwxr-xr-x  3   102 Mar 19 17:56 0427
drwxr-xr-x  3   102 Mar 26 11:17 0429
drwxr-xr-x  3   102 Mar 31 10:44 0436
drwxr-xr-x  3   102 Mar 31 10:44 0437
drwxr-xr-x  3   102 Mar 31 10:56 0439
drwxr-xr-x  3   102 Mar 31 10:56 0440
drwxr-xr-x  3   102 Mar 31 10:58 0441
drwxr-xr-x  3   102 Mar 31 10:58 0442
drwxr-xr-x  3   102 Apr 17 13:46 0444
drwxr-xr-x  3   102 Apr 17 13:46 0445
drwxr-xr-x  3   102 Apr 23 11:54 0447
drwxr-xr-x  3   102 Apr 23 12:19 0448
drwxr-xr-x  3   102 Apr 23 12:22 0450
drwxr-xr-x  3   102 Apr 23 12:23 0451
drwxr-xr-x  3   102 Apr 23 16:39 0457
drwxr-xr-x  3   102 Apr 23 16:50 0458
drwxr-xr-x  3   102 Apr 23 17:07 0459
drwxr-xr-x  3   102 Apr 23 17:07 0460
drwxr-xr-x  3   102 Apr 24 10:16 0462
drwxr-xr-x  3   102 Apr 24 10:17 0463
drwxr-xr-x  3   102 Apr 24 10:45 0464
drwxr-xr-x  3   102 Apr 24 10:45 0465
drwxr-xr-x  3   102 Apr 24 11:12 0467
drwxr-xr-x  3   102 Apr 24 11:12 0468
drwxr-xr-x  3   102 Apr 24 14:24 0470
drwxr-xr-x  3   102 Apr 24 14:25 0471
drwxr-xr-x  3   102 Apr 24 14:54 0473
drwxr-xr-x  3   102 Apr 24 14:55 0474
drwxr-xr-x  3   102 Apr 24 15:23 0476
drwxr-xr-x  3   102 Apr 24 15:23 0477
drwxr-xr-x  3   102 Apr 24 16:13 0479
drwxr-xr-x  3   102 Apr 24 16:14 0480
drwxr-xr-x  3   102 Apr 24 16:29 0482
drwxr-xr-x  3   102 Apr 24 16:29 0483
drwxr-xr-x  3   102 Apr 24 16:53 0485
drwxr-xr-x  3   102 Apr 24 16:54 0486
drwxr-xr-x  3   102 Apr 24 17:55 0488
drwxr-xr-x  3   102 Apr 24 17:55 0489
drwxr-xr-x  3   102 Apr 24 17:56 0491

I never went in this directory and started deleting files/folders.

redconfetti commented 9 years ago

I just realized that it's possible that I deleted my entire Canvas repository, without clearing the database, around December 16th. I don't know if I would have done that... but I wouldn't be able to remember now.

I have SisBatch and Attachment records that go back to August 18, 2014. The folder it points to no longer exists. This makes me expect that several folders are missing.

> sis_batch = SisBatch.order('created_at ASC').first
> sis_batch.created_at
=> Mon, 18 Aug 2014 05:23:07 UTC +00:00
> attachment = sis_batch.attachment
> attachment.created_at
=> Mon, 18 Aug 2014 05:23:07 UTC +00:00
> attachment.full_filename
=> "/Users/jasonmiller/Projects/canvas-lms/tmp/files/0000/0001/accounts-terms-sis-import (1).zip"

If I check the logs in my Canvas LMS Git repository, I see actions going back as far as February 7, 2014. I'm pretty sure I would have completely removed the repository folder and re-cloned, resulting in a fresh log. The August 18th date above very likely was when I cleared the database and reconfigured this local instance I'm using for development testing. If anything, there should be extra folders/files, not missing ones.

$ head -5 .git/logs/HEAD
329e68ba86b9115ff08cde9bc59f14cb078d9076 277a281f0af88b46d2ec8bf5411471654e867d36 Jason Miller <jason@redconfetti.com> 1391804870 -0800 rebase: checkout upstream/stable
277a281f0af88b46d2ec8bf5411471654e867d36 277a281f0af88b46d2ec8bf5411471654e867d36 Jason Miller <jason@redconfetti.com> 1391804870 -0800 rebase finished: returning to refs/heads/stable
277a281f0af88b46d2ec8bf5411471654e867d36 7c9c2427625ade05f9c7b32e6bc0ad014d2db1d6 Jason Miller <jason@redconfetti.com> 1393270398 -0800 rebase: checkout upstream/stable
7c9c2427625ade05f9c7b32e6bc0ad014d2db1d6 7c9c2427625ade05f9c7b32e6bc0ad014d2db1d6 Jason Miller <jason@redconfetti.com> 1393270398 -0800 rebase finished: returning to refs/heads/stable
7c9c2427625ade05f9c7b32e6bc0ad014d2db1d6 7b3a489ffceda6ebf872c05100ec40261510fa73 Jason Miller <jason@redconfetti.com> 1393372396 -0800 checkout: moving from stable to upstream/master
redconfetti commented 9 years ago

Ok nevermind. I must have deleted tmp/files and recreated it.

$ pwd
/Users/jasonmiller/Projects/canvas-lms
$ ls -go tmp
total 0
drwxr-xr-x  2    68 Dec 16 16:15 cache
drwxr-xr-x  3   102 Dec 17 23:10 files
drwxr-xr-x  4   136 Apr 24 16:46 pids
drwxr-xr-x  2    68 Dec 16 16:15 sessions
drwxr-xr-x  2    68 Dec 16 16:15 sockets
$ ls -go tmp/files
total 0
drwxr-xr-x  208   7072 Apr 24 17:56 0000
kzahel commented 7 years ago

I found this issue because I was trying to import a imscc file and for some reason it was not in the canvas/tmp folder. It turns out I had the wrong permissions on the tmp folder, changing the permissions fixed the problem.