@removed_uuids << link.uuid
link.destroy
end
- if item.owner_uuid == @object.uuid
+
+ # If this object has the 'expires_at' attribute, then simply mark it
+ # expired.
+ if item.attributes.include?("expires_at")
+ item.update_attributes expires_at: Time.now
+ @removed_uuids << item.uuid
+ elsif item.owner_uuid == @object.uuid
# Object is owned by this project. Remove it from the project by
# changing owner to the current user.
begin
<%= hidden_field_tag :offer_return_to, params[:offer_return_to] %>
<%= hidden_field_tag :return_to, profile_user_path(current_user.uuid, offer_return_to: params[:offer_return_to]) %>
<div class="form-group">
- <label for="email" class="col-sm-3 control-label"> Email </label>
+ <label for="email" class="col-sm-3 control-label"> E-mail </label>
<div class="col-sm-8">
<p class="form-control-static" id="email" name="email"><%=current_user.email%></p>
</div>
</div>
<div class="form-group">
- <label for="first_name" class="col-sm-3 control-label"> First name </label>
+ <label for="first_name" class="col-sm-3 control-label"> First Name </label>
<div class="col-sm-8">
<p class="form-control-static" id="first_name" name="first_name"><%=current_user.first_name%></p>
</div>
</div>
<div class="form-group">
- <label for="last_name" class="col-sm-3 control-label"> Last name </label>
+ <label for="last_name" class="col-sm-3 control-label"> Last Name </label>
<div class="col-sm-8">
<p class="form-control-static" id="last_name" name="last_name"><%=current_user.last_name%></p>
</div>
assert_response :success
end
- test "project admin can remove items from the project" do
+ test "project admin can remove collections from the project" do
+ # Deleting an object that supports 'expires_at' should make it
+ # completely inaccessible to API queries, not simply moved out of the project.
coll_key = "collection_to_remove_from_subproject"
coll_uuid = api_fixture("collections")[coll_key]["uuid"]
delete(:remove_item,
assert_response :success
assert_match(/\b#{coll_uuid}\b/, @response.body,
"removed object not named in response")
+
+ use_token :subproject_admin
+ assert_raise ArvadosApiClient::NotFoundException do
+ Collection.find(coll_uuid)
+ end
+ end
+
+ test "project admin can remove items from project other than collections" do
+ # An object which does not have an expired_at field (e.g. Specimen)
+ # should be implicitly moved to the user's Home project when removed.
+ specimen_uuid = api_fixture('specimens', 'in_asubproject')['uuid']
+ delete(:remove_item,
+ { id: api_fixture('groups', 'asubproject')['uuid'],
+ item_uuid: specimen_uuid,
+ format: 'js' },
+ session_for(:subproject_admin))
+ assert_response :success
+ assert_match(/\b#{specimen_uuid}\b/, @response.body,
+ "removed object not named in response")
+
+ use_token :subproject_admin
+ new_specimen = Specimen.find(specimen_uuid)
+ assert_equal api_fixture('users', 'subproject_admin')['uuid'], new_specimen.owner_uuid
end
test 'projects#show tab infinite scroll partial obeys limit' do
when 'Remove'
assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
- visit page_with_token 'active', '/'
- find("#projects-menu").click
- find(".dropdown-menu a", text: "Home").click
- assert page.has_text?(my_collection['name']), 'Collection not found in home project after remove'
- if expect_name_change
- assert page.has_text?(my_collection['name']+' removed from ' + src['name']),
- 'Collection with update name is not found in home project after remove'
- end
end
end
end
assert page.has_no_text?('Projects shared with me'), 'Found text - Projects shared with me'
assert page.has_text?('Profile'), 'No text - Profile'
- assert page.has_text?('First name'), 'No text - First name'
- assert page.has_text?('Last name'), 'No text - Last name'
+ assert page.has_text?('First Name'), 'No text - First Name'
+ assert page.has_text?('Last Name'), 'No text - Last Name'
assert page.has_text?('Identity URL'), 'No text - Identity URL'
- assert page.has_text?('Email'), 'No text - Email'
+ assert page.has_text?('E-mail'), 'No text - E-mail'
assert page.has_text?(user['email']), 'No text - user email'
# Using the default profile which has message and one required field
# Save profile without filling in the required field. Expect to be back in this profile page again
click_button "Save profile"
assert page.has_text?('Profile'), 'No text - Profile'
- assert page.has_text?('First name'), 'No text - First name'
- assert page.has_text?('Last name'), 'No text - Last name'
+ assert page.has_text?('First Name'), 'No text - First Name'
+ assert page.has_text?('Last Name'), 'No text - Last Name'
assert page.has_text?('Save profile'), 'No text - Save profile'
# This time fill in required field and then save. Expect to go to requested page after that.
exclude: ["Rakefile", "tmp", "vendor"]
navbar:
+ start:
+ - Getting Started:
+ - start/index.html.textile.liquid
+ - Quickstart:
+ - start/getting_started/firstpipeline.html.textile.liquid
+ - Common Use Cases:
+ - start/getting_started/sharedata.html.textile.liquid
+
userguide:
- Getting Started:
- user/index.html.textile.liquid
</div>
<div class="collapse navbar-collapse" id="bs-navbar-collapse">
<ul class="nav navbar-nav">
+ <li {% if page.navsection == 'start' %} class="active" {% endif %}><a href="{{ site.baseurl }}/start/index.html">Getting Started</a></li>
<li {% if page.navsection == 'userguide' %} class="active" {% endif %}><a href="{{ site.baseurl }}/user/index.html">User Guide</a></li>
<li {% if page.navsection == 'sdk' %} class="active" {% endif %}><a href="{{ site.baseurl }}/sdk/index.html">SDK Reference</a></li>
<li {% if page.navsection == 'api' %} class="active" {% endif %}><a href="{{ site.baseurl }}/api/index.html">API Reference</a></li>
<link href="{{ site.baseurl }}/css/badges.css" rel="stylesheet">
<link href="{{ site.baseurl }}/css/code.css" rel="stylesheet">
<link href="{{ site.baseurl }}/css/font-awesome.css" rel="stylesheet">
+ <link href="{{ site.baseurl }}/css/carousel-override.css" rel="stylesheet">
<style>
html {
height:100%;
--- /dev/null
+.carousel-control {
+ width: 5%;
+}
+
+.carousel-caption {
+ position: static;
+ background: rgba(0,0,0,0.6);
+ color: white;
+ padding-bottom: 35px;
+ padding-left: 1em;
+ padding-right: 1em;
+ padding-top: 15px;
+}
+
+.carousel {
+ overflow: hidden;
+ border-radius: 5px;
+ max-width: 900px;
+ margin: 1em;
+}
+
+.carousel-indicators {
+ bottom: 0px;
+}
+
<div class="row">
<div class="col-sm-6">
<h1>ARVADOS</h1>
- <p>manuals, guides, and references</p>
+ <p>A free and open source platform for big data science</p>
</div>
<div class="col-sm-6">
<img src="images/dax-reading-book.png" style="max-height: 10em" alt="Dax reading a book" />
<div class="container-fluid">
<div class="row">
<div class="col-sm-5">
- <p>This site contains documentation for the <a href="https://arvados.org/">Arvados platform</a>. The documentation is being developed as part of the open source project. It is a work in progress that has just gotten started. You can get involved by <a href="https://arvados.org/projects/arvados/wiki/Documentation">joining the documentation effort</a>.
+ <p><a href="https://arvados.org/">Arvados</a> enables you to quickly begin using cloud computing resources in your data science work. It allows you to track your methods and datasets, share them securely, and easily re-run analyses.
+ </p>
+ <p>Check out our <a href="{{ site.baseurl }}/start/index.html">key features</a>, complete with screenshots, and then follow our tutorial to <a href="{{ site.baseurl }}/start/getting_started/firstpipeline.html">run your first pipeline</a> using our <a href="http://lp.curoverse.com/beta-signup/">public beta</a>.
+ </p>
+ <p>On this page, you can also find more in-depth guides for using Arvados.
+ </p>
</div>
<div class="col-sm-7" style="border-left: solid; border-width: 1px">
+ <p>
+ <a href="{{ site.baseurl }}/start/index.html">Getting Started</a> — Start here if you're new to Arvados.
+ </p>
<p>
<a href="{{ site.baseurl }}/user/index.html">User Guide</a> — How to manage data and do analysis with Arvados.
</p>
--- /dev/null
+---
+layout: default
+navsection: start
+title: Run your first pipeline in minutes
+...
+
+h2. LobSTR v3
+
+In this quickstart guide, we'll run an existing pipeline with pre-existing data. Step-by-step instructions are shown below. You can follow along using your own local install or by using Curoverse's <a href="http://lp.curoverse.com/beta-signup/">hosted version of Arvados</a> (in public beta, any Google account can be used to login).
+
+(For more information about this pipeline, see our <a href="https://arvados.org/projects/arvados/wiki/LobSTR_tutorial">detailed lobSTR guide</a>).
+
+<div id="carousel-firstpipe" class="carousel slide" data-interval="false">
+ <!-- Indicators -->
+ <ol class="carousel-indicators">
+ <li data-target="#carousel-firstpipe" data-slide-to="0" class="active"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="1"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="2"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="3"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="4"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="5"></li>
+ <li data-target="#carousel-firstpipe" data-slide-to="6"></li>
+ </ol>
+
+ <!-- Wrapper for slides -->
+ <div class="carousel-inner" role="listbox">
+ <div class="item active">
+ <img src="{{ site.baseurl }}/images/quickstart/1.png" alt="Step 1. At the dashboard, click 'Run a pipeline...'.">
+ <div class="carousel-caption">
+ Step 1. At the dashboard, click 'Run a pipeline...'.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/2.png" alt="Choose 'lobstr v.3' and hit 'Next'.">
+ <div class="carousel-caption">
+ Choose 'lobstr v.3' and hit 'Next'.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/3.png" alt="Rename the pipeline instance, then click 'Run'. Click 'Choose' to change the default inputs.">
+ <div class="carousel-caption">
+ Rename the pipeline instance, then click 'Run'. Click 'Choose' to change the default inputs.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/4.png" alt="Here we search for and choose new inputs.">
+ <div class="carousel-caption">
+ Here we search for and choose new inputs.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/5.png" alt="After the job completes, you can re-run it with one click.">
+ <div class="carousel-caption">
+ After the job completes, you can re-run it with one click.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/6.png" alt="You can inspect details about the pipeline which are automatically logged.">
+ <div class="carousel-caption">
+ You can inspect automatically-logged details about the pipeline.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/quickstart/7.png" alt="Click 'Create sharing link' to share the output files with people outside Arvados. [END]">
+ <div class="carousel-caption">
+ Click 'Create sharing link' to share the output files with people outside Arvados. [END]
+ </div>
+ </div>
+
+ </div>
+
+ <!-- Controls -->
+ <a class="left carousel-control" href="#carousel-firstpipe" role="button" data-slide="prev">
+ <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
+ <span class="sr-only">Previous</span>
+ </a>
+ <a class="right carousel-control" href="#carousel-firstpipe" role="button" data-slide="next">
+ <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+ <span class="sr-only">Next</span>
+ </a>
+</div>
+
+Tip: You may need to make your browser window bigger to see full-size images in the gallery above.
--- /dev/null
+---
+layout: default
+navsection: start
+title: Sharing Data
+...
+
+You can easily share data entirely through Workbench, the web interface to Arvados.
+
+h2. Upload and share your existing data
+
+Step-by-step instructions are shown below.
+
+<div id="carousel-sharedata" class="carousel slide" data-interval="false">
+ <!-- Indicators -->
+ <ol class="carousel-indicators">
+ <li data-target="#carousel-sharedata" data-slide-to="0" class="active"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="1"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="2"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="3"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="4"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="5"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="6"></li>
+ <li data-target="#carousel-sharedata" data-slide-to="7"></li>
+ </ol>
+
+ <!-- Wrapper for slides -->
+ <div class="carousel-inner" role="listbox">
+ <div class="item active">
+ <img src="{{ site.baseurl }}/images/uses/gotohome.png" alt="Step 1. From the dashboard, go to your Home project.">
+ <div class="carousel-caption">
+ Step 1. From the dashboard, go to your Home project.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/uploaddata.png" alt="Click 'Add data' → 'Upload files'.">
+ <div class="carousel-caption">
+ Click 'Add data' → 'Upload files'.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/choosefiles.png" alt="A new collection is created automatically. Choose files to upload and hit Start.">
+ <div class="carousel-caption">
+ A new collection is created automatically. Choose files to upload and hit Start.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/uploading.png" alt="Files will upload and stay uploaded even if the browser is closed.">
+ <div class="carousel-caption">
+ Files will upload and stay uploaded even if the browser is closed.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/rename.png" alt="Rename the collection appropriately.">
+ <div class="carousel-caption">
+ Rename the collection appropriately.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/share.png" alt="Click 'Create sharing link'. You can click 'unshare' at any later point.">
+ <div class="carousel-caption">
+ Click 'Create sharing link'. You can click 'Unshare' at any later point.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/shared.png" alt="Now just share this link with anyone you want.">
+ <div class="carousel-caption">
+ Now just share this link with anyone you want.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/uses/sharedsubdirs.png" alt="Here's a more complex collection. [END]">
+ <div class="carousel-caption">
+ Here's a more complex collection. [END]
+ </div>
+ </div>
+
+ </div>
+
+ <!-- Controls -->
+ <a class="left carousel-control" href="#carousel-sharedata" role="button" data-slide="prev">
+ <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
+ <span class="sr-only">Previous</span>
+ </a>
+ <a class="right carousel-control" href="#carousel-sharedata" role="button" data-slide="next">
+ <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+ <span class="sr-only">Next</span>
+ </a>
+</div>
+
+Tip: You may need to make your browser window bigger to see full-size images in the gallery above.
--- /dev/null
+---
+layout: default
+navsection: start
+title: Welcome to Arvados!
+...
+
+This guide provides an introduction to using Arvados to solve big data bioinformatics problems.
+
+h2. What is Arvados?
+
+Arvados is a free and open source bioinformatics platform for genomic and biomedical data.
+
+We address the needs of IT directors, lab principals, and bioinformaticians.
+
+h2. Why use Arvados?
+
+Arvados enables you to quickly begin using cloud computing resources in your bioinformatics work. It allows you to track your methods and datasets, share them securely, and easily re-run analyses.
+
+h3. Take a look (Screenshots gallery)
+
+<div id="carousel-keyfeatures" class="carousel slide" data-interval="false">
+ <!-- Indicators -->
+ <ol class="carousel-indicators">
+ <li data-target="#carousel-keyfeatures" data-slide-to="0" class="active"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="1"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="2"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="3"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="4"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="5"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="6"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="7"></li>
+ <li data-target="#carousel-keyfeatures" data-slide-to="8"></li>
+ </ol>
+
+ <!-- Wrapper for slides -->
+ <div class="carousel-inner" role="listbox">
+ <div class="item active">
+ <img src="{{ site.baseurl }}/images/keyfeatures/dashboard2.png" alt="[START] After logging in, you will see Workbench's dashboard.">
+ <div class="carousel-caption">
+ [START] After logging in, you will see Workbench's dashboard.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/running2.png" alt="Pipelines describe a set of computational tasks (jobs).">
+ <div class="carousel-caption">
+ Pipelines describe a set of computational tasks (jobs).
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/log.png" alt="The output of all jobs is logged and stored automatically.">
+ <div class="carousel-caption">
+ The output of all jobs is logged and stored automatically.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/graph.png" alt="Pipelines can also be viewed in auto-generated graph form.">
+ <div class="carousel-caption">
+ Pipelines can also be viewed in auto-generated graph form.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/rerun.png" alt="Pipelines can easily be re-run exactly as before, or...">
+ <div class="carousel-caption">
+ Pipelines can easily be re-run exactly as before, or...
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/chooseinputs.png" alt="...you can change parameters or pick new datasets.">
+ <div class="carousel-caption">
+ ...you can change parameters or pick new datasets.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/webupload.png" alt="With web upload, data can be uploaded right in Workbench.">
+ <div class="carousel-caption">
+ With web upload, data can be uploaded right in Workbench.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/collectionpage.png" alt="Collections allow sharing datasets and job outputs easily. 'Create sharing link' with one click.">
+ <div class="carousel-caption">
+ Collections allow sharing datasets and job outputs easily. 'Create sharing link' with one click.
+ </div>
+ </div>
+
+ <div class="item">
+ <img src="{{ site.baseurl }}/images/keyfeatures/provenance.png" alt="Data provenance is tracked automatically. [END]">
+ <div class="carousel-caption">
+ Data provenance is tracked automatically. [END]
+ </div>
+ </div>
+
+
+ </div>
+
+ <!-- Controls -->
+ <a class="left carousel-control" href="#carousel-keyfeatures" role="button" data-slide="prev">
+ <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
+ <span class="sr-only">Previous</span>
+ </a>
+ <a class="right carousel-control" href="#carousel-keyfeatures" role="button" data-slide="next">
+ <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
+ <span class="sr-only">Next</span>
+ </a>
+</div>
+
+Note: Workbench is the web interface to Arvados.
+Tip: You may need to make your browser window bigger to see full-size images in the gallery above.
+
+h3. Key Features
+
+<ul>
+<li><strong>Track your methods</strong><br/>
+We log every compute job: software versions, machine images, input and output data hashes. Rely on a computer, not your memory and your note-taking skills.<br/><br/></li>
+<li><strong>Share your methods</strong><br/>
+Show other people what you did. Let them use your workflow on their own data. Publish a permalink to your methods and data, so others can reproduce and build on them easily.<br/><br/></li>
+<li><strong>Track data origin</strong><br/>
+Did you really only use fully consented public data in this analysis?<br/><br/></li>
+<li><strong>Get results sooner</strong><br/>
+Run your compute jobs faster by using multi-nodes and multi-cores, even if your programs are single-threaded.<br/><br/></li>
+</ul>
--- /dev/null
+---
+layout: default
+navsection: start
+title: Welcome to Arvados!
+...
+
+This guide provides an introduction to using Arvados to solve big data bioinformatics problems.
+
+
+h2. Typographic conventions
+
+This manual uses the following typographic conventions:
+
+<notextile>
+<ul>
+<li>Code blocks which are set aside from the text indicate user input to the system. Commands that should be entered into a Unix shell are indicated by the directory where you should enter the command ('~' indicates your home directory) followed by '$', followed by the highlighted <span class="userinput">command to enter</span> (do not enter the '$'), and possibly followed by example command output in black. For example, the following block indicates that you should type <code>ls foo.*</code> while in your home directory and the expected output will be "foo.input" and "foo.output".
+</notextile>
+
+<div class="custom-container key-features">
+<a class="prev" href="#">‹</a>
+
+<div class="carousel">
+ <ul>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/dashboard2.png" style="width:909px; height:503px;" title="[START] After logging in, you see Workbench's dashboard."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/running2.png" style="width:909px; height:503px;" title="Pipelines describe a set of computational tasks (jobs)."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/log.png" style="width:909px; height:503px;" title="The output of all jobs is logged and stored automatically."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/graph.png" style="width:909px; height:503px;" title="Pipelines can be also viewed in auto-generated graph form."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/rerun.png" style="width:909px; height:503px;" title="Pipelines can easily be re-run..."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/chooseinputs.png" style="width:909px; height:503px;" title="...by changing parameters or picking new datasets..."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/webupload.png" style="width:909px; height:503px;" title="...which can be uploaded right in Workbench."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/collectionpage.png" style="width:909px; height:503px;" title="Collections allow sharing datasets and job outputs easily."></li>
+ <li><img class="hascaption" src="{{ site.baseurl }}/images/keyfeatures/provenance.png" style="width:909px; height:503px;" title="Data provenance is tracked automatically. [END]"></li>
+ </ul>
+</div>
+<a class="next" href="#">›</a>
+<div class="clear"></div>
+</div>
+
+<script type="text/javascript">
+(function() {
+ $(".key-features .carousel").jCarouselLite({
+ btnNext: ".key-features .next",
+ btnPrev: ".key-features .prev",
+ visible: 1,
+ });
+});
+('.hascaption').each(function() {
+ $(this).after( "<div style='background: rgba(0,0,0,0.6); color: white; padding: 1.4em;'>" + $(this).attr('title') + "</div>" );
+});
+</script>
unlink "$destdir.commit";
mkdir $destdir;
-open TARX, "|-", "tar", "-xC", $destdir;
-{
- local $/ = undef;
- print TARX <DATA>;
+
+if (!open(TARX, "|-", "tar", "-xC", $destdir)) {
+ die "Error launching 'tar -xC $destdir': $!";
+}
+# If we send too much data to tar in one write (> 4-5 MiB), it stops, and we
+# get SIGPIPE. We must feed it data incrementally.
+my $tar_input;
+while (read(DATA, $tar_input, 65536)) {
+ print TARX $tar_input;
}
if(!close(TARX)) {
die "'tar -xC $destdir' exited $?: $!";
class EventClient(WebSocketClient):
def __init__(self, url, filters, on_event):
- ssl_options = None
- if re.match(r'(?i)^(true|1|yes)$',
- config.get('ARVADOS_API_HOST_INSECURE', 'no')):
- ssl_options={'cert_reqs': ssl.CERT_NONE}
+ # Prefer system's CA certificates (if available)
+ ssl_options = {}
+ certs_path = '/etc/ssl/certs/ca-certificates.crt'
+ if os.path.exists(certs_path):
+ ssl_options['ca_certs'] = certs_path
+ if config.flag_is_true('ARVADOS_API_HOST_INSECURE'):
+ ssl_options['cert_reqs'] = ssl.CERT_NONE
else:
- ssl_options={'cert_reqs': ssl.CERT_REQUIRED}
+ ssl_options['cert_reqs'] = ssl.CERT_REQUIRED
super(EventClient, self).__init__(url, ssl_options=ssl_options)
self.filters = filters
self.on_event = on_event
cid string
}
-func CopyPipeToChan(in io.Reader, out chan string, done chan<- bool) {
+func CopyPipeToChan(in io.ReadCloser, out chan string, done chan<- bool) {
+ defer in.Close()
+
+ // TODO(twp): handle long input records gracefully, if possible
+ // without killing the child task (#4889)
+ //
s := bufio.NewScanner(in)
for s.Scan() {
out <- s.Text()
}
+ if s.Err() != nil {
+ out <- fmt.Sprintf("crunchstat: line buffering error: %s", s.Err())
+ }
done <- true
}
}
var logChan chan string
+
func LogPrintf(format string, args ...interface{}) {
if logChan == nil {
return
}
- logChan <- fmt.Sprintf("crunchstat: " + format, args...)
+ logChan <- fmt.Sprintf("crunchstat: "+format, args...)
}
func ReadAllOrWarn(in *os.File) ([]byte, error) {
package main
import (
+ "bufio"
+ "io"
"os"
"regexp"
"testing"
t.Fatalf("Expected channel to close, got %s", msg)
}
}
+
+// Test that if CopyPipeToChan reads a line longer than
+// bufio.MaxScanTokenSize, it emits an error to the output channel.
+func TestCopyPipeToChanLongLines(t *testing.T) {
+ logChan := make(chan string)
+ control := make(chan bool)
+
+ pipeIn, pipeOut := io.Pipe()
+ go CopyPipeToChan(pipeIn, logChan, control)
+
+ go func() {
+ long_line := make([]byte, bufio.MaxScanTokenSize+1)
+ for i := range long_line {
+ long_line[i] = byte('x')
+ }
+ pipeOut.Write(long_line)
+ }()
+
+ // Expect error message from logChan.
+
+ errmsg := <-logChan
+ if matched, err := regexp.MatchString("^crunchstat: line buffering error:.*token too long", errmsg); err != nil || !matched {
+ t.Fatalf("expected CopyPipeToChan error, got %s", errmsg)
+ }
+
+ <-control
+}