if test -z "$packages" ; then
packages="arvados-api-server
+ arvados-client
arvados-docker-cleaner
arvados-git-httpd
arvados-node-manager
cd $WORKSPACE/packages/$TARGET
export GOPATH=$(mktemp -d)
go get github.com/kardianos/govendor
+package_go_binary cmd/arvados-client arvados-client \
+ "Arvados command line tool (beta)"
package_go_binary sdk/go/crunchrunner crunchrunner \
"Crunchrunner executes a command inside a container and uploads the output"
package_go_binary services/arv-git-httpd arvados-git-httpd \
apps/workbench_integration (*)
apps/workbench_benchmark
apps/workbench_profile
+cmd/arvados-client
doc
+lib/cli
+lib/cmd
+lib/crunchstat
services/api
services/arv-git-httpd
services/crunchstat
export PERLINSTALLBASE
export PERLLIB="$PERLINSTALLBASE/lib/perl5:${PERLLIB:+$PERLLIB}"
+
export GOPATH
mkdir -p "$GOPATH/src/git.curoverse.com"
-rmdir --parents "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
-ln -snfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
+rmdir -v --parents --ignore-fail-on-non-empty "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
+for d in \
+ "$GOPATH/src/git.curoverse.com/arvados.git/arvados.git" \
+ "$GOPATH/src/git.curoverse.com/arvados.git"; do
+ [[ -d "$d" ]] && rmdir "$d"
+ [[ -h "$d" ]] && rm "$d"
+done
+ln -vsnfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
|| fatal "symlink failed"
go get -v github.com/kardianos/govendor \
|| fatal "govendor install failed"
+cd "$GOPATH/src/git.curoverse.com/arvados.git" \
+ || fatal
+# Remove cached source dirs in workdir. Otherwise, they won't qualify
+# as +missing or +external below, and we won't be able to detect that
+# they're missing from vendor/vendor.json.
+rm -r vendor/*/
+go get -v -d ...
+"$GOPATH/bin/govendor" sync \
+ || fatal "govendor sync failed"
+[[ -z $("$GOPATH/bin/govendor" list +unused +missing +external | tee /dev/stderr) ]] \
+ || fatal "vendor/vendor.json has unused or missing dependencies -- try:
+* govendor remove +unused
+* govendor add +missing +external
+"
+cd "$WORKSPACE"
+
setup_virtualenv "$VENVDIR" --python python2.7
. "$VENVDIR/bin/activate"
}
do_install services/api apiserver
-cd "$GOPATH/src/git.curoverse.com/arvados.git" && \
- "$GOPATH/bin/govendor" sync -v || \
- fatal "govendor sync failed"
declare -a gostuff
gostuff=(
+ cmd/arvados-client
+ lib/cli
+ lib/cmd
+ lib/crunchstat
sdk/go/arvados
sdk/go/arvadosclient
sdk/go/blockdigest
sdk/go/asyncbuf
sdk/go/crunchrunner
sdk/go/stats
- lib/crunchstat
services/arv-git-httpd
services/crunchstat
services/health
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "runtime"
+
+ "git.curoverse.com/arvados.git/lib/cli"
+ "git.curoverse.com/arvados.git/lib/cmd"
+)
+
+var (
+ version = "dev"
+ cmdVersion cmd.Handler = versionCmd{}
+ handler = cmd.Multi(map[string]cmd.Handler{
+ "-e": cmdVersion,
+ "version": cmdVersion,
+ "-version": cmdVersion,
+ "--version": cmdVersion,
+
+ "copy": cli.Copy,
+ "create": cli.Create,
+ "edit": cli.Edit,
+ "get": cli.Get,
+ "keep": cli.Keep,
+ "pipeline": cli.Pipeline,
+ "run": cli.Run,
+ "tag": cli.Tag,
+ "ws": cli.Ws,
+
+ "api_client_authorization": cli.APICall,
+ "api_client": cli.APICall,
+ "authorized_key": cli.APICall,
+ "collection": cli.APICall,
+ "container": cli.APICall,
+ "container_request": cli.APICall,
+ "group": cli.APICall,
+ "human": cli.APICall,
+ "job": cli.APICall,
+ "job_task": cli.APICall,
+ "keep_disk": cli.APICall,
+ "keep_service": cli.APICall,
+ "link": cli.APICall,
+ "log": cli.APICall,
+ "node": cli.APICall,
+ "pipeline_instance": cli.APICall,
+ "pipeline_template": cli.APICall,
+ "repository": cli.APICall,
+ "specimen": cli.APICall,
+ "trait": cli.APICall,
+ "user_agreement": cli.APICall,
+ "user": cli.APICall,
+ "virtual_machine": cli.APICall,
+ "workflow": cli.APICall,
+ })
+)
+
+type versionCmd struct{}
+
+func (versionCmd) RunCommand(prog string, args []string, _ io.Reader, stdout, _ io.Writer) int {
+ prog = regexp.MustCompile(` -*version$`).ReplaceAllLiteralString(prog, "")
+ fmt.Fprintf(stdout, "%s %s (%s)\n", prog, version, runtime.Version())
+ return 0
+}
+
+func fixLegacyArgs(args []string) []string {
+ flags, _ := cli.LegacyFlagSet()
+ return cmd.SubcommandToFront(args, flags)
+}
+
+func main() {
+ os.Exit(handler.RunCommand(os.Args[0], fixLegacyArgs(os.Args[1:]), os.Stdin, os.Stdout, os.Stderr))
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package main
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+
+ check "gopkg.in/check.v1"
+)
+
+// Gocheck boilerplate
+func Test(t *testing.T) {
+ check.TestingT(t)
+}
+
+var _ = check.Suite(&ClientSuite{})
+
+type ClientSuite struct{}
+
+func (s *ClientSuite) TestBadCommand(c *check.C) {
+ exited := handler.RunCommand("arvados-client", []string{"no such command"}, bytes.NewReader(nil), ioutil.Discard, ioutil.Discard)
+ c.Check(exited, check.Equals, 2)
+}
+
+func (s *ClientSuite) TestBadSubcommandArgs(c *check.C) {
+ exited := handler.RunCommand("arvados-client", []string{"get"}, bytes.NewReader(nil), ioutil.Discard, ioutil.Discard)
+ c.Check(exited, check.Equals, 2)
+}
+
+func (s *ClientSuite) TestVersion(c *check.C) {
+ stdout := bytes.NewBuffer(nil)
+ stderr := bytes.NewBuffer(nil)
+ exited := handler.RunCommand("arvados-client", []string{"version"}, bytes.NewReader(nil), stdout, stderr)
+ c.Check(exited, check.Equals, 0)
+ c.Check(stdout.String(), check.Matches, `arvados-client dev \(go[0-9\.]+\)\n`)
+ c.Check(stderr.String(), check.Equals, "")
+}
- user/topics/run-command.html.textile.liquid
- user/reference/job-pipeline-ref.html.textile.liquid
- user/examples/crunch-examples.html.textile.liquid
+ - Admin tools:
- user/topics/arvados-sync-groups.html.textile.liquid
+ - admin/change-account-owner.html.textile.liquid
+ - admin/merge-remote-account.html.textile.liquid
- Query the metadata database:
- user/topics/tutorial-trait-search.html.textile.liquid
- Arvados License:
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: "Changing account ownership"
+...
+{% comment %}
+Copyright (C) The Arvados Authors. All rights reserved.
+
+SPDX-License-Identifier: CC-BY-SA-3.0
+{% endcomment %}
+
+It is sometimes necessary to reassign an existing Arvados user account to a new Google account.
+
+Examples:
+* A user’s email address has changed from <code>person@old.example.com</code> to <code>person@new.example.com</code>.
+* A user who used to authenticate via LDAP is switching to Google login.
+
+This can be done by an administrator using Arvados APIs.
+
+First, determine the user’s existing UUID, e.g., @aaaaa-tpzed-abcdefghijklmno@.
+
+Ensure the new email address is not already associated with a different Arvados account. If it is, disassociate it by clearing that account’s @identity_url@ and @email@ fields.
+
+Clear the @identity_url@ field of the existing user record.
+
+Create a Link object with the following attributes (where @tail_uuid@ is the new email address, and @head_uuid@ is the existing user UUID):
+
+<notextile>
+<pre><code>{
+ "link_class":"permission",
+ "name":"can_login",
+ "tail_uuid":"<span class="userinput">person@new.example.com</span>",
+ "head_uuid":"<span class="userinput">aaaaa-tpzed-abcdefghijklmno</span>",
+ "properties":{
+ "identity_url_prefix":"https://www.google.com/"
+ }
+}
+</code></pre>
+</notextile>
+
+Have the user log in using their <code>person@new.example.com</code> Google account. You can verify this by checking that the @identity_url@ field has been populated.
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: "Merging a remote account"
+...
+{% comment %}
+Copyright (C) The Arvados Authors. All rights reserved.
+
+SPDX-License-Identifier: CC-BY-SA-3.0
+{% endcomment %}
+
+When you use federation capabilities to connect two or more clusters that were already operating, some users might already have accounts on multiple clusters. Typically, they will want to choose a single account on one of the clusters and abandon the rest, transferring all data or permissions from their old “remote” accounts to a single “home” account.
+
+This effect can be achieved by changing the UUIDs of the user records on the remote clusters. This should be done before the user has ever used federation features to access cluster B with cluster A credentials. Otherwise, see "managing conflicting accounts" below.
+
+For example, a user might have:
+* an account A on cluster A with uuid @aaaaa-tpzed-abcdefghijklmno@, and
+* an account B on cluster B with uuid @bbbbb-tpzed-lmnopqrstuvwxyz@
+
+An administrator at cluster B can merge the two accounts by renaming account B to account A.
+
+<notextile>
+<pre><code>#!/usr/bin/env python
+import arvados
+arvados.api('v1').users().update_uuid(
+ uuid="<span class="userinput">bbbbb-tpzed-lmnopqrstuvwxyz</span>",
+ new_uuid="<span class="userinput">aaaaa-tpzed-abcdefghijklmno</span>").execute()
+</code></pre></notextile>
+
+This should be done when the user is idle, i.e., not logged in and not running any jobs or containers.
+
+h2. Managing conflicting accounts
+
+If the user has already used federation capabilities to access cluster B using account A before the above migration has been done, this will have already created a database entry for account A on cluster B, and the above program will error out. To fix this, the same "update_uuid API call":../api/methods/users.html#update_uuid can be used to move the conflicting account out of the way first.
+
+<notextile>
+<pre><code>#!/usr/bin/env python
+import arvados
+import random
+import string
+random_chars = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(15))
+arvados.api('v1').users().update_uuid(
+ uuid="<span class="userinput">aaaaa-tpzed-abcdefghijklmno</span>",
+ new_uuid="bbbbb-tpzed-"+random_chars).execute()
+</code></pre></notextile>
+
+After this is done and the migration is complete, the affected user should wait 5 minutes for the authorization cache to expire before using the remote cluster.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the User in question.|path||
|user|object||query||
+
+h3(#update_uuid). update_uuid
+
+Change the UUID of an existing user, updating all database references accordingly.
+
+This method can only be used by an admin user. It should only be used when the affected user is idle. New references to the affected user that are established _while the update_uuid operation is in progress_ might not be migrated as expected.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |_. Example |
+{background:#ccffcc}.|uuid|string|The current UUID of the user in question.|path|@zzzzz-tpzed-12345abcde12345@|
+{background:#ccffcc}.|new_uuid|string|The desired new UUID. It is an error to use a UUID belonging to an existing user.|query|@zzzzz-tpzed-abcde12345abcde@|
*@ControlMachine@* should be a DNS name that resolves to the SLURM controller (dispatch/API server). This must resolve correctly on all SLURM worker nodes as well as the controller itself. In general SLURM is very sensitive about all of the nodes being able to communicate with the controller _and one another_, all using the same DNS names.
+*@SelectType=select/linear@* is needed on cloud-based installations that update node sizes dynamically, but it can only schedule one container at a time on each node. On a static or homogeneous cluster, use @SelectType=select/cons_res@ with @SelectTypeParameters=CR_CPU_Memory@ instead to enable node sharing.
+
*@NodeName=compute[0-255]@* establishes that the hostnames of the worker nodes will be compute0, compute1, etc. through compute255.
* There are several ways to compress sequences of names, like @compute[0-9,80,100-110]@. See the "hostlist" discussion in the @slurm.conf(5)@ and @scontrol(1)@ man pages for more information.
* It is not necessary for all of the nodes listed here to be alive in order for SLURM to work, although you should make sure the DNS entries exist. It is easiest to define lots of hostnames up front, assigning them to real nodes and updating your DNS records as the nodes appear. This minimizes the frequency of @slurm.conf@ updates and use of @scontrol reconfigure@.
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package cli
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os/exec"
+ "strings"
+ "syscall"
+
+ "git.curoverse.com/arvados.git/lib/cmd"
+)
+
+var (
+ Create = rubyArvCmd{"create"}
+ Edit = rubyArvCmd{"edit"}
+
+ Copy = externalCmd{"arv-copy"}
+ Tag = externalCmd{"arv-tag"}
+ Ws = externalCmd{"arv-ws"}
+ Run = externalCmd{"arv-run"}
+
+ Keep = cmd.Multi(map[string]cmd.Handler{
+ "get": externalCmd{"arv-get"},
+ "put": externalCmd{"arv-put"},
+ "ls": externalCmd{"arv-ls"},
+ "normalize": externalCmd{"arv-normalize"},
+ "docker": externalCmd{"arv-keepdocker"},
+ })
+ Pipeline = cmd.Multi(map[string]cmd.Handler{
+ "run": externalCmd{"arv-run-pipeline-instance"},
+ })
+ // user, group, container, specimen, etc.
+ APICall = apiCallCmd{}
+)
+
+// When using the ruby "arv" command, flags must come before the
+// subcommand: "arv --format=yaml get foo" works, but "arv get
+// --format=yaml foo" does not work.
+func legacyFlagsToFront(subcommand string, argsin []string) (argsout []string) {
+ flags, _ := LegacyFlagSet()
+ flags.SetOutput(ioutil.Discard)
+ flags.Parse(argsin)
+ narg := flags.NArg()
+ argsout = append(argsout, argsin[:len(argsin)-narg]...)
+ argsout = append(argsout, subcommand)
+ argsout = append(argsout, argsin[len(argsin)-narg:]...)
+ return
+}
+
+type apiCallCmd struct{}
+
+func (cmd apiCallCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ split := strings.Split(prog, " ")
+ if len(split) < 2 {
+ fmt.Fprintf(stderr, "internal error: no api model in %q\n", prog)
+ return 2
+ }
+ model := split[len(split)-1]
+ return externalCmd{"arv"}.RunCommand("arv", legacyFlagsToFront(model, args), stdin, stdout, stderr)
+}
+
+type rubyArvCmd struct {
+ subcommand string
+}
+
+func (rc rubyArvCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ return externalCmd{"arv"}.RunCommand("arv", legacyFlagsToFront(rc.subcommand, args), stdin, stdout, stderr)
+}
+
+type externalCmd struct {
+ prog string
+}
+
+func (ec externalCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ cmd := exec.Command(ec.prog, args...)
+ cmd.Stdin = stdin
+ cmd.Stdout = stdout
+ cmd.Stderr = stderr
+ err := cmd.Run()
+ switch err := err.(type) {
+ case nil:
+ return 0
+ case *exec.ExitError:
+ status := err.Sys().(syscall.WaitStatus)
+ if status.Exited() {
+ return status.ExitStatus()
+ }
+ fmt.Fprintf(stderr, "%s failed: %s\n", ec.prog, err)
+ return 1
+ case *exec.Error:
+ fmt.Fprintln(stderr, err)
+ if ec.prog == "arv" || ec.prog == "arv-run-pipeline-instance" {
+ fmt.Fprint(stderr, rubyInstallHints)
+ } else if strings.HasPrefix(ec.prog, "arv-") {
+ fmt.Fprint(stderr, pythonInstallHints)
+ }
+ return 1
+ default:
+ fmt.Fprintf(stderr, "error running %s: %s\n", ec.prog, err)
+ return 1
+ }
+}
+
+var (
+ rubyInstallHints = `
+Note: This subcommand uses the arvados-cli Ruby gem. If that is not
+installed, try "gem install arvados-cli", or see
+https://doc.arvados.org/install for more details.
+
+`
+ pythonInstallHints = `
+Note: This subcommand uses the "arvados" Python module. If that is
+not installed, try:
+* "pip install arvados" (either as root or in a virtualenv), or
+* "sudo apt-get install python-arvados-python-client", or
+* see https://doc.arvados.org/install for more details.
+
+`
+)
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package cli
+
+import (
+ "flag"
+
+ "git.curoverse.com/arvados.git/lib/cmd"
+ "rsc.io/getopt"
+)
+
+type LegacyFlagValues struct {
+ Format string
+ DryRun bool
+ Short bool
+ Verbose bool
+}
+
+func LegacyFlagSet() (cmd.FlagSet, *LegacyFlagValues) {
+ values := &LegacyFlagValues{Format: "json"}
+ flags := getopt.NewFlagSet("", flag.ContinueOnError)
+ flags.BoolVar(&values.DryRun, "dry-run", false, "Don't actually do anything")
+ flags.Alias("n", "dry-run")
+ flags.StringVar(&values.Format, "format", values.Format, "Output format: json, yaml, or uuid")
+ flags.Alias("f", "format")
+ flags.BoolVar(&values.Short, "short", false, "Return only UUIDs (equivalent to --format=uuid)")
+ flags.Alias("s", "short")
+ flags.BoolVar(&values.Verbose, "verbose", false, "Print more debug/progress messages on stderr")
+ flags.Alias("v", "verbose")
+ return flags, values
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package cli
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+
+ "git.curoverse.com/arvados.git/lib/cmd"
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "github.com/ghodss/yaml"
+)
+
+var Get cmd.Handler = getCmd{}
+
+type getCmd struct{}
+
+func (getCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ var err error
+ defer func() {
+ if err != nil {
+ fmt.Fprintf(stderr, "%s\n", err)
+ }
+ }()
+
+ flags, opts := LegacyFlagSet()
+ flags.SetOutput(stderr)
+ err = flags.Parse(args)
+ if err != nil {
+ return 2
+ }
+ if len(flags.Args()) != 1 {
+ fmt.Fprintf(stderr, "usage of %s:\n", prog)
+ flags.PrintDefaults()
+ return 2
+ }
+ if opts.Short {
+ opts.Format = "uuid"
+ }
+
+ id := flags.Args()[0]
+ client := arvados.NewClientFromEnv()
+ path, err := client.PathForUUID("show", id)
+ if err != nil {
+ return 1
+ }
+
+ var obj map[string]interface{}
+ err = client.RequestAndDecode(&obj, "GET", path, nil, nil)
+ if err != nil {
+ err = fmt.Errorf("GET %s: %s", path, err)
+ return 1
+ }
+ if opts.Format == "yaml" {
+ var buf []byte
+ buf, err = yaml.Marshal(obj)
+ if err == nil {
+ _, err = stdout.Write(buf)
+ }
+ } else if opts.Format == "uuid" {
+ fmt.Fprintln(stdout, obj["uuid"])
+ } else {
+ enc := json.NewEncoder(stdout)
+ enc.SetIndent("", " ")
+ err = enc.Encode(obj)
+ }
+ if err != nil {
+ err = fmt.Errorf("encoding: %s", err)
+ return 1
+ }
+ return 0
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package cli
+
+import (
+ "bytes"
+ "regexp"
+ "testing"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvadostest"
+ check "gopkg.in/check.v1"
+)
+
+// Gocheck boilerplate
+func Test(t *testing.T) {
+ check.TestingT(t)
+}
+
+var _ = check.Suite(&GetSuite{})
+
+type GetSuite struct{}
+
+func (s *GetSuite) TestGetCollectionJSON(c *check.C) {
+ stdout := bytes.NewBuffer(nil)
+ stderr := bytes.NewBuffer(nil)
+ exited := Get.RunCommand("arvados-client get", []string{arvadostest.FooCollection}, bytes.NewReader(nil), stdout, stderr)
+ c.Check(stdout.String(), check.Matches, `(?ms){.*"uuid": "`+arvadostest.FooCollection+`".*}\n`)
+ c.Check(stdout.String(), check.Matches, `(?ms){.*"portable_data_hash": "`+regexp.QuoteMeta(arvadostest.FooCollectionPDH)+`".*}\n`)
+ c.Check(stderr.String(), check.Equals, "")
+ c.Check(exited, check.Equals, 0)
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+// package cmd helps define reusable functions that can be exposed as
+// [subcommands of] command line programs.
+package cmd
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "sort"
+ "strings"
+)
+
+type Handler interface {
+ RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int
+}
+
+type HandlerFunc func(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int
+
+func (f HandlerFunc) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ return f(prog, args, stdin, stdout, stderr)
+}
+
+// Multi is a Handler that looks up its first argument in a map, and
+// invokes the resulting Handler with the remaining args.
+//
+// Example:
+//
+// os.Exit(Multi(map[string]Handler{
+// "foobar": HandlerFunc(func(prog string, args []string) int {
+// fmt.Println(args[0])
+// return 2
+// }),
+// })("/usr/bin/multi", []string{"foobar", "baz"}))
+//
+// ...prints "baz" and exits 2.
+type Multi map[string]Handler
+
+func (m Multi) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+ if len(args) < 1 {
+ fmt.Fprintf(stderr, "usage: %s command [args]\n", prog)
+ m.Usage(stderr)
+ return 2
+ }
+ if cmd, ok := m[args[0]]; !ok {
+ fmt.Fprintf(stderr, "unrecognized command %q\n", args[0])
+ m.Usage(stderr)
+ return 2
+ } else {
+ return cmd.RunCommand(prog+" "+args[0], args[1:], stdin, stdout, stderr)
+ }
+}
+
+func (m Multi) Usage(stderr io.Writer) {
+ fmt.Fprintf(stderr, "\nAvailable commands:\n")
+ m.listSubcommands(stderr, "")
+}
+
+func (m Multi) listSubcommands(out io.Writer, prefix string) {
+ var subcommands []string
+ for sc := range m {
+ if strings.HasPrefix(sc, "-") {
+ // Some subcommands have alternate versions
+ // like "--version" for compatibility. Don't
+ // clutter the subcommand summary with those.
+ continue
+ }
+ subcommands = append(subcommands, sc)
+ }
+ sort.Strings(subcommands)
+ for _, sc := range subcommands {
+ switch cmd := m[sc].(type) {
+ case Multi:
+ cmd.listSubcommands(out, prefix+sc+" ")
+ default:
+ fmt.Fprintf(out, " %s%s\n", prefix, sc)
+ }
+ }
+}
+
+type FlagSet interface {
+ Init(string, flag.ErrorHandling)
+ Args() []string
+ NArg() int
+ Parse([]string) error
+ SetOutput(io.Writer)
+ PrintDefaults()
+}
+
+// SubcommandToFront silently parses args using flagset, and returns a
+// copy of args with the first non-flag argument moved to the
+// front. If parsing fails or consumes all of args, args is returned
+// unchanged.
+//
+// SubcommandToFront invokes methods on flagset that have side
+// effects, including Parse. In typical usage, flagset will not used
+// for anything else after being passed to SubcommandToFront.
+func SubcommandToFront(args []string, flagset FlagSet) []string {
+ flagset.Init("", flag.ContinueOnError)
+ flagset.SetOutput(ioutil.Discard)
+ if err := flagset.Parse(args); err != nil || flagset.NArg() == 0 {
+ // No subcommand found.
+ return args
+ }
+ // Move subcommand to the front.
+ flagargs := len(args) - flagset.NArg()
+ newargs := make([]string, len(args))
+ newargs[0] = args[flagargs]
+ copy(newargs[1:flagargs+1], args[:flagargs])
+ copy(newargs[flagargs+1:], args[flagargs+1:])
+ return newargs
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package cmd
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "strings"
+ "testing"
+
+ "git.curoverse.com/arvados.git/lib/cmdtest"
+ check "gopkg.in/check.v1"
+)
+
+// Gocheck boilerplate
+func Test(t *testing.T) {
+ check.TestingT(t)
+}
+
+var _ = check.Suite(&CmdSuite{})
+
+type CmdSuite struct{}
+
+var testCmd = Multi(map[string]Handler{
+ "echo": HandlerFunc(func(prog string, args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) int {
+ fmt.Fprintln(stdout, strings.Join(args, " "))
+ return 0
+ }),
+})
+
+func (s *CmdSuite) TestHello(c *check.C) {
+ defer cmdtest.LeakCheck(c)()
+ stdout := bytes.NewBuffer(nil)
+ stderr := bytes.NewBuffer(nil)
+ exited := testCmd.RunCommand("prog", []string{"echo", "hello", "world"}, bytes.NewReader(nil), stdout, stderr)
+ c.Check(exited, check.Equals, 0)
+ c.Check(stdout.String(), check.Equals, "hello world\n")
+ c.Check(stderr.String(), check.Equals, "")
+}
+
+func (s *CmdSuite) TestUsage(c *check.C) {
+ defer cmdtest.LeakCheck(c)()
+ stdout := bytes.NewBuffer(nil)
+ stderr := bytes.NewBuffer(nil)
+ exited := testCmd.RunCommand("prog", []string{"nosuchcommand", "hi"}, bytes.NewReader(nil), stdout, stderr)
+ c.Check(exited, check.Equals, 2)
+ c.Check(stdout.String(), check.Equals, "")
+ c.Check(stderr.String(), check.Matches, `(?ms)^unrecognized command "nosuchcommand"\n.*echo.*\n`)
+}
+
+func (s *CmdSuite) TestSubcommandToFront(c *check.C) {
+ defer cmdtest.LeakCheck(c)()
+ flags := flag.NewFlagSet("", flag.ContinueOnError)
+ flags.String("format", "json", "")
+ flags.Bool("n", false, "")
+ args := SubcommandToFront([]string{"--format=yaml", "-n", "-format", "beep", "echo", "hi"}, flags)
+ c.Check(args, check.DeepEquals, []string{"echo", "--format=yaml", "-n", "-format", "beep", "hi"})
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+// Package cmdtest provides tools for testing command line tools.
+package cmdtest
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+
+ check "gopkg.in/check.v1"
+)
+
+// LeakCheck tests for output being leaked to os.Stdout and os.Stderr
+// that should be sent elsewhere (e.g., the stdout and stderr streams
+// passed to a cmd.RunFunc).
+//
+// It redirects os.Stdout and os.Stderr to a tempfile, and returns a
+// func, which the caller is expected to defer, that restores os.* and
+// checks that the tempfile is empty.
+//
+// Example:
+//
+// func (s *Suite) TestSomething(c *check.C) {
+// defer cmdtest.LeakCheck(c)()
+// // ... do things that shouldn't print to os.Stderr or os.Stdout
+// }
+func LeakCheck(c *check.C) func() {
+ tmpfiles := map[string]*os.File{"stdout": nil, "stderr": nil}
+ for i := range tmpfiles {
+ var err error
+ tmpfiles[i], err = ioutil.TempFile("", "")
+ c.Assert(err, check.IsNil)
+ err = os.Remove(tmpfiles[i].Name())
+ c.Assert(err, check.IsNil)
+ }
+
+ stdout, stderr := os.Stdout, os.Stderr
+ os.Stdout, os.Stderr = tmpfiles["stdout"], tmpfiles["stderr"]
+ return func() {
+ os.Stdout, os.Stderr = stdout, stderr
+
+ for i, tmpfile := range tmpfiles {
+ c.Log("checking %s", i)
+ _, err := tmpfile.Seek(0, io.SeekStart)
+ c.Assert(err, check.IsNil)
+ leaked, err := ioutil.ReadAll(tmpfile)
+ c.Assert(err, check.IsNil)
+ c.Check(string(leaked), check.Equals, "")
+ }
+ }
+}
import ruamel.yaml as yaml
-from .runner import upload_dependencies, packed_workflow, upload_workflow_collection, trim_anonymous_location, remove_redundant_fields
+from .runner import (upload_dependencies, packed_workflow, upload_workflow_collection,
+ trim_anonymous_location, remove_redundant_fields, discover_secondary_files)
from .pathmapper import ArvPathMapper, trim_listing
from .arvtool import ArvadosCommandTool
from .perf import Perf
raise WorkflowException("%s object must have 'id'" % (self.tool["class"]))
document_loader, workflowobj, uri = (self.doc_loader, self.doc_loader.fetch(self.tool["id"]), self.tool["id"])
+ discover_secondary_files(self.tool["inputs"], joborder)
+
with Perf(metrics, "subworkflow upload_deps"):
upload_dependencies(self.arvrunner,
os.path.basename(joborder.get("id", "#")),
"inputs": self.tool["inputs"],
"outputs": self.tool["outputs"],
"stdout": "cwl.output.json",
- "requirements": workflowobj["requirements"]+[
+ "requirements": self.requirements+[
{
"class": "InitialWorkDirRequirement",
"listing": [{
"entry": json.dumps(joborder_keepmount, indent=2, sort_keys=True, separators=(',',': ')).replace("\\", "\\\\").replace('$(', '\$(').replace('${', '\${')
}]
}],
- "hints": workflowobj["hints"],
+ "hints": self.hints,
"arguments": ["--no-container", "--move-outputs", "--preserve-entire-environment", "workflow.cwl#main", "cwl.input.yml"]
})
kwargs["loader"] = self.doc_loader
packed["http://schema.org/version"] = githash
-def upload_job_order(arvrunner, name, tool, job_order):
- """Upload local files referenced in the input object and return updated input
- object with 'location' updated to the proper keep references.
- """
-
- for t in tool.tool["inputs"]:
+def discover_secondary_files(inputs, job_order):
+ for t in inputs:
def setSecondary(fileobj):
if isinstance(fileobj, dict) and fileobj.get("class") == "File":
if "secondaryFiles" not in fileobj:
if shortname(t["id"]) in job_order and t.get("secondaryFiles"):
setSecondary(job_order[shortname(t["id"])])
+def upload_job_order(arvrunner, name, tool, job_order):
+ """Upload local files referenced in the input object and return updated input
+ object with 'location' updated to the proper keep references.
+ """
+
+ discover_secondary_files(tool.tool["inputs"], job_order)
+
jobmapper = upload_dependencies(arvrunner,
name,
tool.doc_loader,
out: out
tool: wf/runin-wf.cwl
doc: "RunInSingleContainer cwl.input.json needs to be consistent with pathmapper manipulations"
+
+- job: secondary/wf-job.yml
+ output: {}
+ tool: secondary/wf.cwl
+ doc: "RunInSingleContainer applies secondaryFile discovery & manipulation before generating cwl.input.yml"
+
+- job: null
+ output:
+ out: out
+ tool: wf/runin-with-ttl-wf.cwl
+ doc: "RunInSingleContainer respects outputTTL"
--- /dev/null
+cwlVersion: v1.0
+class: CommandLineTool
+inputs:
+ i:
+ type: File
+ inputBinding:
+ position: 1
+ secondaryFiles:
+ - .fai
+outputs: []
+arguments: [ls, $(inputs.i), $(inputs.i.path).fai]
--- /dev/null
+cwlVersion: v1.0
+class: Workflow
+$namespaces:
+ arv: "http://arvados.org/cwl#"
+ cwltool: "http://commonwl.org/cwltool#"
+inputs:
+ i:
+ type: File
+ secondaryFiles:
+ - .fai
+outputs: []
+steps:
+ step1:
+ in:
+ i: i
+ out: []
+ run: ls.cwl
--- /dev/null
+i:
+ class: File
+ location: keep:f225e6259bdd63bc7240599648dde9f1+97/hg19.fa
--- /dev/null
+cwlVersion: v1.0
+class: Workflow
+$namespaces:
+ arv: "http://arvados.org/cwl#"
+ cwltool: "http://commonwl.org/cwltool#"
+requirements:
+ SubworkflowFeatureRequirement: {}
+inputs:
+ i:
+ type: File
+ # secondaryFiles:
+ # - .fai
+ # - .ann
+ # - .amb
+outputs: []
+steps:
+ step1:
+ in:
+ i: i
+ out: []
+ run: sub.cwl
+ requirements:
+ arv:RunInSingleContainer: {}
--- /dev/null
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+class: Workflow
+cwlVersion: v1.0
+$namespaces:
+ arv: "http://arvados.org/cwl#"
+inputs:
+ fileblub:
+ type: File
+ default:
+ class: File
+ location: keep:d7514270f356df848477718d58308cc4+94/a
+ secondaryFiles:
+ - class: File
+ location: keep:d7514270f356df848477718d58308cc4+94/b
+outputs:
+ out:
+ type: string
+ outputSource: substep/out
+requirements:
+ SubworkflowFeatureRequirement: {}
+ ScatterFeatureRequirement: {}
+ InlineJavascriptRequirement: {}
+ StepInputExpressionRequirement: {}
+hints:
+ arv:IntermediateOutput:
+ outputTTL: 60
+steps:
+ substep:
+ in:
+ fileblub: fileblub
+ out: [out]
+ hints:
+ - class: arv:RunInSingleContainer
+ run:
+ class: Workflow
+ id: mysub
+ inputs:
+ fileblub: File
+ outputs:
+ out:
+ type: string
+ outputSource: cat1/out
+ steps:
+ cat1:
+ in:
+ fileblub: fileblub
+ out: [out]
+ run:
+ class: CommandLineTool
+ id: subtool
+ inputs:
+ fileblub:
+ type: File
+ inputBinding: {position: 1}
+ outputs:
+ out:
+ type: string
+ outputBinding:
+ outputEval: "out"
+ baseCommand: cat
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package arvados
+
+import "time"
+
+// Node is an arvados#node resource.
+type Node struct {
+ UUID string `json:"uuid"`
+ Domain string `json:"domain"`
+ Hostname string `json:"hostname"`
+ IPAddress string `json:"ip_address"`
+ LastPingAt *time.Time `json:"last_ping_at,omitempty"`
+ SlotNumber int `json:"slot_number"`
+ Status string `json:"status"`
+ JobUUID string `json:"job_uuid,omitempty"`
+ Properties NodeProperties `json:"properties"`
+}
+
+type NodeProperties struct {
+ CloudNode NodePropertiesCloudNode `json:"cloud_node"`
+ TotalCPUCores int `json:"total_cpu_cores,omitempty"`
+ TotalScratchMB int64 `json:"total_scratch_mb,omitempty"`
+ TotalRAMMB int64 `json:"total_ram_mb,omitempty"`
+}
+
+type NodePropertiesCloudNode struct {
+ Size string `json:"size,omitempty"`
+ Price float64 `json:"price"`
+}
+
+func (c Node) resourceName() string {
+ return "node"
+}
+
+// NodeList is an arvados#nodeList resource.
+type NodeList struct {
+ Items []Node `json:"items"`
+ ItemsAvailable int `json:"items_available"`
+ Offset int `json:"offset"`
+ Limit int `json:"limit"`
+}
SpectatorUserUUID = "zzzzz-tpzed-l1s2piq4t4mps8r"
UserAgreementCollection = "zzzzz-4zz18-uukreo9rbgwsujr" // user_agreement_in_anonymously_accessible_project
FooCollection = "zzzzz-4zz18-fy296fx3hot09f7"
+ FooCollectionPDH = "1f4b0bc7583c2a7f9102c395f4ffc5e3+45"
NonexistentCollection = "zzzzz-4zz18-totallynotexist"
HelloWorldCollection = "zzzzz-4zz18-4en62shvi99lxd4"
FooBarDirCollection = "zzzzz-4zz18-foonbarfilesdir"
[:activate, :current, :system, :setup]
skip_before_filter :render_404_if_no_object, only:
[:activate, :current, :system, :setup]
- before_filter :admin_required, only: [:setup, :unsetup]
+ before_filter :admin_required, only: [:setup, :unsetup, :update_uuid]
def current
if current_user
show
end
+ # Change UUID to a new (unused) uuid and transfer all owned/linked
+ # objects accordingly.
+ def update_uuid
+ @object.update_uuid(new_uuid: params[:new_uuid])
+ show
+ end
+
protected
def self._setup_requires_parameters
}
end
+ def self._update_uuid_requires_parameters
+ {
+ new_uuid: {
+ type: 'string', required: true,
+ },
+ }
+ end
+
def apply_filters(model_class=nil)
return super if @read_users.any?(&:is_admin)
if params[:uuid] != current_user.andand.uuid
# 5 minutes. TODO: Request the actual api_client_auth
# record from the remote server in case it wants the token
# to expire sooner.
- auth.update_attributes!(expires_at: Time.now + 5.minutes)
+ auth.update_attributes!(user: user,
+ api_token: secret,
+ api_client_id: 0,
+ expires_at: Time.now + 5.minutes)
end
return auth
else
end
def permission_to_update
- (permission_to_create and
- not uuid_changed? and
- not user_id_changed? and
- not owner_uuid_changed?)
+ permission_to_create && !uuid_changed? &&
+ (current_user.andand.is_admin || !user_id_changed?)
end
def log_update
end
end
+ def update_uuid(new_uuid:)
+ if !current_user.andand.is_admin
+ raise PermissionDeniedError
+ end
+ if uuid == system_user_uuid || uuid == anonymous_user_uuid
+ raise "update_uuid cannot update system accounts"
+ end
+ if self.class != self.class.resource_class_for_uuid(new_uuid)
+ raise "invalid new_uuid #{new_uuid.inspect}"
+ end
+ transaction(requires_new: true) do
+ reload
+ old_uuid = self.uuid
+ self.uuid = new_uuid
+ save!(validate: false)
+ ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |klass|
+ klass.columns.each do |col|
+ if col.name.end_with?('_uuid')
+ column = col.name.to_sym
+ klass.where(column => old_uuid).update_all(column => new_uuid)
+ end
+ end
+ end
+ end
+ end
+
protected
def ensure_ownership_path_leads_to_user
post 'activate', on: :member
post 'setup', on: :collection
post 'unsetup', on: :member
+ post 'update_uuid', on: :member
end
resources :virtual_machines do
get 'logins', on: :member
uuid: zzzzz-gj3su-077z32aux8dg2s2
api_client: untrusted
user: active
- api_token: 3kg6k6lzmp9kj6bpkcoxie963cmvjahbt2fod9zru30k1jqdmi
+ api_token: it2gl94mgu3rbn5s2d06vzh73ns1y6cthct0tvg82qdlsxvbwk
expires_at: 2038-01-01 00:00:00
-not_running_container_auth:
- uuid: zzzzz-gj3su-077z32aux8dg2s3
+running_to_be_deleted_container_auth:
+ uuid: zzzzz-gj3su-ty6lvu9d7u7c2sq
api_client: untrusted
user: active
- api_token: 4kg6k6lzmp9kj6bpkcoxie963cmvjahbt2fod9zru30k1jqdmj
+ api_token: ge1pez7dkk7nqntwcsj922g2b7a2t27xz6nsx39r15kbcqmp55
expires_at: 2038-01-01 00:00:00
permission_perftest:
runtime_constraints:
ram: 12000000000
vcpus: 4
- auth_uuid: zzzzz-gj3su-077z32aux8dg2s3
failed_container:
uuid: zzzzz-dz642-failedcontainr1
runtime_constraints:
ram: 12000000000
vcpus: 4
- auth_uuid: zzzzz-gj3su-077z32aux8dg2s2
+ auth_uuid: zzzzz-gj3su-ty6lvu9d7u7c2sq
"user's writable_by should include its owner_uuid")
end
+ [
+ [:admin, true],
+ [:active, false],
+ ].each do |auth_user, expect_success|
+ test "update_uuid as #{auth_user}" do
+ authorize_with auth_user
+ orig_uuid = users(:active).uuid
+ post :update_uuid, {
+ id: orig_uuid,
+ new_uuid: 'zbbbb-tpzed-abcde12345abcde',
+ }
+ if expect_success
+ assert_response :success
+ assert_empty User.where(uuid: orig_uuid)
+ else
+ assert_response 403
+ assert_not_empty User.where(uuid: orig_uuid)
+ end
+ end
+ end
+
NON_ADMIN_USER_DATA = ["uuid", "kind", "is_active", "email", "first_name",
"last_name"].sort
get '/arvados/v1/users/current', {format: 'json'}, auth(remote: 'zbbbb')
assert_response 401
+ # simulate cached token indicating wrong user (e.g., local user
+ # entry was migrated out of the way taking the cached token with
+ # it, or authorizing cluster reassigned auth to a different user)
+ ApiClientAuthorization.where(
+ uuid: salted_active_token(remote: 'zbbbb').split('/')[1]).
+ update_all(user_id: users(:active).id)
+
# revive original token and re-authorize
@stub_status = 200
@stub_content[:username] = 'blarney'
c.lock
c.update_attributes! state: Container::Running
- set_user_from_auth :not_running_container_auth
+ set_user_from_auth :running_to_be_deleted_container_auth
assert_raises ArvadosModel::PermissionDeniedError do
c.update_attributes! output: collections(:foo_file).portable_data_hash
end
end
end
+ [
+ [:active, 'zzzzz-borkd-abcde12345abcde'],
+ [:active, 'zzzzz-j7d0g-abcde12345abcde'],
+ [:active, 'zzzzz-tpzed-borkd'],
+ [:system_user, 'zzzzz-tpzed-abcde12345abcde'],
+ [:anonymous, 'zzzzz-tpzed-abcde12345abcde'],
+ ].each do |fixture, new_uuid|
+ test "disallow update_uuid #{fixture} -> #{new_uuid}" do
+ u = users(fixture)
+ orig_uuid = u.uuid
+ act_as_system_user do
+ assert_raises do
+ u.update_uuid(new_uuid: new_uuid)
+ end
+ end
+ # "Successfully aborted orig->new" outcome looks the same as
+ # "successfully updated new->orig".
+ assert_update_success(old_uuid: new_uuid,
+ new_uuid: orig_uuid,
+ expect_owned_objects: fixture == :active)
+ end
+ end
+
+ [:active, :spectator, :admin].each do |target|
+ test "update_uuid on #{target} as non-admin user" do
+ act_as_user users(:active) do
+ assert_raises(ArvadosModel::PermissionDeniedError) do
+ users(target).update_uuid(new_uuid: 'zzzzz-tpzed-abcde12345abcde')
+ end
+ end
+ end
+ end
+
+ test "update_uuid to existing uuid" do
+ u = users(:active)
+ orig_uuid = u.uuid
+ new_uuid = users(:admin).uuid
+ act_as_system_user do
+ assert_raises do
+ u.update_uuid(new_uuid: new_uuid)
+ end
+ end
+ u.reload
+ assert_equal u.uuid, orig_uuid
+ assert_not_empty Collection.where(owner_uuid: orig_uuid)
+ assert_not_empty Group.where(owner_uuid: orig_uuid)
+ end
+
+ [
+ [:active, 'zbbbb-tpzed-abcde12345abcde'],
+ [:active, 'zzzzz-tpzed-abcde12345abcde'],
+ [:admin, 'zbbbb-tpzed-abcde12345abcde'],
+ [:admin, 'zzzzz-tpzed-abcde12345abcde'],
+ ].each do |fixture, new_uuid|
+ test "update_uuid #{fixture} to unused uuid #{new_uuid}" do
+ u = users(fixture)
+ orig_uuid = u.uuid
+ act_as_system_user do
+ u.update_uuid(new_uuid: new_uuid)
+ end
+ assert_update_success(old_uuid: orig_uuid,
+ new_uuid: new_uuid,
+ expect_owned_objects: fixture == :active)
+ end
+ end
+
+ def assert_update_success(old_uuid:, new_uuid:, expect_owned_objects: true)
+ [[User, :uuid],
+ [Link, :head_uuid],
+ [Link, :tail_uuid],
+ [Group, :owner_uuid],
+ [Collection, :owner_uuid],
+ ].each do |klass, attr|
+ assert_empty klass.where(attr => old_uuid)
+ if klass == User || expect_owned_objects
+ assert_not_empty klass.where(attr => new_uuid)
+ end
+ end
+ end
end
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/git-httpd/git-httpd.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/crunch-dispatch-slurm/crunch-dispatch-slurm.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
cmd []string
}
-// LogNodeInfo gathers node information and store it on the log for debugging
-// purposes.
-func (runner *ContainerRunner) LogNodeInfo() (err error) {
+// LogHostInfo logs info about the current host, for debugging and
+// accounting purposes. Although it's logged as "node-info", this is
+// about the environment where crunch-run is actually running, which
+// might differ from what's described in the node record (see
+// LogNodeRecord).
+func (runner *ContainerRunner) LogHostInfo() (err error) {
w := runner.NewLogWriter("node-info")
commands := []infoCommand{
}
// LogContainerRecord gets and saves the raw JSON container record from the API server
-func (runner *ContainerRunner) LogContainerRecord() (err error) {
+func (runner *ContainerRunner) LogContainerRecord() error {
+ logged, err := runner.logAPIResponse("container", "containers", map[string]interface{}{"filters": [][]string{{"uuid", "=", runner.Container.UUID}}}, nil)
+ if !logged && err == nil {
+ err = fmt.Errorf("error: no container record found for %s", runner.Container.UUID)
+ }
+ return err
+}
+
+// LogNodeRecord logs arvados#node record corresponding to the current host.
+func (runner *ContainerRunner) LogNodeRecord() error {
+ hostname := os.Getenv("SLURMD_NODENAME")
+ if hostname == "" {
+ hostname, _ = os.Hostname()
+ }
+ _, err := runner.logAPIResponse("node", "nodes", map[string]interface{}{"filters": [][]string{{"hostname", "=", hostname}}}, func(resp interface{}) {
+ // The "info" field has admin-only info when obtained
+ // with a privileged token, and should not be logged.
+ node, ok := resp.(map[string]interface{})
+ if ok {
+ delete(node, "info")
+ }
+ })
+ return err
+}
+
+func (runner *ContainerRunner) logAPIResponse(label, path string, params map[string]interface{}, munge func(interface{})) (logged bool, err error) {
w := &ArvLogWriter{
ArvClient: runner.ArvClient,
UUID: runner.Container.UUID,
- loggingStream: "container",
- writeCloser: runner.LogCollection.Open("container.json"),
+ loggingStream: label,
+ writeCloser: runner.LogCollection.Open(label + ".json"),
}
- // Get Container record JSON from the API Server
- reader, err := runner.ArvClient.CallRaw("GET", "containers", runner.Container.UUID, "", nil)
+ reader, err := runner.ArvClient.CallRaw("GET", path, "", "", arvadosclient.Dict(params))
if err != nil {
- return fmt.Errorf("While retrieving container record from the API server: %v", err)
+ return false, fmt.Errorf("error getting %s record: %v", label, err)
}
defer reader.Close()
dec := json.NewDecoder(reader)
dec.UseNumber()
- var cr map[string]interface{}
- if err = dec.Decode(&cr); err != nil {
- return fmt.Errorf("While decoding the container record JSON response: %v", err)
+ var resp map[string]interface{}
+ if err = dec.Decode(&resp); err != nil {
+ return false, fmt.Errorf("error decoding %s list response: %v", label, err)
+ }
+ items, ok := resp["items"].([]interface{})
+ if !ok {
+ return false, fmt.Errorf("error decoding %s list response: no \"items\" key in API list response", label)
+ } else if len(items) < 1 {
+ return false, nil
+ }
+ if munge != nil {
+ munge(items[0])
}
// Re-encode it using indentation to improve readability
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
- if err = enc.Encode(cr); err != nil {
- return fmt.Errorf("While logging the JSON container record: %v", err)
+ if err = enc.Encode(items[0]); err != nil {
+ return false, fmt.Errorf("error logging %s record: %v", label, err)
}
err = w.Close()
if err != nil {
- return fmt.Errorf("While closing container.json log: %v", err)
+ return false, fmt.Errorf("error closing %s.json in log collection: %v", label, err)
}
- return nil
+ return true, nil
}
// AttachStreams connects the docker container stdin, stdout and stderr logs
if err != nil {
return
}
-
- // Gather and record node information
- err = runner.LogNodeInfo()
+ err = runner.LogHostInfo()
+ if err != nil {
+ return
+ }
+ err = runner.LogNodeRecord()
if err != nil {
return
}
- // Save container.json record on log collection
err = runner.LogContainerRecord()
if err != nil {
return
func (client *ArvTestClient) CallRaw(method, resourceType, uuid, action string,
parameters arvadosclient.Dict) (reader io.ReadCloser, err error) {
var j []byte
- if method == "GET" && resourceType == "containers" && action == "" && !client.callraw {
- j, err = json.Marshal(client.Container)
+ if method == "GET" && resourceType == "nodes" && uuid == "" && action == "" {
+ j = []byte(`{
+ "kind": "arvados#nodeList",
+ "items": [{
+ "uuid": "zzzzz-7ekkf-2z3mc76g2q73aio",
+ "hostname": "compute2",
+ "properties": {"total_cpu_cores": 16}
+ }]}`)
+ } else if method == "GET" && resourceType == "containers" && action == "" && !client.callraw {
+ if uuid == "" {
+ j, err = json.Marshal(map[string]interface{}{
+ "items": []interface{}{client.Container},
+ "kind": "arvados#nodeList",
+ })
+ } else {
+ j, err = json.Marshal(client.Container)
+ }
} else {
j = []byte(`{
"command": ["sleep", "1"],
}
func (s *TestSuite) TestNodeInfoLog(c *C) {
+ os.Setenv("SLURMD_NODENAME", "compute2")
api, _, _ := FullRunHelper(c, `{
"command": ["sleep", "1"],
"container_image": "d4ab34d3d4f8a72f5c4973051ae69fab+122",
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
c.Check(api.CalledWith("container.state", "Complete"), NotNil)
+ c.Assert(api.Logs["node"], NotNil)
+ json := api.Logs["node"].String()
+ c.Check(json, Matches, `(?ms).*"uuid": *"zzzzz-7ekkf-2z3mc76g2q73aio".*`)
+ c.Check(json, Matches, `(?ms).*"total_cpu_cores": *16.*`)
+ c.Check(json, Not(Matches), `(?ms).*"info":.*`)
+
c.Assert(api.Logs["node-info"], NotNil)
- c.Check(api.Logs["node-info"].String(), Matches, `(?ms).*Host Information.*`)
- c.Check(api.Logs["node-info"].String(), Matches, `(?ms).*CPU Information.*`)
- c.Check(api.Logs["node-info"].String(), Matches, `(?ms).*Memory Information.*`)
- c.Check(api.Logs["node-info"].String(), Matches, `(?ms).*Disk Space.*`)
- c.Check(api.Logs["node-info"].String(), Matches, `(?ms).*Disk INodes.*`)
+ json = api.Logs["node-info"].String()
+ c.Check(json, Matches, `(?ms).*Host Information.*`)
+ c.Check(json, Matches, `(?ms).*CPU Information.*`)
+ c.Check(json, Matches, `(?ms).*Memory Information.*`)
+ c.Check(json, Matches, `(?ms).*Disk Space.*`)
+ c.Check(json, Matches, `(?ms).*Disk INodes.*`)
}
func (s *TestSuite) TestContainerRecordLog(c *C) {
"regexp"
"git.curoverse.com/arvados.git/sdk/go/arvados"
- "gopkg.in/src-d/go-billy.v3/osfs"
+ "gopkg.in/src-d/go-billy.v4/osfs"
git "gopkg.in/src-d/go-git.v4"
git_config "gopkg.in/src-d/go-git.v4/config"
git_plumbing "gopkg.in/src-d/go-git.v4/plumbing"
}
err = repo.Fetch(&git.FetchOptions{
RemoteName: "origin",
- Auth: git_http.NewBasicAuth("none", token),
+ Auth: &git_http.BasicAuth{
+ Username: "none",
+ Password: token,
+ },
})
if err != nil {
return fmt.Errorf("git fetch %q: %s", u.String(), err)
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/docker-cleaner/docker-cleaner.json
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
# Collection, and if so, invokes it with the "scl" wrapper.
ExecStart=/bin/sh -c 'if [ -e /opt/rh/python33/root/bin/arvados-docker-cleaner ]; then exec scl enable python33 arvados-docker-cleaner; else exec arvados-docker-cleaner; fi'
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/config.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStart=/usr/bin/arvados-health
Restart=always
-RestartSec=1s
+RestartSec=1
+
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/keep-balance/keep-balance.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=10s
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/keep-web/keep-web.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/keepproxy/keepproxy.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
_, _, err := kc.Ask(hash)
errNotFound, _ := err.(keepclient.ErrNotFound)
c.Check(errNotFound, NotNil)
- c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true)
+ c.Assert(err, ErrorMatches, `.*HTTP 405.*`)
c.Log("Ask 1")
}
blocklen, _, err := kc.Ask(hash)
errNotFound, _ := err.(keepclient.ErrNotFound)
c.Check(errNotFound, NotNil)
- c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true)
+ c.Assert(err, ErrorMatches, `.*HTTP 405.*`)
c.Check(blocklen, Equals, int64(0))
c.Log("Ask 2")
}
_, blocklen, _, err := kc.Get(hash)
errNotFound, _ := err.(keepclient.ErrNotFound)
c.Check(errNotFound, NotNil)
- c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true)
+ c.Assert(err, ErrorMatches, `.*HTTP 405.*`)
c.Check(blocklen, Equals, int64(0))
c.Log("Get")
}
c.Check(err, NotNil)
errNotFound, _ := err.(*keepclient.ErrNotFound)
c.Check(errNotFound.Temporary(), Equals, true)
- c.Assert(strings.Contains(err.Error(), "connection refused"), Equals, true)
+ c.Assert(err, ErrorMatches, ".*connection refused.*")
// Get should result in temporary connection refused error
_, _, _, err = kc.Get(hash)
c.Check(err, NotNil)
errNotFound, _ = err.(*keepclient.ErrNotFound)
c.Check(errNotFound.Temporary(), Equals, true)
- c.Assert(strings.Contains(err.Error(), "connection refused"), Equals, true)
+ c.Assert(err, ErrorMatches, ".*connection refused.*")
}
func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) {
resp := httptest.NewRecorder()
rtr.ServeHTTP(resp, req)
c.Check(resp.Code, Equals, 200)
- c.Assert(strings.Contains(resp.Body.String(), `{"health":"OK"}`), Equals, true)
+ c.Assert(resp.Body.String(), Matches, `{"health":"OK"}\n?`)
}
response = IssueRequest(datamanagerWrongMethodReq)
ExpectStatusCode(t,
"Only PUT method is supported for untrash",
- http.StatusBadRequest,
+ http.StatusMethodNotAllowed,
response)
// datamanagerReq => StatusOK
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/keepstore/keepstore.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
Documentation=https://doc.arvados.org/
After=network.target
AssertPathExists=/etc/arvados/ws/ws.yml
-# systemd<230
+
+# systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
StartLimitInterval=0
-# systemd>=230
+
+# systemd>=230 (debian:9) obeys StartLimitIntervalSec in the [Unit] section
StartLimitIntervalSec=0
[Service]
Restart=always
RestartSec=1
+# systemd<=219 (centos:7, debian:8, ubuntu:trusty) obeys StartLimitInterval in the [Service] section
+StartLimitInterval=0
+
[Install]
WantedBy=multi-user.target
"--volume=$PIPCACHE:/var/lib/pip:rw" \
"--volume=$NPMCACHE:/var/lib/npm:rw" \
"--volume=$GOSTUFF:/var/lib/gopath:rw" \
- arvados/arvbox-dev$TAG \
- /usr/local/bin/runsvinit -svdir=/etc/test-service
+ "--env=SVDIR=/etc/test-service" \
+ arvados/arvbox-dev$TAG
docker exec -ti \
$ARVBOX_CONTAINER \
RUN rm -rf /var/lib/postgresql && mkdir -p /var/lib/postgresql
-RUN cd /root && \
- GOPATH=$PWD go get github.com/curoverse/runsvinit && \
- install bin/runsvinit /usr/local/bin
-
ENV PJSVERSION=1.9.8
# bitbucket is the origin, but downloads fail sometimes, so use our own mirror instead.
#ENV PJSURL=https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-${PJSVERSION}-linux-x86_64.tar.bz2
application_yml_override.py api-setup.sh \
/usr/local/lib/arvbox/
-RUN mkdir /etc/docker
-ADD daemon.json /etc/docker/
+ADD runit /etc/runit
# Start the supervisor.
-CMD ["/usr/local/bin/runsvinit"]
+ENV SVDIR /etc/service
+STOPSIGNAL SIGINT
+CMD ["/sbin/runit"]
else
frozen=""
fi
- if ! test -x bundle ; then
+ if ! test -x /var/lib/gems/bin/bundler ; then
bundlergem=$(ls -r $GEM_HOME/cache/bundler-*.gem 2>/dev/null | head -n1 || true)
if test -n "$bundlergem" ; then
flock /var/lib/gems/gems.lock gem install --local --no-document $bundlergem
else
flock /var/lib/gems/gems.lock gem install --no-document bundler
fi
- ln -sf /var/lib/gems/bin/bundle /usr/local/bin
fi
- if ! flock /var/lib/gems/gems.lock bundle install --path $GEM_HOME --local --no-deployment $frozen "$@" ; then
- flock /var/lib/gems/gems.lock bundle install --path $GEM_HOME --no-deployment $frozen "$@"
+ if ! flock /var/lib/gems/gems.lock bundler install --path $GEM_HOME --local --no-deployment $frozen "$@" ; then
+ flock /var/lib/gems/gems.lock bundler install --path $GEM_HOME --no-deployment $frozen "$@"
fi
}
--- /dev/null
+#!/bin/sh
+# system one time tasks
+
+PATH=/command:/sbin:/bin:/usr/sbin:/usr/bin
+
+touch /run/runit.stopit
+chmod 0 /run/runit.stopit
--- /dev/null
+#!/bin/sh
+
+PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin
+
+echo
+echo "Arvados-in-a-box starting"
+echo
+
+exec env - PATH=$PATH \
+runsvdir -P $SVDIR
--- /dev/null
+#!/bin/sh
+exec 2>&1
+
+PATH=/command:/sbin:/bin:/usr/sbin:/usr/bin
+
+LAST=0
+test -x /run/runit.reboot && LAST=6
+
+echo 'Waiting for services to stop...'
+sv -w196 force-stop /service/*
+sv exit /service/*
+
+echo 'Shutdown...'
+/etc/init.d/rc $LAST
--- /dev/null
+#!/bin/sh
+exec 2>&1
+
+PATH=/command:/sbin:/bin:/usr/sbin:/usr/bin
+
+LAST=0
+test -x /run/runit.reboot && LAST=6
+
+echo 'Waiting for services to stop...'
+sv -w196 force-stop $SVDIR/*
+sv exit $SVDIR/*
+
+echo 'Shutdown...'
read pid cmd state ppid pgrp session tty_nr tpgid rest < /proc/self/stat
trap "kill -TERM -$pgrp; exit" EXIT TERM KILL SIGKILL SIGTERM SIGQUIT
-if ! docker daemon --storage-driver=overlay $DOCKER_DAEMON_ARGS ; then
- docker daemon $DOCKER_DAEMON_ARGS
+mkdir /etc/docker
+# Prefer overlay2
+echo '{"storage-driver": "overlay2"}' > /etc/docker/daemon.json
+
+if ! dockerd ; then
+ # Oops overlay2 didn't work, let docker choose a default.
+ echo '{}' > /etc/docker/daemon.json
+ dockerd
fi
set -eu -o pipefail
if ! [[ -d /tmp/arvbox-ready ]] ; then
- echo
- echo "Arvados-in-a-box starting"
- echo
echo "Note: if this is a fresh arvbox installation, it may take 10-15 minutes (or longer) to download and"
echo "install dependencies. Use \"arvbox log\" to monitor the progress of specific services."
echo
-#!/bin/sh
+#!/bin/bash
# Copyright (C) The Arvados Authors. All rights reserved.
#
# SPDX-License-Identifier: AGPL-3.0
set -e
+. /usr/local/lib/arvbox/common.sh
+
/usr/local/lib/arvbox/runsu.sh $0-service $1
cd /usr/src/arvados/apps/workbench
"revisionTime": "2017-07-27T13:52:37Z"
},
{
- "checksumSHA1": "Rjy2uYZkQ8Kjht6ZFU0qzm2I/kI=",
- "origin": "github.com/docker/docker/vendor/github.com/Microsoft/go-winio",
+ "checksumSHA1": "o/3cn04KAiwC7NqNVvmfVTD+hgA=",
"path": "github.com/Microsoft/go-winio",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "78439966b38d69bf38227fbf57ac8a6fee70f69a",
+ "revisionTime": "2017-08-04T20:09:54Z"
},
{
- "checksumSHA1": "DYv6Q1+VfnUVxMwvk5IshAClLvw=",
+ "checksumSHA1": "CWLxwFSj7MNed2MzAOSm0Cg9p+o=",
"path": "github.com/Sirupsen/logrus",
- "revision": "5e5dc898656f695e2a086b8e12559febbfc01562",
- "revisionTime": "2017-05-15T10:45:16Z"
+ "revision": "d682213848ed68c0a260ca37d6dd5ace8423f5ba",
+ "revisionTime": "2017-12-05T20:32:29Z"
},
{
"checksumSHA1": "+Zz+leZHHC9C0rx8DoRuffSRPso=",
"path": "github.com/coreos/go-systemd/daemon",
- "revision": "1f9909e51b2dab2487c26d64c8f2e7e580e4c9f5",
- "revisionTime": "2017-03-24T09:58:19Z"
+ "revision": "cc4f39464dc797b91c8025330de585294c2a6950",
+ "revisionTime": "2018-01-08T08:51:32Z"
},
{
"checksumSHA1": "pAu+do4x7E5SFLfIqJeGwhcOd6E=",
},
{
"checksumSHA1": "Gj+xR1VgFKKmFXYOJMnAczC3Znk=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/distribution/digestset",
"path": "github.com/docker/distribution/digestset",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "277ed486c948042cab91ad367c379524f3b25e18",
+ "revisionTime": "2018-01-05T23:27:52Z"
},
{
- "checksumSHA1": "m4wEFD0Mh+ClfprUqgl0GyNmk7Q=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/distribution/reference",
+ "checksumSHA1": "2Fe4D6PGaVE2he4fUeenLmhC1lE=",
"path": "github.com/docker/distribution/reference",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "277ed486c948042cab91ad367c379524f3b25e18",
+ "revisionTime": "2018-01-05T23:27:52Z"
},
{
- "checksumSHA1": "5b7eC73lORtIUFCjz548jXkLlKU=",
+ "checksumSHA1": "QKCQfrTv4wTL0KBDMHpWM/jHl9I=",
"path": "github.com/docker/docker/api",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "jFY7z3SSvQaJg51/nwzUkB/LDAc=",
+ "checksumSHA1": "b91BIyJbqy05pXpEh1eGCJkdjYc=",
"path": "github.com/docker/docker/api/types",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "jVJDbe0IcyjoKc2xbohwzQr+FF0=",
"path": "github.com/docker/docker/api/types/blkiodev",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "AeSC0BOu1uapkGqfSXtfVSpwJzs=",
+ "checksumSHA1": "DuOqFTQ95vKSuSE/Va88yRN/wb8=",
"path": "github.com/docker/docker/api/types/container",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "fzeGodcTcWuV18AT0BcvB4EFByo=",
+ "checksumSHA1": "XDP7i6sMYGnUKeFzgt+mFBJwjjw=",
"path": "github.com/docker/docker/api/types/events",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "J2OKngfI3vgswudr9PZVUFcRRu0=",
+ "checksumSHA1": "S4SWOa0XduRd8ene8Alwih2Nwcw=",
"path": "github.com/docker/docker/api/types/filters",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "yeB781yxPhnN6OXQ9/qSsyih3ek=",
+ "checksumSHA1": "KuC0C6jo1t7tlvIqb7G3u1FIaZU=",
"path": "github.com/docker/docker/api/types/image",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "UK+VdM648oWzyqE4OqttgmPqjoA=",
+ "checksumSHA1": "uJeLBKpHZXP+bWhXP4HhpyUTWYI=",
"path": "github.com/docker/docker/api/types/mount",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "oC2We2SzAYMULIfr7fXaoofnF+c=",
+ "checksumSHA1": "Gskp+nvbVe8Gk1xPLHylZvNmqTg=",
"path": "github.com/docker/docker/api/types/network",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "r2vWq7Uc3ExKzMqYgH0b4AKjLKY=",
"path": "github.com/docker/docker/api/types/registry",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "VTxWyFud/RedrpllGdQonVtGM/A=",
"path": "github.com/docker/docker/api/types/strslice",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "B+yL7OD7dDV+n+XURK5x0N8U1pQ=",
+ "checksumSHA1": "Q0U3queMsCw+rPPztXnRHwAxQEc=",
"path": "github.com/docker/docker/api/types/swarm",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "B7ZwKzrv3t3Vlox6/bYMHhMjsM8=",
+ "checksumSHA1": "kVfD1e4Gak7k6tqDX5nrgQ57EYY=",
+ "path": "github.com/docker/docker/api/types/swarm/runtime",
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
+ },
+ {
+ "checksumSHA1": "77axKFOjRx1nGrzIggGXfTxUYVQ=",
"path": "github.com/docker/docker/api/types/time",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "uDPQ3nHsrvGQc9tg/J9OSC4N5dQ=",
"path": "github.com/docker/docker/api/types/versions",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "IBJy2zPEnYmcFJ3lM1eiRWnCxTA=",
"path": "github.com/docker/docker/api/types/volume",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "3bbQi817xzhn5andyThfuZcmHvk=",
+ "checksumSHA1": "zQvx3WYTAwbPZEaVPjAsrmW7V00=",
"path": "github.com/docker/docker/client",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "jmo/t2zXAxirEPoFucNPXA/1SEc=",
- "path": "github.com/docker/docker/pkg/ioutils",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "ndnAFCfsGC3upNQ6jAEwzxcurww=",
- "path": "github.com/docker/docker/pkg/longpath",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "3u2xJnbqYSxOP3kOORetQD7P1Co=",
- "path": "github.com/docker/docker/pkg/mount",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "nhKmQDaWa+qKP2VWEy05CrTyids=",
- "path": "github.com/docker/docker/pkg/system",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "8I0Ez+aUYGpsDEVZ8wN/Ztf6Zqs=",
- "path": "github.com/docker/docker/pkg/tlsconfig",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "JbiWTzH699Sqz25XmDlsARpMN9w=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/go-connections/nat",
"path": "github.com/docker/go-connections/nat",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "3ede32e2033de7505e6500d6c868c2b9ed9f169d",
+ "revisionTime": "2017-06-23T20:36:43Z"
},
{
"checksumSHA1": "jUfDG3VQsA2UZHvvIXncgiddpYA=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/go-connections/sockets",
"path": "github.com/docker/go-connections/sockets",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "3ede32e2033de7505e6500d6c868c2b9ed9f169d",
+ "revisionTime": "2017-06-23T20:36:43Z"
},
{
- "checksumSHA1": "tuSzlS1UQ03+5Fvtqr5hI5sLLhA=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/go-connections/tlsconfig",
+ "checksumSHA1": "c6lDGNwTm5mYq18IHP+lqYpk8xU=",
"path": "github.com/docker/go-connections/tlsconfig",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "3ede32e2033de7505e6500d6c868c2b9ed9f169d",
+ "revisionTime": "2017-06-23T20:36:43Z"
},
{
- "checksumSHA1": "Pv1NbtDY4wETwwSD2DsI+s8de/I=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/go-units",
+ "checksumSHA1": "kP4hqQGUNNXhgYxgB4AMWfNvmnA=",
"path": "github.com/docker/go-units",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
- },
- {
- "checksumSHA1": "r5hHPg1v9SL/gyatPWdaujG9aoE=",
- "origin": "github.com/docker/docker/vendor/github.com/docker/libtrust",
- "path": "github.com/docker/libtrust",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "d59758554a3d3911fa25c0269de1ebe2f1912c39",
+ "revisionTime": "2017-12-21T20:03:56Z"
},
{
"checksumSHA1": "ImX1uv6O09ggFeBPUJJ2nu7MPSA=",
"revision": "0ca9ea5df5451ffdf184b4428c902747c2c11cd7",
"revisionTime": "2017-03-27T23:54:44Z"
},
+ {
+ "checksumSHA1": "wn2shNJMwRZpvuvkf1s7h0wvqHI=",
+ "path": "github.com/gogo/protobuf/proto",
+ "revision": "160de10b2537169b5ae3e7e221d28269ef40d311",
+ "revisionTime": "2018-01-04T10:21:28Z"
+ },
{
"checksumSHA1": "iIUYZyoanCQQTUaWsu8b+iOSPt4=",
"origin": "github.com/docker/docker/vendor/github.com/gorilla/context",
"path": "github.com/gorilla/context",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "zmCk+lgIeiOf0Ng9aFP9aFy8ksE=",
+ "checksumSHA1": "fSs1WcPh2F5JJtxqYC+Jt8yCkYc=",
"path": "github.com/gorilla/mux",
- "revision": "4c1c3952b7d9d0a061a3fa7b36fd373ba0398ebc",
- "revisionTime": "2017-04-27T04:12:50Z"
+ "revision": "5bbbb5b2b5729b132181cc7f4aa3b3c973e9a0ed",
+ "revisionTime": "2018-01-07T15:57:08Z"
+ },
+ {
+ "checksumSHA1": "d9PxF1XQGLMJZRct2R8qVM/eYlE=",
+ "path": "github.com/hashicorp/golang-lru",
+ "revision": "0a025b7e63adc15a622f29b0b2c4c3848243bbf6",
+ "revisionTime": "2016-08-13T22:13:03Z"
+ },
+ {
+ "checksumSHA1": "9hffs0bAIU6CquiRhKQdzjHnKt0=",
+ "path": "github.com/hashicorp/golang-lru/simplelru",
+ "revision": "0a025b7e63adc15a622f29b0b2c4c3848243bbf6",
+ "revisionTime": "2016-08-13T22:13:03Z"
+ },
+ {
+ "checksumSHA1": "iCsyavJDnXC9OY//p52IWJWy7PY=",
+ "path": "github.com/jbenet/go-context/io",
+ "revision": "d14ea06fba99483203c19d92cfcd13ebe73135f4",
+ "revisionTime": "2015-07-11T00:45:18Z"
+ },
+ {
+ "checksumSHA1": "oX6jFQD74oOApvDIhOzW2dXpg5Q=",
+ "path": "github.com/kevinburke/ssh_config",
+ "revision": "802051befeb51da415c46972b5caf36e7c33c53d",
+ "revisionTime": "2017-10-13T21:14:58Z"
},
{
- "checksumSHA1": "uTUsjF7bymOuKvXbW2BpkK/w4Vg=",
+ "checksumSHA1": "IfZcD4U1dtllJKlPNeD2aU4Jn98=",
"path": "github.com/lib/pq",
- "revision": "2704adc878c21e1329f46f6e56a1c387d788ff94",
- "revisionTime": "2017-03-24T20:46:54Z"
+ "revision": "83612a56d3dd153a94a629cd64925371c9adad78",
+ "revisionTime": "2017-11-26T05:04:59Z"
},
{
- "checksumSHA1": "q5SZBWFVC3wOIzftf+l/h5WLG1k=",
+ "checksumSHA1": "AU3fA8Sm33Vj9PBoRPSeYfxLRuE=",
"path": "github.com/lib/pq/oid",
- "revision": "2704adc878c21e1329f46f6e56a1c387d788ff94",
- "revisionTime": "2017-03-24T20:46:54Z"
+ "revision": "83612a56d3dd153a94a629cd64925371c9adad78",
+ "revisionTime": "2017-11-26T05:04:59Z"
},
{
- "checksumSHA1": "OUupkCHnh8e3RHRNcMFqQJqhaQI=",
- "origin": "github.com/docker/docker/vendor/github.com/opencontainers/go-digest",
+ "checksumSHA1": "V/quM7+em2ByJbWBLOsEwnY3j/Q=",
+ "path": "github.com/mitchellh/go-homedir",
+ "revision": "b8bc1bf767474819792c23f32d8286a45736f1c6",
+ "revisionTime": "2016-12-03T19:45:07Z"
+ },
+ {
+ "checksumSHA1": "OFNit1Qx2DdWhotfREKodDNUwCM=",
"path": "github.com/opencontainers/go-digest",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "279bed98673dd5bef374d3b6e4b09e2af76183bf",
+ "revisionTime": "2017-06-07T19:53:33Z"
},
{
- "checksumSHA1": "qzsBSt0cnEYNIkYk7slHjmPl7o0=",
+ "checksumSHA1": "ZGlIwSRjdLYCUII7JLE++N4w7Xc=",
"path": "github.com/opencontainers/image-spec/specs-go",
- "revision": "f03dbe35d449c54915d235f1a3cf8f585a24babe",
- "revisionTime": "2017-05-15T20:58:57Z"
+ "revision": "577479e4dc273d3779f00c223c7e0dba4cd6b8b0",
+ "revisionTime": "2017-11-25T02:40:18Z"
},
{
- "checksumSHA1": "vp5gfnUG920xBY1genCCoppZILc=",
+ "checksumSHA1": "jdbXRRzeu0njLE9/nCEZG+Yg/Jk=",
"path": "github.com/opencontainers/image-spec/specs-go/v1",
- "revision": "f03dbe35d449c54915d235f1a3cf8f585a24babe",
- "revisionTime": "2017-05-15T20:58:57Z"
+ "revision": "577479e4dc273d3779f00c223c7e0dba4cd6b8b0",
+ "revisionTime": "2017-11-25T02:40:18Z"
},
{
- "checksumSHA1": "PdQm3s8DoVJ17Vk8n7o5iPa7PK0=",
- "origin": "github.com/docker/docker/vendor/github.com/pkg/errors",
+ "checksumSHA1": "F1IYMLBLAZaTOWnmXsgaxTGvrWI=",
+ "path": "github.com/pelletier/go-buffruneio",
+ "revision": "c37440a7cf42ac63b919c752ca73a85067e05992",
+ "revisionTime": "2017-02-27T22:03:11Z"
+ },
+ {
+ "checksumSHA1": "xCv4GBFyw07vZkVtKF/XrUnkHRk=",
"path": "github.com/pkg/errors",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "e881fd58d78e04cf6d0de1217f8707c8cc2249bc",
+ "revisionTime": "2017-12-16T07:03:16Z"
+ },
+ {
+ "checksumSHA1": "UwtyqB7CaUWPlw0DVJQvw0IFQZs=",
+ "path": "github.com/sergi/go-diff/diffmatchpatch",
+ "revision": "1744e2970ca51c86172c8190fadad617561ed6e7",
+ "revisionTime": "2017-11-10T11:01:46Z"
+ },
+ {
+ "checksumSHA1": "8QeSG127zQqbA+YfkO1WkKx/iUI=",
+ "path": "github.com/src-d/gcfg",
+ "revision": "f187355171c936ac84a82793659ebb4936bc1c23",
+ "revisionTime": "2016-10-26T10:01:55Z"
+ },
+ {
+ "checksumSHA1": "yf5NBT8BofPfGYCXoLnj7BIA1wo=",
+ "path": "github.com/src-d/gcfg/scanner",
+ "revision": "f187355171c936ac84a82793659ebb4936bc1c23",
+ "revisionTime": "2016-10-26T10:01:55Z"
+ },
+ {
+ "checksumSHA1": "C5Z8YVyNTuvupM9AUr9KbPlps4Q=",
+ "path": "github.com/src-d/gcfg/token",
+ "revision": "f187355171c936ac84a82793659ebb4936bc1c23",
+ "revisionTime": "2016-10-26T10:01:55Z"
+ },
+ {
+ "checksumSHA1": "mDkN3UpR7auuFbwUuIwExz4DZgY=",
+ "path": "github.com/src-d/gcfg/types",
+ "revision": "f187355171c936ac84a82793659ebb4936bc1c23",
+ "revisionTime": "2016-10-26T10:01:55Z"
+ },
+ {
+ "checksumSHA1": "iHiMTBffQvWYlOLu3130JXuQpgQ=",
+ "path": "github.com/xanzy/ssh-agent",
+ "revision": "ba9c9e33906f58169366275e3450db66139a31a9",
+ "revisionTime": "2015-12-15T15:34:51Z"
+ },
+ {
+ "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=",
+ "path": "golang.org/x/crypto/cast5",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
},
{
- "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",
+ "checksumSHA1": "IQkUIOnvlf0tYloFx9mLaXSvXWQ=",
+ "path": "golang.org/x/crypto/curve25519",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "1hwn8cgg4EVXhCpJIqmMbzqnUo0=",
+ "path": "golang.org/x/crypto/ed25519",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=",
+ "path": "golang.org/x/crypto/ed25519/internal/edwards25519",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "ooU7jaiYSUKlg5BVllI8lsq+5Qk=",
+ "path": "golang.org/x/crypto/openpgp",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=",
+ "path": "golang.org/x/crypto/openpgp/armor",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=",
+ "path": "golang.org/x/crypto/openpgp/elgamal",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=",
+ "path": "golang.org/x/crypto/openpgp/errors",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "Pq88+Dgh04UdXWZN6P+bLgYnbRc=",
+ "path": "golang.org/x/crypto/openpgp/packet",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=",
+ "path": "golang.org/x/crypto/openpgp/s2k",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "NHjGg73p5iGZ+7tflJ4cVABNmKE=",
+ "path": "golang.org/x/crypto/ssh",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "NMRX0onGReaL9IfLr0XQ3kl5Id0=",
+ "path": "golang.org/x/crypto/ssh/agent",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "zBHtHvMj+MXa1qa4aglBt46uUck=",
+ "path": "golang.org/x/crypto/ssh/knownhosts",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "X1NTlfcau2XcV6WtAHF6b/DECOA=",
+ "path": "golang.org/x/crypto/ssh/terminal",
+ "revision": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8",
+ "revisionTime": "2017-11-25T19:00:56Z"
+ },
+ {
+ "checksumSHA1": "Y+HGqEkYM15ir+J93MEaHdyFy0c=",
"origin": "github.com/docker/docker/vendor/golang.org/x/net/context",
"path": "golang.org/x/net/context",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
"checksumSHA1": "WHc3uByvGaMcnSoI21fhzYgbOgg=",
- "origin": "github.com/docker/docker/vendor/golang.org/x/net/context/ctxhttp",
"path": "golang.org/x/net/context/ctxhttp",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "434ec0c7fe3742c984919a691b2018a6e9694425",
+ "revisionTime": "2017-09-25T09:26:47Z"
},
{
- "checksumSHA1": "LvdVRE0FqdR68SvVpRkHs1rxhcA=",
- "origin": "github.com/docker/docker/vendor/golang.org/x/net/proxy",
+ "checksumSHA1": "r9l4r3H6FOLQ0c2JaoXpopFjpnw=",
"path": "golang.org/x/net/proxy",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "434ec0c7fe3742c984919a691b2018a6e9694425",
+ "revisionTime": "2017-09-25T09:26:47Z"
},
{
- "checksumSHA1": "yppNZB5y0GmJrt/TYOASrhe2oVc=",
+ "checksumSHA1": "TBlnCuZUOzJHLu5DNY7XEj8TvbU=",
"path": "golang.org/x/net/webdav",
- "revision": "f01ecb60fe3835d80d9a0b7b2bf24b228c89260e",
- "revisionTime": "2017-07-11T11:58:19Z"
+ "revision": "434ec0c7fe3742c984919a691b2018a6e9694425",
+ "revisionTime": "2017-09-25T09:26:47Z"
},
{
"checksumSHA1": "XgtZlzd39qIkBHs6XYrq9dhTCog=",
"path": "golang.org/x/net/webdav/internal/xml",
- "revision": "f01ecb60fe3835d80d9a0b7b2bf24b228c89260e",
- "revisionTime": "2017-07-11T11:58:19Z"
+ "revision": "434ec0c7fe3742c984919a691b2018a6e9694425",
+ "revisionTime": "2017-09-25T09:26:47Z"
},
{
"checksumSHA1": "7EZyXN0EmZLgGxZxK01IJua4c8o=",
"path": "golang.org/x/net/websocket",
- "revision": "513929065c19401a1c7b76ecd942f9f86a0c061b",
- "revisionTime": "2017-05-12T22:20:15Z"
+ "revision": "434ec0c7fe3742c984919a691b2018a6e9694425",
+ "revisionTime": "2017-09-25T09:26:47Z"
},
{
- "checksumSHA1": "dUfdXzRJupI9VpqNR2LlppeZvLc=",
+ "checksumSHA1": "znPq37/LZ4pJh7B4Lbu0ZuoMhNk=",
"origin": "github.com/docker/docker/vendor/golang.org/x/sys/unix",
"path": "golang.org/x/sys/unix",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
},
{
- "checksumSHA1": "fpW2dhGFC6SrVzipJx7fjg2DIH8=",
+ "checksumSHA1": "8BcMOi8XTSigDtV2npDc8vMrS60=",
"origin": "github.com/docker/docker/vendor/golang.org/x/sys/windows",
"path": "golang.org/x/sys/windows",
- "revision": "280327cb4d1e1fe4f118d00596ce0b3a6ae6d07e",
- "revisionTime": "2017-05-17T20:48:28Z"
+ "revision": "94b8a116fbf1cd90e68d8f5361b520d326a66f9b",
+ "revisionTime": "2018-01-09T01:38:17Z"
+ },
+ {
+ "checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=",
+ "path": "golang.org/x/text/transform",
+ "revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3",
+ "revisionTime": "2017-12-24T20:31:28Z"
+ },
+ {
+ "checksumSHA1": "BCNYmf4Ek93G4lk5x3ucNi/lTwA=",
+ "path": "golang.org/x/text/unicode/norm",
+ "revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3",
+ "revisionTime": "2017-12-24T20:31:28Z"
},
{
"checksumSHA1": "CEFTYXtWmgSh+3Ik1NmDaJcz4E0=",
"revisionTime": "2016-12-08T18:13:25Z"
},
{
- "checksumSHA1": "fALlQNY1fM99NesfLJ50KguWsio=",
+ "checksumSHA1": "GdsHg+yOsZtdMvD9HJFovPsqKec=",
+ "path": "gopkg.in/src-d/go-billy.v4",
+ "revision": "053dbd006f81a230434f712314aacfb540b52cc5",
+ "revisionTime": "2017-11-27T19:20:57Z"
+ },
+ {
+ "checksumSHA1": "yscejfasrttJfPq91pn7gArFb5o=",
+ "path": "gopkg.in/src-d/go-billy.v4/helper/chroot",
+ "revision": "053dbd006f81a230434f712314aacfb540b52cc5",
+ "revisionTime": "2017-11-27T19:20:57Z"
+ },
+ {
+ "checksumSHA1": "B7HAyGfl+ONIAvlHzbvSsLisx9o=",
+ "path": "gopkg.in/src-d/go-billy.v4/helper/polyfill",
+ "revision": "053dbd006f81a230434f712314aacfb540b52cc5",
+ "revisionTime": "2017-11-27T19:20:57Z"
+ },
+ {
+ "checksumSHA1": "1CnG3JdmIQoa6mE0O98BfymLmuM=",
+ "path": "gopkg.in/src-d/go-billy.v4/osfs",
+ "revision": "053dbd006f81a230434f712314aacfb540b52cc5",
+ "revisionTime": "2017-11-27T19:20:57Z"
+ },
+ {
+ "checksumSHA1": "lo42NuhQJppy2ne/uwPR2T9BSPY=",
+ "path": "gopkg.in/src-d/go-billy.v4/util",
+ "revision": "053dbd006f81a230434f712314aacfb540b52cc5",
+ "revisionTime": "2017-11-27T19:20:57Z"
+ },
+ {
+ "checksumSHA1": "ydjzL2seh3M8h9svrSDV5y/KQJU=",
+ "path": "gopkg.in/src-d/go-git.v4",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "TSoIlaADKlw3Zx0ysCCBn6kyXNE=",
+ "path": "gopkg.in/src-d/go-git.v4/config",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "B2OLPJ4wnJIM2TMjTyzusYluUeI=",
+ "path": "gopkg.in/src-d/go-git.v4/internal/revision",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "o9YH41kQMefVGUS7d3WWSLLhIRk=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "BrsKLhmB0BtaMY+ol1oglnHhvrs=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/cache",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "pHPMiAzXG/TJqTLEKj2SHjxX4zs=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/filemode",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "UGIM9BX7w3MhiadsuN6f8Bx0VZU=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/config",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "L1H7nPf65//6nQGt3Lzq16vLD8w=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/diff",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "87WhYdropmGA4peZOembY5hEgq8=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/gitignore",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "G0TX3efLdk7noo/n1Dt9Tzempig=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "q7HtzrSzVE9qN5N3QOxkLFcZI1U=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/index",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "0IxJpGMfdnr3cuuVE59u+1B5n9o=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/objfile",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "LJnyldAM69WmMXW5avaEeSScKTU=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/packfile",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "T8efjPxCKp23RvSBI51qugHzgxw=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/format/pktline",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "97LEL3gxgDWPP/UlRHMfKb5I0RA=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/object",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "PQmY1mHiPdNBNrh3lESZe3QH36c=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "JjHHYoWDYf0H//nP2FIS05ZLgj8=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "wVfbzV5BNhjW/HFFJuTCjkPSJ5M=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "m8nTTRFD7kmX9nT5Yfr9lqabR4s=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/revlist",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "Xito+BwVCMpKrhcvgz5wU+MRmEo=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/storer",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "AVSX04sTj3cBv1muAmIbPE9D9FY=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "cmOntUALmiRvvblEXAQXNO4Oous=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/client",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "gaKy+c/OjPQFLhENnSAFEZUngok=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/file",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "chcAwbm6J5uXXn6IV58+G6RKCjU=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/git",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "m9TNeIIGUBdZ0qdSl5Xa/0TIvfo=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/http",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "6asrmcjb98FpRr83ICCODXdGWdE=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "MGiWWrsy8iQ5ZdCXEN2Oc4oprCk=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/server",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "vat8YhxXGXNcg8HvCDfHAR6BcL0=",
+ "path": "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "FlVLBdu4cjlXj9zjRRNDurRLABU=",
+ "path": "gopkg.in/src-d/go-git.v4/storage",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "IpSxC31PynwJBajOaHR7gtnVc7I=",
+ "path": "gopkg.in/src-d/go-git.v4/storage/filesystem",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "OaZO6dgvn6PMvezw0bYQUGLSrF0=",
+ "path": "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "jPRm9YqpcJzx4oasd6PBdD33Dgo=",
+ "path": "gopkg.in/src-d/go-git.v4/storage/memory",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "AzdUpuGqSNnNK6DgdNjWrn99i3o=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/binary",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "vniUxB6bbDYazl21cOfmhdZZiY8=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/diff",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "cspCXRxvzvoNOEUB7wRgOKYrVjQ=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/ioutil",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "shsY2I1OFbnjopNWF21Tkfx+tac=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/merkletrie",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "QiHHx1Qb/Vv4W6uQb+mJU2zMqLo=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "M+6y9mdBFksksEGBceBh9Se3W7Y=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/merkletrie/index",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "7eEw/xsSrFLfSppRf/JIt9u7lbU=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "qCb9d3cwnPHVLqS/U9NAzK+1Ptg=",
+ "path": "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder",
+ "revision": "bf3b1f1fb9e0a04d0f87511a7ded2562b48a19d8",
+ "revisionTime": "2018-01-08T13:05:52Z"
+ },
+ {
+ "checksumSHA1": "I4c3qsEX8KAUTeB9+2pwVX/2ojU=",
+ "path": "gopkg.in/warnings.v0",
+ "revision": "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b",
+ "revisionTime": "2017-11-15T19:30:34Z"
+ },
+ {
+ "checksumSHA1": "qOmvuDm+F+2nQQecUZBVkZrTn6Y=",
"path": "gopkg.in/yaml.v2",
- "revision": "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b",
- "revisionTime": "2017-04-07T17:21:22Z"
+ "revision": "d670f9405373e636a5a2765eea47fac0c9bc91a4",
+ "revisionTime": "2018-01-09T11:43:31Z"
+ },
+ {
+ "checksumSHA1": "rBIcwbUjE9w1aV0qh7lAL1hcxCQ=",
+ "path": "rsc.io/getopt",
+ "revision": "20be20937449f18bb9967c10d732849fb4401e63",
+ "revisionTime": "2017-08-11T00:05:52Z"
}
],
"rootPath": "git.curoverse.com/arvados.git"