ciocore 5.1.1__py2.py3-none-any.whl → 10.0.0b3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ciocore/VERSION +1 -1
- ciocore/__init__.py +23 -1
- ciocore/api_client.py +655 -160
- ciocore/auth/__init__.py +5 -3
- ciocore/cli.py +501 -0
- ciocore/common.py +15 -13
- ciocore/conductor_submit.py +77 -60
- ciocore/config.py +127 -13
- ciocore/data.py +162 -77
- ciocore/docsite/404.html +746 -0
- ciocore/docsite/apidoc/api_client/index.html +3605 -0
- ciocore/docsite/apidoc/apidoc/index.html +909 -0
- ciocore/docsite/apidoc/config/index.html +1652 -0
- ciocore/docsite/apidoc/data/index.html +1553 -0
- ciocore/docsite/apidoc/hardware_set/index.html +2460 -0
- ciocore/docsite/apidoc/package_environment/index.html +1507 -0
- ciocore/docsite/apidoc/package_tree/index.html +2386 -0
- ciocore/docsite/assets/_mkdocstrings.css +16 -0
- ciocore/docsite/assets/images/favicon.png +0 -0
- ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js +29 -0
- ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js.map +7 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/tinyseg.js +206 -0
- ciocore/docsite/assets/javascripts/lunr/wordcut.js +6708 -0
- ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js +42 -0
- ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js.map +7 -0
- ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css +1 -0
- ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
- ciocore/docsite/assets/stylesheets/palette.06af60db.min.css +1 -0
- ciocore/docsite/assets/stylesheets/palette.06af60db.min.css.map +1 -0
- ciocore/docsite/cmdline/docs/index.html +871 -0
- ciocore/docsite/cmdline/downloader/index.html +934 -0
- ciocore/docsite/cmdline/packages/index.html +878 -0
- ciocore/docsite/cmdline/uploader/index.html +995 -0
- ciocore/docsite/how-to-guides/index.html +869 -0
- ciocore/docsite/index.html +895 -0
- ciocore/docsite/logo.png +0 -0
- ciocore/docsite/objects.inv +0 -0
- ciocore/docsite/search/search_index.json +1 -0
- ciocore/docsite/sitemap.xml +3 -0
- ciocore/docsite/sitemap.xml.gz +0 -0
- ciocore/docsite/stylesheets/extra.css +26 -0
- ciocore/docsite/stylesheets/tables.css +167 -0
- ciocore/downloader/base_downloader.py +644 -0
- ciocore/downloader/download_runner_base.py +47 -0
- ciocore/downloader/job_downloader.py +119 -0
- ciocore/{downloader.py → downloader/legacy_downloader.py} +12 -9
- ciocore/downloader/log.py +73 -0
- ciocore/downloader/logging_download_runner.py +87 -0
- ciocore/downloader/perpetual_downloader.py +63 -0
- ciocore/downloader/registry.py +97 -0
- ciocore/downloader/reporter.py +135 -0
- ciocore/exceptions.py +8 -2
- ciocore/file_utils.py +51 -50
- ciocore/hardware_set.py +449 -0
- ciocore/loggeria.py +89 -20
- ciocore/package_environment.py +110 -48
- ciocore/package_query.py +182 -0
- ciocore/package_tree.py +319 -258
- ciocore/retry.py +0 -0
- ciocore/uploader/_uploader.py +547 -364
- ciocore/uploader/thread_queue_job.py +176 -0
- ciocore/uploader/upload_stats/__init__.py +3 -4
- ciocore/uploader/upload_stats/stats_formats.py +10 -4
- ciocore/validator.py +34 -2
- ciocore/worker.py +174 -151
- ciocore-10.0.0b3.dist-info/METADATA +928 -0
- ciocore-10.0.0b3.dist-info/RECORD +128 -0
- {ciocore-5.1.1.dist-info → ciocore-10.0.0b3.dist-info}/WHEEL +1 -1
- ciocore-10.0.0b3.dist-info/entry_points.txt +2 -0
- tests/instance_type_fixtures.py +175 -0
- tests/package_fixtures.py +205 -0
- tests/test_api_client.py +297 -12
- tests/test_base_downloader.py +104 -0
- tests/test_cli.py +149 -0
- tests/test_common.py +1 -7
- tests/test_config.py +40 -18
- tests/test_data.py +162 -173
- tests/test_downloader.py +118 -0
- tests/test_hardware_set.py +139 -0
- tests/test_job_downloader.py +213 -0
- tests/test_package_query.py +38 -0
- tests/test_package_tree.py +91 -291
- tests/test_submit.py +44 -18
- tests/test_uploader.py +1 -4
- ciocore/__about__.py +0 -10
- ciocore/cli/conductor.py +0 -191
- ciocore/compat.py +0 -15
- ciocore-5.1.1.data/scripts/conductor +0 -19
- ciocore-5.1.1.data/scripts/conductor.bat +0 -13
- ciocore-5.1.1.dist-info/METADATA +0 -408
- ciocore-5.1.1.dist-info/RECORD +0 -47
- tests/mocks/api_client_mock.py +0 -51
- /ciocore/{cli → downloader}/__init__.py +0 -0
- {ciocore-5.1.1.dist-info → ciocore-10.0.0b3.dist-info}/top_level.txt +0 -0
ciocore/auth/__init__.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import webbrowser
|
|
2
3
|
from ciocore.auth import server
|
|
3
4
|
import logging
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def run(creds_file, base_url):
|
|
8
|
+
port = int(os.environ.get('CONDUCTOR_AUTH_PORT', 8085))
|
|
7
9
|
logging.debug("Base URL is %s" % base_url)
|
|
8
|
-
url = "{}/api/oauth_jwt?redirect_uri=http://localhost:
|
|
10
|
+
url = "{}/api/oauth_jwt?redirect_uri=http://localhost:{}/index.html&scope=user&response_type=client_token".format(base_url, port)
|
|
9
11
|
if webbrowser.open_new(url):
|
|
10
|
-
server.run(port=
|
|
12
|
+
server.run(port=port, creds_file=creds_file)
|
|
11
13
|
else:
|
|
12
|
-
raise RuntimeError("Unable to open web browser.
|
|
14
|
+
raise RuntimeError("Unable to open web browser on port {}. Try setting the CONDUCTOR_AUTH_PORT environment variable to a different port.".format(port))
|
ciocore/cli.py
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
import click
|
|
4
|
+
import webbrowser
|
|
5
|
+
import http.server
|
|
6
|
+
import socketserver
|
|
7
|
+
|
|
8
|
+
from ciocore import loggeria, config, api_client, package_query
|
|
9
|
+
|
|
10
|
+
from ciocore import version as VERSION
|
|
11
|
+
|
|
12
|
+
from ciocore.uploader import Uploader
|
|
13
|
+
from ciocore.downloader.legacy_downloader import Downloader
|
|
14
|
+
from ciocore.downloader.logging_download_runner import LoggingDownloadRunner
|
|
15
|
+
from ciocore.downloader.log import LOGGER_NAME, LEVEL_MAP
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
LOG_LEVEL_HELP = """The logging level to display"""
|
|
19
|
+
|
|
20
|
+
LOG_DIR_HELP = """
|
|
21
|
+
Write a log file to the given directory. The log rotates, creating a new log file every day, while
|
|
22
|
+
storing logs for the last 7 days.
|
|
23
|
+
"""
|
|
24
|
+
LOG_TO_CONSOLE_HELP = """
|
|
25
|
+
If set, logging will be output to the console as well as the logging file."""
|
|
26
|
+
|
|
27
|
+
THREADS_HELP = """The number of threads that should download simultaneously"""
|
|
28
|
+
|
|
29
|
+
UPLOADER_DATABASE_FILEPATH_HELP = (
|
|
30
|
+
"Specify a filepath to the local md5 caching database."
|
|
31
|
+
)
|
|
32
|
+
LOCATION_HELP = """
|
|
33
|
+
Specify a location tag to associate with uploads, downloads, and submissions. A location tag allows
|
|
34
|
+
you to limit the scope of your uploads and downloads to jobs sharing the same location tag. This is
|
|
35
|
+
useful while using the uploader or downloader in daemon mode.
|
|
36
|
+
"""
|
|
37
|
+
UPLOADER_MD5_CACHING_HELP = """
|
|
38
|
+
Use cached md5s. This can dramatically improve the uploading times, as md5 checking can be very
|
|
39
|
+
time consuming. Caching md5s allows subsequent uploads (of the same files) to skip the md5
|
|
40
|
+
generation process (if the files appear to not have been modified since the last time they were
|
|
41
|
+
submitted). The cache is stored locally and uses a file's modification time and file size to
|
|
42
|
+
intelligently guess whether the file has changed. Set this flag to False if there is concern that
|
|
43
|
+
files may not be getting re-uploaded properly
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
UPLOADER_PATHS_HELP = """
|
|
47
|
+
A list of paths to upload. Use quotes if paths contain spaces or special characters"""
|
|
48
|
+
|
|
49
|
+
DOWNLOADER_JOB_ID_HELP = """
|
|
50
|
+
The job id(s) to download. When specified will only download those jobs and terminate afterwards
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
DOWNLOADER_OUTPUT_PATH_HELP = """
|
|
54
|
+
Override the output directory"""
|
|
55
|
+
|
|
56
|
+
PACKAGES_FORMAT_OPTIONS = ["text", "markdown", "html"]
|
|
57
|
+
PACKAGES_FORMAT_HELP = """
|
|
58
|
+
text: The output is a simple list of software names and versions, with nesting to indicate plugin
|
|
59
|
+
compatibility. Output is sent to stdout.
|
|
60
|
+
|
|
61
|
+
markdown: Designed for use in other markdown documentation systems where it benefits from consistent
|
|
62
|
+
styling. Output is sent to stdout and can be piped to a file.
|
|
63
|
+
|
|
64
|
+
html: Opens a browser window and displays the output in a simple html page.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
DOCS_PORT_HELP = """
|
|
68
|
+
The port to serve the documentation on. Defaults to 8025.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
DOWNLOADER_PAGE_SIZE_HELP = """
|
|
72
|
+
The number of files to request from the Conductor API at a time. Defaults to 50.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
PROGRESS_INTERVAL_HELP = """
|
|
76
|
+
The number of milliseconds to pass before printing a emitting a progress message. Defaults to 500.
|
|
77
|
+
"""
|
|
78
|
+
DEFAULT_PROGRESS_INTERVAL = 500
|
|
79
|
+
|
|
80
|
+
DOWNLOADER_FORCE_DOWNLOAD_HELP = """
|
|
81
|
+
Force download of files even if they already locally. MD5s will not be calculated or checked for this mode. The default is False.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
DOWNLOAD_REGEX_HELP = """
|
|
85
|
+
A regular expression to filter the files to download. Only files whose names match the regex are downloaded. If a task has multiple files and the regex matches only a subset of them, that subset is considered to be the entire task. This means that by default, tasks are reported to the server as downloaded, even though they weren't all downloaded.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
DOWNLOAD_DISABLE_REPORTING_HELP = """
|
|
89
|
+
Decide whether to report back to the server with the status of the download. If you use this flag the state of tasks on the server remains unaffected, whether it is downloaded or pernding.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
SEQ_FORMAT_HELP = """
|
|
93
|
+
The format of the graph to display. The default is text.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
DEFAULT_DOCS_PORT = 8025
|
|
98
|
+
|
|
99
|
+
LOG_FORMATTER = logging.Formatter(
|
|
100
|
+
"%(asctime)s %(name)s%(levelname)9s %(threadName)s: %(message)s"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
logger = logging.getLogger("conductor.cli")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
cfg = config.get()
|
|
107
|
+
DEFAULT_CONFIG_MD5_CACHING = cfg["md5_caching"]
|
|
108
|
+
DEFAULT_CONFIG_THREAD_COUNT = cfg["thread_count"]
|
|
109
|
+
DEFAULT_CONFIG_LOG_LEVEL = cfg["log_level"]
|
|
110
|
+
DEFAULT_DOWNLOADER_PAGE_SIZE = cfg["downloader_page_size"]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _set_logging(log_level, log_to_console=True, log_dir=None, log_filename=None):
|
|
114
|
+
level = loggeria.LEVEL_MAP.get(log_level)
|
|
115
|
+
loggeria.setup_conductor_logging(
|
|
116
|
+
logger_level=level,
|
|
117
|
+
log_dirpath=log_dir,
|
|
118
|
+
log_filename=log_filename,
|
|
119
|
+
console_formatter=loggeria.FORMATTER_VERBOSE,
|
|
120
|
+
disable_console_logging= not log_to_console,
|
|
121
|
+
use_system_log=True,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
print("Logging to %s" % loggeria.LOG_PATH)
|
|
125
|
+
|
|
126
|
+
def _register(client):
|
|
127
|
+
api_client.ApiClient.register_client(
|
|
128
|
+
client_name=client.CLIENT_NAME, client_version=VERSION
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
########################### MAIN #################################
|
|
132
|
+
@click.group(invoke_without_command=True)
|
|
133
|
+
@click.pass_context
|
|
134
|
+
@click.option("-v", "--version", is_flag=True, help="Print the version and exit.")
|
|
135
|
+
def main(ctx, version):
|
|
136
|
+
"""
|
|
137
|
+
Conductor Command-line interface.
|
|
138
|
+
|
|
139
|
+
To get help on subcommands, use the --help flag after the subcommand.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
conductor download --help
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
if not ctx.invoked_subcommand:
|
|
146
|
+
if version:
|
|
147
|
+
click.echo(VERSION)
|
|
148
|
+
ctx.exit()
|
|
149
|
+
click.echo(ctx.get_help())
|
|
150
|
+
ctx.exit()
|
|
151
|
+
|
|
152
|
+
############################# UPLOAD #############################
|
|
153
|
+
@main.command()
|
|
154
|
+
@click.option("-db", "--database_filepath", help=UPLOADER_DATABASE_FILEPATH_HELP)
|
|
155
|
+
@click.option(
|
|
156
|
+
"-md5",
|
|
157
|
+
"--md5_caching",
|
|
158
|
+
help=UPLOADER_MD5_CACHING_HELP,
|
|
159
|
+
type=bool,
|
|
160
|
+
default=DEFAULT_CONFIG_MD5_CACHING,
|
|
161
|
+
)
|
|
162
|
+
@click.option(
|
|
163
|
+
"-lv",
|
|
164
|
+
"--log_level",
|
|
165
|
+
help=LOG_LEVEL_HELP,
|
|
166
|
+
type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
|
|
167
|
+
show_choices=True,
|
|
168
|
+
default=DEFAULT_CONFIG_LOG_LEVEL,
|
|
169
|
+
)
|
|
170
|
+
@click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
|
|
171
|
+
@click.option("-lcl", "--log_to_console", is_flag=True, help=LOG_TO_CONSOLE_HELP, default=False)
|
|
172
|
+
@click.option(
|
|
173
|
+
"-tc",
|
|
174
|
+
"--thread_count",
|
|
175
|
+
type=int,
|
|
176
|
+
help=THREADS_HELP,
|
|
177
|
+
default=DEFAULT_CONFIG_THREAD_COUNT,
|
|
178
|
+
)
|
|
179
|
+
@click.option("-lc", "--location", help=LOCATION_HELP)
|
|
180
|
+
@click.argument("paths", nargs=-1, type=click.Path(exists=True, resolve_path=True))
|
|
181
|
+
def upload(
|
|
182
|
+
database_filepath, location, md5_caching, log_level, log_to_console, log_dir, thread_count, paths
|
|
183
|
+
):
|
|
184
|
+
"""Upload files to Conductor.
|
|
185
|
+
|
|
186
|
+
With no arguments, the uploader runs in daemon mode, watching for files to upload for submitted
|
|
187
|
+
jobs.
|
|
188
|
+
|
|
189
|
+
Alternatively, specify a list of paths to upload.
|
|
190
|
+
|
|
191
|
+
Example:
|
|
192
|
+
conductor upload file1 file2 file3
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
_set_logging(log_level, log_to_console=log_to_console, log_dir=log_dir, log_filename="conductor_uploader.log")
|
|
196
|
+
|
|
197
|
+
args_dict = {
|
|
198
|
+
"database_filepath": database_filepath,
|
|
199
|
+
"location": location,
|
|
200
|
+
"md5_caching": md5_caching,
|
|
201
|
+
"thread_count": thread_count,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
up = Uploader(args_dict)
|
|
205
|
+
|
|
206
|
+
if paths:
|
|
207
|
+
up.assets_only(*paths)
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
up.main()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
########################### PACKAGES #############################
|
|
214
|
+
@main.command()
|
|
215
|
+
@click.option(
|
|
216
|
+
"-f",
|
|
217
|
+
"--fmt",
|
|
218
|
+
"--format",
|
|
219
|
+
default="text",
|
|
220
|
+
help=PACKAGES_FORMAT_HELP,
|
|
221
|
+
type=click.Choice(choices=PACKAGES_FORMAT_OPTIONS, case_sensitive=False),
|
|
222
|
+
)
|
|
223
|
+
def packages(fmt):
|
|
224
|
+
"""List the software packages available on the render nodes in the cloud."""
|
|
225
|
+
package_query.pq(format=fmt)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
########################### DOCS #############################
|
|
229
|
+
@main.command()
|
|
230
|
+
@click.option(
|
|
231
|
+
"-p",
|
|
232
|
+
"--port",
|
|
233
|
+
help=DOCS_PORT_HELP,
|
|
234
|
+
type=int,
|
|
235
|
+
default=DEFAULT_DOCS_PORT,
|
|
236
|
+
)
|
|
237
|
+
def docs(port):
|
|
238
|
+
"""Open the Conductor Core documentation in a web browser."""
|
|
239
|
+
|
|
240
|
+
handler = http.server.SimpleHTTPRequestHandler
|
|
241
|
+
socketserver.TCPServer.allow_reuse_address = True
|
|
242
|
+
with socketserver.TCPServer(("", port), handler) as httpd:
|
|
243
|
+
print(f"Server started at http://localhost:{port}")
|
|
244
|
+
print("Press Ctrl+C to stop the server")
|
|
245
|
+
|
|
246
|
+
# Change to the directory containing your site
|
|
247
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
248
|
+
site_dir = os.path.join(current_dir, "docsite")
|
|
249
|
+
os.chdir(site_dir)
|
|
250
|
+
|
|
251
|
+
# Start the server
|
|
252
|
+
localhost_url = f"http://localhost:{port}"
|
|
253
|
+
webbrowser.open(localhost_url)
|
|
254
|
+
httpd.serve_forever()
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
########################### DEPRECATIONS #############################
|
|
258
|
+
############################# UPLOADER #############################
|
|
259
|
+
DEPRECATED_PATHS_HELP = "Specify a list of paths to upload."
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@main.command(deprecated=True)
|
|
263
|
+
@click.option("-db", "--database_filepath", help=UPLOADER_DATABASE_FILEPATH_HELP)
|
|
264
|
+
@click.option(
|
|
265
|
+
"-md5",
|
|
266
|
+
"--md5_caching",
|
|
267
|
+
help=UPLOADER_MD5_CACHING_HELP,
|
|
268
|
+
type=bool,
|
|
269
|
+
default=DEFAULT_CONFIG_MD5_CACHING,
|
|
270
|
+
)
|
|
271
|
+
@click.option(
|
|
272
|
+
"-lv",
|
|
273
|
+
"--log_level",
|
|
274
|
+
help=LOG_LEVEL_HELP,
|
|
275
|
+
type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
|
|
276
|
+
show_choices=True,
|
|
277
|
+
default=DEFAULT_CONFIG_LOG_LEVEL,
|
|
278
|
+
)
|
|
279
|
+
@click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
|
|
280
|
+
@click.option(
|
|
281
|
+
"-tc",
|
|
282
|
+
"--thread_count",
|
|
283
|
+
type=int,
|
|
284
|
+
help=THREADS_HELP,
|
|
285
|
+
default=DEFAULT_CONFIG_THREAD_COUNT,
|
|
286
|
+
)
|
|
287
|
+
@click.option("-lcl", "--log_to_console", is_flag=True, help=LOG_TO_CONSOLE_HELP, default=False)
|
|
288
|
+
@click.option("-lc", "--location", help=LOCATION_HELP)
|
|
289
|
+
@click.option(
|
|
290
|
+
"-p",
|
|
291
|
+
"--paths",
|
|
292
|
+
help=DEPRECATED_PATHS_HELP,
|
|
293
|
+
multiple=True,
|
|
294
|
+
type=click.Path(exists=True, resolve_path=True),
|
|
295
|
+
)
|
|
296
|
+
def uploader(
|
|
297
|
+
database_filepath, location, md5_caching, log_level, log_dir, log_to_console, thread_count, paths
|
|
298
|
+
):
|
|
299
|
+
"""Upload files to Conductor.
|
|
300
|
+
|
|
301
|
+
With no arguments, the uploader runs in daemon mode, watching for files to upload for submitted
|
|
302
|
+
jobs.
|
|
303
|
+
|
|
304
|
+
Alternatively, specify a list of paths to upload with the --paths option.
|
|
305
|
+
|
|
306
|
+
Example:
|
|
307
|
+
conductor upload file1 file2 file3
|
|
308
|
+
"""
|
|
309
|
+
_set_logging(log_level, log_to_console=log_to_console, log_dir=log_dir, log_filename="conductor_uploader.log")
|
|
310
|
+
|
|
311
|
+
args_dict = {
|
|
312
|
+
"database_filepath": database_filepath,
|
|
313
|
+
"location": location,
|
|
314
|
+
"md5_caching": md5_caching,
|
|
315
|
+
"thread_count": thread_count,
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
up = Uploader(args_dict)
|
|
319
|
+
|
|
320
|
+
if paths:
|
|
321
|
+
up.assets_only(*paths)
|
|
322
|
+
return
|
|
323
|
+
|
|
324
|
+
up.main()
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
########################### DOWNLOADER #############################
|
|
328
|
+
DEPRECATED_JOBID_HELP = (
|
|
329
|
+
"Download all the files from completed tasks for the given jobs."
|
|
330
|
+
)
|
|
331
|
+
DEPRECATED_TASKID_HELP = "Download the files from the given tasks in the specified job."
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@main.command(deprecated=True)
|
|
335
|
+
@click.option("-o", "--output", help=DOWNLOADER_OUTPUT_PATH_HELP)
|
|
336
|
+
@click.option("-j", "--job_id", help=DEPRECATED_JOBID_HELP)
|
|
337
|
+
@click.option("-t", "--task_id", help=DEPRECATED_TASKID_HELP)
|
|
338
|
+
@click.option(
|
|
339
|
+
"-lv",
|
|
340
|
+
"--log_level",
|
|
341
|
+
help=LOG_LEVEL_HELP,
|
|
342
|
+
type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
|
|
343
|
+
show_choices=True,
|
|
344
|
+
default=DEFAULT_CONFIG_LOG_LEVEL,
|
|
345
|
+
)
|
|
346
|
+
@click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
|
|
347
|
+
@click.option(
|
|
348
|
+
"-tc",
|
|
349
|
+
"--thread_count",
|
|
350
|
+
type=int,
|
|
351
|
+
help=THREADS_HELP,
|
|
352
|
+
default=DEFAULT_CONFIG_THREAD_COUNT,
|
|
353
|
+
)
|
|
354
|
+
@click.option("-lc", "--location", help=LOCATION_HELP)
|
|
355
|
+
@click.pass_context
|
|
356
|
+
def downloader(
|
|
357
|
+
ctx, job_id, task_id, output, location, log_level, log_dir, thread_count
|
|
358
|
+
):
|
|
359
|
+
"""
|
|
360
|
+
Download renders and other output files from Conductor. You can specify a job id and optional task id to
|
|
361
|
+
download, or you can omit all options and the downloader will run in daemon mode.
|
|
362
|
+
|
|
363
|
+
In daemon mode, the downloader polls for new jobs to download. You can specify a location tag to
|
|
364
|
+
limit the scope of the downloader to only download jobs that were submitted with the same
|
|
365
|
+
location tag.
|
|
366
|
+
|
|
367
|
+
Examples:
|
|
368
|
+
conductor downloader # daemon mode
|
|
369
|
+
conductor downloader --job_id --task_id 01234
|
|
370
|
+
conductor downloader --task_id --task_id 123
|
|
371
|
+
"""
|
|
372
|
+
click.secho("This command has been deprecated. Please use conductor download instead.", fg='red')
|
|
373
|
+
logfile = log_dir and os.path.join(log_dir, "conductor_dl.log")
|
|
374
|
+
_set_logging(log_level, logfile)
|
|
375
|
+
_register(Downloader)
|
|
376
|
+
|
|
377
|
+
if not job_id and not task_id:
|
|
378
|
+
Downloader.start_daemon(
|
|
379
|
+
thread_count=thread_count, location=location, output_dir=output
|
|
380
|
+
)
|
|
381
|
+
ctx.exit(0)
|
|
382
|
+
|
|
383
|
+
Downloader.download_jobs(
|
|
384
|
+
(job_id,),
|
|
385
|
+
task_id=task_id,
|
|
386
|
+
thread_count=thread_count,
|
|
387
|
+
output_dir=output,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
########################### PAGED DOWNLOAD #############################
|
|
392
|
+
@main.command()
|
|
393
|
+
@click.option("-f", "--force", is_flag=True, help=DOWNLOADER_FORCE_DOWNLOAD_HELP)
|
|
394
|
+
@click.option(
|
|
395
|
+
"-ps",
|
|
396
|
+
"--page_size",
|
|
397
|
+
type=int,
|
|
398
|
+
help=DOWNLOADER_PAGE_SIZE_HELP,
|
|
399
|
+
default=DEFAULT_DOWNLOADER_PAGE_SIZE,
|
|
400
|
+
)
|
|
401
|
+
@click.option(
|
|
402
|
+
"-o", "--output-path",
|
|
403
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
|
|
404
|
+
help=DOWNLOADER_OUTPUT_PATH_HELP,
|
|
405
|
+
)
|
|
406
|
+
@click.option(
|
|
407
|
+
"-pi",
|
|
408
|
+
"--progress_interval",
|
|
409
|
+
type=int,
|
|
410
|
+
help=PROGRESS_INTERVAL_HELP,
|
|
411
|
+
default=DEFAULT_PROGRESS_INTERVAL,
|
|
412
|
+
)
|
|
413
|
+
@click.option(
|
|
414
|
+
"-lv",
|
|
415
|
+
"--log_level",
|
|
416
|
+
help=LOG_LEVEL_HELP,
|
|
417
|
+
type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
|
|
418
|
+
show_choices=True,
|
|
419
|
+
default=DEFAULT_CONFIG_LOG_LEVEL,
|
|
420
|
+
)
|
|
421
|
+
@click.option(
|
|
422
|
+
"-tc",
|
|
423
|
+
"--thread_count",
|
|
424
|
+
type=int,
|
|
425
|
+
help=THREADS_HELP,
|
|
426
|
+
default=DEFAULT_CONFIG_THREAD_COUNT,
|
|
427
|
+
)
|
|
428
|
+
@click.option(
|
|
429
|
+
"-dr",
|
|
430
|
+
"--disable-reporting",
|
|
431
|
+
help=DOWNLOAD_DISABLE_REPORTING_HELP,
|
|
432
|
+
is_flag=True,
|
|
433
|
+
default=False,
|
|
434
|
+
)
|
|
435
|
+
@click.option("-r", "--regex", help=DOWNLOAD_REGEX_HELP)
|
|
436
|
+
@click.option("-lc", "--location", help=LOCATION_HELP)
|
|
437
|
+
@click.argument("jobids", nargs=-1)
|
|
438
|
+
def download(
|
|
439
|
+
jobids,
|
|
440
|
+
page_size,
|
|
441
|
+
output_path,
|
|
442
|
+
location,
|
|
443
|
+
progress_interval,
|
|
444
|
+
log_level,
|
|
445
|
+
thread_count,
|
|
446
|
+
force,
|
|
447
|
+
regex,
|
|
448
|
+
disable_reporting,
|
|
449
|
+
):
|
|
450
|
+
|
|
451
|
+
"""
|
|
452
|
+
Download renders and other output files from Conductor. You can give a list of job ids to
|
|
453
|
+
download, or you can omit jobids and the downloader will run in daemon mode.
|
|
454
|
+
|
|
455
|
+
If you provide jobids, the default behavior is to download all the files from completed tasks
|
|
456
|
+
for those jobs. You can however specify an explicit set of tasks to downloade by providing a
|
|
457
|
+
task range spec after each job id. To do so, append a colon to the job id and then a compact
|
|
458
|
+
task specification. See the examples.
|
|
459
|
+
|
|
460
|
+
In daemon mode, the downloader polls for new jobs to download. You can specify a location tag to
|
|
461
|
+
limit the scope of the downloader to only download jobs that were submitted with the same
|
|
462
|
+
location tag.
|
|
463
|
+
|
|
464
|
+
Examples:
|
|
465
|
+
|
|
466
|
+
conductor download # daemon mode
|
|
467
|
+
|
|
468
|
+
conductor download 1234 1235
|
|
469
|
+
|
|
470
|
+
conductor download 1234:1-10
|
|
471
|
+
|
|
472
|
+
conductor download 1234:1-5x2,10,12-14
|
|
473
|
+
|
|
474
|
+
conductor download 1234:1-5 1235:5-10
|
|
475
|
+
|
|
476
|
+
"""
|
|
477
|
+
|
|
478
|
+
_register(LoggingDownloadRunner)
|
|
479
|
+
|
|
480
|
+
# No longer uses Loggeria.
|
|
481
|
+
# Instead, it gets the logger with broken-pipe handling from the downloader.log module.
|
|
482
|
+
logging.getLogger(LOGGER_NAME).setLevel(LEVEL_MAP[log_level])
|
|
483
|
+
|
|
484
|
+
kwargs = {
|
|
485
|
+
"output_path": output_path,
|
|
486
|
+
"num_threads": thread_count,
|
|
487
|
+
"progress_interval": progress_interval,
|
|
488
|
+
"page_size": page_size,
|
|
489
|
+
"force": force,
|
|
490
|
+
"regex": regex,
|
|
491
|
+
"disable_reporting": disable_reporting,
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
dl = LoggingDownloadRunner(
|
|
495
|
+
jobids,
|
|
496
|
+
location,
|
|
497
|
+
**kwargs
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
dl.run()
|
|
501
|
+
|
ciocore/common.py
CHANGED
|
@@ -14,17 +14,10 @@ import sys
|
|
|
14
14
|
import time
|
|
15
15
|
import traceback
|
|
16
16
|
|
|
17
|
-
try:
|
|
18
|
-
from importlib.reload import reload
|
|
19
|
-
except ImportError:
|
|
20
|
-
from imp import reload
|
|
21
|
-
except ImportError:
|
|
22
|
-
reload = reload
|
|
23
|
-
|
|
24
17
|
BYTES_1KB = 1024
|
|
25
|
-
BYTES_1MB = BYTES_1KB
|
|
26
|
-
BYTES_1GB = BYTES_1KB
|
|
27
|
-
BYTES_1TB = BYTES_1KB
|
|
18
|
+
BYTES_1MB = BYTES_1KB**2
|
|
19
|
+
BYTES_1GB = BYTES_1KB**3
|
|
20
|
+
BYTES_1TB = BYTES_1KB**4
|
|
28
21
|
|
|
29
22
|
CONDUCTOR_LOGGER_NAME = "conductor"
|
|
30
23
|
|
|
@@ -283,7 +276,7 @@ class DecRetry(object):
|
|
|
283
276
|
sleep_time = self.static_sleep
|
|
284
277
|
else:
|
|
285
278
|
# use random for jitter.
|
|
286
|
-
sleep_time = random.randrange(0, 2
|
|
279
|
+
sleep_time = random.randrange(0, 2**try_num)
|
|
287
280
|
msg = "%s, Retrying in %d seconds..." % (str(e), sleep_time)
|
|
288
281
|
logger.warning(msg)
|
|
289
282
|
self.sleep(sleep_time)
|
|
@@ -371,7 +364,16 @@ def generate_md5(
|
|
|
371
364
|
|
|
372
365
|
while len(file_buffer) > 0:
|
|
373
366
|
hash_obj.update(file_buffer)
|
|
374
|
-
|
|
367
|
+
try:
|
|
368
|
+
file_buffer = file_obj.read(MD5_BLOCKSIZE)
|
|
369
|
+
except OSError:
|
|
370
|
+
logger.log(
|
|
371
|
+
log_level,
|
|
372
|
+
"Cannot read file '%s'. Is it corrupted or unavailable?",
|
|
373
|
+
filepath,
|
|
374
|
+
)
|
|
375
|
+
raise
|
|
376
|
+
|
|
375
377
|
curtime = time.time()
|
|
376
378
|
bytes_processed = buffer_count * MD5_BLOCKSIZE
|
|
377
379
|
percentage_processed = int((bytes_processed / float(file_size)) * 100)
|
|
@@ -435,4 +437,4 @@ def get_human_timestamp(seconds_since_epoch):
|
|
|
435
437
|
"""
|
|
436
438
|
convert the given seconds since epoch (float)
|
|
437
439
|
"""
|
|
438
|
-
return str(datetime.datetime.fromtimestamp(int(seconds_since_epoch)))
|
|
440
|
+
return str(datetime.datetime.fromtimestamp(int(seconds_since_epoch)))
|