Merge branch '16343-create-cr-with-logincluster-token'
authorTom Clegg <tom@tomclegg.ca>
Wed, 29 Apr 2020 21:09:19 +0000 (17:09 -0400)
committerTom Clegg <tom@tomclegg.ca>
Wed, 29 Apr 2020 21:09:19 +0000 (17:09 -0400)
fixes #16343

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

36 files changed:
AUTHORS
apps/workbench/Gemfile.lock
doc/_config.yml
doc/examples/config/zzzzz.yml
doc/install/arvados-on-kubernetes-GKE.html.textile.liquid
doc/install/arvados-on-kubernetes-minikube.html.textile.liquid
doc/install/arvados-on-kubernetes.html.textile.liquid
doc/install/configure-azure-blob-storage.html.textile.liquid
doc/install/configure-s3-object-storage.html.textile.liquid
doc/install/install-keepstore.html.textile.liquid
go.mod
go.sum
lib/boot/cert.go
lib/boot/cmd.go
lib/boot/nginx.go
lib/boot/supervisor.go
lib/config/cmd_test.go
lib/config/config.default.yml
lib/config/generated_config.go
lib/controller/integration_test.go
lib/dispatchcloud/container/queue.go
sdk/cwl/tests/federation/arvbox-make-federation.cwl
sdk/cwl/tests/federation/arvboxcwl/start.cwl
sdk/go/arvados/config.go
sdk/python/tests/fed-migrate/arvbox-make-federation.cwl
sdk/python/tests/fed-migrate/jenkins.sh [new file with mode: 0755]
sdk/python/tests/nginx.conf
sdk/python/tests/run_test_server.py
services/api/Gemfile.lock
services/keepproxy/keepproxy.go
services/keepproxy/keepproxy_test.go
tools/arvbox/bin/arvbox
tools/arvbox/lib/arvbox/docker/Dockerfile.demo
tools/arvbox/lib/arvbox/docker/service/controller/run
tools/arvbox/lib/arvbox/docker/service/websockets/run [changed from symlink to file mode: 0755]
tools/arvbox/lib/arvbox/docker/service/websockets/run-service [deleted file]

diff --git a/AUTHORS b/AUTHORS
index 436a504c36ab9f93d89e0742c9f9414032b6b8b6..93bdb37dc8f89fa0e8452804beee4943faa9c22e 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,3 +19,5 @@ Thomas Mooney <tmooney@genome.wustl.edu>
 Chen Chen <aflyhorse@gmail.com>
 Veritas Genetics, Inc. <*@veritasgenetics.com>
 Curii Corporation, Inc. <*@curii.com>
+Dante Tsang <dante@dantetsang.com>
+Codex Genetics Ltd <info@codexgenetics.com>
\ No newline at end of file
index 2af9c8b16f0b282ef3abc1a4d7c3880e690f7420..e722fa24196d1bc9b38ced9ba1cc27102471ac88 100644 (file)
@@ -214,7 +214,7 @@ GEM
       multi_json (~> 1.0)
       websocket-driver (>= 0.2.0)
     public_suffix (4.0.3)
-    rack (2.0.7)
+    rack (2.2.2)
     rack-mini-profiler (1.0.2)
       rack (>= 1.2.0)
     rack-test (0.6.3)
@@ -375,4 +375,4 @@ DEPENDENCIES
   uglifier (~> 2.0)
 
 BUNDLED WITH
-   1.11
+   1.16.6
index a8394300ea195d72dd072b6d463ebcc3b7ea6b72..9917b0fdf127c49e76c474dddb64fea7ca39e936 100644 (file)
@@ -187,6 +187,8 @@ navbar:
       - install/arvbox.html.textile.liquid
     - Arvados on Kubernetes:
       - install/arvados-on-kubernetes.html.textile.liquid
+      - install/arvados-on-kubernetes-minikube.html.textile.liquid
+      - install/arvados-on-kubernetes-GKE.html.textile.liquid
     - Manual installation:
       - install/install-manual-prerequisites.html.textile.liquid
       - install/packages.html.textile.liquid
index c63550edf709ad916f13c452b136c83208527afa..d1e1336d545c435fffc58c1778e5ffd4e9027367 100644 (file)
@@ -1,3 +1,4 @@
+AutoReloadConfig: true
 Clusters:
   zzzzz:
     ManagementToken: e687950a23c3a9bceec28c6223a06c79
index 88b2d5730d95f9f41817e22f4288e77bbfca9ac9..c4236b1c224bb4529500542b720f6824ac43a6c4 100644 (file)
@@ -1,7 +1,7 @@
 ---
 layout: default
 navsection: installguide
-title: Arvados on Kubernetes - Google Kubernetes Engine
+title: Arvados on GKE
 ...
 {% comment %}
 Copyright (C) The Arvados Authors. All rights reserved.
@@ -9,7 +9,13 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-This page documents the setup of the prerequisites to run the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Google Kubernetes Engine@ (GKE).
+This page documents setting up and running the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Google Kubernetes Engine@ (GKE).
+
+{% include 'notebox_begin_warning' %}
+This Helm chart does not retain any state after it is deleted. An Arvados cluster created with this Helm chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down. This will be fixed in a future version.
+{% include 'notebox_end' %}
+
+h2. Prerequisites
 
 h3. Install tooling
 
@@ -27,12 +33,12 @@ Install @helm@:
 
 * Follow the instructions at "https://docs.helm.sh/using_helm/#installing-helm":https://docs.helm.sh/using_helm/#installing-helm
 
-h3. Boot the GKE cluster
+h3. Create the GKE cluster
 
 This can be done via the "cloud console":https://console.cloud.google.com/kubernetes/ or via the command line:
 
 <pre>
-$ gcloud container clusters create <CLUSTERNAME> --zone us-central1-a --machine-type n1-standard-2 --cluster-version 1.10
+$ gcloud container clusters create <CLUSTERNAME> --zone us-central1-a --machine-type n1-standard-2 --cluster-version 1.15
 </pre>
 
 It takes a few minutes for the cluster to be initialized.
@@ -59,4 +65,91 @@ Test the connection:
 $ kubectl get nodes
 </pre>
 
-Now proceed to the "Initialize helm on the Kubernetes cluster":/install/arvados-on-kubernetes.html#helm section.
+Test @helm@ by running
+
+<pre>
+$ helm ls
+</pre>
+
+There should be no errors. The command will return nothing.
+
+h2(#git). Clone the repository
+
+Clone the repository and nagivate to the @arvados-kubernetes/charts/arvados@ directory:
+
+<pre>
+$ git clone https://github.com/arvados/arvados-kubernetes.git
+$ cd arvados-kubernetes/charts/arvados
+</pre>
+
+h2(#Start). Start the Arvados cluster
+
+Next, determine the IP address that the Arvados cluster will use to expose its API, Workbench, etc. If you want this Arvados cluster to be reachable from places other than the local machine, the IP address will need to be routable as appropriate.
+
+<pre>
+$ ./cert-gen.sh <IP ADDRESS>
+</pre>
+
+The @values.yaml@ file contains a number of variables that can be modified. At a minimum, review and/or modify the values for
+
+<pre>
+  adminUserEmail
+  adminUserPassword
+  superUserSecret
+  anonymousUserSecret
+</pre>
+
+Now start the Arvados cluster:
+
+<pre>
+$ helm install arvados . --set externalIP=<IP ADDRESS>
+</pre>
+
+At this point, you can use kubectl to see the Arvados cluster boot:
+
+<pre>
+$ kubectl get pods
+$ kubectl get svc
+</pre>
+
+After a few minutes, there shouldn't be any services listed with a 'Pending' external IP address. At that point you can access Arvados Workbench at the IP address specified
+
+* https://&lt;IP ADDRESS&gt;
+
+with the username and password specified in the @values.yaml@ file.
+
+Alternatively, use the Arvados cli tools or SDKs. First set the environment variables:
+
+<pre>
+$ export ARVADOS_API_TOKEN=<superUserSecret from values.yaml>
+$ export ARVADOS_API_HOST=<STATIC IP>:444
+$ export ARVADOS_API_HOST_INSECURE=true
+</pre>
+
+Test access with:
+
+<pre>
+$ arv user current
+</pre>
+
+h2(#reload). Reload
+
+If you make changes to the Helm chart (e.g. to @values.yaml@), you can reload Arvados with
+
+<pre>
+$ helm upgrade arvados .
+</pre>
+
+h2. Shut down
+
+{% include 'notebox_begin_warning' %}
+This Helm chart does not retain any state after it is deleted. An Arvados cluster created with this Helm chart is entirely ephemeral, and <strong>all data stored on the Arvados cluster will be deleted</strong> when it is shut down. This will be fixed in a future version.
+{% include 'notebox_end' %}
+
+<pre>
+$ helm del arvados
+</pre>
+
+<pre>
+$ gcloud container clusters delete <CLUSTERNAME> --zone us-central1-a
+</pre>
index 132b443dffb0a42dedd9759b64aeebbc2c1da6a5..56a51b035f08d42f26b6ba53c7dc9490bad7ca80 100644 (file)
@@ -1,7 +1,7 @@
 ---
 layout: default
 navsection: installguide
-title: Arvados on Kubernetes - Minikube
+title: Arvados on Minikube
 ...
 {% comment %}
 Copyright (C) The Arvados Authors. All rights reserved.
@@ -9,7 +9,13 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-This page documents the setup of the prerequisites to run the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Minikube@.
+This page documents setting up and running the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Minikube@.
+
+{% include 'notebox_begin_warning' %}
+This Helm chart does not retain any state after it is deleted. An Arvados cluster created with this Helm chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down. This will be fixed in a future version.
+{% include 'notebox_end' %}
+
+h2. Prerequisites
 
 h3. Install tooling
 
@@ -31,4 +37,100 @@ Test the connection:
 $ kubectl get nodes
 </pre>
 
-Now proceed to the "Initialize helm on the Kubernetes cluster":/install/arvados-on-kubernetes.html#helm section.
+Test @helm@ by running
+
+<pre>
+$ helm ls
+</pre>
+
+There should be no errors. The command will return nothing.
+
+h2(#git). Clone the repository
+
+Clone the repository and nagivate to the @arvados-kubernetes/charts/arvados@ directory:
+
+<pre>
+$ git clone https://github.com/arvados/arvados-kubernetes.git
+$ cd arvados-kubernetes/charts/arvados
+</pre>
+
+h2(#Start). Start the Arvados cluster
+
+All Arvados services will be accessible on Minikube's IP address. This will be a local IP address, you can see what it is by running
+
+<pre>
+$ minikube ip
+192.168.39.15
+</pre>
+
+Generate self-signed SSL certificates for the Arvados services:
+
+<pre>
+$ ./cert-gen.sh `minikube ip`
+</pre>
+
+The @values.yaml@ file contains a number of variables that can be modified. At a minimum, review and/or modify the values for
+
+<pre>
+  adminUserEmail
+  adminUserPassword
+  superUserSecret
+  anonymousUserSecret
+</pre>
+
+Now start the Arvados cluster:
+
+<pre>
+$ helm install arvados . --set externalIP=`minikube ip`
+</pre>
+
+And update the Kubernetes services to have the Minikube IP as their 'external' IP:
+
+<pre>
+$ ./minikube-external-ip.sh
+</pre>
+
+At this point, you can use kubectl to see the Arvados cluster boot:
+
+<pre>
+$ kubectl get pods
+$ kubectl get svc
+</pre>
+
+After a few minutes, you can access Arvados Workbench at the Minikube IP address:
+
+* https://&lt;MINIKUBE IP&gt;
+
+with the username and password specified in the @values.yaml@ file.
+
+Alternatively, use the Arvados cli tools or SDKs. First set the environment variables:
+
+<pre>
+$ export ARVADOS_API_TOKEN=<superUserSecret from values.yaml>
+$ export ARVADOS_API_HOST=<MINIKUBE IP>:444
+$ export ARVADOS_API_HOST_INSECURE=true
+</pre>
+
+Test access with:
+
+<pre>
+$ arv user current
+</pre>
+
+h2(#reload). Reload
+
+If you make changes to the Helm chart (e.g. to @values.yaml@), you can reload Arvados with
+
+<pre>
+$ helm upgrade arvados .
+</pre>
+
+h2. Shut down
+
+{% include 'notebox_begin_warning' %}
+This Helm chart does not retain any state after it is deleted. An Arvados cluster created with this Helm chart is entirely ephemeral, and <strong>all data stored on the Arvados cluster will be deleted</strong> when it is shut down. This will be fixed in a future version.
+{% include 'notebox_end' %}
+
+<pre>
+$ helm del arvados
+</pre>
index 08b2c7329e1223f27d2650b8c43f0d3aec413784..3169b32479776003ee38f03d94588a3b7ada71e7 100644 (file)
@@ -9,125 +9,29 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-Arvados on Kubernetes is implemented as a Helm Chart.
+Arvados on Kubernetes is implemented as a @Helm 3@ chart.
 
 {% include 'notebox_begin_warning' %}
-This Helm Chart does not retain any state after it is deleted. An Arvados cluster created with this Helm Chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down. This will be fixed in a future version.
+This Helm chart does not retain any state after it is deleted. An Arvados cluster created with this Helm chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down. This will be fixed in a future version.
 {% include 'notebox_end' %}
 
 h2(#overview). Overview
 
-This Helm Chart provides a basic, small Arvados cluster.
+This Helm chart provides a basic, small Arvados cluster.
 
 Current limitations, to be addressed in the future:
 
-* An Arvados cluster created with this Helm Chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down.
-* No dynamic scaling of compute nodes (but you can adjust @values.yaml@ and "reload the Helm Chart":#reload
+* An Arvados cluster created with this Helm chart is entirely ephemeral, and all data stored on the cluster will be deleted when it is shut down.
+* Workbench2 is not present yet
+* No dynamic scaling of compute nodes (but you can adjust @values.yaml@ and reload the Helm chart)
 * All compute nodes are the same size
 * Compute nodes have no cpu/memory/disk constraints yet
 * No git server
 
 h2. Requirements
 
-* Kubernetes 1.10+ cluster with at least 3 nodes, 2 or more cores per node
-* @kubectl@ and @helm@ installed locally, and able to connect to your Kubernetes cluster
+* Minikube or Google Kubernetes Engine (Kubernetes 1.10+ with at least 3 nodes, 2+ cores per node)
+* @kubectl@ and @Helm 3@ installed locally, and able to connect to your Kubernetes cluster
 
-If you do not have a Kubernetes cluster already set up, you can use "Google Kubernetes Engine":/install/arvados-on-kubernetes-GKE.html for multi-node development and testing or "another Kubernetes solution":https://kubernetes.io/docs/setup/pick-right-solution/. Minikube is not supported yet.
+Please refer to "Arvados on Minikube":/install/arvados-on-kubernetes-minikube.html or "Arvados on GKE":/install/arvados-on-kubernetes-GKE.html for detailed installation instructions.
 
-h2(#helm). Initialize helm on the Kubernetes cluster
-
-If you already have helm running on the Kubernetes cluster, proceed directly to "Start the Arvados cluster":#Start below.
-
-<pre>
-$ helm init
-$ kubectl create serviceaccount --namespace kube-system tiller
-$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
-$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
-</pre>
-
-Test @helm@ by running
-
-<pre>
-$ helm ls
-</pre>
-
-There should be no errors. The command will return nothing.
-
-h2(#git). Clone the repository
-
-Clone the repository and nagivate to the @arvados-kubernetes/charts/arvados@ directory:
-
-<pre>
-$ git clone https://github.com/arvados/arvados-kubernetes.git
-$ cd arvados-kubernetes/charts/arvados
-</pre>
-
-h2(#Start). Start the Arvados cluster
-
-Next, determine the IP address that the Arvados cluster will use to expose its API, Workbench, etc. If you want this Arvados cluster to be reachable from places other than the local machine, the IP address will need to be routable as appropriate.
-
-<pre>
-$ ./cert-gen.sh <IP ADDRESS>
-</pre>
-
-The @values.yaml@ file contains a number of variables that can be modified. At a minimum, review and/or modify the values for
-
-<pre>
-  adminUserEmail
-  adminUserPassword
-  superUserSecret
-  anonymousUserSecret
-</pre>
-
-Now start the Arvados cluster:
-
-<pre>
-$ helm install --name arvados . --set externalIP=<IP ADDRESS>
-</pre>
-
-At this point, you can use kubectl to see the Arvados cluster boot:
-
-<pre>
-$ kubectl get pods
-$ kubectl get svc
-</pre>
-
-After a few minutes, you can access Arvados Workbench at the IP address specified
-
-* https://&lt;IP ADDRESS&gt;
-
-with the username and password specified in the @values.yaml@ file.
-
-Alternatively, use the Arvados cli tools or SDKs:
-
-Set the environment variables:
-
-<pre>
-$ export ARVADOS_API_TOKEN=<superUserSecret from values.yaml>
-$ export ARVADOS_API_HOST=<STATIC IP>:444
-$ export ARVADOS_API_HOST_INSECURE=true
-</pre>
-
-Test access with:
-
-<pre>
-$ arv user current
-</pre>
-
-h2(#reload). Reload
-
-If you make changes to the Helm Chart (e.g. to @values.yaml@), you can reload Arvados with
-
-<pre>
-$ helm upgrade arvados .
-</pre>
-
-h2. Shut down
-
-{% include 'notebox_begin_warning' %}
-This Helm Chart does not retain any state after it is deleted. An Arvados cluster created with this Helm Chart is entirely ephemeral, and <strong>all data stored on the Arvados cluster will be deleted</strong> when it is shut down. This will be fixed in a future version.
-{% include 'notebox_end' %}
-
-<pre>
-$ helm del arvados --purge
-</pre>
index 8c5098abe30782e4d354593ecbb4bcf0953f415f..2ccec586e415665e12612276d5636999f004d98b 100644 (file)
@@ -67,8 +67,8 @@ Volumes are configured in the @Volumes@ section of the cluster configuration fil
           # If the AccessViaHosts section is empty or omitted, all
           # keepstore servers will have read/write access to the
           # volume.
-          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107/": {}
-          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107/": {ReadOnly: true}
+          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107": {}
+          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107": {ReadOnly: true}
 
         Driver: <span class="userinput">Azure</span>
         DriverParameters:
index 9708ea5cd10b5f8bc020cb69b02cdb9c8bb1f56e..e953f660fbc0defa81bc13ca34ab2138f4f7dc08 100644 (file)
@@ -25,8 +25,8 @@ Volumes are configured in the @Volumes@ section of the cluster configuration fil
           # If the AccessViaHosts section is empty or omitted, all
           # keepstore servers will have read/write access to the
           # volume.
-          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107/": {}
-          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107/": {ReadOnly: true}
+          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107": {}
+          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107": {ReadOnly: true}
 
         Driver: <span class="userinput">S3</span>
         DriverParameters:
index fedeb3c3f6d73190e63d96e9c286bd90995d439e..869ca15d9eb65c4e0feb22a0d29916bee3b354f5 100644 (file)
@@ -61,8 +61,8 @@ Add each keepstore server to the @Services.Keepstore@ section of @/etc/arvados/c
       Keepstore:
         # No ExternalURL because they are only accessed by the internal subnet.
         InternalURLs:
-          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107/": {}
-          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107/": {}
+          "http://<span class="userinput">keep0.ClusterID.example.com</span>:25107": {}
+          "http://<span class="userinput">keep1.ClusterID.example.com</span>:25107": {}
           # and so forth
 </code></pre>
 </notextile>
diff --git a/go.mod b/go.mod
index 4491b359813c00ca2d39af34f4d6587e49290699..34b7e0779072fcf060d325ddffe77f54adffdfbf 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -11,6 +11,7 @@ require (
        github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
        github.com/arvados/cgofuse v1.2.0-arvados1
        github.com/aws/aws-sdk-go v1.25.30
+       github.com/bgentry/speakeasy v0.1.0 // indirect
        github.com/coreos/go-oidc v2.1.0+incompatible
        github.com/coreos/go-systemd v0.0.0-20180108085132-cc4f39464dc7
        github.com/dgrijalva/jwt-go v3.1.0+incompatible // indirect
@@ -21,6 +22,7 @@ require (
        github.com/docker/go-connections v0.3.0 // indirect
        github.com/docker/go-units v0.3.3-0.20171221200356-d59758554a3d // indirect
        github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
+       github.com/fsnotify/fsnotify v1.4.9
        github.com/ghodss/yaml v1.0.0
        github.com/gliderlabs/ssh v0.2.2 // indirect
        github.com/gogo/protobuf v1.1.1
diff --git a/go.sum b/go.sum
index 18cf89b0e17e6130fa2e18cb2b4b067de54d506d..03b2f77b6d9ce62ecc5c2cf6abae2f4995bb3152 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -27,6 +27,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
 github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -54,6 +56,8 @@ github.com/docker/go-units v0.3.3-0.20171221200356-d59758554a3d h1:dVaNRYvaGV23A
 github.com/docker/go-units v0.3.3-0.20171221200356-d59758554a3d/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
@@ -213,6 +217,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII=
 golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
index 4b12c72edd9063a72afd7c287d9d86f2cc752b3f..f0797c2ac51fb7ec9f861413a371f133b3237bd9 100644 (file)
@@ -6,7 +6,9 @@ package boot
 
 import (
        "context"
+       "fmt"
        "io/ioutil"
+       "net"
        "path/filepath"
 )
 
@@ -23,6 +25,13 @@ func (createCertificates) String() string {
 }
 
 func (createCertificates) Run(ctx context.Context, fail func(error), super *Supervisor) error {
+       var san string
+       if net.ParseIP(super.ListenHost) != nil {
+               san = fmt.Sprintf("IP:%s", super.ListenHost)
+       } else {
+               san = fmt.Sprintf("DNS:%s", super.ListenHost)
+       }
+
        // Generate root key
        err := super.RunProgram(ctx, super.tempdir, nil, nil, "openssl", "genrsa", "-out", "rootCA.key", "4096")
        if err != nil {
@@ -43,10 +52,7 @@ func (createCertificates) Run(ctx context.Context, fail func(error), super *Supe
        if err != nil {
                return err
        }
-       err = ioutil.WriteFile(filepath.Join(super.tempdir, "server.cfg"), append(defaultconf, []byte(`
-[SAN]
-subjectAltName=DNS:localhost,DNS:localhost.localdomain
-`)...), 0644)
+       err = ioutil.WriteFile(filepath.Join(super.tempdir, "server.cfg"), append(defaultconf, []byte(fmt.Sprintf("\n[SAN]\nsubjectAltName=DNS:localhost,DNS:localhost.localdomain,%s\n", san))...), 0644)
        if err != nil {
                return err
        }
@@ -56,7 +62,7 @@ subjectAltName=DNS:localhost,DNS:localhost.localdomain
                return err
        }
        // Sign certificate
-       err = super.RunProgram(ctx, super.tempdir, nil, nil, "openssl", "x509", "-req", "-in", "server.csr", "-CA", "rootCA.crt", "-CAkey", "rootCA.key", "-CAcreateserial", "-out", "server.crt", "-days", "3650", "-sha256")
+       err = super.RunProgram(ctx, super.tempdir, nil, nil, "openssl", "x509", "-req", "-in", "server.csr", "-CA", "rootCA.crt", "-CAkey", "rootCA.key", "-CAcreateserial", "-out", "server.crt", "-extfile", "server.cfg", "-extensions", "SAN", "-days", "3650", "-sha256")
        if err != nil {
                return err
        }
index 5147e3ac33bb65ea8dc0305f986b30a69d736785..e0e2755220a1ec3bbdb8737067c54a579209f40e 100644 (file)
@@ -29,24 +29,33 @@ type supervisedTask interface {
        String() string
 }
 
+var errNeedConfigReload = errors.New("config changed, restart needed")
+
 type bootCommand struct{}
 
-func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
-       super := &Supervisor{
-               Stderr: stderr,
-               logger: ctxlog.New(stderr, "json", "info"),
+func (bcmd bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+       logger := ctxlog.New(stderr, "json", "info")
+       ctx := ctxlog.Context(context.Background(), logger)
+       for {
+               err := bcmd.run(ctx, prog, args, stdin, stdout, stderr)
+               if err == errNeedConfigReload {
+                       continue
+               } else if err != nil {
+                       logger.WithError(err).Info("exiting")
+                       return 1
+               } else {
+                       return 0
+               }
        }
+}
 
-       ctx := ctxlog.Context(context.Background(), super.logger)
+func (bcmd bootCommand) run(ctx context.Context, prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) error {
        ctx, cancel := context.WithCancel(ctx)
        defer cancel()
-
-       var err error
-       defer func() {
-               if err != nil {
-                       super.logger.WithError(err).Info("exiting")
-               }
-       }()
+       super := &Supervisor{
+               Stderr: stderr,
+               logger: ctxlog.FromContext(ctx),
+       }
 
        flags := flag.NewFlagSet(prog, flag.ContinueOnError)
        flags.SetOutput(stderr)
@@ -60,26 +69,25 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
        flags.BoolVar(&super.OwnTemporaryDatabase, "own-temporary-database", false, "bring up a postgres server and create a temporary database")
        timeout := flags.Duration("timeout", 0, "maximum time to wait for cluster to be ready")
        shutdown := flags.Bool("shutdown", false, "shut down when the cluster becomes ready")
-       err = flags.Parse(args)
+       err := flags.Parse(args)
        if err == flag.ErrHelp {
-               err = nil
-               return 0
+               return nil
        } else if err != nil {
-               return 2
+               return err
        } else if *versionFlag {
-               return cmd.Version.RunCommand(prog, args, stdin, stdout, stderr)
+               cmd.Version.RunCommand(prog, args, stdin, stdout, stderr)
+               return nil
        } else if super.ClusterType != "development" && super.ClusterType != "test" && super.ClusterType != "production" {
-               err = fmt.Errorf("cluster type must be 'development', 'test', or 'production'")
-               return 2
+               return fmt.Errorf("cluster type must be 'development', 'test', or 'production'")
        }
 
        loader.SkipAPICalls = true
        cfg, err := loader.Load()
        if err != nil {
-               return 1
+               return err
        }
 
-       super.Start(ctx, cfg)
+       super.Start(ctx, cfg, loader.Path)
        defer super.Stop()
 
        var timer *time.Timer
@@ -89,20 +97,19 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
 
        url, ok := super.WaitReady()
        if timer != nil && !timer.Stop() {
-               err = errors.New("boot timed out")
-               return 1
+               return errors.New("boot timed out")
        } else if !ok {
-               err = errors.New("boot failed")
-               return 1
-       }
-       // Write controller URL to stdout. Nothing else goes to
-       // stdout, so this provides an easy way for a calling script
-       // to discover the controller URL when everything is ready.
-       fmt.Fprintln(stdout, url)
-       if *shutdown {
-               super.Stop()
+               super.logger.Error("boot failed")
+       } else {
+               // Write controller URL to stdout. Nothing else goes
+               // to stdout, so this provides an easy way for a
+               // calling script to discover the controller URL when
+               // everything is ready.
+               fmt.Fprintln(stdout, url)
+               if *shutdown {
+                       super.Stop()
+               }
        }
        // Wait for signal/crash + orderly shutdown
-       <-super.done
-       return 0
+       return super.Wait()
 }
index ecbb7a9d3a40f9cfb916f7c89ff3f5841a38ac23..0f105d6b6ca3ad8b835f90c626060edd454aa513 100644 (file)
@@ -47,6 +47,7 @@ func (runNginx) Run(ctx context.Context, fail func(error), super *Supervisor) er
                {"KEEPWEBDL", super.cluster.Services.WebDAVDownload},
                {"KEEPPROXY", super.cluster.Services.Keepproxy},
                {"GIT", super.cluster.Services.GitHTTP},
+               {"HEALTH", super.cluster.Services.Health},
                {"WORKBENCH1", super.cluster.Services.Workbench1},
                {"WS", super.cluster.Services.Websocket},
        } {
index 7f5d6a9baae2dd4eaa2b2e66fea9585f7be3bdc1..c444ec3001acd3b3b8b86faa40acae38eb110922 100644 (file)
@@ -19,15 +19,18 @@ import (
        "os/signal"
        "os/user"
        "path/filepath"
+       "reflect"
        "strings"
        "sync"
        "syscall"
        "time"
 
+       "git.arvados.org/arvados.git/lib/config"
        "git.arvados.org/arvados.git/lib/service"
        "git.arvados.org/arvados.git/sdk/go/arvados"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
        "git.arvados.org/arvados.git/sdk/go/health"
+       "github.com/fsnotify/fsnotify"
        "github.com/sirupsen/logrus"
 )
 
@@ -45,7 +48,8 @@ type Supervisor struct {
 
        ctx           context.Context
        cancel        context.CancelFunc
-       done          chan struct{}
+       done          chan struct{} // closed when child procs/services have shut down
+       err           error         // error that caused shutdown (valid when done is closed)
        healthChecker *health.Aggregator
        tasksReady    map[string]chan bool
        waitShutdown  sync.WaitGroup
@@ -55,30 +59,66 @@ type Supervisor struct {
        environ    []string // for child processes
 }
 
-func (super *Supervisor) Start(ctx context.Context, cfg *arvados.Config) {
+func (super *Supervisor) Start(ctx context.Context, cfg *arvados.Config, cfgPath string) {
        super.ctx, super.cancel = context.WithCancel(ctx)
        super.done = make(chan struct{})
 
        go func() {
+               defer close(super.done)
+
                sigch := make(chan os.Signal)
                signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM)
                defer signal.Stop(sigch)
                go func() {
                        for sig := range sigch {
                                super.logger.WithField("signal", sig).Info("caught signal")
+                               if super.err == nil {
+                                       super.err = fmt.Errorf("caught signal %s", sig)
+                               }
+                               super.cancel()
+                       }
+               }()
+
+               hupch := make(chan os.Signal)
+               signal.Notify(hupch, syscall.SIGHUP)
+               defer signal.Stop(hupch)
+               go func() {
+                       for sig := range hupch {
+                               super.logger.WithField("signal", sig).Info("caught signal")
+                               if super.err == nil {
+                                       super.err = errNeedConfigReload
+                               }
                                super.cancel()
                        }
                }()
 
+               if cfgPath != "" && cfgPath != "-" && cfg.AutoReloadConfig {
+                       go watchConfig(super.ctx, super.logger, cfgPath, copyConfig(cfg), func() {
+                               if super.err == nil {
+                                       super.err = errNeedConfigReload
+                               }
+                               super.cancel()
+                       })
+               }
+
                err := super.run(cfg)
                if err != nil {
                        super.logger.WithError(err).Warn("supervisor shut down")
+                       if super.err == nil {
+                               super.err = err
+                       }
                }
-               close(super.done)
        }()
 }
 
+func (super *Supervisor) Wait() error {
+       <-super.done
+       return super.err
+}
+
 func (super *Supervisor) run(cfg *arvados.Config) error {
+       defer super.cancel()
+
        cwd, err := os.Getwd()
        if err != nil {
                return err
@@ -549,6 +589,7 @@ func (super *Supervisor) autofillConfig(cfg *arvados.Config) error {
                if svc.ExternalURL.Host == "" {
                        if svc == &cluster.Services.Controller ||
                                svc == &cluster.Services.GitHTTP ||
+                               svc == &cluster.Services.Health ||
                                svc == &cluster.Services.Keepproxy ||
                                svc == &cluster.Services.WebDAV ||
                                svc == &cluster.Services.WebDAVDownload ||
@@ -706,3 +747,67 @@ func waitForConnect(ctx context.Context, addr string) error {
        }
        return ctx.Err()
 }
+
+func copyConfig(cfg *arvados.Config) *arvados.Config {
+       pr, pw := io.Pipe()
+       go func() {
+               err := json.NewEncoder(pw).Encode(cfg)
+               if err != nil {
+                       panic(err)
+               }
+               pw.Close()
+       }()
+       cfg2 := new(arvados.Config)
+       err := json.NewDecoder(pr).Decode(cfg2)
+       if err != nil {
+               panic(err)
+       }
+       return cfg2
+}
+
+func watchConfig(ctx context.Context, logger logrus.FieldLogger, cfgPath string, prevcfg *arvados.Config, fn func()) {
+       watcher, err := fsnotify.NewWatcher()
+       if err != nil {
+               logger.WithError(err).Error("fsnotify setup failed")
+               return
+       }
+       defer watcher.Close()
+
+       err = watcher.Add(cfgPath)
+       if err != nil {
+               logger.WithError(err).Error("fsnotify watcher failed")
+               return
+       }
+
+       for {
+               select {
+               case <-ctx.Done():
+                       return
+               case err, ok := <-watcher.Errors:
+                       if !ok {
+                               return
+                       }
+                       logger.WithError(err).Warn("fsnotify watcher reported error")
+               case _, ok := <-watcher.Events:
+                       if !ok {
+                               return
+                       }
+                       for len(watcher.Events) > 0 {
+                               <-watcher.Events
+                       }
+                       loader := config.NewLoader(&bytes.Buffer{}, &logrus.Logger{Out: ioutil.Discard})
+                       loader.Path = cfgPath
+                       loader.SkipAPICalls = true
+                       cfg, err := loader.Load()
+                       if err != nil {
+                               logger.WithError(err).Warn("error reloading config file after change detected; ignoring new config for now")
+                       } else if reflect.DeepEqual(cfg, prevcfg) {
+                               logger.Debug("config file changed but is still DeepEqual to the existing config")
+                       } else {
+                               logger.Debug("config changed, notifying supervisor")
+                               fn()
+                               prevcfg = cfg
+                       }
+               }
+       }
+}
index f4f2d5653b66692315e45a7aa95f366579bf438a..3c420a04eb43e28e39fa69f8e1baa3330b803d64 100644 (file)
@@ -162,7 +162,7 @@ Clusters:
        code := DumpCommand.RunCommand("arvados config-dump", []string{"-config", "-"}, bytes.NewBufferString(in), &stdout, &stderr)
        c.Check(code, check.Equals, 0)
        c.Check(stderr.String(), check.Matches, `(?ms).*deprecated or unknown config entry: Clusters.z1234.UnknownKey.*`)
-       c.Check(stdout.String(), check.Matches, `(?ms)Clusters:\n  z1234:\n.*`)
+       c.Check(stdout.String(), check.Matches, `(?ms)(.*\n)?Clusters:\n  z1234:\n.*`)
        c.Check(stdout.String(), check.Matches, `(?ms).*\n *ManagementToken: secret\n.*`)
        c.Check(stdout.String(), check.Not(check.Matches), `(?ms).*UnknownKey.*`)
 }
index fcccdd0634e48fe1611f8bf531126f0d8803b081..d4870919eaad2bb0fdb7c1695bf7d28028b38236 100644 (file)
@@ -1228,3 +1228,8 @@ Clusters:
     # implementation. Note that it also disables some new federation
     # features and will be removed in a future release.
     ForceLegacyAPI14: false
+
+# (Experimental) Restart services automatically when config file
+# changes are detected. Only supported by `arvados-server boot` in
+# dev/test mode.
+AutoReloadConfig: false
index 4a8d7024fb5a75d9d275adcdd70241c3ace18fcd..42707396dddc0558d8a901d3ab6e39d79e36e03d 100644 (file)
@@ -1234,4 +1234,9 @@ Clusters:
     # implementation. Note that it also disables some new federation
     # features and will be removed in a future release.
     ForceLegacyAPI14: false
+
+# (Experimental) Restart services automatically when config file
+# changes are detected. Only supported by ` + "`" + `arvados-server boot` + "`" + ` in
+# dev/test mode.
+AutoReloadConfig: false
 `)
index 6e8544817b556e3c7d0579f6edf4f52c33f4e7fd..4939b116b0bce22dfe9c3ad1c2bf79a89797b655 100644 (file)
@@ -123,7 +123,7 @@ func (s *IntegrationSuite) SetUpSuite(c *check.C) {
                        },
                        config: *cfg,
                }
-               s.testClusters[id].super.Start(context.Background(), &s.testClusters[id].config)
+               s.testClusters[id].super.Start(context.Background(), &s.testClusters[id].config, "-")
        }
        for _, tc := range s.testClusters {
                au, ok := tc.super.WaitReady()
index d128c265f84c13594ec309f5ac36d93b65d82b21..45b346383fab8641b27d16063a46bc4468fc96ce 100644 (file)
@@ -382,7 +382,7 @@ func (cq *Queue) poll() (map[string]*arvados.Container, error) {
                        *next[upd.UUID] = upd
                }
        }
-       selectParam := []string{"uuid", "state", "priority", "runtime_constraints", "container_image", "mounts"}
+       selectParam := []string{"uuid", "state", "priority", "runtime_constraints", "container_image", "mounts", "scheduling_parameters"}
        limitParam := 1000
 
        mine, err := cq.fetchAll(arvados.ResourceListParams{
index 593f2399f5ef3b734fa4f67f3466cc6a4bf98656..ed3f1d1384b4fc4f11b535007c749ec76fc26bb3 100644 (file)
@@ -33,6 +33,9 @@ inputs:
   logincluster:
     type: boolean
     default: false
+  arvbox_mode:
+    type: string?
+    default: "dev"
 outputs:
   arvados_api_token:
     type: string
@@ -71,6 +74,7 @@ steps:
       arvbox_data: mkdir/arvbox_data
       arvbox_bin: arvbox
       branch: branch
+      arvbox_mode: arvbox_mode
     out: [cluster_id, container_host, arvbox_data_out, superuser_token]
     scatter: [container_name, arvbox_data]
     scatterMethod: dotproduct
index a7f46d6b22a58a79a3fac916c28c53c1da4984ee..c933de254aac8fe7aa24ae7b5075e412d5fc1965 100644 (file)
@@ -14,6 +14,9 @@ inputs:
   branch:
     type: string
     default: master
+  arvbox_mode:
+    type: string?
+    default: "dev"
 outputs:
   cluster_id:
     type: string
@@ -71,24 +74,28 @@ arguments:
   - shellQuote: false
     valueFrom: |
       set -ex
-      mkdir -p $ARVBOX_DATA
-      if ! test -d $ARVBOX_DATA/arvados ; then
-        cd $ARVBOX_DATA
-        git clone https://git.arvados.org/arvados.git
+      if test $(inputs.arvbox_mode) = dev ; then
+        mkdir -p $ARVBOX_DATA
+        if ! test -d $ARVBOX_DATA/arvados ; then
+          cd $ARVBOX_DATA
+          git clone https://git.arvados.org/arvados.git
+        fi
+        cd $ARVBOX_DATA/arvados
+        gitver=`git rev-parse HEAD`
+        git fetch
+        git checkout -f $(inputs.branch)
+        git pull
+        pulled=`git rev-parse HEAD`
+        git --no-pager log -n1 $pulled
+      else
+        export ARVBOX_BASE=$(runtime.tmpdir)
+        unset ARVBOX_DATA
       fi
-      cd $ARVBOX_DATA/arvados
-      gitver=`git rev-parse HEAD`
-      git fetch
-      git checkout -f $(inputs.branch)
-      git pull
-      pulled=`git rev-parse HEAD`
-      git --no-pager log -n1 $pulled
-
       cd $(runtime.outdir)
       if test "$gitver" = "$pulled" ; then
-        $(inputs.arvbox_bin.path) start dev
+        $(inputs.arvbox_bin.path) start $(inputs.arvbox_mode)
       else
-        $(inputs.arvbox_bin.path) restart dev
+        $(inputs.arvbox_bin.path) restart $(inputs.arvbox_mode)
       fi
       $(inputs.arvbox_bin.path) status > status.txt
       $(inputs.arvbox_bin.path) cat /var/lib/arvados/superuser_token > superuser_token.txt
index 6b83fb96d49e6359e656c3e634a273b6f29c4e16..38de6b8ea40983081a14db18b270e3db31a6a895 100644 (file)
@@ -23,7 +23,8 @@ var DefaultConfigFile = func() string {
 }()
 
 type Config struct {
-       Clusters map[string]Cluster
+       Clusters         map[string]Cluster
+       AutoReloadConfig bool
 }
 
 // GetConfig returns the current system config, loading it from
@@ -66,6 +67,7 @@ type WebDAVCacheConfig struct {
        MaxPermissionEntries int
        MaxUUIDEntries       int
 }
+
 type Cluster struct {
        ClusterID       string `json:"-"`
        ManagementToken string
index aa859cba4fdb416513361d7ba4e291ab74a256ae..cc0fb0fe061af0135f585f3fbc2b23976997c185 100644 (file)
@@ -9,6 +9,8 @@ inputs:
   branch:
     type: string
     default: master
+  arvbox_mode:
+    type: string?
 outputs:
   arvados_api_hosts:
     type: string[]
@@ -39,6 +41,7 @@ steps:
     in:
       arvbox_base: arvbox_base
       branch: branch
+      arvbox_mode: arvbox_mode
       logincluster:
         default: true
     out: [arvados_api_hosts, arvados_cluster_ids, arvado_api_host_insecure, superuser_tokens, arvbox_containers, arvbox_bin]
diff --git a/sdk/python/tests/fed-migrate/jenkins.sh b/sdk/python/tests/fed-migrate/jenkins.sh
new file mode 100755 (executable)
index 0000000..e5dd8aa
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if test -z "$WORKSPACE" ; then
+    echo "WORKSPACE unset"
+    exit 1
+fi
+
+docker stop fedbox1 fedbox2 fedbox3
+docker rm fedbox1 fedbox2 fedbox3
+docker rm fedbox1-data fedbox2-data fedbox3-data
+
+set -ex
+
+mkdir -p $WORKSPACE/tmp
+cd $WORKSPACE/tmp
+virtualenv --python python3 venv3
+. venv3/bin/activate
+
+cd $WORKSPACE/sdk/python
+pip install -e .
+
+cd $WORKSPACE/sdk/cwl
+pip install -e .
+
+export PATH=$PATH:$WORKSPACE/tools/arvbox/bin
+
+mkdir -p $WORKSPACE/tmp/arvbox
+cd $WORKSPACE/sdk/python/tests/fed-migrate
+cwltool arvbox-make-federation.cwl \
+       --arvbox_base $WORKSPACE/tmp/arvbox \
+       --branch $(git rev-parse HEAD) \
+       --arvbox_mode localdemo > fed.json
+
+cwltool fed-migrate.cwl fed.json
index 6e872a615c5fe9a8bebbe0c315497a527dd77e21..85b4f5b37bc619b3da2076c130b2494d9f977956 100644 (file)
@@ -71,6 +71,25 @@ http {
       proxy_request_buffering off;
     }
   }
+  upstream health {
+    server {{LISTENHOST}}:{{HEALTHPORT}};
+  }
+  server {
+    listen {{LISTENHOST}}:{{HEALTHSSLPORT}} ssl default_server;
+    server_name health;
+    ssl_certificate "{{SSLCERT}}";
+    ssl_certificate_key "{{SSLKEY}}";
+    location  / {
+      proxy_pass http://health;
+      proxy_set_header Host $http_host;
+      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+      proxy_set_header X-Forwarded-Proto https;
+      proxy_redirect off;
+
+      proxy_http_version 1.1;
+      proxy_request_buffering off;
+    }
+  }
   server {
     listen {{LISTENHOST}}:{{KEEPWEBDLSSLPORT}} ssl default_server;
     server_name keep-web-dl ~.*;
index 734bb04270bcfc7c94891542add7806b390350bc..779ac4bfc0614f853da77e77068eb8ed539f8865 100644 (file)
@@ -615,6 +615,8 @@ def run_nginx():
     nginxconf['KEEPPROXYSSLPORT'] = external_port_from_config("Keepproxy")
     nginxconf['GITPORT'] = internal_port_from_config("GitHTTP")
     nginxconf['GITSSLPORT'] = external_port_from_config("GitHTTP")
+    nginxconf['HEALTHPORT'] = internal_port_from_config("Health")
+    nginxconf['HEALTHSSLPORT'] = external_port_from_config("Health")
     nginxconf['WSPORT'] = internal_port_from_config("Websocket")
     nginxconf['WSSSLPORT'] = external_port_from_config("Websocket")
     nginxconf['WORKBENCH1PORT'] = internal_port_from_config("Workbench1")
@@ -654,6 +656,8 @@ def setup_config():
     workbench1_external_port = find_available_port()
     git_httpd_port = find_available_port()
     git_httpd_external_port = find_available_port()
+    health_httpd_port = find_available_port()
+    health_httpd_external_port = find_available_port()
     keepproxy_port = find_available_port()
     keepproxy_external_port = find_available_port()
     keepstore_ports = sorted([str(find_available_port()) for _ in xrange(0,4)])
@@ -709,6 +713,12 @@ def setup_config():
                 "http://%s:%s"%(localhost, git_httpd_port): {}
             },
         },
+        "Health": {
+            "ExternalURL": "https://%s:%s" % (localhost, health_httpd_external_port),
+            "InternalURLs": {
+                "http://%s:%s"%(localhost, health_httpd_port): {}
+            },
+        },
         "Keepstore": {
             "InternalURLs": {
                 "http://%s:%s"%(localhost, port): {} for port in keepstore_ports
index 24d5ad5b64982c1e5d10e8f218336978d1e2b857..9f3a5fb2b3d787e1a320d8dc3734126ac1ee33f4 100644 (file)
@@ -180,7 +180,7 @@ GEM
     pg (1.1.4)
     power_assert (1.1.4)
     public_suffix (4.0.3)
-    rack (2.0.7)
+    rack (2.2.2)
     rack-test (0.6.3)
       rack (>= 1.0)
     rails (5.0.7.2)
@@ -317,4 +317,4 @@ DEPENDENCIES
   uglifier (~> 2.0)
 
 BUNDLED WITH
-   1.11
+   1.16.6
index 2b15d79940844285bbb57c1f771bb31a4c15ff78..547e77e5f510922da5463f5f585f8eb6aa87efbd 100644 (file)
@@ -116,6 +116,12 @@ func run(logger log.FieldLogger, cluster *arvados.Cluster) error {
                return fmt.Errorf("Error setting up arvados client %v", err)
        }
 
+       // If a config file is available, use the keepstores defined there
+       // instead of the legacy autodiscover mechanism via the API server
+       for k := range cluster.Services.Keepstore.InternalURLs {
+               arv.KeepServiceURIs = append(arv.KeepServiceURIs, k.String())
+       }
+
        if cluster.SystemLogs.LogLevel == "debug" {
                keepclient.DebugPrintf = log.Printf
        }
index aa32356806abdb32e73ea0de9534e76567e5e83e..94ed05bff1dbdb0585226741a792d2b77fa7fd29 100644 (file)
@@ -40,6 +40,12 @@ var _ = Suite(&ServerRequiredSuite{})
 // Tests that require the Keep server running
 type ServerRequiredSuite struct{}
 
+// Gocheck boilerplate
+var _ = Suite(&ServerRequiredConfigYmlSuite{})
+
+// Tests that require the Keep servers running as defined in config.yml
+type ServerRequiredConfigYmlSuite struct{}
+
 // Gocheck boilerplate
 var _ = Suite(&NoKeepServerSuite{})
 
@@ -83,6 +89,21 @@ func (s *ServerRequiredSuite) TearDownSuite(c *C) {
        arvadostest.StopAPI()
 }
 
+func (s *ServerRequiredConfigYmlSuite) SetUpSuite(c *C) {
+       arvadostest.StartAPI()
+       // config.yml defines 4 keepstores
+       arvadostest.StartKeep(4, false)
+}
+
+func (s *ServerRequiredConfigYmlSuite) SetUpTest(c *C) {
+       arvadostest.ResetEnv()
+}
+
+func (s *ServerRequiredConfigYmlSuite) TearDownSuite(c *C) {
+       arvadostest.StopKeep(4)
+       arvadostest.StopAPI()
+}
+
 func (s *NoKeepServerSuite) SetUpSuite(c *C) {
        arvadostest.StartAPI()
        // We need API to have some keep services listed, but the
@@ -99,12 +120,17 @@ func (s *NoKeepServerSuite) TearDownSuite(c *C) {
        arvadostest.StopAPI()
 }
 
-func runProxy(c *C, bogusClientToken bool) *keepclient.KeepClient {
+func runProxy(c *C, bogusClientToken bool, loadKeepstoresFromConfig bool) *keepclient.KeepClient {
        cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
        c.Assert(err, Equals, nil)
        cluster, err := cfg.GetCluster("")
        c.Assert(err, Equals, nil)
 
+       if !loadKeepstoresFromConfig {
+               // Do not load Keepstore InternalURLs from the config file
+               cluster.Services.Keepstore.InternalURLs = make(map[arvados.URL]arvados.ServiceInstance)
+       }
+
        cluster.Services.Keepproxy.InternalURLs = map[arvados.URL]arvados.ServiceInstance{arvados.URL{Host: ":0"}: arvados.ServiceInstance{}}
 
        listener = nil
@@ -131,7 +157,7 @@ func runProxy(c *C, bogusClientToken bool) *keepclient.KeepClient {
 }
 
 func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) {
-       runProxy(c, false)
+       runProxy(c, false, false)
        defer closeListener()
 
        req, err := http.NewRequest("POST",
@@ -158,7 +184,7 @@ func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestLoopDetection(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        sr := map[string]string{
@@ -176,7 +202,7 @@ func (s *ServerRequiredSuite) TestLoopDetection(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestStorageClassesHeader(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        // Set up fake keepstore to record request headers
@@ -203,7 +229,7 @@ func (s *ServerRequiredSuite) TestStorageClassesHeader(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        content := []byte("TestDesiredReplicas")
@@ -220,7 +246,7 @@ func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        content := []byte("TestPutWrongContentLength")
@@ -259,7 +285,7 @@ func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
        router.(*proxyHandler).timeout = time.Nanosecond
 
@@ -286,7 +312,7 @@ func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPutAskGet(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
@@ -363,7 +389,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) {
-       kc := runProxy(c, true)
+       kc := runProxy(c, true, false)
        defer closeListener()
 
        hash := fmt.Sprintf("%x+3", md5.Sum([]byte("bar")))
@@ -389,7 +415,7 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestCorsHeaders(c *C) {
-       runProxy(c, false)
+       runProxy(c, false, false)
        defer closeListener()
 
        {
@@ -420,7 +446,7 @@ func (s *ServerRequiredSuite) TestCorsHeaders(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) {
-       runProxy(c, false)
+       runProxy(c, false, false)
        defer closeListener()
 
        {
@@ -463,7 +489,22 @@ func (s *ServerRequiredSuite) TestStripHint(c *C) {
 //   With a valid but non-existing prefix (expect "\n")
 //   With an invalid prefix (expect error)
 func (s *ServerRequiredSuite) TestGetIndex(c *C) {
-       kc := runProxy(c, false)
+       getIndexWorker(c, false)
+}
+
+// Test GetIndex
+//   Uses config.yml
+//   Put one block, with 2 replicas
+//   With no prefix (expect the block locator, twice)
+//   With an existing prefix (expect the block locator, twice)
+//   With a valid but non-existing prefix (expect "\n")
+//   With an invalid prefix (expect error)
+func (s *ServerRequiredConfigYmlSuite) TestGetIndex(c *C) {
+       getIndexWorker(c, true)
+}
+
+func getIndexWorker(c *C, useConfig bool) {
+       kc := runProxy(c, false, useConfig)
        defer closeListener()
 
        // Put "index-data" blocks
@@ -526,7 +567,7 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
        hash, _, err := kc.PutB([]byte("shareddata"))
        c.Check(err, IsNil)
@@ -539,7 +580,7 @@ func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        // Put a test block
@@ -576,7 +617,7 @@ func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        // Point keepproxy at a non-existent keepstore
@@ -602,7 +643,7 @@ func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) {
 }
 
 func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
@@ -625,7 +666,7 @@ func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPing(c *C) {
-       kc := runProxy(c, false)
+       kc := runProxy(c, false, false)
        defer closeListener()
 
        rtr := MakeRESTRouter(kc, 10*time.Second, arvadostest.ManagementToken)
index af9824c3a8dcd9efc4e8f80cc5bd039ab9b8a9fc..59aca1e5b4cabbc4f1f20117d9e1d76f474dc826 100755 (executable)
@@ -236,7 +236,7 @@ run() {
         mkdir -p "$PG_DATA" "$VAR_DATA" "$PASSENGER" "$GEMS" "$PIPCACHE" "$NPMCACHE" "$GOSTUFF" "$RLIBS"
 
         if ! test -d "$ARVADOS_ROOT" ; then
-            git clone https://github.com/arvados/arvados.git "$ARVADOS_ROOT"
+            git clone https://git.arvados.org/arvados.git "$ARVADOS_ROOT"
         fi
         if ! test -d "$SSO_ROOT" ; then
             git clone https://github.com/arvados/sso-devise-omniauth-provider.git "$SSO_ROOT"
@@ -614,6 +614,7 @@ sv stop keepstore0
 sv stop keepstore1
 sv stop keepproxy
 cd /usr/src/arvados/services/api
+export DISABLE_DATABASE_ENVIRONMENT_CHECK=1
 export RAILS_ENV=development
 bundle exec rake db:drop
 rm /var/lib/arvados/api_database_setup
index c459260ace7dae8825212823cbf5fc10167697fd..34d3845eafae9ce7dfc89346f933ce2b59b54e35 100644 (file)
@@ -43,6 +43,6 @@ RUN sudo -u arvbox /var/lib/arvbox/service/vm/run-service --only-deps
 RUN sudo -u arvbox /var/lib/arvbox/service/keepproxy/run-service --only-deps
 RUN sudo -u arvbox /var/lib/arvbox/service/arv-git-httpd/run-service --only-deps
 RUN sudo -u arvbox /var/lib/arvbox/service/crunch-dispatch-local/run-service --only-deps
-RUN sudo -u arvbox /var/lib/arvbox/service/websockets/run-service --only-deps
+RUN sudo -u arvbox /var/lib/arvbox/service/websockets/run --only-deps
 RUN sudo -u arvbox /usr/local/lib/arvbox/keep-setup.sh --only-deps
 RUN sudo -u arvbox /var/lib/arvbox/service/sdk/run-service
index 7c16e08e2ebac969eb28bf5121d9e530069fca04..588e9d2dad216faffa9e96686977507b3bfe2eb8 100755 (executable)
@@ -17,4 +17,4 @@ fi
 
 /usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
 
-exec /usr/local/lib/arvbox/runsu.sh /usr/local/bin/arvados-controller
+exec /usr/local/bin/arvados-controller
deleted file mode 120000 (symlink)
index a388c8b67bf16bbb16601007540e58f1372ebc85..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-/usr/local/lib/arvbox/runsu.sh
\ No newline at end of file
new file mode 100755 (executable)
index 0000000000000000000000000000000000000000..efa2e08a7a7f34c3a04ee4c213931ed37a4f65ab
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+exec 2>&1
+set -ex -o pipefail
+
+. /usr/local/lib/arvbox/common.sh
+. /usr/local/lib/arvbox/go-setup.sh
+
+(cd /usr/local/bin && ln -sf arvados-server arvados-ws)
+
+if test "$1" = "--only-deps" ; then
+    exit
+fi
+
+/usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
+
+exec /usr/local/lib/arvbox/runsu.sh /usr/local/bin/arvados-ws
diff --git a/tools/arvbox/lib/arvbox/docker/service/websockets/run-service b/tools/arvbox/lib/arvbox/docker/service/websockets/run-service
deleted file mode 100755 (executable)
index efa2e08..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-exec 2>&1
-set -ex -o pipefail
-
-. /usr/local/lib/arvbox/common.sh
-. /usr/local/lib/arvbox/go-setup.sh
-
-(cd /usr/local/bin && ln -sf arvados-server arvados-ws)
-
-if test "$1" = "--only-deps" ; then
-    exit
-fi
-
-/usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
-
-exec /usr/local/lib/arvbox/runsu.sh /usr/local/bin/arvados-ws