We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Quantpendia failed to upload to S3
### Context

We kicked off quantpendia jobs for all organisms but they weren't succeeding because they couldn't upload to S3.

### Problem or idea

This is probably just because the worker instances don't have access to the compendia S3 bucket. The smasher probably has those permissions, but it looks like the workers don't.

### Solution or next step

Give worker instances permissions to push to the compendia S3 bucket.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `workers/data_refinery_workers/processors/create_quantpendia.py`
Content:
```
1 import os
2 import logging
3 import shutil
4 import time
5 from django.utils import timezone
6 from typing import Dict, List, Tuple
7 import psutil
8 
9 from data_refinery_common.job_lookup import PipelineEnum
10 from data_refinery_common.logging import get_and_configure_logger
11 from data_refinery_common.models import (ComputationalResult,
12                                          ComputedFile,
13                                          Organism,
14                                          Pipeline,
15                                          Sample)
16 from data_refinery_common.utils import get_env_variable
17 from data_refinery_workers.processors import smashing_utils, utils
18 
19 S3_BUCKET_NAME = get_env_variable("S3_BUCKET_NAME", "data-refinery")
20 SMASHING_DIR = "/home/user/data_store/smashed/"
21 
22 logger = get_and_configure_logger(__name__)
23 logger.setLevel(logging.getLevelName('DEBUG'))
24 
25 def create_quantpendia(job_id: int) -> None:
26     pipeline = Pipeline(name=PipelineEnum.CREATE_QUANTPENDIA.value)
27     job_context = utils.run_pipeline({"job_id": job_id, "pipeline": pipeline},
28                                      [utils.start_job,
29                                       make_dirs,
30                                       download_files,
31                                       create_result_objects,
32                                       remove_job_dir,
33                                       utils.end_job])
34     return job_context
35 
36 
37 def download_files(job_context: Dict) -> Dict:
38     job_context['time_start'] = timezone.now()
39 
40     num_samples = 0
41     for key, samples in job_context['samples'].items():
42         outfile_dir = job_context['output_dir'] + key + '/'
43         os.makedirs(outfile_dir, exist_ok=True)
44 
45         logger.debug("Downloading quant.sf files for quantpendia.",
46                     accession_code=key,
47                     job_id=job_context['job_id'],
48                     **get_process_stats())
49 
50         # download quant.sf files directly into the dataset folder
51         num_samples += smashing_utils.sync_quant_files(outfile_dir, samples)
52 
53     job_context['num_samples'] = num_samples
54     job_context['time_end'] = timezone.now()
55     job_context['formatted_command'] = "create_quantpendia.py"
56 
57     logger.debug("Finished downloading quant.sf files for quantpendia.",
58                 job_id=job_context['job_id'],
59                 total_downloaded_files=num_samples,
60                 **get_process_stats())
61 
62     return job_context
63 
64 
65 def create_result_objects(job_context: Dict) -> Dict:
66     """
67     Store and host the result as a ComputationalResult object.
68     """
69     result = ComputationalResult()
70     result.commands.append(" ".join(job_context['formatted_command']))
71     result.is_ccdl = True
72     result.is_public = True
73     result.time_start = job_context['time_start']
74     result.time_end = job_context['time_end']
75     try:
76         processor_key = "CREATE_QUANTPENDIA"
77         result.processor = utils.find_processor(processor_key)
78     except Exception as e:
79         return utils.handle_processor_exception(job_context, processor_key, e)
80     result.save()
81 
82     compendia_organism = _get_organisms(job_context['samples']).first()
83 
84     # Create the resulting archive
85     smashing_utils.write_non_data_files(job_context)
86     final_zip_base = job_context['job_dir'] + compendia_organism.name + "_rnaseq_compendia"
87     shutil.copy("/home/user/README_QUANT.md", job_context["output_dir"] + "/README.md")
88 
89     archive_path = shutil.make_archive(final_zip_base, 'zip', job_context["output_dir"])
90     compendia_version = _get_next_compendia_version(compendia_organism)
91 
92     archive_computed_file = ComputedFile()
93 
94     archive_computed_file.absolute_file_path = archive_path
95     archive_computed_file.filename = archive_path.split('/')[-1]
96     archive_computed_file.calculate_sha1()
97     archive_computed_file.calculate_size()
98     archive_computed_file.is_smashable = False
99     archive_computed_file.is_qn_target = False
100     archive_computed_file.result = result
101     archive_computed_file.is_compendia = True
102     archive_computed_file.quant_sf_only = True
103     archive_computed_file.compendia_organism = compendia_organism
104     archive_computed_file.compendia_version = compendia_version
105     archive_computed_file.save()
106 
107     logger.info("Quantpendia created!",
108                 archive_path=archive_path,
109                 organism_name=compendia_organism.name)
110 
111     # Upload the result to S3
112     timestamp = str(int(time.time()))
113     s3_key = compendia_organism.name + "_" + str(compendia_version) + "_" + timestamp + ".zip"
114     archive_computed_file.sync_to_s3(S3_BUCKET_NAME, s3_key)
115 
116     job_context['result'] = result
117     job_context['computed_files'] = [archive_computed_file]
118     job_context['success'] = True
119 
120     return job_context
121 
122 
123 def remove_job_dir(job_context: Dict):
124     """ remove the directory when the job is successful. At this point
125     the quantpendia was already zipped and uploaded. """
126     shutil.rmtree(job_context["job_dir"], ignore_errors=True)
127     return job_context
128 
129 def make_dirs(job_context: Dict):
130     dataset_id = str(job_context["dataset"].pk)
131     job_context["job_dir"] = "/home/user/data_store/smashed/" + dataset_id + "/"
132     os.makedirs(job_context["job_dir"], exist_ok=True)
133     job_context["output_dir"] = job_context["job_dir"] + "output/"
134     os.makedirs(job_context["output_dir"], exist_ok=True)
135     return job_context
136 
137 def get_process_stats():
138     BYTES_IN_GB = 1024 * 1024 * 1024
139     process = psutil.Process(os.getpid())
140     ram_in_GB = process.memory_info().rss / BYTES_IN_GB
141     return { 'total_cpu': psutil.cpu_percent(), 'process_ram': ram_in_GB }
142 
143 
144 def _get_organisms(aggregated_samples: Dict[str, Sample]) -> List[Organism]:
145     organisms = set()
146     for key, samples in aggregated_samples.items():
147         organism_ids = samples.values_list('organism__id', flat=True).distinct()
148         organisms.update(organism_ids)
149 
150     return Organism.objects.filter(id__in=list(organisms))
151 
152 
153 def _get_next_compendia_version(organism: Organism) -> int:
154     last_compendia = ComputedFile.objects\
155         .filter(is_compendia=True, quant_sf_only=True, compendia_organism=organism)\
156         .order_by('-compendia_version').first()
157 
158     if last_compendia:
159         return last_compendia.compendia_version + 1
160 
161     # otherwise this is the first compendia that we are generating
162     return 1
163
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/workers/data_refinery_workers/processors/create_quantpendia.py b/workers/data_refinery_workers/processors/create_quantpendia.py
--- a/workers/data_refinery_workers/processors/create_quantpendia.py
+++ b/workers/data_refinery_workers/processors/create_quantpendia.py
@@ -3,6 +3,7 @@
 import shutil
 import time
 from django.utils import timezone
+from django.conf import settings
 from typing import Dict, List, Tuple
 import psutil
 
@@ -114,7 +115,6 @@
     archive_computed_file.sync_to_s3(S3_BUCKET_NAME, s3_key)
 
     job_context['result'] = result
-    job_context['computed_files'] = [archive_computed_file]
     job_context['success'] = True
 
     return job_context
@@ -123,7 +123,9 @@
 def remove_job_dir(job_context: Dict):
     """ remove the directory when the job is successful. At this point
     the quantpendia was already zipped and uploaded. """
-    shutil.rmtree(job_context["job_dir"], ignore_errors=True)
+    # don't remove the files when running locally or for tests
+    if settings.RUNNING_IN_CLOUD:
+        shutil.rmtree(job_context["job_dir"], ignore_errors=True)
     return job_context
 
 def make_dirs(job_context: Dict):

{"golden_diff": "diff --git a/workers/data_refinery_workers/processors/create_quantpendia.py b/workers/data_refinery_workers/processors/create_quantpendia.py\n--- a/workers/data_refinery_workers/processors/create_quantpendia.py\n+++ b/workers/data_refinery_workers/processors/create_quantpendia.py\n@@ -3,6 +3,7 @@\n import shutil\n import time\n from django.utils import timezone\n+from django.conf import settings\n from typing import Dict, List, Tuple\n import psutil\n \n@@ -114,7 +115,6 @@\n     archive_computed_file.sync_to_s3(S3_BUCKET_NAME, s3_key)\n \n     job_context['result'] = result\n-    job_context['computed_files'] = [archive_computed_file]\n     job_context['success'] = True\n \n     return job_context\n@@ -123,7 +123,9 @@\n def remove_job_dir(job_context: Dict):\n     \"\"\" remove the directory when the job is successful. At this point\n     the quantpendia was already zipped and uploaded. \"\"\"\n-    shutil.rmtree(job_context[\"job_dir\"], ignore_errors=True)\n+    # don't remove the files when running locally or for tests\n+    if settings.RUNNING_IN_CLOUD:\n+        shutil.rmtree(job_context[\"job_dir\"], ignore_errors=True)\n     return job_context\n \n def make_dirs(job_context: Dict):\n", "issue": "Quantpendia failed to upload to S3\n### Context\r\n\r\nWe kicked off quantpendia jobs for all organisms but they weren't succeeding because they couldn't upload to S3.\r\n\r\n### Problem or idea\r\n\r\nThis is probably just because the worker instances don't have access to the compendia S3 bucket. The smasher probably has those permissions, but it looks like the workers don't.\r\n\r\n### Solution or next step\r\n\r\nGive worker instances permissions to push to the compendia S3 bucket.\n", "before_files": [{"content": "import os\nimport logging\nimport shutil\nimport time\nfrom django.utils import timezone\nfrom typing import Dict, List, Tuple\nimport psutil\n\nfrom data_refinery_common.job_lookup import PipelineEnum\nfrom data_refinery_common.logging import get_and_configure_logger\nfrom data_refinery_common.models import (ComputationalResult,\n                                         ComputedFile,\n                                         Organism,\n                                         Pipeline,\n                                         Sample)\nfrom data_refinery_common.utils import get_env_variable\nfrom data_refinery_workers.processors import smashing_utils, utils\n\nS3_BUCKET_NAME = get_env_variable(\"S3_BUCKET_NAME\", \"data-refinery\")\nSMASHING_DIR = \"/home/user/data_store/smashed/\"\n\nlogger = get_and_configure_logger(__name__)\nlogger.setLevel(logging.getLevelName('DEBUG'))\n\ndef create_quantpendia(job_id: int) -> None:\n    pipeline = Pipeline(name=PipelineEnum.CREATE_QUANTPENDIA.value)\n    job_context = utils.run_pipeline({\"job_id\": job_id, \"pipeline\": pipeline},\n                                     [utils.start_job,\n                                      make_dirs,\n                                      download_files,\n                                      create_result_objects,\n                                      remove_job_dir,\n                                      utils.end_job])\n    return job_context\n\n\ndef download_files(job_context: Dict) -> Dict:\n    job_context['time_start'] = timezone.now()\n\n    num_samples = 0\n    for key, samples in job_context['samples'].items():\n        outfile_dir = job_context['output_dir'] + key + '/'\n        os.makedirs(outfile_dir, exist_ok=True)\n\n        logger.debug(\"Downloading quant.sf files for quantpendia.\",\n                    accession_code=key,\n                    job_id=job_context['job_id'],\n                    **get_process_stats())\n\n        # download quant.sf files directly into the dataset folder\n        num_samples += smashing_utils.sync_quant_files(outfile_dir, samples)\n\n    job_context['num_samples'] = num_samples\n    job_context['time_end'] = timezone.now()\n    job_context['formatted_command'] = \"create_quantpendia.py\"\n\n    logger.debug(\"Finished downloading quant.sf files for quantpendia.\",\n                job_id=job_context['job_id'],\n                total_downloaded_files=num_samples,\n                **get_process_stats())\n\n    return job_context\n\n\ndef create_result_objects(job_context: Dict) -> Dict:\n    \"\"\"\n    Store and host the result as a ComputationalResult object.\n    \"\"\"\n    result = ComputationalResult()\n    result.commands.append(\" \".join(job_context['formatted_command']))\n    result.is_ccdl = True\n    result.is_public = True\n    result.time_start = job_context['time_start']\n    result.time_end = job_context['time_end']\n    try:\n        processor_key = \"CREATE_QUANTPENDIA\"\n        result.processor = utils.find_processor(processor_key)\n    except Exception as e:\n        return utils.handle_processor_exception(job_context, processor_key, e)\n    result.save()\n\n    compendia_organism = _get_organisms(job_context['samples']).first()\n\n    # Create the resulting archive\n    smashing_utils.write_non_data_files(job_context)\n    final_zip_base = job_context['job_dir'] + compendia_organism.name + \"_rnaseq_compendia\"\n    shutil.copy(\"/home/user/README_QUANT.md\", job_context[\"output_dir\"] + \"/README.md\")\n\n    archive_path = shutil.make_archive(final_zip_base, 'zip', job_context[\"output_dir\"])\n    compendia_version = _get_next_compendia_version(compendia_organism)\n\n    archive_computed_file = ComputedFile()\n\n    archive_computed_file.absolute_file_path = archive_path\n    archive_computed_file.filename = archive_path.split('/')[-1]\n    archive_computed_file.calculate_sha1()\n    archive_computed_file.calculate_size()\n    archive_computed_file.is_smashable = False\n    archive_computed_file.is_qn_target = False\n    archive_computed_file.result = result\n    archive_computed_file.is_compendia = True\n    archive_computed_file.quant_sf_only = True\n    archive_computed_file.compendia_organism = compendia_organism\n    archive_computed_file.compendia_version = compendia_version\n    archive_computed_file.save()\n\n    logger.info(\"Quantpendia created!\",\n                archive_path=archive_path,\n                organism_name=compendia_organism.name)\n\n    # Upload the result to S3\n    timestamp = str(int(time.time()))\n    s3_key = compendia_organism.name + \"_\" + str(compendia_version) + \"_\" + timestamp + \".zip\"\n    archive_computed_file.sync_to_s3(S3_BUCKET_NAME, s3_key)\n\n    job_context['result'] = result\n    job_context['computed_files'] = [archive_computed_file]\n    job_context['success'] = True\n\n    return job_context\n\n\ndef remove_job_dir(job_context: Dict):\n    \"\"\" remove the directory when the job is successful. At this point\n    the quantpendia was already zipped and uploaded. \"\"\"\n    shutil.rmtree(job_context[\"job_dir\"], ignore_errors=True)\n    return job_context\n\ndef make_dirs(job_context: Dict):\n    dataset_id = str(job_context[\"dataset\"].pk)\n    job_context[\"job_dir\"] = \"/home/user/data_store/smashed/\" + dataset_id + \"/\"\n    os.makedirs(job_context[\"job_dir\"], exist_ok=True)\n    job_context[\"output_dir\"] = job_context[\"job_dir\"] + \"output/\"\n    os.makedirs(job_context[\"output_dir\"], exist_ok=True)\n    return job_context\n\ndef get_process_stats():\n    BYTES_IN_GB = 1024 * 1024 * 1024\n    process = psutil.Process(os.getpid())\n    ram_in_GB = process.memory_info().rss / BYTES_IN_GB\n    return { 'total_cpu': psutil.cpu_percent(), 'process_ram': ram_in_GB }\n\n\ndef _get_organisms(aggregated_samples: Dict[str, Sample]) -> List[Organism]:\n    organisms = set()\n    for key, samples in aggregated_samples.items():\n        organism_ids = samples.values_list('organism__id', flat=True).distinct()\n        organisms.update(organism_ids)\n\n    return Organism.objects.filter(id__in=list(organisms))\n\n\ndef _get_next_compendia_version(organism: Organism) -> int:\n    last_compendia = ComputedFile.objects\\\n        .filter(is_compendia=True, quant_sf_only=True, compendia_organism=organism)\\\n        .order_by('-compendia_version').first()\n\n    if last_compendia:\n        return last_compendia.compendia_version + 1\n\n    # otherwise this is the first compendia that we are generating\n    return 1\n", "path": "workers/data_refinery_workers/processors/create_quantpendia.py"}], "after_files": [{"content": "import os\nimport logging\nimport shutil\nimport time\nfrom django.utils import timezone\nfrom django.conf import settings\nfrom typing import Dict, List, Tuple\nimport psutil\n\nfrom data_refinery_common.job_lookup import PipelineEnum\nfrom data_refinery_common.logging import get_and_configure_logger\nfrom data_refinery_common.models import (ComputationalResult,\n                                         ComputedFile,\n                                         Organism,\n                                         Pipeline,\n                                         Sample)\nfrom data_refinery_common.utils import get_env_variable\nfrom data_refinery_workers.processors import smashing_utils, utils\n\nS3_BUCKET_NAME = get_env_variable(\"S3_BUCKET_NAME\", \"data-refinery\")\nSMASHING_DIR = \"/home/user/data_store/smashed/\"\n\nlogger = get_and_configure_logger(__name__)\nlogger.setLevel(logging.getLevelName('DEBUG'))\n\ndef create_quantpendia(job_id: int) -> None:\n    pipeline = Pipeline(name=PipelineEnum.CREATE_QUANTPENDIA.value)\n    job_context = utils.run_pipeline({\"job_id\": job_id, \"pipeline\": pipeline},\n                                     [utils.start_job,\n                                      make_dirs,\n                                      download_files,\n                                      create_result_objects,\n                                      remove_job_dir,\n                                      utils.end_job])\n    return job_context\n\n\ndef download_files(job_context: Dict) -> Dict:\n    job_context['time_start'] = timezone.now()\n\n    num_samples = 0\n    for key, samples in job_context['samples'].items():\n        outfile_dir = job_context['output_dir'] + key + '/'\n        os.makedirs(outfile_dir, exist_ok=True)\n\n        logger.debug(\"Downloading quant.sf files for quantpendia.\",\n                    accession_code=key,\n                    job_id=job_context['job_id'],\n                    **get_process_stats())\n\n        # download quant.sf files directly into the dataset folder\n        num_samples += smashing_utils.sync_quant_files(outfile_dir, samples)\n\n    job_context['num_samples'] = num_samples\n    job_context['time_end'] = timezone.now()\n    job_context['formatted_command'] = \"create_quantpendia.py\"\n\n    logger.debug(\"Finished downloading quant.sf files for quantpendia.\",\n                job_id=job_context['job_id'],\n                total_downloaded_files=num_samples,\n                **get_process_stats())\n\n    return job_context\n\n\ndef create_result_objects(job_context: Dict) -> Dict:\n    \"\"\"\n    Store and host the result as a ComputationalResult object.\n    \"\"\"\n    result = ComputationalResult()\n    result.commands.append(\" \".join(job_context['formatted_command']))\n    result.is_ccdl = True\n    result.is_public = True\n    result.time_start = job_context['time_start']\n    result.time_end = job_context['time_end']\n    try:\n        processor_key = \"CREATE_QUANTPENDIA\"\n        result.processor = utils.find_processor(processor_key)\n    except Exception as e:\n        return utils.handle_processor_exception(job_context, processor_key, e)\n    result.save()\n\n    compendia_organism = _get_organisms(job_context['samples']).first()\n\n    # Create the resulting archive\n    smashing_utils.write_non_data_files(job_context)\n    final_zip_base = job_context['job_dir'] + compendia_organism.name + \"_rnaseq_compendia\"\n    shutil.copy(\"/home/user/README_QUANT.md\", job_context[\"output_dir\"] + \"/README.md\")\n\n    archive_path = shutil.make_archive(final_zip_base, 'zip', job_context[\"output_dir\"])\n    compendia_version = _get_next_compendia_version(compendia_organism)\n\n    archive_computed_file = ComputedFile()\n\n    archive_computed_file.absolute_file_path = archive_path\n    archive_computed_file.filename = archive_path.split('/')[-1]\n    archive_computed_file.calculate_sha1()\n    archive_computed_file.calculate_size()\n    archive_computed_file.is_smashable = False\n    archive_computed_file.is_qn_target = False\n    archive_computed_file.result = result\n    archive_computed_file.is_compendia = True\n    archive_computed_file.quant_sf_only = True\n    archive_computed_file.compendia_organism = compendia_organism\n    archive_computed_file.compendia_version = compendia_version\n    archive_computed_file.save()\n\n    logger.info(\"Quantpendia created!\",\n                archive_path=archive_path,\n                organism_name=compendia_organism.name)\n\n    # Upload the result to S3\n    timestamp = str(int(time.time()))\n    s3_key = compendia_organism.name + \"_\" + str(compendia_version) + \"_\" + timestamp + \".zip\"\n    archive_computed_file.sync_to_s3(S3_BUCKET_NAME, s3_key)\n\n    job_context['result'] = result\n    job_context['success'] = True\n\n    return job_context\n\n\ndef remove_job_dir(job_context: Dict):\n    \"\"\" remove the directory when the job is successful. At this point\n    the quantpendia was already zipped and uploaded. \"\"\"\n    # don't remove the files when running locally or for tests\n    if settings.RUNNING_IN_CLOUD:\n        shutil.rmtree(job_context[\"job_dir\"], ignore_errors=True)\n    return job_context\n\ndef make_dirs(job_context: Dict):\n    dataset_id = str(job_context[\"dataset\"].pk)\n    job_context[\"job_dir\"] = \"/home/user/data_store/smashed/\" + dataset_id + \"/\"\n    os.makedirs(job_context[\"job_dir\"], exist_ok=True)\n    job_context[\"output_dir\"] = job_context[\"job_dir\"] + \"output/\"\n    os.makedirs(job_context[\"output_dir\"], exist_ok=True)\n    return job_context\n\ndef get_process_stats():\n    BYTES_IN_GB = 1024 * 1024 * 1024\n    process = psutil.Process(os.getpid())\n    ram_in_GB = process.memory_info().rss / BYTES_IN_GB\n    return { 'total_cpu': psutil.cpu_percent(), 'process_ram': ram_in_GB }\n\n\ndef _get_organisms(aggregated_samples: Dict[str, Sample]) -> List[Organism]:\n    organisms = set()\n    for key, samples in aggregated_samples.items():\n        organism_ids = samples.values_list('organism__id', flat=True).distinct()\n        organisms.update(organism_ids)\n\n    return Organism.objects.filter(id__in=list(organisms))\n\n\ndef _get_next_compendia_version(organism: Organism) -> int:\n    last_compendia = ComputedFile.objects\\\n        .filter(is_compendia=True, quant_sf_only=True, compendia_organism=organism)\\\n        .order_by('-compendia_version').first()\n\n    if last_compendia:\n        return last_compendia.compendia_version + 1\n\n    # otherwise this is the first compendia that we are generating\n    return 1\n", "path": "workers/data_refinery_workers/processors/create_quantpendia.py"}]}