From da5858d5f794c14cf00b830166bb34b1bcd79ba5 Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Mon, 22 Apr 2024 10:38:33 -0400 Subject: [PATCH] 15397: Remove code, configs, and docs for hosted git repo feature. Arvados-DCO-1.1-Signed-off-by: Tom Clegg --- build/rails-package-scripts/README.md | 1 - .../arvados-api-server.sh | 20 -- build/rails-package-scripts/postinst.sh | 2 - build/rails-package-scripts/step2.sh | 3 - build/run-build-packages-one-target.sh | 1 - build/run-build-packages.sh | 2 - build/run-tests.sh | 12 +- cmd/arvados-server/arvados-git-httpd.service | 23 -- cmd/arvados-server/cmd.go | 2 - doc/_config.yml | 5 - doc/_includes/_mount_types.liquid | 9 - doc/_includes/_ssh_intro.liquid | 2 +- .../_tutorial_git_repo_expectations.liquid | 9 - doc/admin/config-urls.html.textile.liquid | 1 - doc/admin/inspect.html.textile.liquid | 1 - .../management-token.html.textile.liquid | 1 - doc/admin/metrics.html.textile.liquid | 2 - .../user-management-cli.html.textile.liquid | 20 -- doc/admin/user-management.html.textile.liquid | 1 - doc/architecture/index.html.textile.liquid | 1 - doc/images/add-new-repository.png | Bin 56606 -> 0 bytes doc/install/arvbox.html.textile.liquid | 2 +- .../install-arv-git-httpd.html.textile.liquid | 298 ------------------ .../install-composer.html.textile.liquid | 65 ---- .../install-jobs-image.html.textile.liquid | 38 --- ...l-manual-prerequisites.html.textile.liquid | 4 +- .../install-shell-server.html.textile.liquid | 12 - .../add-new-repository.html.textile.liquid | 47 --- .../git-arvados-guide.html.textile.liquid | 87 ----- lib/boot/nginx.go | 1 - lib/boot/supervisor.go | 3 - lib/config/config.default.yml | 31 -- lib/config/deprecated.go | 50 --- lib/config/deprecated_test.go | 46 --- lib/config/export.go | 203 ++++++------ lib/config/load.go | 6 - lib/controller/integration_test.go | 138 ++++---- lib/crunchrun/crunchrun.go | 11 - lib/crunchrun/crunchrun_test.go | 50 --- lib/crunchrun/git_mount.go | 114 ------- lib/crunchrun/git_mount_test.go | 201 ------------ lib/install/deps.go | 1 - lib/install/init.go | 4 - lib/service/cmd.go | 4 +- sdk/go/arvados/config.go | 13 +- sdk/go/arvados/container.go | 3 - sdk/go/arvadosclient/pool.go | 4 +- sdk/go/health/aggregator_test.go | 1 - sdk/python/arvados/commands/arv_copy.py | 52 --- sdk/python/tests/nginx.conf | 16 - sdk/python/tests/run_test_server.py | 42 --- .../arvados/v1/schema_controller.rb | 1 - services/api/config/arvados_config.rb | 4 - services/api/script/arvados-git-sync.rb | 271 ---------------- .../migrate-gitolite-to-uuid-storage.rb | 226 ------------- services/githttpd/auth_handler.go | 211 ------------- services/githttpd/auth_handler_test.go | 175 ---------- services/githttpd/cmd.go | 32 -- services/githttpd/git_handler.go | 80 ----- services/githttpd/git_handler_test.go | 75 ----- services/githttpd/gitolite_test.go | 114 ------- services/githttpd/integration_test.go | 147 --------- services/githttpd/server_test.go | 106 ------- services/workbench2/cypress/e2e/search.cy.js | 2 - .../arvbox/lib/arvbox/docker/Dockerfile.base | 3 +- .../arvbox/lib/arvbox/docker/Dockerfile.demo | 1 - tools/arvbox/lib/arvbox/docker/api-setup.sh | 2 - .../lib/arvbox/docker/cluster-config.sh | 11 - tools/arvbox/lib/arvbox/docker/common.sh | 2 - tools/arvbox/lib/arvbox/docker/gitolite.rc | 217 ------------- .../service/arv-git-httpd/log/main/.gitstub | 0 .../docker/service/arv-git-httpd/log/run | 1 - .../arvbox/docker/service/arv-git-httpd/run | 1 - .../docker/service/arv-git-httpd/run-service | 22 -- .../docker/service/gitolite/log/main/.gitstub | 0 .../arvbox/docker/service/gitolite/log/run | 1 - .../lib/arvbox/docker/service/gitolite/run | 1 - .../docker/service/gitolite/run-service | 130 -------- .../lib/arvbox/docker/service/nginx/run | 94 ++---- tools/arvbox/lib/arvbox/docker/service/vm/run | 3 - .../multi_host/aws/pillars/arvados.sls | 1 - .../multiple_hostnames/pillars/arvados.sls | 1 - .../single_hostname/pillars/arvados.sls | 1 - 83 files changed, 203 insertions(+), 3398 deletions(-) delete mode 100644 cmd/arvados-server/arvados-git-httpd.service delete mode 100644 doc/_includes/_tutorial_git_repo_expectations.liquid delete mode 100644 doc/images/add-new-repository.png delete mode 100644 doc/install/install-arv-git-httpd.html.textile.liquid delete mode 100644 doc/install/install-composer.html.textile.liquid delete mode 100644 doc/install/install-jobs-image.html.textile.liquid delete mode 100644 doc/user/tutorials/add-new-repository.html.textile.liquid delete mode 100644 doc/user/tutorials/git-arvados-guide.html.textile.liquid delete mode 100644 lib/crunchrun/git_mount.go delete mode 100644 lib/crunchrun/git_mount_test.go delete mode 100755 services/api/script/arvados-git-sync.rb delete mode 100755 services/api/script/migrate-gitolite-to-uuid-storage.rb delete mode 100644 services/githttpd/auth_handler.go delete mode 100644 services/githttpd/auth_handler_test.go delete mode 100644 services/githttpd/cmd.go delete mode 100644 services/githttpd/git_handler.go delete mode 100644 services/githttpd/git_handler_test.go delete mode 100644 services/githttpd/gitolite_test.go delete mode 100644 services/githttpd/integration_test.go delete mode 100644 services/githttpd/server_test.go delete mode 100644 tools/arvbox/lib/arvbox/docker/gitolite.rc delete mode 100644 tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/main/.gitstub delete mode 120000 tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/run delete mode 120000 tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run delete mode 100755 tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service delete mode 100644 tools/arvbox/lib/arvbox/docker/service/gitolite/log/main/.gitstub delete mode 120000 tools/arvbox/lib/arvbox/docker/service/gitolite/log/run delete mode 120000 tools/arvbox/lib/arvbox/docker/service/gitolite/run delete mode 100755 tools/arvbox/lib/arvbox/docker/service/gitolite/run-service diff --git a/build/rails-package-scripts/README.md b/build/rails-package-scripts/README.md index 6ac2539f8e..08772ce02f 100644 --- a/build/rails-package-scripts/README.md +++ b/build/rails-package-scripts/README.md @@ -13,5 +13,4 @@ Since our build process is a tower of shell scripts, concatenating files seemed postinst.sh lets the early parts define a few hooks to control behavior: * After it installs the core configuration files (database.yml, application.yml, and production.rb) to /etc/arvados/server, it calls setup_extra_conffiles. By default this is a noop function (in step2.sh). -* Before it restarts nginx, it calls setup_before_nginx_restart. By default this is a noop function (in step2.sh). API server defines this to set up the internal git repository, if necessary. * $RAILSPKG_DATABASE_LOAD_TASK defines the Rake task to load the database. API server uses db:structure:load. Workbench doesn't set this, which causes the postinst to skip all database work. diff --git a/build/rails-package-scripts/arvados-api-server.sh b/build/rails-package-scripts/arvados-api-server.sh index a0e356ce32..493147d521 100644 --- a/build/rails-package-scripts/arvados-api-server.sh +++ b/build/rails-package-scripts/arvados-api-server.sh @@ -16,23 +16,3 @@ setup_extra_conffiles() { # can still be there, left over from a previous version of the API server package. rm -f $RELEASE_PATH/config/initializers/omniauth.rb } - -setup_before_nginx_restart() { - # initialize git_internal_dir - # usually /var/lib/arvados/internal.git (set in application.default.yml ) - if [ "$APPLICATION_READY" = "1" ]; then - GIT_INTERNAL_DIR=$($COMMAND_PREFIX bin/rake config:dump 2>&1 | grep GitInternalDir | awk '{ print $2 }' |tr -d '"') - if [ ! -e "$GIT_INTERNAL_DIR" ]; then - run_and_report "Creating git_internal_dir '$GIT_INTERNAL_DIR'" \ - mkdir -p "$GIT_INTERNAL_DIR" - run_and_report "Initializing git_internal_dir '$GIT_INTERNAL_DIR'" \ - git init --quiet --bare $GIT_INTERNAL_DIR - else - echo "Initializing git_internal_dir $GIT_INTERNAL_DIR: directory exists, skipped." - fi - run_and_report "Making sure '$GIT_INTERNAL_DIR' has the right permission" \ - chown -R "$WWW_OWNER:" "$GIT_INTERNAL_DIR" - else - echo "Initializing git_internal_dir... skipped." - fi -} diff --git a/build/rails-package-scripts/postinst.sh b/build/rails-package-scripts/postinst.sh index 95bb920d0b..b5f78f988c 100644 --- a/build/rails-package-scripts/postinst.sh +++ b/build/rails-package-scripts/postinst.sh @@ -248,8 +248,6 @@ configure_version() { chown -R "$WWW_OWNER:" $RELEASE_PATH/tmp - setup_before_nginx_restart - if [ -n "$SERVICE_MANAGER" ]; then service_command "$SERVICE_MANAGER" restart "$WEB_SERVICE" fi diff --git a/build/rails-package-scripts/step2.sh b/build/rails-package-scripts/step2.sh index 41c9cd71e3..4af0e4a01b 100644 --- a/build/rails-package-scripts/step2.sh +++ b/build/rails-package-scripts/step2.sh @@ -26,9 +26,6 @@ SHARED_PATH=$INSTALL_PATH/shared if ! type setup_extra_conffiles >/dev/null 2>&1; then setup_extra_conffiles() { return; } fi -if ! type setup_before_nginx_restart >/dev/null 2>&1; then - setup_before_nginx_restart() { return; } -fi if [ -e /run/systemd/system ]; then USING_SYSTEMD=1 diff --git a/build/run-build-packages-one-target.sh b/build/run-build-packages-one-target.sh index b94f5be919..b1801dd307 100755 --- a/build/run-build-packages-one-target.sh +++ b/build/run-build-packages-one-target.sh @@ -230,7 +230,6 @@ if test -z "$packages" ; then arvados-dispatch-cloud arvados-dispatch-lsf arvados-docker-cleaner - arvados-git-httpd arvados-health arvados-server arvados-src diff --git a/build/run-build-packages.sh b/build/run-build-packages.sh index ef1e430a5b..588ebedb92 100755 --- a/build/run-build-packages.sh +++ b/build/run-build-packages.sh @@ -235,8 +235,6 @@ package_go_binary cmd/arvados-server arvados-dispatch-cloud "$FORMAT" "$ARCH" \ "Arvados cluster cloud dispatch" package_go_binary cmd/arvados-server arvados-dispatch-lsf "$FORMAT" "$ARCH" \ "Dispatch Arvados containers to an LSF cluster" -package_go_binary cmd/arvados-server arvados-git-httpd "$FORMAT" "$ARCH" \ - "Provide authenticated http access to Arvados-hosted git repositories" package_go_binary services/crunch-dispatch-local crunch-dispatch-local "$FORMAT" "$ARCH" \ "Dispatch Crunch containers on the local system" package_go_binary cmd/arvados-server crunch-dispatch-slurm "$FORMAT" "$ARCH" \ diff --git a/build/run-tests.sh b/build/run-tests.sh index 19acf06294..7d7089589d 100755 --- a/build/run-tests.sh +++ b/build/run-tests.sh @@ -38,7 +38,7 @@ services/api_test="TEST=test/functional/arvados/v1/collections_controller_test.r Restrict apiserver tests to the given file sdk/python_test="--test-suite tests.test_keep_locator" Restrict Python SDK tests to the given class -services/githttpd_test="-check.vv" +lib/dispatchcloud_test="-check.vv" Show all log messages, even when tests pass (also works with services/keepstore_test etc.) ARVADOS_DEBUG=1 @@ -85,7 +85,6 @@ lib/mount lib/pam lib/service services/api -services/githttpd services/dockercleaner services/fuse services/fuse:py3 @@ -219,9 +218,6 @@ sanity_checks() { echo -n 'nginx: ' PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" nginx -v \ || fatal "No nginx. Try: apt-get install nginx" - echo -n 'gitolite: ' - which gitolite \ - || fatal "No gitolite. Try: apt-get install gitolite3" echo -n 'npm: ' npm --version \ || fatal "No npm. Try: wget -O- https://nodejs.org/dist/v12.22.12/node-v12.22.12-linux-x64.tar.xz | sudo tar -C /usr/local -xJf - && sudo ln -s ../node-v12.22.12-linux-x64/bin/{node,npm} /usr/local/bin/" @@ -393,7 +389,7 @@ start_services() { return 0 fi . "$VENV3DIR/bin/activate" - echo 'Starting API, controller, keepproxy, keep-web, githttpd, ws, and nginx ssl proxy...' + echo 'Starting API, controller, keepproxy, keep-web, ws, and nginx ssl proxy...' if [[ ! -d "$WORKSPACE/services/api/log" ]]; then mkdir -p "$WORKSPACE/services/api/log" fi @@ -421,9 +417,6 @@ start_services() { && python3 sdk/python/tests/run_test_server.py start_keep-web \ && checkpidfile keep-web \ && checkhealth WebDAV \ - && python3 sdk/python/tests/run_test_server.py start_githttpd \ - && checkpidfile githttpd \ - && checkhealth GitHTTP \ && python3 sdk/python/tests/run_test_server.py start_ws \ && checkpidfile ws \ && export ARVADOS_TEST_PROXY_SERVICES=1 \ @@ -444,7 +437,6 @@ stop_services() { . "$VENV3DIR/bin/activate" || return cd "$WORKSPACE" \ && python3 sdk/python/tests/run_test_server.py stop_nginx \ - && python3 sdk/python/tests/run_test_server.py stop_githttpd \ && python3 sdk/python/tests/run_test_server.py stop_ws \ && python3 sdk/python/tests/run_test_server.py stop_keep-web \ && python3 sdk/python/tests/run_test_server.py stop_keep_proxy \ diff --git a/cmd/arvados-server/arvados-git-httpd.service b/cmd/arvados-server/arvados-git-httpd.service deleted file mode 100644 index 517a75c03d..0000000000 --- a/cmd/arvados-server/arvados-git-httpd.service +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) The Arvados Authors. All rights reserved. -# -# SPDX-License-Identifier: AGPL-3.0 - -[Unit] -Description=Arvados git server -Documentation=https://doc.arvados.org/ -After=network.target -AssertPathExists=/etc/arvados/config.yml -StartLimitIntervalSec=0 - -[Service] -Type=notify -EnvironmentFile=-/etc/arvados/environment -ExecStart=/usr/bin/arvados-git-httpd -# Set a reasonable default for the open file limit -LimitNOFILE=65536 -Restart=always -RestartSec=1 -RestartPreventExitStatus=2 - -[Install] -WantedBy=multi-user.target diff --git a/cmd/arvados-server/cmd.go b/cmd/arvados-server/cmd.go index c02b8fb57c..0f267a9b40 100644 --- a/cmd/arvados-server/cmd.go +++ b/cmd/arvados-server/cmd.go @@ -30,7 +30,6 @@ import ( "git.arvados.org/arvados.git/sdk/go/arvados" "git.arvados.org/arvados.git/sdk/go/health" dispatchslurm "git.arvados.org/arvados.git/services/crunch-dispatch-slurm" - "git.arvados.org/arvados.git/services/githttpd" keepbalance "git.arvados.org/arvados.git/services/keep-balance" keepweb "git.arvados.org/arvados.git/services/keep-web" "git.arvados.org/arvados.git/services/keepproxy" @@ -57,7 +56,6 @@ var ( "dispatch-cloud": dispatchcloud.Command, "dispatch-lsf": lsf.DispatchCommand, "dispatch-slurm": dispatchslurm.Command, - "git-httpd": githttpd.Command, "health": healthCommand, "install": install.Command, "init": install.InitCommand, diff --git a/doc/_config.yml b/doc/_config.yml index 053922a24a..d64bc4b7dc 100644 --- a/doc/_config.yml +++ b/doc/_config.yml @@ -141,7 +141,6 @@ navbar: - api/methods/pipeline_instances.html.textile.liquid - api/methods/pipeline_templates.html.textile.liquid - api/methods/nodes.html.textile.liquid - - api/methods/repositories.html.textile.liquid - api/methods/keep_disks.html.textile.liquid - Metadata for bioinformatics (legacy): - api/methods/humans.html.textile.liquid @@ -243,13 +242,9 @@ navbar: - install/install-ws.html.textile.liquid - install/install-workbench2-app.html.textile.liquid - install/workbench.html.textile.liquid -# - install/install-composer.html.textile.liquid - Additional services: - install/install-shell-server.html.textile.liquid - install/install-webshell.html.textile.liquid - - install/install-arv-git-httpd.html.textile.liquid -# - Containers API (all): -# - install/install-jobs-image.html.textile.liquid - Containers API (cloud): - install/crunch2-cloud/install-compute-node.html.textile.liquid - install/crunch2-cloud/install-dispatch-cloud.html.textile.liquid diff --git a/doc/_includes/_mount_types.liquid b/doc/_includes/_mount_types.liquid index 86e05be866..f22f7d3551 100644 --- a/doc/_includes/_mount_types.liquid +++ b/doc/_includes/_mount_types.liquid @@ -24,15 +24,6 @@ At container startup, the target path will have the same directory structure as "kind":"collection", "uuid":"..." }| -|Git tree|@git_tree@|@"uuid"@ must be the UUID of an Arvados-hosted git repository. -@"commit"@ must be a full 40-character commit hash. -@"path"@, if provided, must be "/". -At container startup, the target path will have the source tree indicated by the given commit. The @.git@ metadata directory _will not_ be available.|
{
- "kind":"git_tree",
- "uuid":"zzzzz-s0uqq-xxxxxxxxxxxxxxx",
- "commit":"f315c59f90934cccae6381e72bba59d27ba42099"
-}
-
| |Temporary directory|@tmp@|@"capacity"@: capacity (in bytes) of the storage device. @"device_type"@ (optional, default "network"): one of @{"ram", "ssd", "disk", "network"}@ indicating the acceptable level of performance. (*note: not yet implemented as of v1.5*) At container startup, the target path will be empty. When the container finishes, the content will be discarded. This will be backed by a storage mechanism no slower than the specified type.|
{
diff --git a/doc/_includes/_ssh_intro.liquid b/doc/_includes/_ssh_intro.liquid
index 8cb09f135f..4bf72c1b31 100644
--- a/doc/_includes/_ssh_intro.liquid
+++ b/doc/_includes/_ssh_intro.liquid
@@ -5,7 +5,7 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
 
-Arvados requires a public SSH key in order to securely log in to an Arvados VM instance, or to access an Arvados Git repository. The three sections below help you get started:
+Arvados requires a public SSH key in order to securely log in to an Arvados VM instance. The three sections below help you get started:
 
 # "Getting your SSH key":#gettingkey
 # "Adding your key to Arvados Workbench":#workbench
diff --git a/doc/_includes/_tutorial_git_repo_expectations.liquid b/doc/_includes/_tutorial_git_repo_expectations.liquid
deleted file mode 100644
index 8a172de283..0000000000
--- a/doc/_includes/_tutorial_git_repo_expectations.liquid
+++ /dev/null
@@ -1,9 +0,0 @@
-{% comment %}
-Copyright (C) The Arvados Authors. All rights reserved.
-
-SPDX-License-Identifier: CC-BY-SA-3.0
-{% endcomment %}
-
-{% include 'notebox_begin' %}
-This tutorial assumes that you have a working Arvados repository. If you do not have a repository created, you can follow the instructions in the "Adding a new repository":{{site.baseurl}}/user/tutorials/add-new-repository.html page. We will use the *$USER/tutorial* repository created in that page as the example.
-{% include 'notebox_end' %}
diff --git a/doc/admin/config-urls.html.textile.liquid b/doc/admin/config-urls.html.textile.liquid
index 9158dd6b78..e2d1404332 100644
--- a/doc/admin/config-urls.html.textile.liquid
+++ b/doc/admin/config-urls.html.textile.liquid
@@ -31,7 +31,6 @@ table(table table-bordered table-condensed).
 |controller     |yes                    |yes|yes ^2,4^|InternalURLs used by reverse proxy and container shell connections|
 |arvados-dispatch-cloud|no              |yes|no ^3^|InternalURLs only used to expose Prometheus metrics|
 |arvados-dispatch-lsf|no                |yes|no ^3^|InternalURLs only used to expose Prometheus metrics|
-|git-http       |yes                    |yes|no ^2^|InternalURLs only used by reverse proxy (e.g. Nginx)|
 |git-ssh        |yes                    |no |no    ||
 |keepproxy      |yes                    |yes|no ^2^|InternalURLs only used by reverse proxy (e.g. Nginx)|
 |keepstore      |no                     |yes|yes   |All clients connect to InternalURLs|
diff --git a/doc/admin/inspect.html.textile.liquid b/doc/admin/inspect.html.textile.liquid
index fff94cb55f..601d26c5cb 100644
--- a/doc/admin/inspect.html.textile.liquid
+++ b/doc/admin/inspect.html.textile.liquid
@@ -25,7 +25,6 @@ table(table table-bordered table-condensed table-hover){width:40em}.
 |arvados-controller|✓|
 |arvados-dispatch-cloud|✓|
 |arvados-dispatch-lsf|✓|
-|arvados-git-httpd||
 |arvados-ws|✓|
 |composer||
 |keepproxy|✓|
diff --git a/doc/admin/management-token.html.textile.liquid b/doc/admin/management-token.html.textile.liquid
index a4939b740c..5650c5038d 100644
--- a/doc/admin/management-token.html.textile.liquid
+++ b/doc/admin/management-token.html.textile.liquid
@@ -21,7 +21,6 @@ h2. API server and other services
 The following services also support monitoring.
 
 * API server
-* arvados-git-httpd
 * controller
 * keep-balance
 * keepproxy
diff --git a/doc/admin/metrics.html.textile.liquid b/doc/admin/metrics.html.textile.liquid
index ed9fbbd7ae..113536ff58 100644
--- a/doc/admin/metrics.html.textile.liquid
+++ b/doc/admin/metrics.html.textile.liquid
@@ -35,9 +35,7 @@ table(table table-bordered table-condensed table-hover).
 |arvados-controller|✓|
 |arvados-dispatch-cloud|✓|
 |arvados-dispatch-lsf|✓|
-|arvados-git-httpd||
 |arvados-ws|✓|
-|composer||
 |keepproxy|✓|
 |keepstore|✓|
 |keep-balance|✓|
diff --git a/doc/admin/user-management-cli.html.textile.liquid b/doc/admin/user-management-cli.html.textile.liquid
index c2d4743ddf..dea705ddaa 100644
--- a/doc/admin/user-management-cli.html.textile.liquid
+++ b/doc/admin/user-management-cli.html.textile.liquid
@@ -144,23 +144,3 @@ read -rd $'\000' newlink <
-
-h3. Git repository
-
-Give @$user_uuid@ permission to commit to @$repo_uuid@ as @$repo_username@
-
-
-user_uuid=xxxxxxxchangeme
-repo_uuid=xxxxxxxchangeme
-repo_username=xxxxxxxchangeme
-
-read -rd $'\000' newlink <
diff --git a/doc/admin/user-management.html.textile.liquid b/doc/admin/user-management.html.textile.liquid
index 7d30ee88d1..994081901c 100644
--- a/doc/admin/user-management.html.textile.liquid
+++ b/doc/admin/user-management.html.textile.liquid
@@ -60,7 +60,6 @@ notextile. 
# A new user record is not set up, and not active. An inactive user cannot create or update any object, but can read Arvados objects that the user account has permission to read (such as publicly available items readable by the "anonymous" user). # Using Workbench or the "command line":{{site.baseurl}}/admin/user-management-cli.html , the admin invokes @setup@ on the user. The setup method adds the user to the "All users" group. - If "Users.AutoSetupNewUsers":config.html is true, this happens automatically during user creation, so in that case new users start at step (3). -- If "Users.AutoSetupNewUsersWithRepository":config.html is true, a new git repo is created for the user. - If "Users.AutoSetupNewUsersWithVmUUID":config.html is set, the user is given login permission to the specified shell node # User is set up, but still not yet active. The browser presents "user agreements":#user_agreements (if any) and then invokes the user @activate@ method on the user's behalf. # The user @activate@ method checks that all "user agreements":#user_agreements are signed. If so, or there are no user agreements, the user is activated. diff --git a/doc/architecture/index.html.textile.liquid b/doc/architecture/index.html.textile.liquid index f5405c16e1..230a9be8f5 100644 --- a/doc/architecture/index.html.textile.liquid +++ b/doc/architecture/index.html.textile.liquid @@ -19,7 +19,6 @@ Located in @arvados/services@. table(table table-bordered table-condensed). |_. Component|_. Description| |api|The API server is the core of Arvados. It is backed by a Postgres database and manages information such as metadata for storage, a record of submitted compute jobs, users, groups, and associated permissions.| -|arvados-git-httpd|Provides a git+http interface to Arvados-managed git repositories, with permissions and authentication based on an Arvados API token.| |arvados-dispatch-cloud|Provide elastic computing by creating and destroying cloud based virtual machines on compute demand.| |crunch-dispatch-local|Get compute requests submitted to the API server and execute them locally.| |crunch-dispatch-slurm|Get compute requests submitted to the API server and submit them to slurm.| diff --git a/doc/images/add-new-repository.png b/doc/images/add-new-repository.png deleted file mode 100644 index d62a9869a2f9233dec8ac34dc678ae20e90c42dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56606 zcmeFZXH->Lvo?wW3^XQ^l0}rDo1CMHAQ>cQB(upmN)Q!A1QY}$N69&7Py_@7l(5M` z$!vm127y}(?0(;K&$;7{GsgG*d+Bzx?7h}pbJnb?`8-e6YJUZ}`vhmn&f?(U5J*bg zQ^dhJxrBprEa5aBd_sAN;WYeb$z569QBmK8#@61(1Z`>Rbu)@Jt#e}Uy7XX;PM?*=*bqsCnHD(OzuqI>`!@Hy?j95W z5{JdHhg2_U!ftDZ=~E?Sk%ZM(lfLQc7=QS<+AkYx$i)4bK<{bpWcRe~it0BDhl6pY zfbXO{ubd^*+H|dPaL!&si;5~pii*-G9IYJI8xt0ON`YvA#Ls4P@*bHzg?$Ga$6xf^ zCAxrCR#89w%SkWJXed7vyLj=K*w^b!bb(x44sWW>FL$t&g)iI zy&mgwy>qMUV>&Z&OSLL{CvHnUw68dme*wooMma7%-~@`7?ycW03MxN+ztpE_M43{~yFs2}*^V3u&NEbii%JA34}G1qmCT0h=vj8_>0 z@2?v1c3uARwEr{}2Up0RcWul8vHuygcTU+a+|O?)NKd7hUuDF=?+pGI$-zi54{knb)ZA}p#cdq?&{bwAX zFwcU@9`c&JtUH{^%Va#%IQ-NXYw9d6D&z3K*}IK8$jwlvF^oHv5b!~2;(ea^Y}g6B z3y*0o;40pxVmLvNfd9(pO8#-@`ZMJxY{t*utrxF9&PH=FQt*V)lUSPbL_T}t7Z^^d zjGs(DmG(j7>p5oMo8$bmr$iqT37&k!imU76_Ve7WI~SflVYomX;!8xMB0uvbhVk?s?|y&q?tGmOsREAJUH@dF2bB!` zFCYIBf0mS_AlSpLESyQC^2A)+DQQQ+Md48o#rz4ffYc@KrmsjYj zkB^>Ses#Xl;V0jg;-hP|_#(dXO)M9mp3Xce?aT96wqJ&UHipjek~LxKY3Y0VN&MfU zX60X9TcQiU813KpBKU=k1YO9b7T-zfm)93*!rpYewtjs>g8DP95sLi@g}B_cwCqcM+H8 ztjU@1vvGvgC|>$|7ZeE%PP08LJ)?43=K>k2=7rR=Ccj$6nF81f4V=f zf4-Q#nA{6(;>eVw^j2lOFtHIaA;}u?*h`HsGXpC9oBT;$#F0=E#gYbQPhwYPzZLl?vWWe>k-i2>Lu3F|NN;q?h;(vt zN_(>0{{CccYkNyT+fYk$OT=fFmQE%GVoM?eVksi#n}TWn-xknkirF<;taKl!ep6wS zEzq=6u#=S3VZ63YOH{i_yULe__M7d^b4iZW?pOExaGO4UFsN!23pgKc5}pxmiaN;eDtTFEUL2*7 zTzkX5y@e|jBZZN{np@NowBHz>E+-gM{T7baGTiNv8wj#ev*5AHLsOf2x9-1x^7uq& zVz2%i{g(dLS?7CvmAume=lK13ae2c8gzQx9gPg7H<6PLB27YuczO-An6&mMXx-rva zZ($ql!s9YFKZ?Dxp+56qX{AT0Ep%pJ4%ef?gL2KiSk(z-YE{Ma(|J{RcCY{b2>rke zsa|$ou+6h&4iV8h%eq>p9;avwSFXp*^0?mQ0qgB+G^hl61y@O6#dyHZp+hiw`Q{A zOB2fSOV^BUnk;{b>o>0}aVIZE8EADnPc2pqr8$=`q>o7sU#VN|qj(bYBc`m%*V$>h zb!zEz?C%d#&r<~-3+j$;S!a!?czpFR*!*jWYt+MNIpUG?e$MeHzFofZ&$2&iiIDB9 zZ%q8EP4|2vW+K+SVYunA5lopcq@Z_8J4Qv&?JM@7)|ni-y2-^v+2_{bQEyc#Z&1kz zd|_F=h2>4MH#&GDKgBkcOniGLag#K-FgS>!NC2aKT}?${eZ_TQ#iN(G*NV%W z>pguweV4qTz!lfRW%?a?f|9Nh+>&@KuhVb$x}8zHRX;!Rfu^Jz<%~J#4dwof#O|Op zfhecwEUiykXFGg2(57(*6#J|F8o@Momp{tmhVfa%kEf34^0ml4sKIkrEDM_ zW?6I8bSm9X+LRs9Ov|7(H2UD@sms%PK3cD#OnP=?<># zwtX)aKZgkfx#W&HRSk($Iy<`Fdblv^+RuAHwLAJ{@9AzHRf>qZd-=r0=?D9UiOuij zjpBQLr*3QEkG=9nf3!0gpQ}tePp=Wm;w8Vm*R8z7(OT4nem3WKB{?#nsG~@m5AaPh2+q+C2CEm3+CpaXgoZi`UB5FEc(nx5&0hwmQvYL?O1yL^yd^oP?(|qxz>; zRIzHFL-E3=cG~tHx$eY92zwi*EqpwrNlWVfb(+!Z~Ssd=IPKkl?Hr!i#V2+ zzflLT-ZB^__v#WEc`n3FO{wj@Se`ic^Gc+%q=(x!$B(G58!zhahxDSUywvGRef}{{FJM+=tho2}| z>N}d)*jowF%IX`^$SeKpT4l7Av67=cVl_5yUS2j<9zJ$1UT#hvHqL)tq-t#M01k=_ z%ErpfarBLmA-^~bsSl2Zw$e8>X0f$4J-h|kMt%jftFfi}Js92k=vFp%ZubAz*Bbx! zH7DEA0+3DR2UEbd=p#V^(>lBhEWs~oZ>;ZVW3OyuV<|+7tcwPj&p%(wLhKspJL=!l zcQl5nva)mVvvTuuuqv~0@^i8CvvS>J<>mjE$@yh%jL;@-|9@8_kxC`1^D8 z|KLbGtek8n>>PY3ULFHJ6eqg@2a4B-l^tblz-eM^$ZBN5ZOrjsM|ZF>adgqQH@;&E zb_832b06A@hT&-c8UO3$E@sBa=7PmgtlX&oZZVcWD`r75)Za@MWclw#5j@;`6$fK` zQ5!2HwEoRhcP#(>_P42!^u})qW`K}E85x`CJ6Sr?3M(1f8-vf7**FRwKF$*T?+^cb z5J8sz=}AX-{98(eTaP}2R1KM*<)74lG$xW`|8M^Mafbh!kD#IX&qMxK_Wh5!{$sBH zl?DD+7yrk*{$sBHl?DD+7yrk*{*RgK?7zsPu{FRj7odi8ImEI+EAb4Z@882YK>kUn zNehKf&e%$5IN;!rTu1&KlT@Vp2_K$vl#~@aHG@Zm$BD}`%AyS)U2+stcl?8VaQ+2k zb}wc@ErDQ(d@@zO<&OW$JYG%guN7{AhgW%WvjLqPwUgP-YZpouywzcJ|s|=>Vxm|EiOw2B)QP4}quI|(F za0Q3u>=m6XD&z;~wj#Tpenm66more5s}JrZ^n`wBw54z}|UEe&ugwrFpPtnGbqu+~XG|77$@QLcI?Tk!RLDfe?k0+vnfZsRLvN-^5oITK zor#{FK4~vYHAi!SbbIscY^r>`wajhX1_GXR@j$ZF^#D>9RZYz(x(tmX6Z5{@ShVMz zJC8@*W+){UWBHwWYCK#dyRtQk9LMXAH8wTPH<8=CrIU^3mfhW0Xma`ftS;j-4wP8LkbsZZrO zwn}BzI>tsuPpzD0*4-&ZEBT$~%{t?R^tDECm#GCYsv0VAL5@a|c*xthxLkae>aXgg zzYU}gq)oGwGYsCoPfLrQXHa$-E43P8VquYo{o(d4my6|>i$YIb#IA<+UUUht;Y|BH#IdXOq$A(RrwT2YeWu|6xU)k zt12sn^x`|y*47+hw@9%bjz3pmuZq17ycWmm^j20@GIgp-laiCK@vAB;_xO+Jmg{|F zshp+F(JX1@s$O-kshmv;__(x8G`hX#)!5jWAr?U5{i2?kraWvoSEou@S=p#s!DC~g zz$*UDo5a?zo6#F@QtYQ%2Py|NV_inwLQ>+rb|jylqf~^*>q&o*{Cc-1Q$>2D(n(21 z=2eDe>s!W<6iNZ-^z?KIs^I7H42OQxVQ@XH;q5vOYtO3Sqpf`B#lh?Goi1I?CBg>_ z3zn4pjuK8-OrV)7Z`~M6XG`_vsn#$hEG8!`CMLVQoHuzGyPk>ePK9jb^jY%!@m(IP zL1o>%J_&&u-Mo;{(DgKtJxMk;Hseg=V6Cj=dU;33;`zQjmbrUTWP-`oH0Ah9eH6nV zm$p_W2J5`*=rZ&h{N7)R)3IwLPW>v!|Lu65Nqbb2ymk(WQc#4ODi5E)FjI9#DL zRA!^5um7DGMzU3A+i%DG{ryw-yq8Iw)7(eh z*XOSo4uBUiK!$Psa6RKevUqDphpM}Ko;m;)+3j^bzuqb7(Oxa%6#eURC{)o zc+2Q8C*Y)srQe!%EbCw0el%EO5y3X8o{qiMQNq_w5*-_hg58JQ<+s33uA~{J6=UTc zoRG`eab@-+Q|#%9C@u>Vvawv4R;F@BNLP2a?8GqcDVGw9KIRqdSt{vH=M$ek{bW3P zPAf&)LMms2VA2`F5})UcHl}Ri@e&j^gtA?KTYz3{CP^4Kst*xzgVlJ-H@Yui}I zeeQiV`_UM;UxRmNK*W%7nZKRbxy>__ltjBYQq_ks<~H)iyn6K)GCwpLo%)rTHFoh@ zu;5*@Q%AR!mqTniF4t_5xkafYSi%D!FY)9!{Iz87;80>eC52?G=3r_bN(S5fo*w1O z<|BW_(RajRWJ$GcAJg&SxqkSr!>VPgrl61jyFNeu;Yn(2&Z&iO$)`$=PCA@>2})^l zsm2zg)0?|avtO@vbC-@=gTeUS*U~4B`IeaXz9joIBih$dQS<6lF?CZjGdFp7`qXC% ztS_6PXGr>S)lan@W?USc@de211Qo)s8v!@;xGogrerazfARm-0l$FOnT3NjYokrBy zavvnSSIumXPrZ5Sbo2#|l>D7L9}YB!FAg60B#!YD^ech80!LpbEUYNt9{u(90HGmj z_G{u3Y*TT^pC`)&!^Zw|=liU?&(1bYyzu?k?Q3uxkp(y4xjc3LGm*KAq@<>T=dS$g zwlw*BA7Zu4W;SFzV<;*WnnR4)Bd4(xC0)aA6; zk=E0TM9|-Vjv*u63EC6|ePfklp>iH~nqU z?P(HX;`a_6e9fh!h9j&!hDQV9TyI|9%(5P-d>Ir}YHS}@|784bS~KRvp9%7Eahdn9 z%1T{~scI~DdVan5&-A3^A3drz@6Eg}nJURBV>m2E*7VOD(sHH3n8eLyZrtdRDg5&k zDb>4oeE~UG-8^sYL@&wqhUzuz`J?Z6-Kc`^JI(hX@oafDHWVCRqPb2$X>qhhOE|t$ zSryV)ewdabCRZox_wPrNiVz=BoM=VbW+B^gpHiDK>svhNu6uwZs{?#aFN{>Fxw*MD z+1I$QrxPJhxGf`(5=vLyC*}5%YIS>Rj}l* zI>wzFkw$6q@l^JEqzP%sEjEzmd??x=u!vBTzZa5Fde+W?)fp(ND`E$!eQ$537zf{QVq%Y zGEv+;Fxn*-0^b-Fr@l!6Kq|C3>`=Nm-4WXsi!`3WQj|>Erwn4aebxp{<0HcXFlGVb zWaQ#fvA|@rS-DIE^2GJVdhT-n_DJc>m>>M1( z*eI=18Ng^v3=9fVQZE&il)^$nk|rmO8b1+PgcvUN7l>l}^7?kxu_Y$$WME+iW@fo{ zY#%~EkOzp}zh8yfa~bnAy>%a~2rl9z)HmH8EnDUM4{4waa8QW;jLWT_$s($`O{-I>3M(kzw`a9;RY z>$%%gj8;PMV0$!=+EA%gz#bWbhBXTeo?&vd(t5MhEWrA3+{S=?a`BnVZGBPlH{SwKs-o{dA2KNq@+a((q8ur47ToxFanRxG7%`$7sQmn;z9R9Efa;gD3 z0una;B{CUiYc*8bUJUrwgVSMJ#;`&(?3qMQ5t=GxBBhVv!v>*iJ?l`0t-8SV=O z&6X1`x^7cpzzd}MS1AOXW$;OEv4%M<4Qs&RKN*2^KjPeDD8H`T^W?nn?D=z#hMn`7 z>(;uYO)YVe)03p|OAMb9vhGpu15crqPlTyX0VJrGvuzGPNq?#7x{2l0Y-oO7w65E8 z7W)0O!F;ed;{gUdX^3>{m41Ic+h7`)ee)tuV7 z`eGbw5MP1~XAR$7$EMj$G|lCdjdndfLwI*-C{grO&HfHH_o{e4P!gf-$lHVz_LugZ*fSgCAb}+XNO)K;!1rC?0@<)F_t&njcL*$-!43LlRs)6a zn}VtHRy##R7D@rQ_HuLzCIdi!I^2O>pMOTGdz#PB7_hc%=VsM%tg zf3>m5wn<7#R{s2me?8Xh>cpBcmtsXlMdehu)<-|*kTozXHqK+of2$wBO80u79yNP0 z{?p^Y9x)-;rKL)!R)78Cbp1J=pBU>%`@4E`)B{#RZC?crn*|_GUsOP{wY9YiOzH$P z&dksMTFeaD3{beT3BdVyF1vt zUWf?f0ZGIf5H(!ru9O#fGrP-mYRjWFqJGYgcff#IB+S~E?Gd;k{GWW4G9Q!%9l(Cf$>-KlD@Ce8zD@W)0<@A*$ zqu31n7I%PJSztfm;*-pVsp;AYjY59yeJ@Sg{E(fIv85!edtsmmISL)9SKeI)jL=dX zt979aXa=yJ{??rD+N>75PL0HBZ`Er?9Xf?BK9djO1mS4JsZS?$h3o`maUHz?2(f|6 zfT{vKOK^PU<{(ONC+VS50O&h)2fHH8J8$J2XKJ>mqq)5I9}QLd5s+uPERVvm7B*2k z(HzX;Z*sJ+?{o{GS38?H4xi1s~R)fU`HNt>lV2erqI#qY-xCn+M z6>%Ow#a4L{eOMJBvOUT7&o^)W0_MbN*`NPHv}wq?3N`6&fvs!|AiXIdATTL>KZv3r zaC;z4p4#gga&q5({bSmO?fc!Tai_=4ruMdFaPSP3D+{@=v7$B?29!j8|9nzVZPpD281LM-`_#P1sGHVmY`3!QJ=sdjn-Ko5`2U zS_7V&BWVK5)!mmxvHb;xnl(;n8tumt_ZB_nwd9x=)k`U1f0QELif?E&X<;v^JIzxCP9nyc3 zlc}-s9E3G7ghh=+fR3r_Rlm^yzkk7h4T(P#dLVD-+FG;1d^vlSv5)ll8o|#X{bOho>%$RDle$6^E~?pfJ8Q8pDYW z87#B0;XeQ`S%btK<+}pM<7{%UaF^cxuZaA<%M^bBVATbzp`0up2!9A96#?F^ZA}D6 zZ)lX;CR&$&$LllHY;MG_KI9TU2WMXCkqQRIIynzKjQc^syEVqq3&*XsruA5D%_TxY zS!1~gU9m15%%BiAaAJq)FAv6QJp*yB^7Cs#O6q&dsATy#F5S^gRRChLI)!(?VAxv*?dKu0@}QRc3mOWp_d~wcZaANY@fO+NN=6Ux>#9pu zK&Iq^(?5`cPZ5#{99<(a-#b3}6UrWwH84n;?u^f~$gOB9)`5(HJictyy=~)nEu4lg za<2o@IoR&>mPynZk0S@hi+CDSJRE1JcOC8RCAexMRW5xNc{L`G&oV$5L@>f)R8e7} z<%G@7BVjGl4sfIXyH)k8uB+`lR?WkpfMwKyA59W!Nw>Cy(hJDdK1h?JtohY?vlLU8 zd_S05mf{jJyY;22W%K@g{mP|E?5hGHU|oqplmbzuv0N6apA9vz<=_@zi%WH32r#ct z;=K}0--U60JjKCRF5vaMJXJ2%eD@bR?Dgx1QBUvif72;VNT^@$C+D`zcRKL+;ZKiv zee)t5$LVQt?o3J8{l2<=V@)|ZISj;_j@D@%`_9H!s3 zg2dHmbI4R}$KU2vOj%tlDF=m{|K^SN>JTl9__agXA$>Y7v5NsN=`B>*IW-|6As&% zuk&ZDza>3Gy(0&uJwQ>T|yK5*GUf#^j zf7ULSZ5RT2OOKOar4Mp^0ROmJ<{ucy6-dk|sa0yphSC}n0f)A@hboOZo&?TH9vmCQ zWEa{zi|=K^DaV7T^g3fXlVu1)_CXNqUie zltQDG!9}cVq;8&CgpTu-xE)|7?Y@bIl-5!B@e-WzS;2`zF{PQ@E|D7=j)cY&3_yDROZ_;gr5J0!piaFh%K7D#oTm2kAF+23x zZ%A^blBC1xPs+!`)w}$^e#Nen<-~#tpPHS0E1CGAExsU}St%)WP7D3t%2VrkT^?Vt z%0X?=5|q4b$nkK>2Qm;9KGPY$JlM{r?fKlo&gGjJshHz%Qy_VCI3%pMQ0V{~!~`-J zMwUBd=88g{m#0$M6zqPq=CO_Cu`zD(ACQ4K^*^4JeaCtSa(MStgkCPU)nGbQTrxF^ zrqO%93-DY(sJruN7eo_*NsHx4D3t}z_V?*|*PxxhZ?Dc^A;?oD6+nZv{196rcBm@W z>(F>OL?wLWDt9o?bh+`|RW4Lo@Zk5V`~LP!fK!ay>U4%)omVP*e5WbCXtrMI2roeb z^*p{ea8UUjd~ZqoeS2@F>_k&Jxge|Gr4kxit3Zmg0KTUd5P0uzn_E!KPc*Oa)eX>8;M#1X@adkz4Cek;gGrkc7{&Q=8`jOUzxZ>_w>=IF$Zs5h5~ zra(mkwx^#Y{RSP~Q;H$xVJ>wo^u~OzG*WFLlo$NIBRp7O_*{5@%TQ9$+&mMCILUx$ zZZb3H_K0|A$Dc=ZN7pd`cLSr;kVa3t#j9`HLGgwh2=%+Wy-=r!^yLFTg3JRVMA%q0 z;z<{LyJZSN94T#5rz(qmav(&`l$BzlNnjm&DIaPgS{mi5CW&|bA7bjSbup(Xw%}S= zw??q&(KZ)2?+OxcZ*P~fV<#^@R&}^?jg{e|hE|_O1n|un{y;utMfH(d zB%~9i-v^99=Po5-p|^moKuU5MQ_)=6uZisPf2?j>>YRR}p>^UJneA9Bqr$C#Y}9ik zSPi?y=HJ8f zD06HkSq2ocSSNRY;oWnL0WELHliJlreR%?sGzpdrIFN;=GrkN<#pEUAqyV|U4=C3f zq!;s+kn6e2%`q_)1Qfgq9Ht#eC`&DJ72$1vD58E|1a$ zIL%%cP=JPuwJwFC9vl=53o8xJEHH-Z&DHqVg@pFbuk3J|_k8Bu9|ww<2Usbre+Bqo zZa7Md43*W@)#Zq2-tWwS6mT;41Gzz;ba`yI1Yeu*=ayU_o4Z6wnFD#Ed-6Q2UKP@s z^wgthZYy@pYknb-k?5QFjswMbRv_KjTGCR?)llTNxdQ2P0zK@oyxKX_4Jo60UrOpD*jeG!j_14{GU zxuq1sksD8*AiVcJk+XVpeofABl4pc+`Q($633?oOb^9#}hJ02wLSs>Lid zVfgV~Sa8R76V;nzrDbKgOss@K^s^jFOG~@o)4K&ct8^**gN{|h$O+K=%rV)Kz_U_; z3FtsQrRVik(N_;uL!eIlATuw5Yk{f5qnnIV{MV_+KcIdWe?#Wo!&?BWwBT4SD=95< z&N{3Gyu&R^Eedj&;arNPcQsC-=MD9(0-oAm*+N{F)d!nyqd8h?6+I_iXJmuB`r#Dy zJ>}rXAAXIfKdAyY?dG+xF0~vm*!`%ds!_$jtXs|dBlm6Dh;uYZ*9N~I?XC9(4dHg) zW|BlGN(pPBb6QD9N+lpQr5YEgKYVJsB5(z>+rH?gMG3WBQXR)P86BX4iY^((o^EId zDZoba+|m*SNctcQckhg!5xr~YZv7!t;MEn5rnN^O12v%hr-O(|sfESGoZF9TyPbo* zf3?u_0}kuogDnx>TT@bs=0Bu{V{3oRd;aD)^y|p zI^Q8}vEwABg-)}?e2RD1m;n-hQ5cBQ4aJsLo=BbB@X|>h#Numn-J;e|YM5bQWBaDO zG3v4WtY$hiHf(+KE9|M(z$xlS7o6*^ONYPH{2@U|+Tdp>xw99I58}zqeBhrCDk? zCp{)XPCF}*oC6U83tv$Q4Q}vVUeZOZfDSOMtYJEUpK?F=LOr2`>8yl=gzbWt>-JPcRh&pq zWp^T!)evnW!x8~66JKy|fp86~WK_njuH0Zqt&Uc>k#F97cV#KF9Ox>xT-1#N2wn#q zJhy0YXU_`}6-%wNT}GTD&;vW8h$l9b(jxT@nYKf`S6%ZElWzkeFH)(qs)Eg)15J!4 ztY+&+K&l-{4#aDU$5KVJGWWxJAI0dFes>m7hG$Zih!I=eo)k=MDhx>Z9sFgGNv=!s z{J6~`b2Q8VcKdQ0L?;=aeF{1n3Y0qDd+SjGF1c(RMqXaE5S@wS*5!BFB3OcFhrtB{ zQ77GCZbW+ zMFE~QiDuk-e2VI{ThKX5exj^uz(zq+pcVufmd46Gc<`XKg$OAqQ3<)5!P%0kAq|D( zH9$!g^*+Z^7lEFo!~Tjn)_$er1qK!94$qus0cAl|pAga+OLG2wK7=$W8 zC=69@kAV*J-dP@WzecCnKCIAOWE|qOGlf3R z^&^G}Xz&B1@_g}&dKCel;O;^ZDB2 zGF2H`j-Vo2*Q~2b()$*ItM=!Lj00^bd1jGlIaG>D8c(+wtId5pPU$k7cwTs`evO}5 zuT~r3cXR_Lrst;D-K|hxk8gIoV>6V&`eLtwt_u5uf!YQIeWHY{Y%dt;kz(GRKr${% zV`{IhL_`CXq_0#zbtCl!P(nl##@9aa*c&v4AZn4N9rqEiUgOfV9tGqE=*bzeL@lNe zqV|A#HQVSQ{(Smc$QedoH(I{&NHc&~rB}2(*5{qNngQ45g1jhe3}B>~fK|lq$0q|2 zQ@G*%lA=z?{EDIU^4ul;XRbq$|6r?GWM3gq19pCG+52EgFp!AHU149XCS16T85^m2VQ2o3xJ+Omf|}d zC}N0i^wHVs-0V4g;CktfiY-}U*^N6}w)G17E|CcbL(AnVM zx)12f)5{`pUC$yCx)GqtDkU4Agq#Ne;4~}j-$N~uR0Rx&DCUsKK{BLfPr-i=1x(Ni zz5(4ux-g&xjqF$tLaISEkGaUR4KiF9z$*}R(ZHNDfh|Kl9i(6L3>fAa{3MK{?qXU>4;89tB6$zs;2>^D(zvWJ8b+4TGo6eoIs9Bw}nMoKV?P&JD68}Rl(k7)h!MHyHWB3?rMG##{#)DafW}jbQ zg?>-=%4R&5(2{VVY89tktR<;GP}({>;4j%u4)3 zJBg1mrD2>@P3K)*aD0BI%0wDy)0=+he)L zl!=`6ArA3jmAz46_*FaM5>BJed7Q0@A!q>e0?G@mD$3+M)(8ZZDH`0E{np_0Y+Y zo{cEN#Wboz&xbt3$ETqL%@wYsq?GZNLjg{6 zF32U&%m++Z4gixXY*KH+ofAxl)iNm`Xsd#zyw6q!v_cnfBov{_2Etv&3l42)qi~#w zby2){II))>pSi?IH0549>==ZPq*Tklv^!+}Y2?ANwZCg@6ZZqp;pAa^15CGtQLc3Q zj0=tLpXR3o$EU4hf^y_XtqC~1d%i_{@^s{f;e&(2AS9;|^W6N;Z>?0#H*y{0qpy9~UyT20K4N(Cl6d%=ED17c92{P*Hzt;Gp#y)q zcW=*~Hgb&nv2^q$&UnwgkP^10Lq`JJ<6Zd>%Qcn!?9cDE?!3khaPQ&zVLcgVA}YSA z{27?x$>~3%_^^Mz_RKo`K99!HsK_!$&Fuczgd-3N{X0KKk``i+$U;;8SSrMt*J&G)x|LvA|!i+_U{>yxb2u>CDBBd4JlLUZ$11 zk)!^Z%fH#-UlU|VEf?6@^8zt3Eb4@hfz;4WbXTc$1YL>Eh+=P+s@<^lL@A|anQ?T7 zz$QhB_2{dY$R7D{yg2fWdqYj-l=YI(R={mDnhn(!g*F@o85_@?XZzdx^dTv6v4eBn zYH@bMON$vC>pujjv6``t=Jx{pg$I7fs~?(CGtx8W|`YhGQk>H_SR~Zy8g4#>}dX z_7pW7sAli+SdC@yNqZ?g`&Cd`=p@aBR_`or-@NJl1`@C_D*7f5i@e@}ONFzE(fp3w zqB8vog=E)dmEhVMm`Smw5lN|hQy%WBS0wQQTWMxJ4FF!on~QrO_y z?-$KR$U1QP>rBOd#WGpiszHl26mk@jaTM+Y~Dqf!QKu|q|^ZWNiceCF&n@Z0M?j^Z9 zo2TiQji%(55vU|~nr2Iq)A7= z;)~Gs+l*(1RGg6>j$5}XuJwLyl)LTn0BhU^1C19CuvK&*nTeSGgX0Sud}v9n?4=(!XzEcyXw}G^<=z% zMqQojVZD@0?>C&$NL`Zw#=9=rrg~sL#FBAG$Lif?r0$jV1m|0EiL1Vv-FrXhhIW?U zdSgQ);xS{(zl-S5jf0$qd-%(bvcH@d$kZIjYS;75ouQ)2G<|*`YhmJ*5)gGAS<{wx zU1z{yYIsjKnOz87$%%eA32(IrD&OxoEz?Q5|BQ?%7TJA`EsfBN$?S`Jq`oZg`cXM9 zB0g`6DeSsrg_~RHUel)(_myObL6GECOZ#of01?cKL>wXREYklq4Ha*^c*Vy3sR$1RyBFS~r9#m9M%jSnX1 z`+_SCFP`dod)WJ?R&#dPRha~mGgLhAZ2vtiFmkXKFj#DrR=OnBXH&KLt|`M|kVQSL zoL91In_xbw^~85wpH8(Dq1{3{N$QR*sQ_%J1xF|Uc0U<=G#GZ$97tlfc+2U%FX4jo5ZC7w%h=?R~1 z!}=1PH4MGpY!z`9m+h9>dd)P`5O-(oN?hskU~;(>G1v6|oq6}h_vY$prO*h)T(=^( zSM2QRudCF4AY$i7SF`g;blz^tICtm_a8rDMHXtYjHyWeeSs=2Viat~RI&yO=kj=4pxnpG{B45j;Uq^3^eBoOsv z#irByjm(vIOl<41mU^{0cc0qcldmJPe^sT#Ha?gel9J(2`(XO9WwIdsX8F=(KDmI1 zJjFYAjg9sJzw{4MP3%nbu08O-l&PZ9DYqy!>E0y7s!siA zB`k=lO{FMzuNOOi?j?#enWa`Y8={#Af|~Tca6SIvA=60IvgNG!g2crdB@euB^bd?N_fE3R%+)70knPsfw8yQ5 zFue`#^|Pu&@AQog23@(uKRDq^AXmrw1KRiIBdO<;OeFc;Z>b@(8r`={Ej&l1_=LZN zb9ux&^G>X0bv|Mf1*s&zzpfbkWl3uG0QzSU%@a4G4Bg!{tB2j(T?go|;DKXHModhM z_*=1)X{BNmr=pbNwQKJLoPU?A=8UDJ5?~nZX=m14aER#xlLYpQx zOW3Nom{^8g4L|tMITj>}aAG=^A6wr9=QGkQl~er#ToTsG@m!|bB6v{nb`f~x;m_?e zXa16&Y2qpeZk9R)dVo^&(HHgTA7sNSdAcLTF|o0-R)5Awll)BLf@xs@)^Y!^!*2bD0ZEZ^8;&>%T-Ih3SLvD+c7B=dD+OJY% zBC9k2qXF}0Grw?jFN2u4?F{#xB~Vi$LPA5Pp>n%xTz{jEOMovc8)NAjKYfB%GQ?90 zp(oV*Z%`u^C&8VmTT_|ScI#*;pRNgi#|DH=0Ala?gKlieTwfO1L1p>$@}H}^6VyNG zz)KyVi{35!8$G>slQW^m8XYQ1aGg~6bEc!qaayT-|L)rUi}r66+Dh|(?8CF*3xoP|IO2fiMffqcM`N1t}O9sbvhOHQCI@-ubhsu zppyg=*$wi+$Erho+3Ev}LE3gg=%6Bh59FtW!;$e^K8QS4b(Q-btCCK0v&;6&+~vgM z`Qy!rnhV4;yw-iw&aoKwwAH6)mub%koiOQ$K?~M?_ak?Gjs!zJ^(SCH#n6`|*)PuwZ@_S-%pncnHM9$bEt6E^!%dlnUMM{Y$>Y^yL9`)i>oH&N$bG znCD#n2_9~GuH@uirC2{u_wor?e zg!v@Cu5*>&xc8IJWs)RfdgWr_pvkC!moK&R1bSA_m3nMiBcg0b3bdVw!&@HJqIOMC zZh40kb0OxDcR#3t)08`B;3YzM2Mb=tK=?H3=<6QiL^fZu-d1xS&Z&4Vb$H&_MA>=tl!nBCl0u z!Iq0}gT~QYV0a%|nk7PzUJn9l;bG@51%}P@Pg?O=bi zE-Wm}c&N-{a|tPxDJm+;ObrYSAZi93qJmcLZ49k{B9y;eRDm~a*G%cY_5HaDboN4v zixdcEoVjWtAfBza-poUKz{E9lb>pDXI2~T`1GPZfd%H~!X^FB}`O%na2&$ZBr_g2$ zdQ1WgF9oydh61_F6v!J;zS`@_Qe&|ehuAochz-y;nM&)^J)3Q1XG*XPop?W)X|%CL z^((PYu}tLXi0*N0K24)KsR;Mf^Rf&2AhGqraQ(t1W=`su~R zROoW=6iSl}y-}gthqN$4A1(4KDbNMZR(yQ?z-H)FSA?ERiYIl@79tIL1+-7cezWK9 zhr*R(w=54DNEYiFB;NTbWC)3*h%zp!n=`dhZjid@%-q06p$OO+l2{ zaxZ9r)vR>P;I`~ffY+LC^7BVU6T*?C0@6+n(uoF*deAKT7#h5(O4WRU*nz4}*D|rf zaAW#j%InC;45&zVQ(JE?kL7_v53ec3LKR1u*EYn=Zu8(o6?AedxspoS&T!teWJo+- zrtm?{woI#RykqA#ZDcyF^1~UDVO-5E4eU3@PepM&%C;`>LTG!efLe$nXpdR&%2Ks} zow)n=XQZ#bLSHZ<<(rRIR{*nHM=F*Rf>0@{Ijr6u^MvAjIy5SfC-#e;7fNBN-MS0% zYd5$hbS|F1GIJT+j=5${(a;U#dwAJo-JQ#Q%?xR8N80!H-^cy?-l`F*QpLjxb!x>$9F&d2&>P&^G5DFEXn6knV2+0 zA5&7WX3Tp41}#~yPy@=>cNtJ%z>$a{|JkB*Gn>^F+vOvm_XmDWcI!Z7PAKp(3@M=0 zlo|;IB-ERU5S$r|IrkJfzxgr=Oi~le3t&ntG~i=^OG6G2{0`v-gIKDj4xL8*mKcw< zeCQ98K7T%U@wfPJHva0nyW`C9uYRuq0bV*`y|eyLUwub^J#&xJI(1}ML4d-o9_!@!{nyiXi`~rY z<5|l44r7f@C*{pCjUZ*R=wDq{gg;=w2Gh{VwBJ9=dCr8RYu2Us52&C^(83w6LPblU zfnyMKh8-wgUt3nNW&mqVC^DhodlZX@Kzy|VDEof(`|+BiZhfSD&m6iS!6?x@mOmwH zzj!YuX2V1FYotjL3KmVk|NJHoBS6Xg3=r)hG-L;qq9hz!AZW<~VrdvL()5-KsD9(a zmP}y70&8~{$5KlQ*d&0W6M%X}Zqax~?Y9yS4}v3u&RPwxh)E;0jalgM58)wb)t{M0 z^M@Zg|2!72$y|%Ye2D@5L#G{4? zH^lDMol|^Jxg6Jz?Ooh|W1PHnGAT;E<%r#_EtBLgbx?VuSCGrev)$6TU)y2Sd^F2F zFMT2M^635Lw5`n@JWIciXXjB1S1abVIBI<8rb-1})bmV?gMjZV1|W~_*wsPVg{SL+ zO*jnG4RSnXOd5fl#EWkO2|hY2#TAPL65gBU`xfzN6Wo5!zA*$x_VwwHm!Pt8Yza1- zKvwbn(X+{|r5k{fQGnEY(=J{t3y!=(9OnLCc=kFKz3=mEF#mXObB@w=oKSDzOVajO zn~OOZ^|O(MCocjzY+9r3jC`f|P`WO?qeDCY)dGyfG4oyZ{HvuobonQL4ee2e--RQO$;UU3M6zrqZK zP0)(ip6BX6F`s}!2SleRwv4z^b@MZ3@}O>7xFW>AzN}7&Nm>W40CNr; z^uRapuYBoM;tANDDX7qXY^b1{UQ^eA!V$`}y+r+KngnmL)Y{TO#jQ}z^I2$4h|2wN zC;U5vn73&?Zole#H)k}6%8%wD8z6)>k75yE(7-Hay*F$}zk$p+D(&>}Df-7Fa4>m<3A_`2%!B&Pf`0* z#{Ftg#oKW&I!RUxKo0pZq-4q)lvH=to~J+eMM8n! zSwr-o81w5D{!9wm(2k!cyPSr7!+iedSE3RhZ~@!6g{&Kly5I_L*wfJE?46U+KG+oa zyd>Tp-<*TJZD0l)g1=Sf%O8V-HlgGIHZ`Ux=+KD>aK@w&pM334Ysn~%p}0m*f&Qee zlaXHHZzmJK2hwuqW$VSa>z}OqIBKW=mc%oCb2`X=s9mKpErmL}=XzI>O1Ix#4{Rs_ z?JgVEFT=#j(rpB7iy;dOwb(_cV*REJokjJ;KC4$`sQCn8)DQy63sX{iOTjqY;spbN z68_pc2j5{~6X6OFrKDo=67d$T$8x)_*;y<}QBa9G&~?pzx!#g-72+9@%XHhB1P&OD z6?uZwz4iC&v_QmfDe1txF50H9sdvhH7D5xrF)rEn@=p zMkd5$e(sTAZhx*VPvwR|l7AgTKoE=PQI_zE$`xYr5H>;nSa{&qr!GsstZ18CUR79Z z#UYyZEBx_eBgx^!l!6)|adf1m?G=C4i*UqvcSTE^ksJFBTe^O1kvS$N<98s-&(6zN zWq60M?ENPD&>m`_ecXggXbh&h{$3KE4OL1LX7!@HSgaazEz^e*u?VQGVU@_EiW{^?&y_+D0m z+Q6=!ADCKY!^Wyx*+tFPz?-+dn_}J64&_x!Cs_0D_+iMQt?v@Es1Z%g`C9daOPg7D zI!Rt)R(TMqK2>$v#CBVB@W(%Nd(6e}n}qlXZL&LF(rHieq;OS!XInm{Q%k#1vc35> zrl>Xh4pZQl1(vOPZhHVpXlyf z5c|+A4WX_&LRP-y)WKXv$X<<&jgN3~)ux|?Ahh(^3)J&(2D`etf;+*>N1fSF6P(GD z=NIdjq!T~1KvxtLYE7ma-^bl0VnwEh_GYB=9k-KSysfvnf!Q{elTud_F)3IC#iK2A zW&47Dpr8^qG0{UIOB}ZFJ-&PKLI!qD!s2%B*oCRWsS^Y4HmDd0{`8IgofcC<8HfG| zjC`wtKcj)$8`N>1+e{(Q`-Aqt9zO~nkQpS}e`>F+T{F)jf=` z0^y`Q?lk>^;NrS()gDt2?fCZXTX5zKm9E{_Q=`2lC93RTxEdSd&W54V$HXSoAO#B@ z76H~-Xl@J&{ZTEfsA{|Fj`tKx{8&KU{tElUkEDpmkH^w%iLN&$vcjKwg+=mg;>D{B zMJMa@-d)*^gHgm5Vm(y0Lllo?Hslh^$%U4O3MCGbvED~}EkKmz)WWSCn{UdII4zYB-(sJVf0&^(9>UxEiG1v%&53Jeqkn3uy;2(iI{^ zF9>z*%?@4^ikKlH;i%c(;Sffzd^HM32&S6x6jCFpnU60=%_KKv&P7cV|~3LG#80e!pLIY}V*7Q{B9Jx&Ab>5juTs?E#m zrB^n28QhidRpyEJu{?6-xljJRvnD3S-{s7$`WlNJrkcl&9UJQ?ZWXE%s;jXYtxMKD zb6)U?kj*JF%ohe4N(Kre_Mw%vX^COS`p@E-rCa@%Tu!h_UVR{FY62N#!|%vNXO9yx zij%cNLqo5UlD1-HeHpPkeC!zgdJF!Wi%alXyLxhAyjn#xf1KqBi^_I7(cm+S7i~YB zj3d3?m)WqC$>jJ;J>r+fNczj7q$pL5w@nYVc}?phWv#9GNPCYTXU4Se|9U!zUX~^} zJp2J>(s$HQ@jAIYXjdOVSWw#C-Mw$hd0|{zx5$Zh2b-h}ev_P>Tm=}THmmdRSz`bu zuOSsc4o39J+81eQGVt92TdJK41BJs)pb2-X?%n&*v;~1Gnr(h&}XOp*)VYpK-Wd`ghYuY#(jZF zbbCk$il0y||Hh(?4|=VF4EMdWmk<^ezyDGqK5K8Y*Nw(?uGQoP7uzv`CuC+vPO98^ zpfxbd7wqs**v?P*HliH#Tc)*+QQrhsf!%onvHQ%dww(`WYjuf7p=pLzF|OG3>eUyF zhcEUI4&KLX)NsyU`u$s5*fl8|UREC;pH1@e^466c`}e;xhn#F1QmA&Z4-XC1to0`A zh(e#pOe|J15?u1Ky1IK{38pUA4??@+qj#O_6@Z@!Q5>{*_)8wlmre zXP6w$G_X`;2^#gFw|@Lh5&%WaRi=K29=*HGA+OQ@=hP+VajH^{tp~@9kk60gy`!>mg;bCFbw>Ru4tc;R$-bvzfn!ai##LV^( zj|zVVi_=7zr!=oW4S`~&56ku=+LUzb?{a&P# zT!}6%ORvSJQeVN5(sfvV;rM&@x4agTO811sIJe0$@!kw7jk;W7TxRi2VDj4uzsr5~ z;SI-Dbt~3I>&dfreG0wpVEfD&-&p~sOFje%u(|*9aUA$y(Kz>%??ZyI_coRXc)OQb zS-bGGAeqVGmN~@QlmeMeMk~7TM3Yq47^nWtaFp+;`uzD5kc032{p86SW7FxO4-+yg z1qSMAt_pPB=c~^Vyd9ALS=geW<|yUF^3s*Q1o_kqr*G+Es&Eyo7Yn5df1J_fzaFj@!LL!UJM@PT`5?VCG!`Pm4t$Yi&ZXOM(Z*0sDa7+1Q z)}ag0pRjv;sss*g_?=cgy)q{;snIq(V=%Ua?CG{PCBebiDZ`@eBeUTJHD_84dCW{# zZV$ek*G^jH&y}PN5rh!jcpnWdt!g$M6Vnl@NdSuckQ>6lPlqyrV%qxW8%SkeLc-K< zk#+f4f!)Z*j~oftf{Zn_M+^rhGd*v8IsZrJ%rUdK3zyH5$qbO5Tqda;lQEriPcmL{ z{rzh#ap+g%;L^=SsUcoK{1B0r%x>Is;fqEKfiNnHNUWsX zs7OF!_FwyHcN{vfi2Emh#4_e#yCMF#Y;|^WDlIF!ODX%~lX=>ve;xt;8M$MF<3F#1 ze=7Ujk@)B5@y|n_N?HH;5|~|d*ZKng{hg}K{ML&9{?3nkU0M|K@`1y&ZBh6Cej*2T zw}l|F+v;Xx3?_Ap8sI9F{%ryK37^fFaBPzPOpLhPpaP8lpK#_2# z5VAiGK|wkwEVvK;J1(!zyg6PG6%oPW<>jRU-&^?3f1i))K|u-e`+k1Z*d#Zyv$Kcq z`mevq5KBzL-=MW7yK?19US3|>r+b*2(d(|ci)xB32&5+&#W!UgYO;)*g$wZKh- zl&+1WFJ?kNky}Q6-{)v@-8A54-yj&}Hj0Xh?%qnHA( zs2#$xKceJDo4x~p%Z9n(2GcufmhYHhhL%g!FaARO`_X18>LXpor;77)Z}!Kyvrnw2`(#NnpeeQYa_b~iAipvlKE|0Dv{PU5Yz%jA zt*tt;NBoxjf)mB3I9F_D41ME|joG2`^WAGBux=qWnVn-(P|x_!+Id(Z&Z4ACvk}hFrUY zk1I~5si~P`|FFt{F;8#+%p}q{KjN{L5956O@i-afRmVlMNCf!Nb9GyA@Hu@_rYQ~&Z7FHejl z90c^OsaF*1o(q2;7}$U@0Gh*fdksY7kD(!QlCG{Ux5J%Ko+->HKyu?=9G@<~vb z;|1*c1$LWZ0wXloNjiCA=D;jX1x`^OmFK06-{~pH(E5=)foeas>;$#6$%}+rQof~Lx#Cs_ z(2$0mov6(TCHkiA+coOipaoWNa1bHAK#(Jvxs=hx`s!*~C_F7$#_W!Fq5Z;H!Wokc z-fnj*JVkeaB*eabTh`P>cl-8j;?u%FKc(^tYVFf!&d8~${r!;eiBnKfeQaoGuynUu zUbyi%EbIf4`hYT1O!K*pA=M!7_Udt$#mRuazN?v2H_kIPr|9V<;Zh%z!`3!7{MxO6 zc5%dUTk)2?H?Y!!FSHE2P)KmFCqDki)>Z~tSy>FRC+vUShy={fCpH4*NHMYig}cGQ zG+!2RNxkT zC#YPrH$JYXZycD$3M0M{>e;V=a_r#CNf7bO1{fLq`0+ikVEve*(=#)&Xv%5W*z~{8 z#VEfm0}mO3zs9yhj3&lcK}Lpz1KdE}b+YK1dTqryQp|=N0a?*oCx(dfJ5syogErK7+&`TFbOXwldS zlkA*~c?qT`F$d|db3J~mXDOCTMpOG9eG%y1QsSw^!~|hl5MO%q#^sQlNAtFbV&T9t z)lAWq#e*bb2$q(YUt_tLjBS*q!Eo%4ezL7H%%DVgeBglvTej_G=dr^UIRmKI4_RdD z6ub#zbIj4-Ko=5q4ix-Tgof}TBFF$+(?>+U+{X_4P#Upfa?l{r(9v<6ixg9R3I>bl z-d+||H8e1ge53(S>|SSJWX%x9m}F~k4`$Hed!Awkb~j1_E|^;C}( zmb(ECDldiCs=8J{AQPtEwvOG$3fzKalMvI}*{QPxeD2<(M?2dsq>(|=ehY4Kk>zd( zLCTGVnFA2EWs)vwd8`xO+wVv!Q#nRWk~1@lN2KlL@{7cqeUGGS^F2}hf;_nEXh57)DPhiOJ#uM!(g`JXE_y7?Pu7ACv7 zblxW=eU9Z3U2}%>uyx}(-5@ItWv#K%pBluq}TZ*M_%e|6R(8c>L{i&Unhiy6h;HdSRDxT1kl(-zTo%{g*E) z`#3mW%l*>3e*N7vSn6j|Im2}khlrhBAJQ2s?bSpR$cIci=}tb_sw$OxrqdQ3o1B9~ z4kqI3f)vPew3`*|J~@BtnaKBz^oD@JxE37uyW4>~q*qjaIjuvXV>B^{wQ2y=Gs8ZS zmHG_Mk^}Fppq2Ot^~C+Es?*J@lR?sJX?auOZ`rm|Q`0>mY?bt_Qh+Mj3&7td|2_kFYcPRhxBGDaNv0ZWAI0af!IW0rEsn(q6s!8d z{@%6KV5n1cc(}OE(oo34m-nE3t_~LD@ym+ZnXK!xPfDuTbdD2&fc4ip1AQzpRXILY zRBXY5yEcANaWn=vmjwlpg1BlYIZ{P`rcgkUTStC?#A6_wsblRi&J zPk*qm?VOTQ$m%)~aMCFg60Jqpb<~~P)N*hTWKadf#T+~v-nJ+2?CI0N?mGe$I8euY z8mEkin=pN6V^ELHD0%HY*5S2*7yIu>*ph9&&hfP|2k%IWk|MESefjtA>a{1)(L7v> zV6Gz;wFhokj$Avwf4`jW0;21kB!n-)+8Z{y{p9-P0_?AQDd)?o6^1;)hl4ExyuBQpW(wH#ixHN50 zZm%B8_Lyo}h&iA?hYcI1B`YCc>K_h{HYIG6lNS3eI=0Z?VAx1OQI%uwTpzU1p?D+t zCgx&nM>OT$t|I4)#7sNkUeIn&P;n{tkA*vJK!Rkf8sW?~Sqwl9Q9{nZ!}wd|j-PFW z4ZHGeu)NE#nyqJlD3Lso)<^JOGgGrDT6V6Z&6dHZ4T*^G1ATb;+>PEMXF*t8xOqh3 zloz_$vj>iV4>jpzxzadJ-l9fST$N*VMeJD4y3ha*HL+(L@oA!=4jvZ9^%lm~a`3WS$^L@SwI&&(3~??j;>$sf|Vhpt;X6 z((Ht1@@Q5GFXGx(^f?s#Ww0UAFfe!%!DqTA*aiA~aYFp;Es+Lz?#=G8qRL%@0*YHZ zg94Kw=eHm@b^}zq{R0H1j^eruAk{R|ay8v<<6k==iR061Iorz03Lg@|&|Y05#?SC` zXJ@C8WICaZ&_XKd_^+EqGgNMFZow#(fNbxTl42zhNcMi9902OI^GE* z!zUvV?ch2D1k*T))XmuW_t;)e-VI5&B8oI?&?3nElU?Bki2td`d2Sk9Uah_>SP}3P zwb6coffXQg@1p3(5NS!aKu-AuicA8wPRca}&feIlmIPO1QejzH88MP1PvRi&0ZD=P z)pP5@qAUWlJ3Tj7)}Cpaju=>^8ECqtLRHp}w3vkMnccklmb1DtGM-5mDwyr%vs9j7 zxnE;bvIbBKLGCnIW}oGso@5)+Yz7pHz<_EzS;Y}L12XpEuTQX8e}U?%+&IquG>$u? z?&srrB7wWnQScj9R7JB07;Qr5y^(=|0jUHVKtIse4#F>62E+cRNjLf%I}U4u46rPu z*tl^3)3GhE?a?aA5fZyITi zg<2i;ERs%qM8phQc0-7d`W??GDSf~iPDk8*VQv@2>7 zyid*G+iCXsDZiNOLQ*-;YdnKHiHTgO0m}a{lL(=8M!>k9;=3D_cy$91$4kS~>zheS zU^PRcqLQ5^aPx^bgaE!ly)I+Ns5bkwskh_{Om4+*zH=E)m1J@>ckB(A@+YTpb9cWF zO7B^n3xEAeXiqy*c`uGTfDh*=By!}q+t;5Q)8TXtLcGn<+q~Dq!!;7Ke_N#q8*|l7 z6KM|DL`o59aVhh{XX7qhe9?8Fi3f5$8|jdqXIpmcV1Pv1xc28S7vgxyXfUXaQqG=8 z{1zvd+FCn#4$nCIBR_eiSQd#UZ?z+A4%J=bn{2d2lujrQU0{_L zPMNUcpvI_ffI;m7AhrZXG>DUyi!LrDx+S>Bpw&#s_ZbBPum0nSn9Io;;RYtU4NNV+ zAU+T068xsdM8qMtP&VZ0tJF9N)bBxCmoarP5o*cL1D<4)F?6v+V0x&v=S&F4J9`g&=k zZM2UcAj!ddtJk^V%+sX4Zv63$lue8O5J$*BUWc}OpT5PO*j>m13h#9R2$GF5lRwJgf3RDdJ4-=F2ON;%s zHz-}R{o?F{zOVWhc036SduGJKY|7nX$R1|05)t?#W1d4`m>^Id>Ur{zxMH4;F_o*pf zS1YK=Gi2S7&SA9vq=(XNEID`ARJ4<`^LGeHY1pq6IjJsqTz8-*tw4;xIR@hU8r8k; z650}GsoCgfr&^dY4nCf=q@S;fXT47iUVBe|O9?}Gzaxc98 zdKKzbGXw}(GGQ;{)=DG639~bX2wT3fR!=N&W52`O$j1Q!0B3p_gw!01C$su6^;f?r ztl03y+uPd^@|28;zRAfz;2G~GFXW(nZiD@t`|c(Z(1Zs#b!#U5HRwmWYca8|fu!ZU z+v|!i1ld8zHojwZ6d58BGA`ckK#?HWeqDVFm_kUmyYht#xl8(J-<=SlcInV^{H77s zaX^LIR9?z&LyaZh8E=o2a8!2qj3^LFlJ(-Gp7u}|&RoaPf?ZBxX1~#$y=XQsA4ce9 z=oV9BlpG(8zF4D0s|}{|#IsjeS;kqhgtN(5n-WyLu=YA04?jeeGc%}qj&0YlN-lwj zu)i0qmsXA?6VU(j;mZ*37%?THr;0AOZNVAv6&en0sTf=#VzP}f$Gfq638a}e)gyzC zWEQB{70}P;=SX}oG-&JDU;!Q#54w~kHC#0pEJZ;qc8O9KY90uA<{JZe^*cv_B=55UAD}2rw(- zVL+_5y;|ciD!?xQ`Sh#k)XAtO6MV94jvkCUSk>9dLL_+i-vZ%IzaC!SXO<_XUFdKO zRi8y;xdJmysK{}DXIIx+Q0niz6^z>Whu4~ z+G~;ketTmA`Vx2q3+}*Dk2*4jT&X8vsU7}mxE?A)VHP7*-o7!p87IHZvJ!890DA29 z>?HhfvRLOco0FEPt$n*IV)c{|iv3CZqoptiSSKf^!)q6qFJ&9Mb`tXB@oRsu{c02~ zi3*v-EtjDKvV3p-gv$G~y~HS{cM_KgcD&IHA|%Dg-lsSl`MA6JByfMvk|SbT#=SIM z$T*_X&$)aRK-vMniW|;z?c&!WnMbCrMZTfJ@eM*#$u(b0NWNSQ7-?uck=%oo86(ZR zc5K_|DS3J16p}+ggEiIEQOWr$9MUNH) z6s|Fk!!sn3-80KSbF^dC%~XnEw&U0Yi#n4d<;=Fly`h=Y%D+S;gH%y%Y7b1WJn zNvY4zg{e_^;6I{PU1=7sG9$VMZYRH%F6}X|{XGRV``Q!bvh?JZ`yM#1`xlcT_D-5q z;n=1X0R4wOl_`l+bVIBtyFVdnPFPme(t5h2^@oXTPEzgbLgefElM7oN4%ad3vAuu) z-dEI%*v)roV8=m2+tf4%}yy@%;e9o(i%@c!U3-l&=l!MR5e(Hg>#2z=`f4 zB}PA-_LaPgsyj|`n@IW%*Qt~M5h=Z{&_`51JuYPXyOWnJ0`#>W{dNR^13mC2Icw{* z_R#Qe_>ku-o};o}JIHcY{>QuVMuTiBdVs1~{&|lof-d(8fLqdwygWvr z1{HYP>E_Kxp}&yLw$au%?`+7EwT#?sde!Z#!Fj5Ck6=O2`o%=OWlO@3HsSiA`Cq?; z3#ILFQGo6OiZhWgKf4$n;6Sxle>vE1HILbG1-6sL(nQMlwtl)>5+ji1Rz zmK+-Wm_}y4p~Gul{VH?Z;T)iFm=kJNqhdSNs{MH1A6`3F7b)d98OfbyVC8Wg798%v ziVm0a?^5{d`$TXxnPa=*h-o;=CCy^bU=veH3W^svh<_D!mv|8KaN_kD+z@tvW&M)N zc5*h8n6rzipjRY{EcYlCOq@JH|cd5tWVg!N3#4e$2*7lyQV7(=o4W%N#FoZgFLl<}l0 zszV}A^fZ{d_xxF$;@y6(1jo(HZ?p{$J-~VIMTXYr)5~z1%)rShizz$#;w;Nt<81Db z$sM6gGN(4-iVpYg7WXTcP0zCQfxOwdz6O(rQ7C0w=321+R_x?D<5Uyhzk|@=(Eka= ztZF*foBUhh4h>4m$_l6plGln_jFgyIFhko8PIw?jwlWJJHO`)m|2%j4RHtp=@g41V zb8{W@54}noax=K~HMY?qS5xZez`$J~nKLUkD06Waje*G&g#?3%HhU;wlN7%K+?Grn6u@t z15WDNirSYofiD=*`4V=_j2AD3I<26l6q)FhH@fmUFOj^$P&EF?l#>m%xRbEn&Y+ny zMBhDV73=EaQp0TBI7yFFF2jm!A+o!vZK`BF5CQ~$_$`FZOeKdNC!-86e-`GiZnv^U zr*a7Za|JvlC@zB#8hl3BO!MoM<>%;a!M${sAn@I(1 zw_0F4){ve!5OOA1)kOjmEGT4yjk6dtQWF!T_Tm5=3_e~aX06#nD!eR?8$dUlDOiuc zp=c}mJo5YBbAqGccq9PgE!sk!Pw=FofrkxiF%Bgu&9~SIO0Jw3Yu&sF1m}L?a&6Z(&5(V z-$h_PNjqle=8X07<7#PD2MsIqgfHsq`lG=vH~KOK8^^iHraO)eqIo=DGbAfOzkK#U=6`7Yh+3=}&-Rd-syC!Ixns znF(xy!oebs zY}GHI)9&57*VkX}=d{pnn%I59a%!{kW5ytA?GV2fc>c6jI|%Z0>s70iJ+VyEK+1Ms z;fRW_2r+EaevMX@_?T@I`w^kka-;H#dK^~#^umGyikzq7d$)aI33BA9d+ajZcc;9; z2E0Z4z^sXY4&8K~`*O}wE^tTC$>(^ux7nv>$C9a7)O3|PMKT{e9;LicTtjy_q{qG0 zJlmvlkC4e(DRV+7H$81_Q&fN_M2Ogcb-b}G;h!|QL~ndCq@ZGHDHVp-u-uJ%^c2rl ziZq)EB^c6#d)sJeAWgA6LcTGbyw2X+e(3MoR<~y>@K|5tXkJS*m1;}9B5l(pe=gN7>#y_e^;l;GGxWrmwe!|w{LeLuREPAq2_C6R@=|bz*B9NtH8;~kDJ_d^ zHgGr(kXC63W;TOgZ5z-tABPO@Cx{9Hn+KPJ zbo$V>tt4zZX*YXMfYD|r{@z#st9(1E(J*^&z7tFeii#2bcMW)RZ}x`QJ*EfS4{C=? z#3#0Us>#0-ooLz0#>?uRn6SaIw9M+zgVJt5@SO4FGWcEnS$rF0u3DWHyYH-ovXx_ ztJ>Q$*~TH2XY@hNvLce3#X=qeRdkwD>e${*w5v`+sJ9VhFESMGFaubzF7PGiwmhcM z6cx3aHvl7_T6aL>4x78wjak*9&e+O+LO0Ud2*e@* z{2Fx|DZT-mOhN=Xr=S!xXgLAb%4bEYeMKmP)|ET|;ba#^6|U;-SK^gHiMstAT*= z;f8^8&xJMvD9?VE=rgm`60faU?02NQnbI2lma%qpiVELD zi8(Xn8~BVcr(~|L1JkR9A6 z^Qp2@XS|BW`{Uj`7J!AcC7E%huOX308jFaVV!>@N7Q=0>x?gG}iGJ5KbuM^@ z|DA}S8@S0)%jo)==wB})A|jFkbux?|I&D~n-YGcBaI0()Gz!|RW|D7S7K}C+ zQ#ihG0|mU;CqJo$ujmY}g2n4M{WfBk(Ry8odFviA8UTgitaq_Ggr6NqlT0WGd=z*Q zcj{3YnV8gg{b|(hei(1gXRTRx`mGjnW|Pe|Lopy+Z``?@k#21iPzlujoZAZQLSc!u z53*wq9kji^M1TDUahFxbq%C@XQ6{m=$1U2ig_J*wdkhoTMr;RVNcKyE2P&fCD*yY4 zc!!P22u;}YC5G*hi5%f;a=3xdNMFB6pof#-v-NVIIsk;fYjNZCTq=uu4<6Jozpl8W zH()69Jj%T5*UO_su~Wo&;r#h>Ol&gAafPF-i3%NYrXcnDdx1U+Gew*_-ejb&&xSmN z^=DGiu?(jwGT(;1O;MrVRZ&^#*RERe;o!)*YQW*b5^RlFErdSYCMMl@yc!^QEzg@+ z`|QT_y{w+Dun7z@^VWn<*nkyipHb=Yi^7gtl_3D&p1ZJ0wV*W3wEdEX9tZ1|?|>*0 zv|I3a!@BbX{BI2UEO>I@7Bw}8@8(uJ8AhIFK|e{zdCm{!!z`9LJOeqopNFffD+f3C z=l|RW+Q%e~be}|>aKCKBibLM@M+f^t%Eq{7LyZyD71}o%WugrP4wuf3CoS~(ILttD zqMrHK*4CE5gF;>E^_Szly*Cmbd&CcKJsZx=@A^6g-!r2!r+#+a-~N)3QSA60aroC~ zZUV<_ZI5^u@5Y#y=_OP~+!o}JpV@!7(aH$)y6=$zRKNo7`s&=@;#{c_P>*#?IC@;= zU0g<(^1gM@5{G-@h@kswCxskK4hW<}$xOh+ap_dTd~Y#|OfDN7iIr%$h4phZ4A_9t>W6gUY)dd2kL>Z3 zSXszx;qK>Q5o&Ld2!}~3M6YT)i^%5#c@}vjf&gD~LS?#X^JW_@ZJnbW?||5~{}3OL z&4g4hMT{9f$#(7R|Ps+n^dEkkEf{we@vsGcKq4ekIAU2B;0 zF##Xns3i16f$k3Iev5GTUHa4YUZo5+b4C-GztvIlO3 zDG^xGpd>i7@&fqwsIkS;v0Df|-?AN>PdE4MUPgyp@x20uc<5|0j_2v8P?%quqFSId> zn(1yU70y9W^^D?sVn!h3!cVe8V!Mq{E8M&_FpTOF+o<=_T)c7hPAOlpiYWTnfDUY0 zMevkOFD_Q**$fzUzl^*y9~%ln1pXhJ@rO`J0ao7N+Z~DvHG*(N5SlpO0V%>(Lu@bk zP9YACw({*~E>PiZ6fxUoaEJLT9I}Kk3u=} ziQxF~C<4I7l1Ruu_J8`6k)Op31Sb-R6>;4wya*t@?t;*)V*c>*<;$nIJ?H!&?XF!1 zSd1LOt@?ltM3VVEf)12)q9N?u&yqNB*u!9}h-lg`nB|qTViP#KEmxwU`x?Lo2+Z;% zRA|6>AK;1%zpk z5cdq~x8S4O2m4`$Y;Hq7puWq-@g`Mc!_03)yx(`d!6gmU#82FS#U0v$p3dmA zVBF@zp95%3F9e!196EUL1FS$09LZuX1&4**$LUa;@e}t{9qqg_ksX8)RV{kchTJbu zll~>E6F1G8-fTlZOb7rlk!m@qLmc?C<)1TclKi|d*7SBqw8xtBJpQI;jJRW>n%ryX zy&)3##;JVgO_*uLtI%!V$4G5K^FT}NUgx4EwTVf;M90Fyg~)+TAb&q1r{zA#;w=dE zrAhFEik8fCDHFpOY7CvWaV_I*Ol^~2%SpH?)J+d<_UJ84on24Boondv5aJvwEUJuk zM3Wu9tv?c^kw}l6dZXDDr0>x8PC=c?S$li_t0Fy*$5~??Ev>`A`n6V0goK2AM1u7B z=-y)2+`XH;reOp3Z9pi9{!Av6t`S8ikmSCyj&UHARDLm(o-e+d-Gdr1JnzBjuj zX=f_HvKS`Cz{Y0PmYV2Mg@pF94$SvS};n+ zm3FA!$`^?s>i&Xxm*Q#oSTC7LZ1LJFuc+u(3(iZ%<{7kpn|gYBG>RLrPu?dQog_na z7rVzk&wkS(-GiESsgMB;p#FXFnDW4XagifjdZOjOgP+sY9E*2zDm3Qq?$0 z@n}bMW~DR8R>E+q;eO?MegLj!cyq%t5#k3McOpxwFeyu_06FL0Eq4J1q+9+b^dq~a z=|~1R`5g*5GwfD6Uh7$&XSwnRnnliC^z`CJ?9F4pC# zpmqavh!d9;!*c7O+B~1aMcnO>X9=aBWj@GEwY~d0i8)IsMsb=mx)N756N1v2N}5Dh z5K{Lm-zO&7jHap;*n)4F!B$czH^p&2NJKO+IBP6E|C`0gtqLUBf?5O|qT)V*gfv3n z0@_onJ1i5LKTd6dg{S9R)Y@AT)Tx1i2zAmA;WD!_R7cY&il24WsU79Wel`pi%H+|^ z93f)#fQX%)_|a-M0TFzdNQ`$^`%`$lv@p!0Leu;9?K^$$95yNrVt@)Ko|q3_bMucs zX1Y>jx7XYjM!T5AfHI>xn{T-{uMp%%i}6P>mSIApbZ00mFcZMa<#F>_aI6DZQ5jYY z6`-VNQax6w0mL40bbx${1)ARnI7<^I=^hl$V1K_@)M+&#l67C$n1Xaca^_x=g#{R} z{ssQ}h2ZxJH*`2TIiV82V9x|069j_SAePr~G*;~tb$4?kd>9FVtUu5g62WUdza7A1 zfo)I2-Ji{?bWUv(#1u==rfY176;j9&T2`(BCu6~eZ7iiX%$BzQyrp?L+jNaZ8C-g;ReUc}{&)&%X zk1i`{j%M0=PZ?HId`>e6XlrCJv=0lW3|k)Y(CL&lw@=7AZ*Jwk(gC` z`0DYs%coKvaR zZ80W2Vt;?9>o?WG8*}-2c~8HcLUEauP zmcX*J7k;d%t1CzQtqS-KXDtNwt(L(r6ZGIw0NYG}WXS_um)AEX6MM@~hc2;`#Rp2&jozJD=(*c4Yv@E9N-42S$!B zhHCC43E6G|XrRjQ zV2xVjg^~6~d=XrwWj)a$oL5*#h}j9pr=Ir}8VWKjW#YL7<2yk9jdN=6;lrB%98J&9 zXSue+P4OMP2jRDXFP<V(y z2KFLJ+<8D4>>>Z=jvgNGW{c-0H2nEFCUwuvaLXWW^yKQCq!+J@KH<)ci{dLluMwyz z6j{WRv>LY2`L8Mj2XlEk17Y~X*-RA2&97EfpZ$7~dH80b7$2X?I8~u>?e48?l8kW5 zEJ5FEz52&Kub_bV(M{X7Wf!z@R)pk|D1Hb@9IB$Q!X#fm zKN~Ph&`p=s)>317sV9{sz6!ita=X~6N&fZMKJ@3?uXE9SEqnQ3YwPyL-o~-b?Q>hZ zLb4Biz`XP^Jc-*y>b^JC(b3Yr(@wieMnwIPJBc}{xVcHf_cbBza_=zZWc(=M#OiPB z$G#kI9VED4&D5f=-twp%JSlKrz^Frkj|aoKw-Im191-x;R@G#lo$+oINd!kjA;LJ{ zGxJt@_2GTFPYZkCZb!>zlv#GhREG0a!dvFNvtZ|3Tnf0C>w%<#B*tE8Qmt+aY=Rg~ zfP#cju$@sHhZ=XQmK4tKLF1nygF{0PfJgZV=DN7L4j@3vl#DiAN>N?}{p5q7pdH{| z4@JBr00altg1bIPmHDkrH+3*Ijo9V6{7T?{s@QxHTxoyb2W)L78&x^sU%iJz#sEMW zXG6nt;aZ-%3v|Q_28BYI;;R=H2ZdPm$9=a1I0d=z$hoK{Vqw4g@W}PtDqxPmy>asL zKX&cs;NXWrVmAeCr!7oe>~7O!uzgf{?ZvM#If{#m@4gb-G@^B@ITA1dei%}iZNzds zaDW0$>Pe(SPEV9>)FqJ!IVoh7K$3q3KfC*|Et=z2k>(Y5depb%q(swzgUch` zg`%Vv0O8Sof55rK4|H<()(|>@XX+xzM*y$cPhKJTnHfY(+WddIRg;Xyk}^2;jKwXu z|8LBedd1#>U!iA^YP0dC4E=7?U{mC%pglXMph&-3CWs^_fS_HWFT*F5AD~ zy6On;c#?B8+|e;MFX~m^N-L8|@>?Tq(x90dIaJ#`JUk|eStu`mX)tM98^5O_-jR=D z=o`6x&_&XPtzFtptIcqBVY~K*GI8-A&vAmJrDoB6GkqcM+-xU zL=sd}cnzDWzu)TB8Dr!R)CF}M_wk7zjW_Omwj9E9rTebqwZ3|EQ_vfJ!eE`-4PEih zb&WsL|9m-Peuk{3v0weYl>!;*Cw_Bo*DLXxA9s5^!W7T3|CU3Fu%w7XLF+9F4DXB0sXf%hlGBmv1gz+}vs-l}j_GKY2KM!`2Ull?D#&%w3fK zOqpleH94VF6K|%Z8eXu{stV63j@~%e>#DEO%N1al;Lzjr_+Phw5JlWR_gFonAmc96 zMJ=S5jN-G3h1*<7nhW!CXtrtG7qP(+Yotr(?<>cv;i)REix^$ClynTGRFJA*n!Qr8QIHK$AMd-8DW6zwAHr1+DdR?+T&om1>_be-3}{RtJ@<4pbTNDTDp*&EOO z*oEB{=i0w7-575l8fMbfT{UFCg;v$xfkT2FzX}(eus8!F=bLz|&`Xak{3XzxOdk7Z zzQ6MqJS*uBPLGycaWvj{40fza&eu+lcav& z^OOH-{9IkYP0c92|42OuIxt`}iCOcxT*=;tEW*w zYAtJE*Zg|xgNcbw#?*~c#xwTSxwdIb)2C)^E?L{oTMpisu@`hWxc_b5uE`YPG^eZa z<%6vU^viBO5wsaK5fPYVcp?ARTk*W6Q2Yd0ugisN^>cTAc4fUE9sA|w`L0v>Rnndt z^Buz7X;)=7w%e|YJF#hIup=$BE17kL#XQgUxXP2=0el%JsqYEByX&c7-}hZ(gBK|; zkJNrY?sR^H-zl3TZP9Kg?O8vZA2ZNMl}YTGx~;ld*~DmI`d8uUBAW~L;um&^Cb?z% z)m5^P9*_QFOc$x|zr{;=oqu*DynkRSG{vBHBx{SiwD8!4E0sY?tz;xzCU)=o_lcV9 zXllnuX-zP*jR^{cU$=VJ+HvGCgrHm#F;B}&@HXQJIC7}!^y8#Oz+=U$+Rwo=n{leDR| z3H=qintyuKz*P@kE3BRG=BKXCAyov`%t&$Ap1220FCKuM9125FF#?h@$~MCtBsc1bA#Y3be-kyt`v ziCy*%`v2bhJ9p2*p_ZL@-kE2fdFB&MeyG5HY=nYKlUhz!^tR8TVSIRo9gXSGsO9R~ zn>h*I`xB=1KhI~U_CjB**sn5DzI>^F19Hv!RcxR*!P%BG&Pks$(p-k1%MB;MOZCSy zO1rCNz8IbD7en2NnW~)lifCHTZ2x&St#$`61o;CF{$MX&>RXcWsQe&%i!7_Zvc@!_HM$wY%k zt&SxxzD@Pdo|ixTpPU{{m1~lXNKM|n{Gjw&d$Uq<_1gfq2HGbWlNuh|F6k*tv_QOf z5a`f4cV}*0LUO@ux$D;2eo!XqoHn&F-HCr+t>MkR)iyI9ua&fu_8=4bIpNVPyWr5R z&E#}>{j2Z2-g z4zeBl8u1NC74{X|6{-0^5C+^+Y&yW$rImN<+cv~ulYx1Mur|5u;@nUeG#f$f+eL9R zL+6j2>)sZ1?jpRHo2*+Ec&{$Y8P;UcLtJchNx5kx`sur`H^j0s*bD77?jZTZ1+-ni zWG-)KQ{{~lUfCf}>^PB%jwIZZ+fzT;7-FzMrB)h|06c=rS?HGlk#~eW-)*d^?Hdl9 z)D2@eV*eDa!h=Y?2;c{u>E7aoy3FtWh6c}8KYJ}$>+VR!zG<|55EFTh_H2Cp=Zw#P>boz z485Yy<$rdsu8-!LGtcw33>P3YP_{0I_pu=^Hf~aeI=(O60uOBm1L)(+1Ya z+nr%q&i5B7I(M*!TQ35B9)lEhBUx{I{_09Lj;^uw-F)_!C!IW_HIi-{Zm>mUkD6|S zIV{m|^y*Ch<7OD%4MC9?Vd;a_2o^UV#%lAvP!_$0yi?5Gw}QFOKfg6>`z%$yHvA;_ zFt=H705x`ik@B!Y-Is7L)A>a0qAbhP=07RGHOv8o{Ri?C;uJV?5ylGy3tt9N%9Tu zm0LkSRlPzjkM+=@7XDR;v**H(KGW+98g{Qccrps?T-n=-s}!?P8Sko1eEm#XNwLl? zc)UOA1`6_jyK1Ms=}ytFXvOf>O&7SqAg&GSIV|~=~D+|kX)}p4OesV zBZiuh7ryKnB{oE#E7VFQ*Lg;wQYqFW0~_XFb9b1YZ;lD@v6kkwAHPC$;FTS7g8V{d7acac|>{!I#%!^zeO%w%9Wb>!P;{`1`d z>6K&IU!O7>e9(JMv0B59y^*XJ0E$NFNCGuyZ2heu;`*ASriBcv*-i?=g&@A-eVF|z zfDwM^&d@tl{y~^nugzS%>lbz_w>m+pf(58tvEOJvTx1Xl5Z2Q%+&a zqeR+#k;(BbA?u5J;-{eb*A)Fh9GSkWk4N{vFBR{0FBLFsx4ccIYJr*S;ItiF^v5A0 z#TK8;?AY<<;Kgp2B$Xf31l5JjV_Y;%m0%qqn-zY8H9-L#>5HpGVp_Au<6QiX(_#|0 zos=H>FKQ87ymYmn8^&s+Woqws?e7F;&7Z7?w;L_#$Aq#AAnR=IR2Y8dCS2ei5Lhkf zX9LsInrniYBkIcy!|o>%wKDjirJ6E3t)&u}kgKK(L)xa(SD$@jB< zjkpM@XB3gC(14AAE1_j-hW$OysVcY!Wwas~AbTC3-k~eb^gAq& z(wLB0w}&AH=Aix%W~H#OUsE|>td-ll>fK0yi_GI3SKnVm4)&~(dv7a$Ij<-@GKee;$&$Ub-$O9#X=>C z$RGHZ9)<>3*KmPJxDehK@r!`ITcI}+~NsFArhjrbDT^vNc_$J7vJkLL4n8A#% zu@Dr%xLrbK^dKcUiddF9`A|q;Vx2vK{Wwz&`|b0|0riN`67G!{%~~wQ&PJT zy=_Ns0#lk?`PX)X>Sw|uA99FhE!T^?h~LDnK1c}S8UJ3jA*|VFDv)teb&FE2w`V>1 z6m!kYU38z<|Hzz;=60P2`mCc`m$B6iPbs`@H{ahMi`&6#$a31labDc z@+pormN(hG@tsQCt>j`RG#Fz0H|ZK8V}-ytG7=k$aHoa!tY_+{g>tjDMQpw$oY>zm z4}l+mxhJ7MiJKz!U;iMJ$U|QiYn-f34&LD|R4X+;J!a=WNvEem50lvP5*ujl$1k?o zhQyM4)6lzD@Z2g)-=HQEv)AIQ^s|2`NEU*tZ;vB_*}W)2!CX70jpwRcKoRgxzrUYt ze$z-ilt3L_@?B_9z<~j~5(PJ}#2|ToN}y@pG58TLd!xE#9U=u4OPoCf&8FwI6{p^s zBhDrLbMCl>lI><5;H^67r@8kVJ$UHqmpHC?C48I-aTX+~)0wo3DHkp|y4VibeVDCT zYSyC=<4*kT7iPjzB!qiGZCWxwS+yk~iQ-z+Ba5r|+4cKtCeYaJZq z)MI6@!_t3(8}QNZ>X~XXH|v*^vjSQ8fiHJ_DOYkqe$E3KodZ7oxQ&L%9+M6)vxSgk zwg{#cml|cdIDf+&lFTBmj<-T~>V8~A*J*x!A&&S}A1hXvFK%47ZV5%L%1@Ukn9ois z*32rb4_;N&L}Jv+&z~1ch&J+ZYtl_4gN6b>_&uOdY3ciVdVdCsdY!!_5M`h&IpbMD z02@h9z7z7>>Fyt@l_Zl=5p*=RmXxdP^W#htliEq9Uq7G)saQ?fNW^;ge`bFO z+rrGJzvfu_P~Yw$k~L5?ZJB%yooQWM*&4nW2-iZR&nEela0#T8-x2g`_y?=ISZkwA0o7Xb<62A$fayV@o9nzGprJ`-{jEJVDbVo_9&cb zl{&ITaqH_TehaUsU*8}jynLQlK7u7oKRzQO;!tA&43{8C+6Ha!YK&itU&+DSV_6aE z(9(V2xoDUYV%92LQB(M% zWY*s=al5PDe7329OK*Fr#3mi0H4dZ{SdRzTBKya~pP2YY5Yst6-PF|LqwD!-E%|7p)PWE_I%sr$+l?s)goc)rm z*?HQTSV&vQa&3k8#T$3Iq#F@^Gr2Rr>5lQr>NihBkC)p_uG@RBKJGrHIV-PgRrA5Pu$a1|)s#Z_Yz}Tbkov9;BoLJiDF=(apyYGd z@VV-Dwy*j8ht1vrM{iRaVCV)mBotQYC;iuKOgN8$$eK3FE)%W}PO!QvhgQPC_LF7YoX(jYZZjwji zzR&ks#Uy>B30H|@kk75n9S3Y&rx6k$3J2qsHc2PrF3orX*{5ck+XXNHvl|jFo<@o+MYS$_f&mQs#0fE6OUb$0w8Xv-;wg5nqT;N`xp(|E7^2KsghN4Hml!iT3<6vK5@$D*t_;r2RlcfAdl5$E4o zw(3V!aRr0%;zy21R`qvpW<2_FtyU&BbFqp>M9U+BzUs+ z@|vNQP;(Uj{WH%w(?xT_i-|KF>|C}CFZ!rNSdWNUhiTa`RPq-p(#v*nycfdkOm_CU24oqEu|8Gq8u|9A{&+RPNAKmu9DfgY&N8cF~Ej39?yY#)jh@*U^|K z>L(vQ>fNkb*N;7sm?!Oqkus>Pd)0Ngw!}FQ# ze1F%A#qq}*c%o8F(2lRma{?yVISI`cUt~(XQ#tlp4tq)@XrTTnc$ra((kVT?iy1CC zm0B+HI;PKTTb#Y!o$5B#pD%=;|D{^$a8oja&yW>kMc$G};Hn&|V^^DVx#0&s&Jngm z%%Ky}xyUwGpVOL}s;%=v?l${!1dm9D_|okosXP{|{h7Yk{WR9AHcgT>zG8x8n)h*W zPSS!({Fc2M@l{?NO~aVYQeOI;@3(pFJ0++Dvol9kezp`|3FL0$%wtCIw2-}d?8%BR z-`CR@u1+`FWU3rKgH*p6U>PGEl8(Le!X0H&i}RL{x7GN_B_mVYTj^ai?d`e~Oic8x zy@X{k=cud zJkaO35bZvn=`=Alk^FP??41xeqAMM9tMA0Cx^UVddzMjgjE51X$bVX%#W_zLd9bHn&wgHb zfre}&cv!Y_Mjm@05A>>j7W%6lVi69u_xoz)Q@e3cdS_)Ep4-YAW+_!X{!+i#x192F z8T+94qYm^*^p(@n?X2)KN{Qq3q6Q3-*IrgO>>kdtZzaC;tGG3%< zcOmni2<#sV4z+J(EC&0odsVS`XKdG=B^bTr`R#qA;{-zWcdHscrx|0Qsq?W_Rwi~pRdOX65##sN+O+kvXKXt%U=6E}Q}OC0pHewDXKNL|1j*Rtnu+@3 zHOP0Nn$Rz{SOE7>`sDgOye=HYaSZEwi6+!?(keB(i@$dnzO4irk}VKRg9Cem!InK) zk5K{ii&x!RDD%X#6!3hk)x{W=4DYAFpsln=_VwBUHoSdDeiRhGJ!n+TmET}&2O(FGq9;=Fu z8)x2@oEnP@gpKhReqN&*Rx+>ou0?4}vT!u_M#8g;#%cRO^c0&QJw~~J$M(UC3 zKW=JCIV9M7K`G?C{orm5D3eNr;so@I(#(kECqI|iTr=X7aag3Mx!5)}LC#Tu?X9P)x4@JVGepDUg=d+n$Tj#F^xk2_$2nu`p`n|Y$jN-C?w<>MrvvIy>}d;D{W!8#Pi+4?ut%(FD`CqQ>_%Dmz9=vAv)TTCZdsaD%WN}U#W z-9lUCcxLFdPmLT_Vg98(j_=T(u!Elp=0r)E42*JD%nT0Hqj zXW3e%Rn<(yjNC)r2}ESP5!dqU$bcZJ8?47)rI3sy^eT8VGc#*r7OI;TWAAt#fa>s* zYB9XvT!iSDFHRo}-$WpTUQGfdU!5iT4>@apb+TT2S*r27KE~Lg7SDBY%o54ARbTX7 zI9GxhFaJQDf79h@KtKZyt%_b*kxjk+tG-~L7@s$+0DhJ=eJOhlKzg82J^q|Y3g3-E z>D8$b10+a{I^2rc{gj9r7R!kLItNU!J&=tZ(V&1oObSW8CI+Lz6L z<$1+jA;^tr`~Q30hXn2aUU&J!o@`)sU@`ai_i7TRsQ@*E!Zbsr%l;+)&uqKFuXa&R zP12i+rz?M(Gq!E_vq*!pK`ktdXLa|=2CCB*!xPC;(vjY^`q;sNx02-V>XtJ0A*QYq zVb@~)g9v`>){r?(J?Dyi>MUK0`jZEXYBD#U3@A3An+6^>brgUBv=QZi2Csg~}uWAy)HZ9cdKNU7Zyi6oQvLjI9IN z|4Vf-*L95j9_h+Z($_n4jt{*{zx{Jp=y__|OWS>5F%MAr_&W>sBKka(;0eAMFyQ%F z+PiO^OKacAUbJptNJGSOFXu~pyEoRWW@BM=tM3gT3ll&8Er1-w352~wEDQ*mysW{4kHS*oz6{7~a_* zKW|25WB?>7P-g_tuDCcLGfxO4pSIY<=WCJo?#ztJ>B<0jBN6`9l#~>+q`xN#VPO_I zfy~5B#giFtV6BLGPg;p3{B5QYf8!etpOySGatD;#ZmVAYtMD#Hpzg*$0lZEK z%;xd*`t);&QLMj{zI+J>@0up%o3dzmc|Z|nB}e1BTC)R`KW(8RR)s)|s-kw>Ry?2+ zfL%PA+Z7qTgWoMNnzf+bIXFcaYnneTci^F;EFb5U5AF;Aa(Fon4WC~B!*dN;nfA`p zQ|y^pH7(lf>y zK)75sg^gBd98P}GDZcC6IL|G-m-oeu2+Z#ul;qO+>l9CR3?)zpOW;zuwK*7X`hUP2 zC6VnXc)NL(p0#@rTy&Dj&Dbz2i`|Wj7Sn0G^DV}*)My!)@jSKteEnG2j4|I{$=~6Y zL+x<*JlOpLTsGAx8Lo`&VaSbfeh>L)f)7!Do=-eApB_qbLMGZaYHdW6X+5B!q3O2f zNmitL`WGJ)W(B1czv$u2n{^+@SIg_5yR5A~bY^^g=GF8aI!j(h`0141`n*1yvtQxp z@Gz^m_&NfCfY-&ukdRYQ{80dKAuy+@-yVjP2-4cOSt1CHKvDl^l|oJ#EspI-!@A(FgAuVSX}EFdF+DRwb#!6fN*3fhRu7yP zgWSeXf!7(a&!3N(KQ;daRi}w2!aE(z_i~z@D>KW1JmXC_qacc{Yp5KSh<< zTnvb;EQt^&NT+p8tq%n*oU7E)m6MZuQeg`~l0e*t30Eed)A+H1LInKV-M`@z zd>YdSEBn~=bZANn&80r*rN9vc7kB5Y=5Uf5F^R4wMI7m-F0kUNGb?w=015{Pz;lHk z7_Uv`Puy$e@vRuMda0&{ldeKp6Xl(^u{zMMs#WF6@W|yFpuVV8z6E?B0H|NPBPCBv zLNbt%s#Ks;iwt54!-B8@$i(pp312@d{Ow_v@UY3ztLpskW%86794DUQ4Wcv8Rg>Eo zY{hu7dBUt9!I82n`jRJeA2@;mo@ZTseZL{d2KZ8kF1;?0NMa9eZP~(?m4*5FovV(< z9v-5`7r^ctAZNc7+%KkJy%r?eet4vfw~t<)@NWg=-cBG|YBm8v80e@Ep`l~r)Jb+(n$afz6$Ot&|!3hEq?p?-)4xf#U4M+gstoi^! zBuGGZ_FW=kVm#clFp)}+1-Jhoa#qlJXy;U=pmt%M?^dQ7r7itZhh80GQu&vwT~kP2 zAUDwU1=#nm7PXzW!UVWqqvV*iDh;E-3hd(Qif0gtg#!5_fXZYd{K?9~!UW`c0p9TU z*4Cw2ogj^J$JrCS{XF#g^`v}}JBwDqcB$BN;7wtCfj%`6F)N*<5eEC6E1);&NC-fq zN3S8l!~#9L`mPz65fBA;-kc<`ba5dEG&cK2TELP9U~h_8e-=|y)2ewSVDdZzd?YxE zj*&5R(LS_mHNdbkIsL#9+#xWI`2+-jbr@lACzFK*=iO^pKvcn%3A54fjr2A8J8{6& zG=?TTN^}d3W<&6d*C;&P$nm7JrVVZ_h!(8%Pu6KQWaKlTA%92{4M3<^A?%TNpUcPL zT##B;R9ynC(c>!_Sb=zfokUy3rX!_elN*%jM+(ZycdokU=H|jBFc{1Ua3_aA0B z*c|}&ka6uS1OkX5Pl4E56Tl!d03S|V?t6f383aJHRh?BJVF9cV0VdN|rIVK`4jeo@ zB+!<5WG^6hk1Z|n=m`UD4d8F04g7vRhE8aysc$78Sqjnsm9LU4#D!S8ilC6tDxjs{ zRBjx3U9!@_xVnpSH8zI0y1L>ZgbNA_bHO?av?^qhVV_ayiU#JE2giUCa5=eun$YbZ zUyRx6HGRD~=8~#OQM=KGxx)5EKy!)tC46l?0*nNt@r!f*7z|V*o-2p`FIp zX4;|9N1(lU2Ed^)r>%`aIF%Tf$i%f;G|sCT7|_4;z}drH)78}lK{*)6GZWyhfRO@> zAt-C!9*vIP1j5D9KxyM!(3>Eptdf!&6p^gI-+?(YIXTI3|9&Ts9KB-bU}N*d&dzSs zoSTA>i-PdOhYukB+=}D&h0T0Ci5k^1i?f+2Q-4SfYAniFb zR@U%c_1CZ2@sXDd4L~3P76BkrK0bDHO1)Ik1#y6%3D9M^@JE!`$N-DgSU43-GUICP z?ku3zy&jjG%uZ`sRa&Y@QFpLY%5)7h^X9`18d_Q$2rzC*N)PUDbEqOM9k*}Zf2^yi zbrZK}a#N=s^KYpm_h%!MNVDzWf0f4sq{&UsBN4u`#t-!Q??uHS*KuqR<(&2kwwEggVcS zj2i9JxlY#HVCI2EfK$|8GXXB41{6Pm$VF6CR90mrDY(BJ92_?r^D8P;()@w9H@N$^ zGQIo84u+k9R6KyafSH4j1eB<1pue%71~^ccfvTvYf&x|D+DZ>#&~PYFO5AOR)a#b% z)+-Qw2j<<8IMq{ATB7MHL_|bkc#>ylXWgz`Ms50T-$4Vwav4J>cBNy&cjg>AkNkw( z0-Q0xBW9Hv85nrt<@E?K;z&ElT1tzGZlbJf{u^u0D3jOR`DZ<{uUKdQ(!5<4`D0D% z#oCHVSPxxnP|2D4CyS~bgC=83Lk!TT7eIXszPT72RH-SZyF8agGO`D!UUZXaN z?H7iC_QM5;48U>}-sAxy0`Ns6*7gUIdzS>nk`hixMp-S8Z46ig8qKjl!8c$nG9uzq zS`d;Ekm#NY1g^UK0Bax_aM#SuS)ni(4y3%i9QdRLE98GYIT6+8Np6bmgo-DB`V?V` z0KsJ6HFbz$)J~TZEJr|r8zRxEvb#l3PY*&dKuZ9@{o7aLUV%}r4X8z6&UPa{W@h@U z?b7Z%`a+CG35{2h{~InY){*Ak{92uD&pWGM1~zHOXo~3QGVvj}f6zWa3g{Uc#sG#{ zoPiFW%r)K5_g=jm_BZGh*g*$7e(Wzu-E>0c0VT6)z;vaG?u|PD+Aw&yNJv=Vy$&*C z!X7gLJcC{konrGt9_ImS*`;)2RBUYItR+e4Q@Ydu${O4yWD5aJxZ_RHEWavaT**4(N6RH@B@23ej#LPH6)9gFu5q^?1R)F*24{zv)uY z@4W>6ILc9!&IIxfDD0ZZJ(!L@N73fa$+{ShUaTXFb_? zH+JZks??){UCX(?d4KV>UC~Oai)?ny>^=HA<2%L}5k8H*p>t>>p2ZfJpH1@nuB6{)yjsN4iUUmlJFe{^z6ba{mGsJPC#Vf2%mv;hT!pZB!mxPORRDL{8VJSv*F)dBkqkpmz3qV?zcMOQ29_x2./arvbox start localdemo Arvados-in-a-box starting -Waiting for workbench2 websockets workbench webshell keep-web controller keepproxy api keepstore1 arv-git-httpd keepstore0 sdk vm ... +Waiting for workbench2 websockets workbench webshell keep-web controller keepproxy api keepstore1 keepstore0 sdk vm ... ... diff --git a/doc/install/install-arv-git-httpd.html.textile.liquid b/doc/install/install-arv-git-httpd.html.textile.liquid deleted file mode 100644 index 476c89005f..0000000000 --- a/doc/install/install-arv-git-httpd.html.textile.liquid +++ /dev/null @@ -1,298 +0,0 @@ ---- -layout: default -navsection: installguide -title: Install the Git server -... -{% comment %} -Copyright (C) The Arvados Authors. All rights reserved. - -SPDX-License-Identifier: CC-BY-SA-3.0 -{% endcomment %} - -# "Introduction":#introduction -# "Install dependencies":#dependencies -# "Create "git" user and storage directory":#create -# "Install gitolite":#gitolite -# "Configure gitolite":#config-gitolite -# "Configure git synchronization":#sync -# "Update config.yml":#update-config -# "Update nginx configuration":#update-nginx -# "Install arvados-git-httpd package":#install-packages -# "Restart the API server and controller":#restart-api -# "Confirm working installation":#confirm-working - -h2(#introduction). Introduction - -Arvados support for git repository management enables using Arvados permissions to control access to git repositories. Users can create their own private and public git repositories and share them with others. - -The git hosting setup involves three components. -* The "arvados-git-sync.rb" script polls the API server for the current list of repositories, creates bare repositories, and updates the local permission cache used by gitolite. -* Gitolite provides SSH access. Users authenticate by SSH keys. -* arvados-git-http provides HTTPS access. Users authenticate by Arvados tokens. - -Git services must be installed on the same host as the Arvados Rails API server. - -h2(#dependencies). Install dependencies - -h3. Alma/CentOS/Red Hat/Rocky - - -
# dnf install git perl-Data-Dumper openssh-server
-
-
- -h3. Debian and Ubuntu - - -
# apt-get --no-install-recommends install git openssh-server
-
-
- -h2(#create). Create "git" user and storage directory - -Gitolite and some additional scripts will be installed in @/var/lib/arvados/git@, which means hosted repository data will be stored in @/var/lib/arvados/git/repositories@. If you choose to install gitolite in a different location, make sure to update the @git_repositories_dir@ entry in your API server's @application.yml@ file accordingly: for example, if you install gitolite at @/data/gitolite@ then your @git_repositories_dir@ will be @/data/gitolite/repositories@. - -A new UNIX account called "git" will own the files. This makes git URLs look familiar to users (git@[...]:username/reponame.git). - -On Debian- or Red Hat-based systems: - - -
gitserver:~$ sudo mkdir -p /var/lib/arvados/git
-gitserver:~$ sudo useradd --comment git --home-dir /var/lib/arvados/git git
-gitserver:~$ sudo chown -R git:git ~git
-
-
- -The git user needs its own SSH key. (It must be able to run ssh git@localhost from scripts.) - - -
gitserver:~$ sudo -u git -i bash
-git@gitserver:~$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
-git@gitserver:~$ cp .ssh/id_rsa.pub .ssh/authorized_keys
-git@gitserver:~$ ssh -o stricthostkeychecking=no localhost cat .ssh/id_rsa.pub
-Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7aBIDAAgMQN16Pg6eHmvc+D+6TljwCGr4YGUBphSdVb25UyBCeAEgzqRiqy0IjQR2BLtSirXr+1SJAcQfBgI/jwR7FG+YIzJ4ND9JFEfcpq20FvWnMMQ6XD3y3xrZ1/h/RdBNwy4QCqjiXuxDpDB7VNP9/oeAzoATPZGhqjPfNS+RRVEQpC6BzZdsR+S838E53URguBOf9yrPwdHvosZn7VC0akeWQerHqaBIpSfDMtaM4+9s1Gdsz0iP85rtj/6U/K/XOuv2CZsuVZZ52nu3soHnEX2nx2IaXMS3L8Z+lfOXB2T6EaJgXF7Z9ME5K1tx9TSNTRcYCiKztXLNLSbp git@gitserver
-git@gitserver:~$ rm .ssh/authorized_keys
-
-
- -h2(#gitolite). Install gitolite - -Check "https://github.com/sitaramc/gitolite/tags":https://github.com/sitaramc/gitolite/tags for the latest stable version. This guide was tested with @v3.6.11@. _Versions below 3.0 are missing some features needed by Arvados, and should not be used._ - -Download and install the version you selected. - - -
$ sudo -u git -i bash
-git@gitserver:~$ echo 'PATH=$HOME/bin:$PATH' >.profile
-git@gitserver:~$ . .profile
-git@gitserver:~$ git clone --branch v3.6.11 https://github.com/sitaramc/gitolite
-...
-Note: checking out '5d24ae666bfd2fa9093d67c840eb8d686992083f'.
-...
-git@gitserver:~$ mkdir bin
-git@gitserver:~$ gitolite/install -ln ~git/bin
-git@gitserver:~$ bin/gitolite setup -pk .ssh/id_rsa.pub
-Initialized empty Git repository in /var/lib/arvados/git/repositories/gitolite-admin.git/
-Initialized empty Git repository in /var/lib/arvados/git/repositories/testing.git/
-WARNING: /var/lib/arvados/git/.ssh/authorized_keys missing; creating a new one
-    (this is normal on a brand new install)
-
-
- -_If this didn't go well, more detail about installing gitolite, and information about how it works, can be found on the "gitolite home page":http://gitolite.com/._ - -Clone the gitolite-admin repository. The arvados-git-sync.rb script works by editing the files in this working directory and pushing them to gitolite. Here we make sure "git push" won't produce any errors or warnings. - - -
git@gitserver:~$ git clone git@localhost:gitolite-admin
-Cloning into 'gitolite-admin'...
-remote: Counting objects: 6, done.
-remote: Compressing objects: 100% (4/4), done.
-remote: Total 6 (delta 0), reused 0 (delta 0)
-Receiving objects: 100% (6/6), done.
-Checking connectivity... done.
-git@gitserver:~$ cd gitolite-admin
-git@gitserver:~/gitolite-admin$ git config user.email arvados
-git@gitserver:~/gitolite-admin$ git config user.name arvados
-git@gitserver:~/gitolite-admin$ git config push.default simple
-git@gitserver:~/gitolite-admin$ git push
-Everything up-to-date
-
-
- -h2(#config-gitolite). Configure gitolite - -Configure gitolite to look up a repository name like @username/reponame.git@ and find the appropriate bare repository storage directory. - -Add the following lines to the top of @~git/.gitolite.rc@: - - -
my $repo_aliases;
-my $aliases_src = "$ENV{HOME}/.gitolite/arvadosaliases.pl";
-if ($ENV{HOME} && (-e $aliases_src)) {
-    $repo_aliases = do $aliases_src;
-}
-$repo_aliases ||= {};
-
-
- -Add the following lines inside the section that begins @%RC = (@: - - -
    REPO_ALIASES => $repo_aliases,
-
-
- -Inside that section, adjust the 'UMASK' setting to @022@, to ensure the API server has permission to read repositories: - - -
    UMASK => 022,
-
-
- -Uncomment the 'Alias' line in the section that begins @ENABLE => [@: - - -
            # access a repo by another (possibly legacy) name
-            'Alias',
-
-
- -h2(#sync). Configure git synchronization - -Create a configuration file @/var/www/arvados-api/current/config/arvados-clients.yml@ using the following template, filling in the appropriate values for your system. -* For @arvados_api_token@, use @SystemRootToken@ -* For @gitolite_arvados_git_user_key@, provide the public key you generated above, i.e., the contents of @~git/.ssh/id_rsa.pub@. - - -
production:
-  gitolite_url: /var/lib/arvados/git/repositories/gitolite-admin.git
-  gitolite_tmp: /var/lib/arvados/git
-  arvados_api_host: ClusterID.example.com
-  arvados_api_token: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-  arvados_api_host_insecure: false
-  gitolite_arvados_git_user_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7aBIDAAgMQN16Pg6eHmvc+D+6TljwCGr4YGUBphSdVb25UyBCeAEgzqRiqy0IjQR2BLtSirXr+1SJAcQfBgI/jwR7FG+YIzJ4ND9JFEfcpq20FvWnMMQ6XD3y3xrZ1/h/RdBNwy4QCqjiXuxDpDB7VNP9/oeAzoATPZGhqjPfNS+RRVEQpC6BzZdsR+S838E53URguBOf9yrPwdHvosZn7VC0akeWQerHqaBIpSfDMtaM4+9s1Gdsz0iP85rtj/6U/K/XOuv2CZsuVZZ52nu3soHnEX2nx2IaXMS3L8Z+lfOXB2T6EaJgXF7Z9ME5K1tx9TSNTRcYCiKztXLNLSbp git@gitserver"
-
-
- -
-$ sudo chown git:git /var/www/arvados-api/current/config/arvados-clients.yml
-$ sudo chmod og-rwx /var/www/arvados-api/current/config/arvados-clients.yml
-
- -h3. Test configuration - -notextile.
$ sudo -u git -i bash -c 'cd /var/www/arvados-api/current && bin/bundle exec script/arvados-git-sync.rb production'
- -h3. Enable the synchronization script - -The API server package includes a script that retrieves the current set of repository names and permissions from the API, writes them to @arvadosaliases.pl@ in a format usable by gitolite, and triggers gitolite hooks which create new empty repositories if needed. This script should run every 2 to 5 minutes. - -Create @/etc/cron.d/arvados-git-sync@ with the following content: - - -
*/5 * * * * git cd /var/www/arvados-api/current && bin/bundle exec script/arvados-git-sync.rb production
-
-
- -h2(#update-config). Update config.yml - -Edit the cluster config at @config.yml@ . - - -
    Services:
-      GitSSH:
-        ExternalURL: "ssh://git@git.ClusterID.example.com"
-      GitHTTP:
-        ExternalURL: https://git.ClusterID.example.com/
-        InternalURLs:
-	  "http://localhost:9001": {}
-    Git:
-      GitCommand: /var/lib/arvados/git/gitolite/src/gitolite-shell
-      GitoliteHome: /var/lib/arvados/git
-      Repositories: /var/lib/arvados/git/repositories
-
-
- -h2(#update-nginx). Update nginx configuration - -Use a text editor to create a new file @/etc/nginx/conf.d/arvados-git.conf@ with the following configuration. Options that need attention are marked in red. - - -
upstream arvados-git-httpd {
-  server                  127.0.0.1:9001;
-}
-server {
-  listen                  443 ssl;
-  server_name             git.ClusterID.example.com;
-  proxy_connect_timeout   90s;
-  proxy_read_timeout      300s;
-
-  ssl_certificate         /YOUR/PATH/TO/cert.pem;
-  ssl_certificate_key     /YOUR/PATH/TO/cert.key;
-
-  # The server needs to accept potentially large refpacks from push clients.
-  client_max_body_size 128m;
-
-  location  / {
-    proxy_pass            http://arvados-git-httpd;
-  }
-}
-
-
- -h2(#install-packages). Install the arvados-git-httpd package - -The arvados-git-httpd package provides HTTP access, using Arvados authentication tokens instead of passwords. It must be installed on the system where your git repositories are stored. - -h3. Alma/CentOS/Red Hat/Rocky - - -
# dnf install arvados-git-httpd
-
-
- -h3. Debian and Ubuntu - - -
# apt-get --no-install-recommends install arvados-git-httpd
-
-
- -h2(#restart-api). Restart the API server and controller - -After adding Workbench to the Services section, make sure the cluster config file is up to date on the API server host, and restart the API server and controller processes to ensure the changes are applied. - - -
# systemctl restart nginx arvados-controller
-
-
- -h2(#confirm-working). Confirm working installation - -Create 'testrepo' in the Arvados database. - - -
~$ arv --format=uuid repository create --repository '{"name":"myusername/testrepo"}'
-
- -The arvados-git-sync cron job will notice the new repository record and create a repository on disk. Because it is on a timer (default 5 minutes) you may have to wait a minute or two for it to show up. - -h3. SSH - -Before you do this, go to Workbench and choose *SSH Keys* from the menu, and upload your public key. Arvados uses the public key to identify you when you access the git repo. - - -
~$ git clone git@git.ClusterID.example.com:username/testrepo.git
-
-
- -h3. HTTP - -Set up git credential helpers as described in "install shell server":install-shell-server.html#config-git for the git command to use your API token instead of prompting you for a username and password. - - -
~$ git clone https://git.ClusterID.example.com/username/testrepo.git
-
-
diff --git a/doc/install/install-composer.html.textile.liquid b/doc/install/install-composer.html.textile.liquid deleted file mode 100644 index 58ba5d03a0..0000000000 --- a/doc/install/install-composer.html.textile.liquid +++ /dev/null @@ -1,65 +0,0 @@ ---- -layout: default -navsection: installguide -title: Install Composer -... -{% comment %} -Copyright (C) The Arvados Authors. All rights reserved. - -SPDX-License-Identifier: CC-BY-SA-3.0 -{% endcomment %} - -Arvados Composer is a web-based javascript application for building Common Workflow Languge (CWL) Workflows. - -# "Install dependencies":#dependencies -# "Update config.yml":#update-config -# "Update Nginx configuration":#update-nginx -# "Install arvados-composer":#install-packages -# "Restart the API server and controller":#restart-api -# "Confirm working installation":#confirm-working - -h2(#dependencies). Install dependencies - -In addition to Arvados core services, Composer requires "Arvados hosted git repositories":install-arv-git-httpd.html which are used for storing workflow files. - -h2(#configure). Update config.yml - -Edit @config.yml@ and set @Services.Composer.ExternalURL@ to the location from which it is served: - - -
    Services:
-      Composer:
-        ExternalURL: https://workbench.CusterID.example.com/composer
-
- -h2(#update-nginx). Update nginx configuration - -Composer may be served from the same host as Workbench. Composer communicates directly with the Arvados API server. It does not require its own backend and should be served as a static file. - -Add the following @location@ sections to @/etc/nginx/conf.d/arvados-workbench.conf@ . - - -
server {
-  [...]
-
-  location /composer {
-    root   /var/www/arvados-composer;
-    index  index.html;
-  }
-
-  location /composer/composer.yml {
-    return 200 '{ "API_HOST": "ClusterID.example.com" }';
-  }
-}
-
-
- -{% assign arvados_component = 'arvados-composer' %} - -{% include 'install_packages' %} - -{% include 'restart_api' %} - -h2(#confirm-working). Confirm working installation - -Visit @https://workbench.ClusterID.example.com/composer@ in a browser. You should be able to log in using the login method you configured previously. diff --git a/doc/install/install-jobs-image.html.textile.liquid b/doc/install/install-jobs-image.html.textile.liquid deleted file mode 100644 index efd8c9649f..0000000000 --- a/doc/install/install-jobs-image.html.textile.liquid +++ /dev/null @@ -1,38 +0,0 @@ ---- -layout: default -navsection: installguide -title: Install arvados/jobs image -... -{% comment %} -Copyright (C) The Arvados Authors. All rights reserved. - -SPDX-License-Identifier: CC-BY-SA-3.0 -{% endcomment %} - -h2. Create a project for Docker images - -Here we create a default project for the standard Arvados Docker images, and give all users read access to it. The project is owned by the system user. - - -
~$ uuid_prefix=$(arv --format=uuid user current | cut -d- -f1)
-~$ project_uuid=$(arv --format=uuid group create --group '{"owner_uuid":"'$uuid_prefix'-tpzed-000000000000000", "group_class":"project", "name":"Arvados Standard Docker Images"}')
-~$ echo "Arvados project uuid is '$project_uuid'"
-~$ read -rd $'\000' newlink <<EOF; arv link create --link "$newlink"
-{
- "tail_uuid":"${uuid_prefix}-j7d0g-fffffffffffffff",
- "head_uuid":"$project_uuid",
- "link_class":"permission",
- "name":"can_read"
-}
-EOF
-
- -h2. Import the arvados/jobs docker image - -In order to start workflows from workbench, there needs to be Docker image @arvados/jobs@ tagged with the version of Arvados you are installing. The following command downloads the latest arvados/jobs image from Docker Hub, loads it into Keep. In this example @$project_uuid@ should be the UUID of the "Arvados Standard Docker Images" project. - - -
~$ arv-keepdocker --pull arvados/jobs latest --project-uuid $project_uuid
-
- -If the image needs to be downloaded from Docker Hub, the command can take a few minutes to complete, depending on available network bandwidth. diff --git a/doc/install/install-manual-prerequisites.html.textile.liquid b/doc/install/install-manual-prerequisites.html.textile.liquid index 8819b0210f..ba179f82dd 100644 --- a/doc/install/install-manual-prerequisites.html.textile.liquid +++ b/doc/install/install-manual-prerequisites.html.textile.liquid @@ -47,7 +47,6 @@ table(table table-bordered table-condensed). |\3=. *Additional services*| |"Websockets server":install-ws.html |Event distribution server.|Required to view streaming container logs in Workbench.| |"Shell server":install-shell-server.html |Grant Arvados users access to Unix shell accounts on dedicated shell nodes.|Optional.| -|"Git server":install-arv-git-httpd.html |Arvados-hosted git repositories, with Arvados-token based authentication.|Optional| |\3=. *Crunch (running containers)*| |"arvados-dispatch-cloud":crunch2-cloud/install-dispatch-cloud.html |Run analysis workflows on cloud by allocating and freeing cloud VM instances on demand.|Optional| |"crunch-dispatch-slurm":crunch2-slurm/install-dispatch.html |Run analysis workflows distributed across a Slurm cluster.|Optional| @@ -96,7 +95,7 @@ For a production installation, this is a reasonable starting point:
table(table table-bordered table-condensed). |_. Function|_. Number of nodes|_. Recommended specs| -|PostgreSQL database, Arvados API server, Arvados controller, Git, Websockets, Container dispatcher|1|16+ GiB RAM, 4+ cores, fast disk for database| +|PostgreSQL database, Arvados API server, Arvados controller, Websockets, Container dispatcher|1|16+ GiB RAM, 4+ cores, fast disk for database| |Workbench, Keepproxy, Keep-web, Keep-balance|1|8 GiB RAM, 2+ cores| |Keepstore servers ^1^|2+|4 GiB RAM| |Compute worker nodes ^1^|0+ |Depends on workload; scaled dynamically in the cloud| @@ -138,7 +137,6 @@ It is possible to use custom DNS names for the Arvados services. table(table table-bordered table-condensed). |_. Function|_. DNS name| |Arvados API|@ClusterID.example.com@| -|Arvados Git server|git.@ClusterID.example.com@| |Arvados Webshell|webshell.@ClusterID.example.com@| |Arvados Websockets endpoint|ws.@ClusterID.example.com@| |Arvados Workbench|workbench.@ClusterID.example.com@| diff --git a/doc/install/install-shell-server.html.textile.liquid b/doc/install/install-shell-server.html.textile.liquid index f864f37563..9520c08397 100644 --- a/doc/install/install-shell-server.html.textile.liquid +++ b/doc/install/install-shell-server.html.textile.liquid @@ -12,7 +12,6 @@ SPDX-License-Identifier: CC-BY-SA-3.0 # "Introduction":#introduction # "Install Dependencies and SDKs":#dependencies # "Install git and curl":#install-packages -# "Update Git Config":#config-git # "Create record for VM":#vm-record # "Install arvados-login-sync":#arvados-login-sync # "Confirm working installation":#confirm-working @@ -44,17 +43,6 @@ h2(#dependencies). Install Dependencies and SDKs {% include 'install_packages' %} -h2(#config-git). Update Git Config - -Configure git to use the ARVADOS_API_TOKEN environment variable to authenticate to arvados-git-httpd. We use the @--system@ flag so it takes effect for all current and future user accounts. It does not affect git's behavior when connecting to other git servers. - - -
-# git config --system 'credential.https://git.ClusterID.example.com/.username' none
-# git config --system 'credential.https://git.ClusterID.example.com/.helper' '!cred(){ cat >/dev/null; if [ "$1" = get ]; then echo password=$ARVADOS_API_TOKEN; fi; };cred'
-
-
- h2(#vm-record). Create record for VM As an admin, create an Arvados virtual_machine object representing this shell server. This will return a uuid. diff --git a/doc/user/tutorials/add-new-repository.html.textile.liquid b/doc/user/tutorials/add-new-repository.html.textile.liquid deleted file mode 100644 index 6046e7d14b..0000000000 --- a/doc/user/tutorials/add-new-repository.html.textile.liquid +++ /dev/null @@ -1,47 +0,0 @@ ---- -layout: default -navsection: userguide -title: Adding a new Arvados git repository -... -{% comment %} -Copyright (C) The Arvados Authors. All rights reserved. - -SPDX-License-Identifier: CC-BY-SA-3.0 -{% endcomment %} - -Arvados supports managing git repositories. You can access these repositories using your Arvados credentials and share them with other Arvados users. - -{% include 'tutorial_expectations' %} - -h2. Setting up Git - -Before you start using Git and arvados repositories, you should do some basic configuration (you only need to do this the first time): - - -
~$ git config --global user.name "Your Name"
-~$ git config --global user.email $USER@example.com
-
- -h2. Add "tutorial" repository - -On the Arvados Workbench, click on the dropdown menu icon (Account Management) in the upper right corner of the top navigation menu to access the user settings menu, and click on the menu item *Repositories*. - -In the *Repositories* page, you will see the + NEW REPOSITORY button. - -!{width: 100%;}{{ site.baseurl }}/images/repositories-panel.png! - -Click the + NEW REPOSITORY button to open the popup to add a new Arvados repository. You will see a text box where you can enter the name of the repository. Enter *tutorial* in this text box and click on *Create*. - -{% include 'notebox_begin' %} -The name you enter here must begin with a letter and can only contain alphanumeric characters. -{% include 'notebox_end' %} - -!{width: 100%;}{{ site.baseurl }}/images/add-new-repository.png! - -This will create a new repository with the name @$USER/tutorial@. It can be accessed using the URL https://git.{{ site.arvados_api_host }}/$USER/tutorial.git or git@git.{{ site.arvados_api_host }}:$USER/tutorial.git - -Back in the *Repositories* page, you should see the @$USER/tutorial@ repository listed in the name column with these URLs. - -!{display: block;margin-left: 25px;margin-right: auto;}{{ site.baseurl }}/images/added-new-repository.png! - -You are now ready to use this *tutorial* repository to run your crunch scripts. diff --git a/doc/user/tutorials/git-arvados-guide.html.textile.liquid b/doc/user/tutorials/git-arvados-guide.html.textile.liquid deleted file mode 100644 index a4ac2a5795..0000000000 --- a/doc/user/tutorials/git-arvados-guide.html.textile.liquid +++ /dev/null @@ -1,87 +0,0 @@ ---- -layout: default -navsection: userguide -title: Working with an Arvados git repository -... -{% comment %} -Copyright (C) The Arvados Authors. All rights reserved. - -SPDX-License-Identifier: CC-BY-SA-3.0 -{% endcomment %} - -This tutorial describes how to work with an Arvados-managed git repository. Working with an Arvados git repository is very similar to working with other public git repositories. - -{% include 'tutorial_expectations' %} - -{% include 'tutorial_git_repo_expectations' %} - -h2. Cloning a git repository - -Before you start using Git, you should do some basic configuration (you only need to do this the first time): - - -
~$ git config --global user.name "Your Name"
-~$ git config --global user.email $USER@example.com
-
- -On the Arvados Workbench, click on the dropdown menu icon in the upper right corner of the top navigation menu to access the Account Management menu, and click on the menu item *Repositories*. In the *Repositories* page, you should see the @$USER/tutorial@ repository listed in the *name* column. Next to *name* is the column *URL*. Copy the *URL* value associated with your repository. This should look like https://git.{{ site.arvados_api_host }}/$USER/tutorial.git. Alternatively, you can use git@git.{{ site.arvados_api_host }}:$USER/tutorial.git - -Next, on the Arvados virtual machine, clone your Git repository: - - -
~$ cd $HOME # (or wherever you want to install)
-~$ git clone https://git.{{ site.arvados_api_host }}/$USER/tutorial.git
-Cloning into 'tutorial'...
-
- -This will create a Git repository in the directory called @tutorial@ in your home directory. Say yes when prompted to continue with connection. -Ignore any warning that you are cloning an empty repository. - -*Note:* If you are prompted for username and password when you try to git clone using this command, you may first need to update your git configuration. Execute the following commands to update your git configuration. - - -
-~$ git config 'credential.https://git.{{ site.arvados_api_host }}/.username' none
-~$ git config 'credential.https://git.{{ site.arvados_api_host }}/.helper' '!cred(){ cat >/dev/null; if [ "$1" = get ]; then echo password=$ARVADOS_API_TOKEN; fi; };cred'
-
-
- -h2. Creating a git branch in an Arvados repository - -Create a git branch named *tutorial_branch* in the *tutorial* Arvados git repository. - - -
~$ cd tutorial
-~/tutorial$ git checkout -b tutorial_branch
-
-
- -h2. Adding scripts to an Arvados repository - -A git repository is a good place to store the CWL workflows that you run on Arvados. - -First, create a simple CWL CommandLineTool: - -notextile.
~/tutorials$ nano hello.cwl
- - {% code tutorial_hello_cwl as yaml %} - -Next, add the file to the git repository. This tells @git@ that the file should be included on the next commit. - -notextile.
~/tutorial$ git add hello.cwl
- -Next, commit your changes. All staged changes are recorded into the local git repository: - - -
~/tutorial$ git commit -m "my first script"
-
-
- -Finally, upload your changes to the remote repository: - - -
~/tutorial/crunch_scripts$ git push origin tutorial_branch
-
-
- -The same steps can be used to add any of your custom bash, R, or python scripts to an Arvados repository. diff --git a/lib/boot/nginx.go b/lib/boot/nginx.go index 22f1e665fa..338a6b5bcc 100644 --- a/lib/boot/nginx.go +++ b/lib/boot/nginx.go @@ -74,7 +74,6 @@ func (runNginx) Run(ctx context.Context, fail func(error), super *Supervisor) er {"KEEPWEB", super.cluster.Services.WebDAV}, {"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}, {"WORKBENCH2", super.cluster.Services.Workbench2}, diff --git a/lib/boot/supervisor.go b/lib/boot/supervisor.go index ac269b933a..67649e75de 100644 --- a/lib/boot/supervisor.go +++ b/lib/boot/supervisor.go @@ -366,7 +366,6 @@ func (super *Supervisor) runCluster() error { runNginx{}, railsDatabase{}, runServiceCommand{name: "controller", svc: super.cluster.Services.Controller, depends: []supervisedTask{railsDatabase{}}}, - runServiceCommand{name: "git-httpd", svc: super.cluster.Services.GitHTTP}, runServiceCommand{name: "health", svc: super.cluster.Services.Health}, runServiceCommand{name: "keepproxy", svc: super.cluster.Services.Keepproxy, depends: []supervisedTask{runPassenger{src: "services/api"}}}, runServiceCommand{name: "keepstore", svc: super.cluster.Services.Keepstore}, @@ -821,7 +820,6 @@ func (super *Supervisor) autofillConfig() error { for _, svc := range []*arvados.Service{ &super.cluster.Services.Controller, &super.cluster.Services.DispatchCloud, - &super.cluster.Services.GitHTTP, &super.cluster.Services.Health, &super.cluster.Services.Keepproxy, &super.cluster.Services.Keepstore, @@ -839,7 +837,6 @@ func (super *Supervisor) autofillConfig() error { } host := net.JoinHostPort(defaultExtHost, port) if svc == &super.cluster.Services.Controller || - svc == &super.cluster.Services.GitHTTP || svc == &super.cluster.Services.Health || svc == &super.cluster.Services.Keepproxy || svc == &super.cluster.Services.WebDAV || diff --git a/lib/config/config.default.yml b/lib/config/config.default.yml index 23ad5e3726..b045553b23 100644 --- a/lib/config/config.default.yml +++ b/lib/config/config.default.yml @@ -74,12 +74,6 @@ Clusters: Keepbalance: InternalURLs: {SAMPLE: {ListenURL: ""}} ExternalURL: "" - GitHTTP: - InternalURLs: {SAMPLE: {ListenURL: ""}} - ExternalURL: "" - GitSSH: - InternalURLs: {SAMPLE: {ListenURL: ""}} - ExternalURL: "" DispatchCloud: InternalURLs: {SAMPLE: {ListenURL: ""}} ExternalURL: "" @@ -340,7 +334,6 @@ Clusters: # AutoSetupUsernameBlacklist is a list of usernames to be blacklisted for auto setup. AutoSetupNewUsers: false AutoSetupNewUsersWithVmUUID: "" - AutoSetupNewUsersWithRepository: false AutoSetupUsernameBlacklist: arvados: {} git: {} @@ -1058,24 +1051,6 @@ Clusters: # production use. TrustPrivateNetworks: false - Git: - # Path to git or gitolite-shell executable. Each authenticated - # request will execute this program with the single argument "http-backend" - GitCommand: /usr/bin/git - - # Path to Gitolite's home directory. If a non-empty path is given, - # the CGI environment will be set up to support the use of - # gitolite-shell as a GitCommand: for example, if GitoliteHome is - # "/gh", then the CGI environment will have GITOLITE_HTTP_HOME=/gh, - # PATH=$PATH:/gh/bin, and GL_BYPASS_ACCESS_CHECKS=1. - GitoliteHome: "" - - # Git repositories must be readable by api server, or you won't be - # able to submit crunch jobs. To pass the test suites, put a clone - # of the arvados tree in {git_repositories_dir}/arvados.git or - # {git_repositories_dir}/arvados/.git - Repositories: /var/lib/arvados/git/repositories - TLS: # Use "file:///var/lib/acme/live/example.com/cert" and # ".../privkey" to load externally managed certificates. @@ -1402,12 +1377,6 @@ Clusters: # 'false' -- disable the Jobs API despite presence of existing records. Enable: 'auto' - # Git repositories must be readable by api server, or you won't be - # able to submit crunch jobs. To pass the test suites, put a clone - # of the arvados tree in {git_repositories_dir}/arvados.git or - # {git_repositories_dir}/arvados/.git - GitInternalDir: /var/lib/arvados/internal.git - CloudVMs: # Enable the cloud scheduler. Enable: false diff --git a/lib/config/deprecated.go b/lib/config/deprecated.go index d518b3414a..0db3de7fc9 100644 --- a/lib/config/deprecated.go +++ b/lib/config/deprecated.go @@ -510,56 +510,6 @@ func (ldr *Loader) loadOldKeepWebConfig(cfg *arvados.Config) error { return nil } -const defaultGitHttpdConfigPath = "/etc/arvados/git-httpd/git-httpd.yml" - -type oldGitHttpdConfig struct { - Client *arvados.Client - Listen *string - GitCommand *string - GitoliteHome *string - RepoRoot *string - ManagementToken *string -} - -func (ldr *Loader) loadOldGitHttpdConfig(cfg *arvados.Config) error { - if ldr.GitHttpdPath == "" { - return nil - } - var oc oldGitHttpdConfig - err := ldr.loadOldConfigHelper("arvados-git-httpd", ldr.GitHttpdPath, &oc) - if os.IsNotExist(err) && ldr.GitHttpdPath == defaultGitHttpdConfigPath { - return nil - } else if err != nil { - return err - } - - cluster, err := cfg.GetCluster("") - if err != nil { - return err - } - - loadOldClientConfig(cluster, oc.Client) - - if oc.Listen != nil { - cluster.Services.GitHTTP.InternalURLs[arvados.URL{Host: *oc.Listen}] = arvados.ServiceInstance{} - } - if oc.ManagementToken != nil { - cluster.ManagementToken = *oc.ManagementToken - } - if oc.GitCommand != nil { - cluster.Git.GitCommand = *oc.GitCommand - } - if oc.GitoliteHome != nil { - cluster.Git.GitoliteHome = *oc.GitoliteHome - } - if oc.RepoRoot != nil { - cluster.Git.Repositories = *oc.RepoRoot - } - - cfg.Clusters[cluster.ClusterID] = *cluster - return nil -} - const defaultKeepBalanceConfigPath = "/etc/arvados/keep-balance/keep-balance.yml" type oldKeepBalanceConfig struct { diff --git a/lib/config/deprecated_test.go b/lib/config/deprecated_test.go index e06a1f231d..f73a92be5c 100644 --- a/lib/config/deprecated_test.go +++ b/lib/config/deprecated_test.go @@ -283,52 +283,6 @@ func fmtKeepproxyConfig(param string, debugLog bool) string { `, debugLog, param) } -func (s *LoadSuite) TestLegacyArvGitHttpdConfig(c *check.C) { - content := []byte(` -{ - "Client": { - "Scheme": "", - "APIHost": "example.com", - "AuthToken": "abcdefg", - }, - "Listen": ":9000", - "GitCommand": "/test/git", - "GitoliteHome": "/test/gitolite", - "RepoRoot": "/test/reporoot", - "ManagementToken": "xyzzy" -} -`) - f := "-legacy-git-httpd-config" - cluster, err := testLoadLegacyConfig(content, f, c) - - c.Assert(err, check.IsNil) - c.Assert(cluster, check.NotNil) - c.Check(cluster.Services.Controller.ExternalURL, check.Equals, arvados.URL{Scheme: "https", Host: "example.com", Path: "/"}) - c.Check(cluster.SystemRootToken, check.Equals, "abcdefg") - c.Check(cluster.ManagementToken, check.Equals, "xyzzy") - c.Check(cluster.Git.GitCommand, check.Equals, "/test/git") - c.Check(cluster.Git.GitoliteHome, check.Equals, "/test/gitolite") - c.Check(cluster.Git.Repositories, check.Equals, "/test/reporoot") - c.Check(cluster.Services.Keepproxy.InternalURLs[arvados.URL{Host: ":9000"}], check.Equals, arvados.ServiceInstance{}) -} - -// Tests fix for https://dev.arvados.org/issues/15642 -func (s *LoadSuite) TestLegacyArvGitHttpdConfigDoesntDisableMissingItems(c *check.C) { - content := []byte(` -{ - "Client": { - "Scheme": "", - "APIHost": "example.com", - "AuthToken": "abcdefg", - } -} -`) - cluster, err := testLoadLegacyConfig(content, "-legacy-git-httpd-config", c) - c.Assert(err, check.IsNil) - // The resulting ManagementToken should be the one set up on the test server. - c.Check(cluster.ManagementToken, check.Equals, TestServerManagementToken) -} - func (s *LoadSuite) TestLegacyKeepBalanceConfig(c *check.C) { f := "-legacy-keepbalance-config" content := []byte(fmtKeepBalanceConfig("")) diff --git a/lib/config/export.go b/lib/config/export.go index f511ebbcb1..3c1e6bc008 100644 --- a/lib/config/export.go +++ b/lib/config/export.go @@ -59,108 +59,106 @@ func ExportJSON(w io.Writer, cluster *arvados.Cluster) error { // exists. var whitelist = map[string]bool{ // | sort -t'"' -k2,2 - "API": true, - "API.AsyncPermissionsUpdateInterval": false, - "API.DisabledAPIs": false, - "API.FreezeProjectRequiresDescription": true, - "API.FreezeProjectRequiresProperties": true, - "API.FreezeProjectRequiresProperties.*": true, - "API.KeepServiceRequestTimeout": false, - "API.LockBeforeUpdate": false, - "API.LogCreateRequestFraction": false, - "API.MaxConcurrentRailsRequests": false, - "API.MaxConcurrentRequests": false, - "API.MaxGatewayTunnels": false, - "API.MaxIndexDatabaseRead": false, - "API.MaxItemsPerResponse": true, - "API.MaxKeepBlobBuffers": false, - "API.MaxQueuedRequests": false, - "API.MaxQueueTimeForLockRequests": false, - "API.MaxRequestAmplification": false, - "API.MaxRequestSize": true, - "API.MaxTokenLifetime": false, - "API.RequestTimeout": true, - "API.SendTimeout": true, - "API.UnfreezeProjectRequiresAdmin": true, - "API.VocabularyPath": false, - "API.WebsocketClientEventQueue": false, - "API.WebsocketServerEventQueue": false, - "AuditLogs": false, - "AuditLogs.MaxAge": false, - "AuditLogs.MaxDeleteBatch": false, - "AuditLogs.UnloggedAttributes": false, - "ClusterID": true, - "Collections": true, - "Collections.BalanceCollectionBatch": false, - "Collections.BalanceCollectionBuffers": false, - "Collections.BalancePeriod": false, - "Collections.BalancePullLimit": false, - "Collections.BalanceTimeout": false, - "Collections.BalanceTrashLimit": false, - "Collections.BalanceUpdateLimit": false, - "Collections.BlobDeleteConcurrency": false, - "Collections.BlobMissingReport": false, - "Collections.BlobReplicateConcurrency": false, - "Collections.BlobSigning": true, - "Collections.BlobSigningKey": false, - "Collections.BlobSigningTTL": true, - "Collections.BlobTrash": false, - "Collections.BlobTrashCheckInterval": false, - "Collections.BlobTrashConcurrency": false, - "Collections.BlobTrashLifetime": false, - "Collections.CollectionVersioning": true, - "Collections.DefaultReplication": true, - "Collections.DefaultTrashLifetime": true, - "Collections.ForwardSlashNameSubstitution": true, - "Collections.KeepproxyPermission": false, - "Collections.ManagedProperties": true, - "Collections.ManagedProperties.*": true, - "Collections.ManagedProperties.*.*": true, - "Collections.PreserveVersionIfIdle": true, - "Collections.S3FolderObjects": true, - "Collections.TrashSweepInterval": false, - "Collections.TrustAllContent": true, - "Collections.WebDAVCache": false, - "Collections.WebDAVLogEvents": false, - "Collections.WebDAVOutputBuffer": false, - "Collections.WebDAVPermission": false, - "Containers": true, - "Containers.AlwaysUsePreemptibleInstances": true, - "Containers.CloudVMs": false, - "Containers.CrunchRunArgumentsList": false, - "Containers.CrunchRunCommand": false, - "Containers.DefaultKeepCacheRAM": true, - "Containers.DispatchPrivateKey": false, - "Containers.JobsAPI": true, - "Containers.JobsAPI.Enable": true, - "Containers.JobsAPI.GitInternalDir": false, - "Containers.LocalKeepBlobBuffersPerVCPU": false, - "Containers.LocalKeepLogsToContainerLog": false, - "Containers.Logging": false, - "Containers.LogReuseDecisions": false, - "Containers.LSF": false, - "Containers.MaxDispatchAttempts": false, - "Containers.MaximumPriceFactor": true, - "Containers.MaxRetryAttempts": true, - "Containers.MinRetryPeriod": true, - "Containers.PreemptiblePriceFactor": false, - "Containers.ReserveExtraRAM": true, - "Containers.RuntimeEngine": true, - "Containers.ShellAccess": true, - "Containers.ShellAccess.Admin": true, - "Containers.ShellAccess.User": true, - "Containers.SLURM": false, - "Containers.StaleLockTimeout": false, - "Containers.SupportedDockerImageFormats": true, - "Containers.SupportedDockerImageFormats.*": true, - "Git": false, - "InstanceTypes": true, - "InstanceTypes.*": true, - "InstanceTypes.*.*": true, - "InstanceTypes.*.*.*": true, - "Login": true, - "Login.Google": true, - "Login.Google.AlternateEmailAddresses": false, + "API": true, + "API.AsyncPermissionsUpdateInterval": false, + "API.DisabledAPIs": false, + "API.FreezeProjectRequiresDescription": true, + "API.FreezeProjectRequiresProperties": true, + "API.FreezeProjectRequiresProperties.*": true, + "API.KeepServiceRequestTimeout": false, + "API.LockBeforeUpdate": false, + "API.LogCreateRequestFraction": false, + "API.MaxConcurrentRailsRequests": false, + "API.MaxConcurrentRequests": false, + "API.MaxGatewayTunnels": false, + "API.MaxIndexDatabaseRead": false, + "API.MaxItemsPerResponse": true, + "API.MaxKeepBlobBuffers": false, + "API.MaxQueuedRequests": false, + "API.MaxQueueTimeForLockRequests": false, + "API.MaxRequestAmplification": false, + "API.MaxRequestSize": true, + "API.MaxTokenLifetime": false, + "API.RequestTimeout": true, + "API.SendTimeout": true, + "API.UnfreezeProjectRequiresAdmin": true, + "API.VocabularyPath": false, + "API.WebsocketClientEventQueue": false, + "API.WebsocketServerEventQueue": false, + "AuditLogs": false, + "AuditLogs.MaxAge": false, + "AuditLogs.MaxDeleteBatch": false, + "AuditLogs.UnloggedAttributes": false, + "ClusterID": true, + "Collections": true, + "Collections.BalanceCollectionBatch": false, + "Collections.BalanceCollectionBuffers": false, + "Collections.BalancePeriod": false, + "Collections.BalancePullLimit": false, + "Collections.BalanceTimeout": false, + "Collections.BalanceTrashLimit": false, + "Collections.BalanceUpdateLimit": false, + "Collections.BlobDeleteConcurrency": false, + "Collections.BlobMissingReport": false, + "Collections.BlobReplicateConcurrency": false, + "Collections.BlobSigning": true, + "Collections.BlobSigningKey": false, + "Collections.BlobSigningTTL": true, + "Collections.BlobTrash": false, + "Collections.BlobTrashCheckInterval": false, + "Collections.BlobTrashConcurrency": false, + "Collections.BlobTrashLifetime": false, + "Collections.CollectionVersioning": true, + "Collections.DefaultReplication": true, + "Collections.DefaultTrashLifetime": true, + "Collections.ForwardSlashNameSubstitution": true, + "Collections.KeepproxyPermission": false, + "Collections.ManagedProperties": true, + "Collections.ManagedProperties.*": true, + "Collections.ManagedProperties.*.*": true, + "Collections.PreserveVersionIfIdle": true, + "Collections.S3FolderObjects": true, + "Collections.TrashSweepInterval": false, + "Collections.TrustAllContent": true, + "Collections.WebDAVCache": false, + "Collections.WebDAVLogEvents": false, + "Collections.WebDAVOutputBuffer": false, + "Collections.WebDAVPermission": false, + "Containers": true, + "Containers.AlwaysUsePreemptibleInstances": true, + "Containers.CloudVMs": false, + "Containers.CrunchRunArgumentsList": false, + "Containers.CrunchRunCommand": false, + "Containers.DefaultKeepCacheRAM": true, + "Containers.DispatchPrivateKey": false, + "Containers.JobsAPI": true, + "Containers.JobsAPI.Enable": true, + "Containers.LocalKeepBlobBuffersPerVCPU": false, + "Containers.LocalKeepLogsToContainerLog": false, + "Containers.Logging": false, + "Containers.LogReuseDecisions": false, + "Containers.LSF": false, + "Containers.MaxDispatchAttempts": false, + "Containers.MaximumPriceFactor": true, + "Containers.MaxRetryAttempts": true, + "Containers.MinRetryPeriod": true, + "Containers.PreemptiblePriceFactor": false, + "Containers.ReserveExtraRAM": true, + "Containers.RuntimeEngine": true, + "Containers.ShellAccess": true, + "Containers.ShellAccess.Admin": true, + "Containers.ShellAccess.User": true, + "Containers.SLURM": false, + "Containers.StaleLockTimeout": false, + "Containers.SupportedDockerImageFormats": true, + "Containers.SupportedDockerImageFormats.*": true, + "InstanceTypes": true, + "InstanceTypes.*": true, + "InstanceTypes.*.*": true, + "InstanceTypes.*.*.*": true, + "Login": true, + "Login.Google": true, + "Login.Google.AlternateEmailAddresses": false, "Login.Google.AuthenticationRequestParameters": false, "Login.Google.ClientID": false, "Login.Google.ClientSecret": false, @@ -243,7 +241,6 @@ var whitelist = map[string]bool{ "Users.AutoAdminFirstUser": false, "Users.AutoAdminUserWithEmail": false, "Users.AutoSetupNewUsers": false, - "Users.AutoSetupNewUsersWithRepository": false, "Users.AutoSetupNewUsersWithVmUUID": false, "Users.AutoSetupUsernameBlacklist": false, "Users.CanCreateRoleGroups": true, diff --git a/lib/config/load.go b/lib/config/load.go index d504f7796c..00c8e28683 100644 --- a/lib/config/load.go +++ b/lib/config/load.go @@ -48,7 +48,6 @@ type Loader struct { CrunchDispatchSlurmPath string WebsocketPath string KeepproxyPath string - GitHttpdPath string KeepBalancePath string configdata []byte @@ -88,7 +87,6 @@ func (ldr *Loader) SetupFlags(flagset *flag.FlagSet) { flagset.StringVar(&ldr.CrunchDispatchSlurmPath, "legacy-crunch-dispatch-slurm-config", defaultCrunchDispatchSlurmConfigPath, "Legacy crunch-dispatch-slurm configuration `file`") flagset.StringVar(&ldr.WebsocketPath, "legacy-ws-config", defaultWebsocketConfigPath, "Legacy arvados-ws configuration `file`") flagset.StringVar(&ldr.KeepproxyPath, "legacy-keepproxy-config", defaultKeepproxyConfigPath, "Legacy keepproxy configuration `file`") - flagset.StringVar(&ldr.GitHttpdPath, "legacy-git-httpd-config", defaultGitHttpdConfigPath, "Legacy arvados-git-httpd configuration `file`") flagset.StringVar(&ldr.KeepBalancePath, "legacy-keepbalance-config", defaultKeepBalanceConfigPath, "Legacy keep-balance configuration `file`") flagset.BoolVar(&ldr.SkipLegacy, "skip-legacy", false, "Don't load legacy config files") } @@ -168,9 +166,6 @@ func (ldr *Loader) MungeLegacyConfigArgs(lgr logrus.FieldLogger, args []string, if legacyConfigArg != "-legacy-keepproxy-config" { ldr.KeepproxyPath = "" } - if legacyConfigArg != "-legacy-git-httpd-config" { - ldr.GitHttpdPath = "" - } if legacyConfigArg != "-legacy-keepbalance-config" { ldr.KeepBalancePath = "" } @@ -296,7 +291,6 @@ func (ldr *Loader) Load() (*arvados.Config, error) { ldr.loadOldCrunchDispatchSlurmConfig, ldr.loadOldWebsocketConfig, ldr.loadOldKeepproxyConfig, - ldr.loadOldGitHttpdConfig, ldr.loadOldKeepBalanceConfig, ) } diff --git a/lib/controller/integration_test.go b/lib/controller/integration_test.go index 70106ed53e..6b603f178e 100644 --- a/lib/controller/integration_test.go +++ b/lib/controller/integration_test.go @@ -826,7 +826,6 @@ func (s *IntegrationSuite) TestFederatedApiClientAuthHandling(c *check.C) { // Test for bug #18076 func (s *IntegrationSuite) TestStaleCachedUserRecord(c *check.C) { rootctx1, _, _ := s.super.RootClients("z1111") - _, rootclnt3, _ := s.super.RootClients("z3333") conn1 := s.super.Conn("z1111") conn3 := s.super.Conn("z3333") @@ -838,92 +837,69 @@ func (s *IntegrationSuite) TestStaleCachedUserRecord(c *check.C) { check.Commentf("incorrect LoginCluster config on cluster %q", cls)) } - for testCaseNr, testCase := range []struct { - name string - withRepository bool - }{ - {"User without local repository", false}, - {"User with local repository", true}, - } { - c.Log(c.TestName() + " " + testCase.name) - // Create some users, request them on the federated cluster so they're cached. - var users []arvados.User - for userNr := 0; userNr < 2; userNr++ { - _, _, _, user := s.super.UserClients("z1111", - rootctx1, - c, - conn1, - fmt.Sprintf("user%d%d@example.com", testCaseNr, userNr), - true) - c.Assert(user.Username, check.Not(check.Equals), "") - users = append(users, user) - - lst, err := conn3.UserList(rootctx1, arvados.ListOptions{Limit: -1}) - c.Assert(err, check.Equals, nil) - userFound := false - for _, fedUser := range lst.Items { - if fedUser.UUID == user.UUID { - c.Assert(fedUser.Username, check.Equals, user.Username) - userFound = true - break - } - } - c.Assert(userFound, check.Equals, true) - - if testCase.withRepository { - var repo interface{} - err = rootclnt3.RequestAndDecode( - &repo, "POST", "arvados/v1/repositories", nil, - map[string]interface{}{ - "repository": map[string]string{ - "name": fmt.Sprintf("%s/test", user.Username), - "owner_uuid": user.UUID, - }, - }, - ) - c.Assert(err, check.IsNil) - } - } + // Create some users, request them on the federated cluster so they're cached. + var users []arvados.User + for userNr := 0; userNr < 2; userNr++ { + _, _, _, user := s.super.UserClients("z1111", + rootctx1, + c, + conn1, + fmt.Sprintf("user0%d@example.com", userNr), + true) + c.Assert(user.Username, check.Not(check.Equals), "") + users = append(users, user) - // Swap the usernames - _, err := conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ - UUID: users[0].UUID, - Attrs: map[string]interface{}{ - "username": "", - }, - }) - c.Assert(err, check.Equals, nil) - _, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ - UUID: users[1].UUID, - Attrs: map[string]interface{}{ - "username": users[0].Username, - }, - }) - c.Assert(err, check.Equals, nil) - _, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ - UUID: users[0].UUID, - Attrs: map[string]interface{}{ - "username": users[1].Username, - }, - }) - c.Assert(err, check.Equals, nil) - - // Re-request the list on the federated cluster & check for updates lst, err := conn3.UserList(rootctx1, arvados.ListOptions{Limit: -1}) c.Assert(err, check.Equals, nil) - var user0Found, user1Found bool - for _, user := range lst.Items { - if user.UUID == users[0].UUID { - user0Found = true - c.Assert(user.Username, check.Equals, users[1].Username) - } else if user.UUID == users[1].UUID { - user1Found = true - c.Assert(user.Username, check.Equals, users[0].Username) + userFound := false + for _, fedUser := range lst.Items { + if fedUser.UUID == user.UUID { + c.Assert(fedUser.Username, check.Equals, user.Username) + userFound = true + break } } - c.Assert(user0Found, check.Equals, true) - c.Assert(user1Found, check.Equals, true) + c.Assert(userFound, check.Equals, true) + } + + // Swap the usernames + _, err := conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ + UUID: users[0].UUID, + Attrs: map[string]interface{}{ + "username": "", + }, + }) + c.Assert(err, check.Equals, nil) + _, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ + UUID: users[1].UUID, + Attrs: map[string]interface{}{ + "username": users[0].Username, + }, + }) + c.Assert(err, check.Equals, nil) + _, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{ + UUID: users[0].UUID, + Attrs: map[string]interface{}{ + "username": users[1].Username, + }, + }) + c.Assert(err, check.Equals, nil) + + // Re-request the list on the federated cluster & check for updates + lst, err := conn3.UserList(rootctx1, arvados.ListOptions{Limit: -1}) + c.Assert(err, check.Equals, nil) + var user0Found, user1Found bool + for _, user := range lst.Items { + if user.UUID == users[0].UUID { + user0Found = true + c.Assert(user.Username, check.Equals, users[1].Username) + } else if user.UUID == users[1].UUID { + user1Found = true + c.Assert(user.Username, check.Equals, users[0].Username) + } } + c.Assert(user0Found, check.Equals, true) + c.Assert(user1Found, check.Equals, true) } // Test for bug #16263 diff --git a/lib/crunchrun/crunchrun.go b/lib/crunchrun/crunchrun.go index 3233ee7e57..607d569e23 100644 --- a/lib/crunchrun/crunchrun.go +++ b/lib/crunchrun/crunchrun.go @@ -626,17 +626,6 @@ func (runner *ContainerRunner) SetupMounts() (map[string]bindmount, error) { // OutputPath is a staging directory. bindmounts[bind] = bindmount{HostPath: tmpfn, ReadOnly: true} } - - case mnt.Kind == "git_tree": - tmpdir, err := runner.MkTempDir(runner.parentTemp, "git_tree") - if err != nil { - return nil, fmt.Errorf("creating temp dir: %v", err) - } - err = gitMount(mnt).extractTree(runner.containerClient, tmpdir, token) - if err != nil { - return nil, err - } - bindmounts[bind] = bindmount{HostPath: tmpdir, ReadOnly: true} } } diff --git a/lib/crunchrun/crunchrun_test.go b/lib/crunchrun/crunchrun_test.go index 1188fe296a..5cb982e1bb 100644 --- a/lib/crunchrun/crunchrun_test.go +++ b/lib/crunchrun/crunchrun_test.go @@ -40,8 +40,6 @@ import ( "git.arvados.org/arvados.git/sdk/go/manifest" . "gopkg.in/check.v1" - git_client "gopkg.in/src-d/go-git.v4/plumbing/transport/client" - git_http "gopkg.in/src-d/go-git.v4/plumbing/transport/http" ) // Gocheck boilerplate @@ -1752,54 +1750,6 @@ func (s *TestSuite) TestSetupMounts(c *C) { cr.CleanupDirs() checkEmpty() } - - // git_tree mounts - { - i = 0 - cr.ArvMountPoint = "" - git_client.InstallProtocol("https", git_http.NewClient(arvados.InsecureHTTPClient)) - cr.token = arvadostest.ActiveToken - cr.Container.Mounts = make(map[string]arvados.Mount) - cr.Container.Mounts = map[string]arvados.Mount{ - "/tip": { - Kind: "git_tree", - UUID: arvadostest.Repository2UUID, - Commit: "fd3531f42995344f36c30b79f55f27b502f3d344", - Path: "/", - }, - "/non-tip": { - Kind: "git_tree", - UUID: arvadostest.Repository2UUID, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - Path: "/", - }, - } - cr.Container.OutputPath = "/tmp" - - bindmounts, err := cr.SetupMounts() - c.Check(err, IsNil) - - for path, mount := range bindmounts { - c.Check(mount.ReadOnly, Equals, !cr.Container.Mounts[path].Writable, Commentf("%s %#v", path, mount)) - } - - data, err := ioutil.ReadFile(bindmounts["/tip"].HostPath + "/dir1/dir2/file with mode 0644") - c.Check(err, IsNil) - c.Check(string(data), Equals, "\000\001\002\003") - _, err = ioutil.ReadFile(bindmounts["/tip"].HostPath + "/file only on testbranch") - c.Check(err, FitsTypeOf, &os.PathError{}) - c.Check(os.IsNotExist(err), Equals, true) - - data, err = ioutil.ReadFile(bindmounts["/non-tip"].HostPath + "/dir1/dir2/file with mode 0644") - c.Check(err, IsNil) - c.Check(string(data), Equals, "\000\001\002\003") - data, err = ioutil.ReadFile(bindmounts["/non-tip"].HostPath + "/file only on testbranch") - c.Check(err, IsNil) - c.Check(string(data), Equals, "testfile\n") - - cr.CleanupDirs() - checkEmpty() - } } func (s *TestSuite) TestStdout(c *C) { diff --git a/lib/crunchrun/git_mount.go b/lib/crunchrun/git_mount.go deleted file mode 100644 index 561ea18de4..0000000000 --- a/lib/crunchrun/git_mount.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package crunchrun - -import ( - "fmt" - "net/url" - "os" - "path/filepath" - "regexp" - - "git.arvados.org/arvados.git/sdk/go/arvados" - "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" - git_http "gopkg.in/src-d/go-git.v4/plumbing/transport/http" - "gopkg.in/src-d/go-git.v4/storage/memory" -) - -type gitMount arvados.Mount - -var ( - sha1re = regexp.MustCompile(`^[0-9a-f]{40}$`) - repoUUIDre = regexp.MustCompile(`^[0-9a-z]{5}-s0uqq-[0-9a-z]{15}$`) -) - -func (gm gitMount) validate() error { - if gm.Path != "" && gm.Path != "/" { - return fmt.Errorf("cannot mount git_tree with path %q -- only \"/\" is supported", gm.Path) - } - if !sha1re.MatchString(gm.Commit) { - return fmt.Errorf("cannot mount git_tree with commit %q -- must be a 40-char SHA1", gm.Commit) - } - if gm.RepositoryName != "" || gm.GitURL != "" { - return fmt.Errorf("cannot mount git_tree -- repository_name and git_url must be empty") - } - if !repoUUIDre.MatchString(gm.UUID) { - return fmt.Errorf("cannot mount git_tree with uuid %q -- must be a repository UUID", gm.UUID) - } - if gm.Writable { - return fmt.Errorf("writable git_tree mount is not supported") - } - return nil -} - -// ExtractTree extracts the specified tree into dir, which is an -// existing empty local directory. -func (gm gitMount) extractTree(ac *arvados.Client, dir string, token string) error { - err := gm.validate() - if err != nil { - return err - } - dd, err := ac.DiscoveryDocument() - if err != nil { - return fmt.Errorf("error getting discovery document: %w", err) - } - u, err := url.Parse(dd.GitURL) - if err != nil { - return fmt.Errorf("parse gitUrl %q: %s", dd.GitURL, err) - } - u, err = u.Parse("/" + gm.UUID + ".git") - if err != nil { - return fmt.Errorf("build git url from %q, %q: %s", dd.GitURL, gm.UUID, err) - } - store := memory.NewStorage() - repo, err := git.Init(store, osfs.New(dir)) - if err != nil { - return fmt.Errorf("init repo: %s", err) - } - _, err = repo.CreateRemote(&git_config.RemoteConfig{ - Name: "origin", - URLs: []string{u.String()}, - }) - if err != nil { - return fmt.Errorf("create remote %q: %s", u.String(), err) - } - err = repo.Fetch(&git.FetchOptions{ - RemoteName: "origin", - Auth: &git_http.BasicAuth{ - Username: "none", - Password: token, - }, - }) - if err != nil { - return fmt.Errorf("git fetch %q: %s", u.String(), err) - } - wt, err := repo.Worktree() - if err != nil { - return fmt.Errorf("worktree failed: %s", err) - } - err = wt.Checkout(&git.CheckoutOptions{ - Hash: git_plumbing.NewHash(gm.Commit), - }) - if err != nil { - return fmt.Errorf("checkout failed: %s", err) - } - err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - // copy user rx bits to group and other, in case - // prevailing umask is more restrictive than 022 - mode := info.Mode() - mode = mode | ((mode >> 3) & 050) | ((mode >> 6) & 5) - return os.Chmod(path, mode) - }) - if err != nil { - return fmt.Errorf("chmod -R %q: %s", dir, err) - } - return nil -} diff --git a/lib/crunchrun/git_mount_test.go b/lib/crunchrun/git_mount_test.go deleted file mode 100644 index ac98dcc480..0000000000 --- a/lib/crunchrun/git_mount_test.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package crunchrun - -import ( - "io/ioutil" - "os" - "path/filepath" - - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/arvadostest" - check "gopkg.in/check.v1" - git_client "gopkg.in/src-d/go-git.v4/plumbing/transport/client" - git_http "gopkg.in/src-d/go-git.v4/plumbing/transport/http" -) - -type GitMountSuite struct { - tmpdir string -} - -var _ = check.Suite(&GitMountSuite{}) - -func (s *GitMountSuite) SetUpTest(c *check.C) { - var err error - s.tmpdir, err = ioutil.TempDir("", "") - c.Assert(err, check.IsNil) - git_client.InstallProtocol("https", git_http.NewClient(arvados.InsecureHTTPClient)) -} - -func (s *GitMountSuite) TearDownTest(c *check.C) { - err := os.RemoveAll(s.tmpdir) - c.Check(err, check.IsNil) -} - -// Commit fd3531f is crunch-run-tree-test -func (s *GitMountSuite) TestExtractTree(c *check.C) { - gm := gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - Commit: "fd3531f42995344f36c30b79f55f27b502f3d344", - } - ac := arvados.NewClientFromEnv() - err := gm.extractTree(ac, s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.IsNil) - - fnm := filepath.Join(s.tmpdir, "dir1/dir2/file with mode 0644") - data, err := ioutil.ReadFile(fnm) - c.Check(err, check.IsNil) - c.Check(data, check.DeepEquals, []byte{0, 1, 2, 3}) - fi, err := os.Stat(fnm) - c.Check(err, check.IsNil) - if err == nil { - c.Check(fi.Mode(), check.Equals, os.FileMode(0644)) - } - - fnm = filepath.Join(s.tmpdir, "dir1/dir2/file with mode 0755") - data, err = ioutil.ReadFile(fnm) - c.Check(err, check.IsNil) - c.Check(string(data), check.DeepEquals, "#!/bin/sh\nexec echo OK\n") - fi, err = os.Stat(fnm) - c.Check(err, check.IsNil) - if err == nil { - c.Check(fi.Mode(), check.Equals, os.FileMode(0755)) - } - - // Ensure there's no extra stuff like a ".git" dir - s.checkTmpdirContents(c, []string{"dir1"}) - - // Ensure tmpdir is world-readable and world-executable so the - // UID inside the container can use it. - fi, err = os.Stat(s.tmpdir) - c.Check(err, check.IsNil) - c.Check(fi.Mode()&os.ModePerm, check.Equals, os.FileMode(0755)) -} - -// Commit 5ebfab0 is not the tip of any branch or tag, but is -// reachable in branch "crunch-run-non-tip-test". -func (s *GitMountSuite) TestExtractNonTipCommit(c *check.C) { - gm := gitMount{ - UUID: arvadostest.Repository2UUID, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - } - err := gm.extractTree(arvados.NewClientFromEnv(), s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.IsNil) - - fnm := filepath.Join(s.tmpdir, "file only on testbranch") - data, err := ioutil.ReadFile(fnm) - c.Check(err, check.IsNil) - c.Check(string(data), check.DeepEquals, "testfile\n") -} - -func (s *GitMountSuite) TestNonexistentRepository(c *check.C) { - gm := gitMount{ - Path: "/", - UUID: "zzzzz-s0uqq-nonexistentrepo", - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - } - err := gm.extractTree(arvados.NewClientFromEnv(), s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.NotNil) - c.Check(err, check.ErrorMatches, ".*repository not found.*") - - s.checkTmpdirContents(c, []string{}) -} - -func (s *GitMountSuite) TestNonexistentCommit(c *check.C) { - gm := gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - Commit: "bb66b6bb6b6bbb6b6b6b66b6b6b6b6b6b6b6b66b", - } - err := gm.extractTree(arvados.NewClientFromEnv(), s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.NotNil) - c.Check(err, check.ErrorMatches, ".*object not found.*") - - s.checkTmpdirContents(c, []string{}) -} - -func (s *GitMountSuite) TestGitUrlDiscoveryFails(c *check.C) { - delete(discoveryMap, "gitUrl") - gm := gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - } - err := gm.extractTree(&arvados.Client{}, s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.ErrorMatches, ".*error getting discovery doc.*") -} - -func (s *GitMountSuite) TestInvalid(c *check.C) { - for _, trial := range []struct { - gm gitMount - matcher string - }{ - { - gm: gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - Commit: "abc123", - }, - matcher: ".*SHA1.*", - }, - { - gm: gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - RepositoryName: arvadostest.Repository2Name, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - }, - matcher: ".*repository_name.*", - }, - { - gm: gitMount{ - Path: "/", - GitURL: "https://localhost:0/" + arvadostest.Repository2Name + ".git", - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - }, - matcher: ".*git_url.*", - }, - { - gm: gitMount{ - Path: "/dir1/", - UUID: arvadostest.Repository2UUID, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - }, - matcher: ".*path.*", - }, - { - gm: gitMount{ - Path: "/", - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - }, - matcher: ".*UUID.*", - }, - { - gm: gitMount{ - Path: "/", - UUID: arvadostest.Repository2UUID, - Commit: "5ebfab0522851df01fec11ec55a6d0f4877b542e", - Writable: true, - }, - matcher: ".*writable.*", - }, - } { - err := trial.gm.extractTree(arvados.NewClientFromEnv(), s.tmpdir, arvadostest.ActiveToken) - c.Check(err, check.NotNil) - s.checkTmpdirContents(c, []string{}) - - err = trial.gm.validate() - c.Check(err, check.ErrorMatches, trial.matcher) - } -} - -func (s *GitMountSuite) checkTmpdirContents(c *check.C, expect []string) { - f, err := os.Open(s.tmpdir) - c.Check(err, check.IsNil) - names, err := f.Readdirnames(-1) - c.Check(err, check.IsNil) - c.Check(names, check.DeepEquals, expect) -} diff --git a/lib/install/deps.go b/lib/install/deps.go index 146c645eca..b27a14a501 100644 --- a/lib/install/deps.go +++ b/lib/install/deps.go @@ -901,7 +901,6 @@ func prodpkgs(osv osversion) []string { "curl", "fuse", "git", - "gitolite3", "graphviz", "haveged", "libcurl3-gnutls", diff --git a/lib/install/init.go b/lib/install/init.go index d9b74f6a06..12ffdd7af3 100644 --- a/lib/install/init.go +++ b/lib/install/init.go @@ -230,10 +230,6 @@ func (initcmd *initCommand) RunCommand(prog string, args []string, stdin io.Read Keepbalance: InternalURLs: "http://0.0.0.0:9019/": {} - GitHTTP: - InternalURLs: - "http://0.0.0.0:9005/": {} - ExternalURL: {{printf "%q" ( print "https://" .Domain ":4445/" ) }} DispatchCloud: InternalURLs: "http://0.0.0.0:9006/": {} diff --git a/lib/service/cmd.go b/lib/service/cmd.go index 82e95fe0b4..9ed0acfb8f 100644 --- a/lib/service/cmd.go +++ b/lib/service/cmd.go @@ -80,9 +80,9 @@ func (c *command) RunCommand(prog string, args []string, stdin io.Reader, stdout loader := config.NewLoader(stdin, log) loader.SetupFlags(flags) - // prog is [keepstore, keep-web, git-httpd, ...] but the + // prog is [keepstore, keep-web, ...] but the // legacy config flags are [-legacy-keepstore-config, - // -legacy-keepweb-config, -legacy-git-httpd-config, ...] + // -legacy-keepweb-config, ...] legacyFlag := "-legacy-" + strings.Replace(prog, "keep-", "keep", 1) + "-config" args = loader.MungeLegacyConfigArgs(log, args, legacyFlag) diff --git a/sdk/go/arvados/config.go b/sdk/go/arvados/config.go index 23a8c66aff..6725611fd0 100644 --- a/sdk/go/arvados/config.go +++ b/sdk/go/arvados/config.go @@ -161,11 +161,6 @@ type Cluster struct { WebDAVLogEvents bool WebDAVOutputBuffer ByteSize } - Git struct { - GitCommand string - GitoliteHome string - Repositories string - } Login struct { LDAP struct { Enable bool @@ -248,7 +243,6 @@ type Cluster struct { AutoAdminFirstUser bool AutoAdminUserWithEmail string AutoSetupNewUsers bool - AutoSetupNewUsersWithRepository bool AutoSetupNewUsersWithVmUUID string AutoSetupUsernameBlacklist StringSet EmailSubjectPrefix string @@ -356,8 +350,6 @@ type Services struct { DispatchCloud Service DispatchLSF Service DispatchSLURM Service - GitHTTP Service - GitSSH Service Health Service Keepbalance Service Keepproxy Service @@ -511,8 +503,7 @@ type ContainersConfig struct { LocalKeepLogsToContainerLog string JobsAPI struct { - Enable string - GitInternalDir string + Enable string } Logging struct { MaxAge Duration @@ -661,7 +652,6 @@ const ( ServiceNameDispatchCloud ServiceName = "arvados-dispatch-cloud" ServiceNameDispatchLSF ServiceName = "arvados-dispatch-lsf" ServiceNameDispatchSLURM ServiceName = "crunch-dispatch-slurm" - ServiceNameGitHTTP ServiceName = "arvados-git-httpd" ServiceNameHealth ServiceName = "arvados-health" ServiceNameKeepbalance ServiceName = "keep-balance" ServiceNameKeepproxy ServiceName = "keepproxy" @@ -681,7 +671,6 @@ func (svcs Services) Map() map[ServiceName]Service { ServiceNameDispatchCloud: svcs.DispatchCloud, ServiceNameDispatchLSF: svcs.DispatchLSF, ServiceNameDispatchSLURM: svcs.DispatchSLURM, - ServiceNameGitHTTP: svcs.GitHTTP, ServiceNameHealth: svcs.Health, ServiceNameKeepbalance: svcs.Keepbalance, ServiceNameKeepproxy: svcs.Keepproxy, diff --git a/sdk/go/arvados/container.go b/sdk/go/arvados/container.go index 91c8fbfe29..eb5c15af46 100644 --- a/sdk/go/arvados/container.go +++ b/sdk/go/arvados/container.go @@ -94,9 +94,6 @@ type Mount struct { Content interface{} `json:"content"` ExcludeFromOutput bool `json:"exclude_from_output"` Capacity int64 `json:"capacity"` - Commit string `json:"commit"` // only if kind=="git_tree" - RepositoryName string `json:"repository_name"` // only if kind=="git_tree" - GitURL string `json:"git_url"` // only if kind=="git_tree" } type CUDARuntimeConstraints struct { diff --git a/sdk/go/arvadosclient/pool.go b/sdk/go/arvadosclient/pool.go index bb7867aef7..4272f0f759 100644 --- a/sdk/go/arvadosclient/pool.go +++ b/sdk/go/arvadosclient/pool.go @@ -13,8 +13,8 @@ import ( // A ClientPool is a pool of ArvadosClients. This is useful for // applications that make API calls using a dynamic set of tokens, // like web services that pass through their own clients' -// credentials. See arvados-git-httpd for an example, and sync.Pool -// for more information about garbage collection. +// credentials. See sync.Pool for more information about garbage +// collection. type ClientPool struct { // Initialize new clients by copying this one. Prototype *ArvadosClient diff --git a/sdk/go/health/aggregator_test.go b/sdk/go/health/aggregator_test.go index f76f7b8ea8..d9f3faf034 100644 --- a/sdk/go/health/aggregator_test.go +++ b/sdk/go/health/aggregator_test.go @@ -372,7 +372,6 @@ func (s *AggregatorSuite) setAllServiceURLs(listen string) { &svcs.DispatchCloud, &svcs.DispatchLSF, &svcs.DispatchSLURM, - &svcs.GitHTTP, &svcs.Keepbalance, &svcs.Keepproxy, &svcs.Keepstore, diff --git a/sdk/python/arvados/commands/arv_copy.py b/sdk/python/arvados/commands/arv_copy.py index 51251737cf..270e4048b7 100755 --- a/sdk/python/arvados/commands/arv_copy.py +++ b/sdk/python/arvados/commands/arv_copy.py @@ -735,58 +735,6 @@ def copy_collection(obj_uuid, src, dst, args): c['manifest_text'] = dst_manifest.getvalue() return create_collection_from(c, src, dst, args) -def select_git_url(api, repo_name, retries, allow_insecure_http, allow_insecure_http_opt): - r = api.repositories().list( - filters=[['name', '=', repo_name]]).execute(num_retries=retries) - if r['items_available'] != 1: - raise Exception('cannot identify repo {}; {} repos found' - .format(repo_name, r['items_available'])) - - https_url = [c for c in r['items'][0]["clone_urls"] if c.startswith("https:")] - http_url = [c for c in r['items'][0]["clone_urls"] if c.startswith("http:")] - other_url = [c for c in r['items'][0]["clone_urls"] if not c.startswith("http")] - - priority = https_url + other_url + http_url - - for url in priority: - if url.startswith("http"): - u = urllib.parse.urlsplit(url) - baseurl = urllib.parse.urlunsplit((u.scheme, u.netloc, "", "", "")) - git_config = ["-c", "credential.%s/.username=none" % baseurl, - "-c", "credential.%s/.helper=!cred(){ cat >/dev/null; if [ \"$1\" = get ]; then echo password=$ARVADOS_API_TOKEN; fi; };cred" % baseurl] - else: - git_config = [] - - try: - logger.debug("trying %s", url) - subprocess.run( - ['git', *git_config, 'ls-remote', url], - check=True, - env={ - 'ARVADOS_API_TOKEN': api.api_token, - 'GIT_ASKPASS': '/bin/false', - 'HOME': os.environ['HOME'], - }, - stdout=subprocess.DEVNULL, - ) - except subprocess.CalledProcessError: - pass - else: - git_url = url - break - else: - raise Exception('Cannot access git repository, tried {}' - .format(priority)) - - if git_url.startswith("http:"): - if allow_insecure_http: - logger.warning("Using insecure git url %s but will allow this because %s", git_url, allow_insecure_http_opt) - else: - raise Exception("Refusing to use insecure git url %s, use %s if you really want this." % (git_url, allow_insecure_http_opt)) - - return (git_url, git_config) - - def copy_docker_image(docker_image, docker_image_tag, src, dst, args): """Copy the docker image identified by docker_image and docker_image_tag from src to dst. Create appropriate diff --git a/sdk/python/tests/nginx.conf b/sdk/python/tests/nginx.conf index 446b95ca42..a382d643ef 100644 --- a/sdk/python/tests/nginx.conf +++ b/sdk/python/tests/nginx.conf @@ -46,22 +46,6 @@ http { proxy_http_version 1.1; } } - upstream arv-git-http { - server {{UPSTREAMHOST}}:{{GITPORT}}; - } - server { - listen {{LISTENHOST}}:{{GITSSLPORT}} ssl; - server_name arv-git-http git.*; - ssl_certificate "{{SSLCERT}}"; - ssl_certificate_key "{{SSLKEY}}"; - location / { - proxy_pass http://arv-git-http; - 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; - } - } upstream keepproxy { server {{UPSTREAMHOST}}:{{KEEPPROXYPORT}}; } diff --git a/sdk/python/tests/run_test_server.py b/sdk/python/tests/run_test_server.py index 3acc234fc5..b17f569b4d 100644 --- a/sdk/python/tests/run_test_server.py +++ b/sdk/python/tests/run_test_server.py @@ -587,27 +587,6 @@ def stop_keep_proxy(): return kill_server_pid(_pidfile('keepproxy')) -def run_arv_git_httpd(): - if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ: - return - stop_arv_git_httpd() - - gitport = internal_port_from_config("GitHTTP") - env = os.environ.copy() - env.pop('ARVADOS_API_TOKEN', None) - logf = open(_logfilename('githttpd'), WRITE_MODE) - agh = subprocess.Popen(['arvados-server', 'git-httpd'], - env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf) - _detachedSubprocesses.append(agh) - with open(_pidfile('githttpd'), 'w') as f: - f.write(str(agh.pid)) - _wait_until_port_listens(gitport) - -def stop_arv_git_httpd(): - if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ: - return - kill_server_pid(_pidfile('githttpd')) - def run_keep_web(): if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ: return @@ -644,8 +623,6 @@ def run_nginx(): nginxconf['KEEPWEBSSLPORT'] = external_port_from_config("WebDAV") nginxconf['KEEPPROXYPORT'] = internal_port_from_config("Keepproxy") 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") @@ -688,8 +665,6 @@ def setup_config(): workbench1_external_port = find_available_port() workbench2_port = find_available_port() workbench2_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() @@ -743,12 +718,6 @@ def setup_config(): "http://%s:%s"%(localhost, workbench2_port): {}, }, }, - "GitHTTP": { - "ExternalURL": "https://%s:%s" % (localhost, git_httpd_external_port), - "InternalURLs": { - "http://%s:%s"%(localhost, git_httpd_port): {} - }, - }, "Health": { "ExternalURL": "https://%s:%s" % (localhost, health_httpd_external_port), "InternalURLs": { @@ -821,13 +790,7 @@ def setup_config(): "ForwardSlashNameSubstitution": "/", "TrashSweepInterval": "-1s", }, - "Git": { - "Repositories": os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'git', 'test'), - }, "Containers": { - "JobsAPI": { - "GitInternalDir": os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'internal.git'), - }, "LocalKeepBlobBuffersPerVCPU": 0, "Logging": { "SweepInterval": 0, # disable, otherwise test cases can't acquire dblock @@ -959,7 +922,6 @@ if __name__ == "__main__": 'start_keep', 'stop_keep', 'start_keep_proxy', 'stop_keep_proxy', 'start_keep-web', 'stop_keep-web', - 'start_githttpd', 'stop_githttpd', 'start_nginx', 'stop_nginx', 'setup_config', ] parser = argparse.ArgumentParser() @@ -1007,10 +969,6 @@ if __name__ == "__main__": run_keep_proxy() elif args.action == 'stop_keep_proxy': stop_keep_proxy() - elif args.action == 'start_githttpd': - run_arv_git_httpd() - elif args.action == 'stop_githttpd': - stop_arv_git_httpd() elif args.action == 'start_keep-web': run_keep_web() elif args.action == 'stop_keep-web': diff --git a/services/api/app/controllers/arvados/v1/schema_controller.rb b/services/api/app/controllers/arvados/v1/schema_controller.rb index 8607325aca..ca803fd386 100644 --- a/services/api/app/controllers/arvados/v1/schema_controller.rb +++ b/services/api/app/controllers/arvados/v1/schema_controller.rb @@ -72,7 +72,6 @@ class Arvados::V1::SchemaController < ApplicationController workbenchUrl: Rails.configuration.Services.Workbench1.ExternalURL.to_s, workbench2Url: Rails.configuration.Services.Workbench2.ExternalURL.to_s, keepWebServiceUrl: Rails.configuration.Services.WebDAV.ExternalURL.to_s, - gitUrl: Rails.configuration.Services.GitHTTP.ExternalURL.to_s, parameters: { alt: { type: "string", diff --git a/services/api/config/arvados_config.rb b/services/api/config/arvados_config.rb index 594e247a36..f514fee641 100644 --- a/services/api/config/arvados_config.rb +++ b/services/api/config/arvados_config.rb @@ -84,7 +84,6 @@ arvcfg = ConfigLoader.new arvcfg.declare_config "ClusterID", NonemptyString, :uuid_prefix arvcfg.declare_config "ManagementToken", String, :ManagementToken arvcfg.declare_config "SystemRootToken", String -arvcfg.declare_config "Git.Repositories", String, :git_repositories_dir arvcfg.declare_config "API.DisabledAPIs", Hash, :disable_api_methods, ->(cfg, k, v) { arrayToHash cfg, "API.DisabledAPIs", v } arvcfg.declare_config "API.MaxRequestSize", Integer, :max_request_size arvcfg.declare_config "API.MaxIndexDatabaseRead", Integer, :max_index_database_read @@ -94,7 +93,6 @@ arvcfg.declare_config "API.RequestTimeout", ActiveSupport::Duration arvcfg.declare_config "API.AsyncPermissionsUpdateInterval", ActiveSupport::Duration, :async_permissions_update_interval arvcfg.declare_config "Users.AutoSetupNewUsers", Boolean, :auto_setup_new_users arvcfg.declare_config "Users.AutoSetupNewUsersWithVmUUID", String, :auto_setup_new_users_with_vm_uuid -arvcfg.declare_config "Users.AutoSetupNewUsersWithRepository", Boolean, :auto_setup_new_users_with_repository arvcfg.declare_config "Users.AutoSetupUsernameBlacklist", Hash, :auto_setup_name_blacklist, ->(cfg, k, v) { arrayToHash cfg, "Users.AutoSetupUsernameBlacklist", v } arvcfg.declare_config "Users.NewUsersAreActive", Boolean, :new_users_are_active arvcfg.declare_config "Users.AutoAdminUserWithEmail", String, :auto_admin_user @@ -148,8 +146,6 @@ arvcfg.declare_config "Services.Controller.ExternalURL", URI arvcfg.declare_config "Services.Workbench1.ExternalURL", URI, :workbench_address arvcfg.declare_config "Services.Websocket.ExternalURL", URI, :websocket_address arvcfg.declare_config "Services.WebDAV.ExternalURL", URI, :keep_web_service_url -arvcfg.declare_config "Services.GitHTTP.ExternalURL", URI, :git_repo_https_base -arvcfg.declare_config "Services.GitSSH.ExternalURL", URI, :git_repo_ssh_base, ->(cfg, k, v) { ConfigLoader.set_cfg cfg, "Services.GitSSH.ExternalURL", "ssh://#{v}" } arvcfg.declare_config "RemoteClusters", Hash, :remote_hosts, ->(cfg, k, v) { h = if cfg["RemoteClusters"] then cfg["RemoteClusters"].deep_dup diff --git a/services/api/script/arvados-git-sync.rb b/services/api/script/arvados-git-sync.rb deleted file mode 100755 index 9f8f050c10..0000000000 --- a/services/api/script/arvados-git-sync.rb +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env ruby -# Copyright (C) The Arvados Authors. All rights reserved. -# -# SPDX-License-Identifier: AGPL-3.0 - -require 'rubygems' -require 'pp' -require 'arvados' -require 'tempfile' -require 'yaml' -require 'fileutils' - -# This script does the actual gitolite config management on disk. -# -# Ward Vandewege - -# Default is development -production = ARGV[0] == "production" - -ENV["RAILS_ENV"] = "development" -ENV["RAILS_ENV"] = "production" if production - -DEBUG = 1 - -# load and merge in the environment-specific application config info -# if present, overriding base config parameters as specified -path = File.absolute_path('../../config/arvados-clients.yml', __FILE__) -if File.exist?(path) then - cp_config = File.open(path) do |f| - YAML.safe_load(f, filename: path)[ENV['RAILS_ENV']] - end -else - puts "Please create a\n #{path}\n file" - exit 1 -end - -gitolite_url = cp_config['gitolite_url'] -gitolite_arvados_git_user_key = cp_config['gitolite_arvados_git_user_key'] - -gitolite_tmpdir = cp_config['gitolite_tmp'] -gitolite_admin = File.join(gitolite_tmpdir, 'gitolite-admin') -gitolite_admin_keydir = File.join(gitolite_admin, 'keydir') -gitolite_keydir = File.join(gitolite_admin, 'keydir', 'arvados') - -ENV['ARVADOS_API_HOST'] = cp_config['arvados_api_host'] -ENV['ARVADOS_API_TOKEN'] = cp_config['arvados_api_token'] -if cp_config['arvados_api_host_insecure'] - ENV['ARVADOS_API_HOST_INSECURE'] = 'true' -else - ENV.delete('ARVADOS_API_HOST_INSECURE') -end - -def ensure_directory(path, mode) - begin - Dir.mkdir(path, mode) - rescue Errno::EEXIST - end -end - -def replace_file(path, contents) - unlink_now = true - dirname, basename = File.split(path) - FileUtils.mkpath(dirname) - new_file = Tempfile.new([basename, ".tmp"], dirname) - begin - new_file.write(contents) - new_file.flush - File.rename(new_file, path) - unlink_now = false - ensure - new_file.close(unlink_now) - end -end - -def file_has_contents?(path, contents) - begin - IO.read(path) == contents - rescue Errno::ENOENT - false - end -end - -module TrackCommitState - module ClassMethods - # Note that all classes that include TrackCommitState will have - # @@need_commit = true if any of them set it. Since this flag reports - # a boolean state of the underlying git repository, that's OK in the - # current implementation. - @@need_commit = false - - def changed? - @@need_commit - end - - def ensure_in_git(path, contents) - unless file_has_contents?(path, contents) - replace_file(path, contents) - system("git", "add", path) - @@need_commit = true - end - end - end - - def ensure_in_git(path, contents) - self.class.ensure_in_git(path, contents) - end - - def self.included(base) - base.extend(ClassMethods) - end -end - -class UserSSHKeys - include TrackCommitState - - def initialize(user_keys_map, key_dir) - @user_keys_map = user_keys_map - @key_dir = key_dir - @installed = {} - end - - def install(filename, pubkey) - unless pubkey.nil? - key_path = File.join(@key_dir, filename) - ensure_in_git(key_path, pubkey) - end - @installed[filename] = true - end - - def ensure_keys_for_user(user_uuid) - return unless key_list = @user_keys_map.delete(user_uuid) - key_list.map { |k| k[:public_key] }.compact.each_with_index do |pubkey, ii| - # Handle putty-style ssh public keys - pubkey.sub!(/^(Comment: "r[^\n]*\n)(.*)$/m,'ssh-rsa \2 \1') - pubkey.sub!(/^(Comment: "d[^\n]*\n)(.*)$/m,'ssh-dss \2 \1') - pubkey.gsub!(/\n/,'') - pubkey.strip! - install("#{user_uuid}@#{ii}.pub", pubkey) - end - end - - def installed?(filename) - @installed[filename] - end -end - -class Repository - include TrackCommitState - - @@aliases = {} - - def initialize(arv_repo, user_keys) - @arv_repo = arv_repo - @user_keys = user_keys - end - - def self.ensure_system_config(conf_root) - ensure_in_git(File.join(conf_root, "conf", "gitolite.conf"), - %Q{include "auto/*.conf"\ninclude "admin/*.conf"\n}) - ensure_in_git(File.join(conf_root, "arvadosaliases.pl"), alias_config) - - conf_path = File.join(conf_root, "conf", "admin", "arvados.conf") - conf_file = %Q{ -@arvados_git_user = arvados_git_user - -repo gitolite-admin - RW = @arvados_git_user - -} - ensure_directory(File.dirname(conf_path), 0755) - ensure_in_git(conf_path, conf_file) - end - - def ensure_config(conf_root) - if name and (File.exist?(auto_conf_path(conf_root, name))) - # This gitolite installation knows the repository by name, rather than - # UUID. Leave it configured that way until a separate migration is run. - basename = name - else - basename = uuid - @@aliases[name] = uuid unless name.nil? - end - conf_file = "\nrepo #{basename}\n" - @arv_repo[:user_permissions].sort.each do |user_uuid, perm| - conf_file += "\t#{perm[:gitolite_permissions]}\t= #{user_uuid}\n" - @user_keys.ensure_keys_for_user(user_uuid) - end - ensure_in_git(auto_conf_path(conf_root, basename), conf_file) - end - - private - - def auto_conf_path(conf_root, basename) - File.join(conf_root, "conf", "auto", "#{basename}.conf") - end - - def uuid - @arv_repo[:uuid] - end - - def name - if @arv_repo[:name].nil? - nil - else - @clean_name ||= - @arv_repo[:name].sub(/^[^A-Za-z]+/, "").gsub(/[^\w\.\/]/, "") - end - end - - def self.alias_config - conf_s = "{\n" - @@aliases.sort.each do |(repo_name, repo_uuid)| - conf_s += "\t'#{repo_name}' \t=> '#{repo_uuid}',\n" - end - conf_s += "};\n" - conf_s - end -end - -begin - # Get our local gitolite-admin repo up to snuff - if not File.exist?(gitolite_admin) then - ensure_directory(gitolite_tmpdir, 0700) - Dir.chdir(gitolite_tmpdir) - `git clone #{gitolite_url}` - Dir.chdir(gitolite_admin) - else - Dir.chdir(gitolite_admin) - `git pull` - end - - arv = Arvados.new - permissions = arv.repository.get_all_permissions - - ensure_directory(gitolite_keydir, 0700) - admin_user_ssh_keys = UserSSHKeys.new(permissions[:user_keys], gitolite_admin_keydir) - # Make sure the arvados_git_user key is installed; put it in gitolite_admin_keydir - # because that is where gitolite will try to put it if we do not. - admin_user_ssh_keys.install('arvados_git_user.pub', gitolite_arvados_git_user_key) - - user_ssh_keys = UserSSHKeys.new(permissions[:user_keys], gitolite_keydir) - permissions[:repositories].each do |repo_record| - repo = Repository.new(repo_record, user_ssh_keys) - repo.ensure_config(gitolite_admin) - end - Repository.ensure_system_config(gitolite_admin) - - # Clean up public key files that should not be present - Dir.chdir(gitolite_keydir) - stale_keys = Dir.glob('*.pub').reject do |key_file| - user_ssh_keys.installed?(key_file) - end - if stale_keys.any? - stale_keys.each { |key_file| puts "Extra file #{key_file}" } - system("git", "rm", "--quiet", *stale_keys) - end - - if UserSSHKeys.changed? or Repository.changed? or stale_keys.any? - message = "#{Time.now().to_s}: update from API" - Dir.chdir(gitolite_admin) - `git add --all` - `git commit -m '#{message}'` - `git push` - end - -rescue => bang - puts "Error: " + bang.to_s - puts bang.backtrace.join("\n") - exit 1 -end - diff --git a/services/api/script/migrate-gitolite-to-uuid-storage.rb b/services/api/script/migrate-gitolite-to-uuid-storage.rb deleted file mode 100755 index 98f25ca537..0000000000 --- a/services/api/script/migrate-gitolite-to-uuid-storage.rb +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env ruby -# Copyright (C) The Arvados Authors. All rights reserved. -# -# SPDX-License-Identifier: AGPL-3.0 - -# -# Prior to April 2015, Arvados Gitolite integration stored repositories by -# name. To improve user repository management, we switched to storing -# repositories by UUID, and aliasing them to names. This makes it easy to -# have rich name hierarchies, and allow users to rename repositories. -# -# This script will migrate a name-based Gitolite configuration to a UUID-based -# one. To use it: -# -# 1. Change the value of REPOS_DIR below, if needed. -# 2. Install this script in the same directory as `update-gitolite.rb`. -# 3. Ensure that no *other* users can access Gitolite: edit gitolite's -# authorized_keys file so it only contains the arvados_git_user key, -# and disable the update-gitolite cron job. -# 4. Run this script: `ruby migrate-gitolite-to-uuid-storage.rb production`. -# 5. Undo step 3. - -require 'rubygems' -require 'pp' -require 'arvados' -require 'tempfile' -require 'yaml' - -REPOS_DIR = "/var/lib/gitolite/repositories" - -# Default is development -production = ARGV[0] == "production" - -ENV["RAILS_ENV"] = "development" -ENV["RAILS_ENV"] = "production" if production - -DEBUG = 1 - -# load and merge in the environment-specific application config info -# if present, overriding base config parameters as specified -path = File.dirname(__FILE__) + '/config/arvados-clients.yml' -if File.exist?(path) then - cp_config = File.open(path) do |f| - YAML.safe_load(f, filename: path)[ENV['RAILS_ENV']] - end -else - puts "Please create a\n " + File.dirname(__FILE__) + "/config/arvados-clients.yml\n file" - exit 1 -end - -gitolite_url = cp_config['gitolite_url'] -gitolite_arvados_git_user_key = cp_config['gitolite_arvados_git_user_key'] - -gitolite_tmpdir = File.join(File.absolute_path(File.dirname(__FILE__)), - cp_config['gitolite_tmp']) -gitolite_admin = File.join(gitolite_tmpdir, 'gitolite-admin') -gitolite_keydir = File.join(gitolite_admin, 'keydir', 'arvados') - -ENV['ARVADOS_API_HOST'] = cp_config['arvados_api_host'] -ENV['ARVADOS_API_TOKEN'] = cp_config['arvados_api_token'] -if cp_config['arvados_api_host_insecure'] - ENV['ARVADOS_API_HOST_INSECURE'] = 'true' -else - ENV.delete('ARVADOS_API_HOST_INSECURE') -end - -def ensure_directory(path, mode) - begin - Dir.mkdir(path, mode) - rescue Errno::EEXIST - end -end - -def replace_file(path, contents) - unlink_now = true - dirname, basename = File.split(path) - new_file = Tempfile.new([basename, ".tmp"], dirname) - begin - new_file.write(contents) - new_file.flush - File.rename(new_file, path) - unlink_now = false - ensure - new_file.close(unlink_now) - end -end - -def file_has_contents?(path, contents) - begin - IO.read(path) == contents - rescue Errno::ENOENT - false - end -end - -module TrackCommitState - module ClassMethods - # Note that all classes that include TrackCommitState will have - # @@need_commit = true if any of them set it. Since this flag reports - # a boolean state of the underlying git repository, that's OK in the - # current implementation. - @@need_commit = false - - def changed? - @@need_commit - end - - def ensure_in_git(path, contents) - unless file_has_contents?(path, contents) - replace_file(path, contents) - system("git", "add", path) - @@need_commit = true - end - end - end - - def ensure_in_git(path, contents) - self.class.ensure_in_git(path, contents) - end - - def self.included(base) - base.extend(ClassMethods) - end -end - -class Repository - include TrackCommitState - - @@aliases = {} - - def initialize(arv_repo) - @arv_repo = arv_repo - end - - def self.ensure_system_config(conf_root) - ensure_in_git(File.join(conf_root, "arvadosaliases.pl"), alias_config) - end - - def self.rename_repos(repos_root) - @@aliases.each_pair do |uuid, name| - begin - File.rename(File.join(repos_root, "#{name}.git/"), - File.join(repos_root, "#{uuid}.git")) - rescue Errno::ENOENT - end - if name == "arvados" - Dir.chdir(repos_root) { File.symlink("#{uuid}.git/", "arvados.git") } - end - end - end - - def ensure_config(conf_root) - return if name.nil? - @@aliases[uuid] = name - name_conf_path = auto_conf_path(conf_root, name) - return unless File.exist?(name_conf_path) - conf_file = IO.read(name_conf_path) - conf_file.gsub!(/^repo #{Regexp.escape(name)}$/m, "repo #{uuid}") - ensure_in_git(auto_conf_path(conf_root, uuid), conf_file) - File.unlink(name_conf_path) - system("git", "rm", "--quiet", name_conf_path) - end - - private - - def auto_conf_path(conf_root, basename) - File.join(conf_root, "conf", "auto", "#{basename}.conf") - end - - def uuid - @arv_repo[:uuid] - end - - def name - if @arv_repo[:name].nil? - nil - else - @clean_name ||= - @arv_repo[:name].sub(/^[^A-Za-z]+/, "").gsub(/[^\w\.\/]/, "") - end - end - - def self.alias_config - conf_s = "{\n" - @@aliases.sort.each do |(repo_name, repo_uuid)| - conf_s += "\t'#{repo_name}' \t=> '#{repo_uuid}',\n" - end - conf_s += "};\n" - conf_s - end -end - -begin - # Get our local gitolite-admin repo up to snuff - if not File.exist?(gitolite_admin) then - ensure_directory(gitolite_tmpdir, 0700) - Dir.chdir(gitolite_tmpdir) - `git clone #{gitolite_url}` - Dir.chdir(gitolite_admin) - else - Dir.chdir(gitolite_admin) - `git pull` - end - - arv = Arvados.new - permissions = arv.repository.get_all_permissions - - permissions[:repositories].each do |repo_record| - repo = Repository.new(repo_record) - repo.ensure_config(gitolite_admin) - end - Repository.ensure_system_config(gitolite_admin) - - message = "#{Time.now().to_s}: migrate to storing repositories by UUID" - Dir.chdir(gitolite_admin) - `git add --all` - `git commit -m '#{message}'` - Repository.rename_repos(REPOS_DIR) - `git push` - -rescue => bang - puts "Error: " + bang.to_s - puts bang.backtrace.join("\n") - exit 1 -end - diff --git a/services/githttpd/auth_handler.go b/services/githttpd/auth_handler.go deleted file mode 100644 index c6b23fd4c8..0000000000 --- a/services/githttpd/auth_handler.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "errors" - "log" - "net/http" - "os" - "regexp" - "strings" - "time" - - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/arvadosclient" - "git.arvados.org/arvados.git/sdk/go/auth" - "git.arvados.org/arvados.git/sdk/go/httpserver" - "github.com/sirupsen/logrus" -) - -type authHandler struct { - handler http.Handler - clientPool *arvadosclient.ClientPool - cluster *arvados.Cluster -} - -func (h *authHandler) CheckHealth() error { - return nil -} - -func (h *authHandler) Done() <-chan struct{} { - return nil -} - -func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { - var statusCode int - var statusText string - var apiToken string - - w := httpserver.WrapResponseWriter(wOrig) - - if r.Method == "OPTIONS" { - method := r.Header.Get("Access-Control-Request-Method") - if method != "GET" && method != "POST" { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type") - w.Header().Set("Access-Control-Allow-Methods", "GET, POST") - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Max-Age", "86400") - w.WriteHeader(http.StatusOK) - return - } - - if r.Header.Get("Origin") != "" { - // Allow simple cross-origin requests without user - // credentials ("user credentials" as defined by CORS, - // i.e., cookies, HTTP authentication, and client-side - // SSL certificates. See - // http://www.w3.org/TR/cors/#user-credentials). - w.Header().Set("Access-Control-Allow-Origin", "*") - } - - defer func() { - if w.WroteStatus() == 0 { - // Nobody has called WriteHeader yet: that - // must be our job. - w.WriteHeader(statusCode) - if statusCode >= 400 { - w.Write([]byte(statusText)) - } - } - }() - - creds := auth.CredentialsFromRequest(r) - if len(creds.Tokens) == 0 { - statusCode, statusText = http.StatusUnauthorized, "no credentials provided" - w.Header().Add("WWW-Authenticate", "Basic realm=\"git\"") - return - } - apiToken = creds.Tokens[0] - - // Access to paths "/foo/bar.git/*" and "/foo/bar/.git/*" are - // protected by the permissions on the repository named - // "foo/bar". - pathParts := strings.SplitN(r.URL.Path[1:], ".git/", 2) - if len(pathParts) != 2 { - statusCode, statusText = http.StatusNotFound, "not found" - return - } - repoName := pathParts[0] - repoName = strings.TrimRight(repoName, "/") - httpserver.SetResponseLogFields(r.Context(), logrus.Fields{ - "repoName": repoName, - }) - - arv := h.clientPool.Get() - if arv == nil { - statusCode, statusText = http.StatusInternalServerError, "connection pool failed: "+h.clientPool.Err().Error() - return - } - defer h.clientPool.Put(arv) - - // Log the UUID if the supplied token is a v2 token, otherwise - // just the last five characters. - httpserver.SetResponseLogFields(r.Context(), logrus.Fields{ - "tokenUUID": func() string { - if strings.HasPrefix(apiToken, "v2/") && strings.IndexRune(apiToken[3:], '/') == 27 { - // UUID part of v2 token - return apiToken[3:30] - } else if len(apiToken) > 5 { - return "[...]" + apiToken[len(apiToken)-5:] - } else { - return apiToken - } - }(), - }) - - // Ask API server whether the repository is readable using - // this token (by trying to read it!) - arv.ApiToken = apiToken - repoUUID, err := h.lookupRepo(arv, repoName) - if err != nil { - statusCode, statusText = http.StatusInternalServerError, err.Error() - return - } - if repoUUID == "" { - statusCode, statusText = http.StatusNotFound, "not found" - return - } - - isWrite := strings.HasSuffix(r.URL.Path, "/git-receive-pack") - if !isWrite { - statusText = "read" - } else { - err := arv.Update("repositories", repoUUID, arvadosclient.Dict{ - "repository": arvadosclient.Dict{ - "modified_at": time.Now().String(), - }, - }, &arvadosclient.Dict{}) - if err != nil { - statusCode, statusText = http.StatusForbidden, err.Error() - return - } - statusText = "write" - } - - // Regardless of whether the client asked for "/foo.git" or - // "/foo/.git", we choose whichever variant exists in our repo - // root, and we try {uuid}.git and {uuid}/.git first. If none - // of these exist, we 404 even though the API told us the repo - // _should_ exist (presumably this means the repo was just - // created, and gitolite sync hasn't run yet). - rewrittenPath := "" - tryDirs := []string{ - "/" + repoUUID + ".git", - "/" + repoUUID + "/.git", - "/" + repoName + ".git", - "/" + repoName + "/.git", - } - for _, dir := range tryDirs { - if fileInfo, err := os.Stat(h.cluster.Git.Repositories + dir); err != nil { - if !os.IsNotExist(err) { - statusCode, statusText = http.StatusInternalServerError, err.Error() - return - } - } else if fileInfo.IsDir() { - rewrittenPath = dir + "/" + pathParts[1] - break - } - } - if rewrittenPath == "" { - log.Println("WARNING:", repoUUID, - "git directory not found in", h.cluster.Git.Repositories, tryDirs) - // We say "content not found" to disambiguate from the - // earlier "API says that repo does not exist" error. - statusCode, statusText = http.StatusNotFound, "content not found" - return - } - r.URL.Path = rewrittenPath - - h.handler.ServeHTTP(w, r) -} - -var uuidRegexp = regexp.MustCompile(`^[0-9a-z]{5}-s0uqq-[0-9a-z]{15}$`) - -func (h *authHandler) lookupRepo(arv *arvadosclient.ArvadosClient, repoName string) (string, error) { - reposFound := arvadosclient.Dict{} - var column string - if uuidRegexp.MatchString(repoName) { - column = "uuid" - } else { - column = "name" - } - err := arv.List("repositories", arvadosclient.Dict{ - "filters": [][]string{{column, "=", repoName}}, - }, &reposFound) - if err != nil { - return "", err - } else if avail, ok := reposFound["items_available"].(float64); !ok { - return "", errors.New("bad list response from API") - } else if avail < 1 { - return "", nil - } else if avail > 1 { - return "", errors.New("name collision") - } - return reposFound["items"].([]interface{})[0].(map[string]interface{})["uuid"].(string), nil -} diff --git a/services/githttpd/auth_handler_test.go b/services/githttpd/auth_handler_test.go deleted file mode 100644 index 2d1ec966a4..0000000000 --- a/services/githttpd/auth_handler_test.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "io" - "log" - "net/http" - "net/http/httptest" - "net/url" - "path/filepath" - "strings" - - "git.arvados.org/arvados.git/lib/config" - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/arvadosclient" - "git.arvados.org/arvados.git/sdk/go/arvadostest" - "git.arvados.org/arvados.git/sdk/go/ctxlog" - check "gopkg.in/check.v1" -) - -var _ = check.Suite(&AuthHandlerSuite{}) - -type AuthHandlerSuite struct { - cluster *arvados.Cluster -} - -func (s *AuthHandlerSuite) SetUpTest(c *check.C) { - arvadostest.ResetEnv() - repoRoot, err := filepath.Abs("../api/tmp/git/test") - c.Assert(err, check.IsNil) - - cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load() - c.Assert(err, check.Equals, nil) - s.cluster, err = cfg.GetCluster("") - c.Assert(err, check.Equals, nil) - - s.cluster.Services.GitHTTP.InternalURLs = map[arvados.URL]arvados.ServiceInstance{{Host: "localhost:0"}: {}} - s.cluster.TLS.Insecure = true - s.cluster.Git.GitCommand = "/usr/bin/git" - s.cluster.Git.Repositories = repoRoot -} - -func (s *AuthHandlerSuite) TestPermission(c *check.C) { - client, err := arvados.NewClientFromConfig(s.cluster) - c.Assert(err, check.IsNil) - ac, err := arvadosclient.New(client) - c.Assert(err, check.IsNil) - h := &authHandler{ - cluster: s.cluster, - clientPool: &arvadosclient.ClientPool{Prototype: ac}, - handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Printf("%v", r.URL) - io.WriteString(w, r.URL.Path) - }), - } - baseURL, err := url.Parse("http://git.example/") - c.Assert(err, check.IsNil) - for _, trial := range []struct { - label string - token string - pathIn string - pathOut string - status int - }{ - { - label: "read repo by name", - token: arvadostest.ActiveToken, - pathIn: arvadostest.Repository2Name + ".git/git-upload-pack", - pathOut: arvadostest.Repository2UUID + ".git/git-upload-pack", - }, - { - label: "read repo by uuid", - token: arvadostest.ActiveToken, - pathIn: arvadostest.Repository2UUID + ".git/git-upload-pack", - pathOut: arvadostest.Repository2UUID + ".git/git-upload-pack", - }, - { - label: "write repo by name", - token: arvadostest.ActiveToken, - pathIn: arvadostest.Repository2Name + ".git/git-receive-pack", - pathOut: arvadostest.Repository2UUID + ".git/git-receive-pack", - }, - { - label: "write repo by uuid", - token: arvadostest.ActiveToken, - pathIn: arvadostest.Repository2UUID + ".git/git-receive-pack", - pathOut: arvadostest.Repository2UUID + ".git/git-receive-pack", - }, - { - label: "uuid not found", - token: arvadostest.ActiveToken, - pathIn: strings.Replace(arvadostest.Repository2UUID, "6", "z", -1) + ".git/git-upload-pack", - status: http.StatusNotFound, - }, - { - label: "name not found", - token: arvadostest.ActiveToken, - pathIn: "nonexistent-bogus.git/git-upload-pack", - status: http.StatusNotFound, - }, - { - label: "read read-only repo", - token: arvadostest.SpectatorToken, - pathIn: arvadostest.FooRepoName + ".git/git-upload-pack", - pathOut: arvadostest.FooRepoUUID + "/.git/git-upload-pack", - }, - { - label: "write read-only repo", - token: arvadostest.SpectatorToken, - pathIn: arvadostest.FooRepoName + ".git/git-receive-pack", - status: http.StatusForbidden, - }, - } { - c.Logf("trial label: %q", trial.label) - u, err := baseURL.Parse(trial.pathIn) - c.Assert(err, check.IsNil) - resp := httptest.NewRecorder() - req := &http.Request{ - Method: "POST", - URL: u, - Header: http.Header{ - "Authorization": {"Bearer " + trial.token}}} - h.ServeHTTP(resp, req) - if trial.status == 0 { - trial.status = http.StatusOK - } - c.Check(resp.Code, check.Equals, trial.status) - if trial.status < 400 { - if trial.pathOut != "" && !strings.HasPrefix(trial.pathOut, "/") { - trial.pathOut = "/" + trial.pathOut - } - c.Check(resp.Body.String(), check.Equals, trial.pathOut) - } - } -} - -func (s *AuthHandlerSuite) TestCORS(c *check.C) { - h := &authHandler{cluster: s.cluster} - - // CORS preflight - resp := httptest.NewRecorder() - req := &http.Request{ - Method: "OPTIONS", - Header: http.Header{ - "Origin": {"*"}, - "Access-Control-Request-Method": {"GET"}, - }, - } - h.ServeHTTP(resp, req) - c.Check(resp.Code, check.Equals, http.StatusOK) - c.Check(resp.Header().Get("Access-Control-Allow-Methods"), check.Equals, "GET, POST") - c.Check(resp.Header().Get("Access-Control-Allow-Headers"), check.Equals, "Authorization, Content-Type") - c.Check(resp.Header().Get("Access-Control-Allow-Origin"), check.Equals, "*") - c.Check(resp.Body.String(), check.Equals, "") - - // CORS actual request. Bogus token and path ensure - // authHandler responds 4xx without calling our wrapped (nil) - // handler. - u, err := url.Parse("git.zzzzz.arvadosapi.com/test") - c.Assert(err, check.Equals, nil) - resp = httptest.NewRecorder() - req = &http.Request{ - Method: "GET", - URL: u, - Header: http.Header{ - "Origin": {"*"}, - "Authorization": {"OAuth2 foobar"}, - }, - } - h.ServeHTTP(resp, req) - c.Check(resp.Header().Get("Access-Control-Allow-Origin"), check.Equals, "*") -} diff --git a/services/githttpd/cmd.go b/services/githttpd/cmd.go deleted file mode 100644 index e6ca3c0743..0000000000 --- a/services/githttpd/cmd.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "context" - - "git.arvados.org/arvados.git/lib/service" - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/arvadosclient" - "github.com/prometheus/client_golang/prometheus" -) - -var Command = service.Command(arvados.ServiceNameGitHTTP, newHandler) - -func newHandler(ctx context.Context, cluster *arvados.Cluster, token string, reg *prometheus.Registry) service.Handler { - client, err := arvados.NewClientFromConfig(cluster) - if err != nil { - return service.ErrorHandler(ctx, cluster, err) - } - ac, err := arvadosclient.New(client) - if err != nil { - return service.ErrorHandler(ctx, cluster, err) - } - return &authHandler{ - clientPool: &arvadosclient.ClientPool{Prototype: ac}, - cluster: cluster, - handler: newGitHandler(ctx, cluster), - } -} diff --git a/services/githttpd/git_handler.go b/services/githttpd/git_handler.go deleted file mode 100644 index 7c94294c04..0000000000 --- a/services/githttpd/git_handler.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "context" - "net" - "net/http" - "net/http/cgi" - "os" - - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/ctxlog" -) - -// gitHandler is an http.Handler that invokes git-http-backend (or -// whatever backend is configured) via CGI, with appropriate -// environment variables in place for git-http-backend or -// gitolite-shell. -type gitHandler struct { - cgi.Handler -} - -func newGitHandler(ctx context.Context, cluster *arvados.Cluster) http.Handler { - const glBypass = "GL_BYPASS_ACCESS_CHECKS" - const glHome = "GITOLITE_HTTP_HOME" - var env []string - path := os.Getenv("PATH") - if cluster.Git.GitoliteHome != "" { - env = append(env, - glHome+"="+cluster.Git.GitoliteHome, - glBypass+"=1") - path = path + ":" + cluster.Git.GitoliteHome + "/bin" - } else if home, bypass := os.Getenv(glHome), os.Getenv(glBypass); home != "" || bypass != "" { - env = append(env, glHome+"="+home, glBypass+"="+bypass) - ctxlog.FromContext(ctx).Printf("DEPRECATED: Passing through %s and %s environment variables. Use GitoliteHome configuration instead.", glHome, glBypass) - } - - var listen arvados.URL - for listen = range cluster.Services.GitHTTP.InternalURLs { - break - } - env = append(env, - "GIT_PROJECT_ROOT="+cluster.Git.Repositories, - "GIT_HTTP_EXPORT_ALL=", - "SERVER_ADDR="+listen.Host, - "PATH="+path) - return &gitHandler{ - Handler: cgi.Handler{ - Path: cluster.Git.GitCommand, - Dir: cluster.Git.Repositories, - Env: env, - Args: []string{"http-backend"}, - }, - } -} - -func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - remoteHost, remotePort, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - ctxlog.FromContext(r.Context()).Errorf("Internal error: SplitHostPort(r.RemoteAddr==%q): %s", r.RemoteAddr, err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - // Copy the wrapped cgi.Handler, so these request-specific - // variables don't leak into the next request. - handlerCopy := h.Handler - handlerCopy.Env = append(handlerCopy.Env, - // In Go1.5 we can skip this, net/http/cgi will do it for us: - "REMOTE_HOST="+remoteHost, - "REMOTE_ADDR="+remoteHost, - "REMOTE_PORT="+remotePort, - // Ideally this would be a real username: - "REMOTE_USER="+r.RemoteAddr, - ) - handlerCopy.ServeHTTP(w, r) -} diff --git a/services/githttpd/git_handler_test.go b/services/githttpd/git_handler_test.go deleted file mode 100644 index ef2ee28e79..0000000000 --- a/services/githttpd/git_handler_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "context" - "net/http" - "net/http/httptest" - "net/url" - "regexp" - - "git.arvados.org/arvados.git/lib/config" - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/ctxlog" - check "gopkg.in/check.v1" -) - -var _ = check.Suite(&GitHandlerSuite{}) - -type GitHandlerSuite struct { - cluster *arvados.Cluster -} - -func (s *GitHandlerSuite) SetUpTest(c *check.C) { - cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load() - c.Assert(err, check.Equals, nil) - s.cluster, err = cfg.GetCluster("") - c.Assert(err, check.Equals, nil) - - s.cluster.Services.GitHTTP.InternalURLs = map[arvados.URL]arvados.ServiceInstance{{Host: "localhost:80"}: {}} - s.cluster.Git.GitoliteHome = "/test/ghh" - s.cluster.Git.Repositories = "/" -} - -func (s *GitHandlerSuite) TestEnvVars(c *check.C) { - u, err := url.Parse("git.zzzzz.arvadosapi.com/test") - c.Check(err, check.Equals, nil) - resp := httptest.NewRecorder() - req := &http.Request{ - Method: "GET", - URL: u, - RemoteAddr: "[::1]:12345", - } - h := newGitHandler(context.Background(), s.cluster) - h.(*gitHandler).Path = "/bin/sh" - h.(*gitHandler).Args = []string{"-c", "printf 'Content-Type: text/plain\r\n\r\n'; env"} - - h.ServeHTTP(resp, req) - - c.Check(resp.Code, check.Equals, http.StatusOK) - body := resp.Body.String() - c.Check(body, check.Matches, `(?ms).*^PATH=.*:/test/ghh/bin$.*`) - c.Check(body, check.Matches, `(?ms).*^GITOLITE_HTTP_HOME=/test/ghh$.*`) - c.Check(body, check.Matches, `(?ms).*^GL_BYPASS_ACCESS_CHECKS=1$.*`) - c.Check(body, check.Matches, `(?ms).*^REMOTE_HOST=::1$.*`) - c.Check(body, check.Matches, `(?ms).*^REMOTE_PORT=12345$.*`) - c.Check(body, check.Matches, `(?ms).*^SERVER_ADDR=`+regexp.QuoteMeta("localhost:80")+`$.*`) -} - -func (s *GitHandlerSuite) TestCGIErrorOnSplitHostPortError(c *check.C) { - u, err := url.Parse("git.zzzzz.arvadosapi.com/test") - c.Check(err, check.Equals, nil) - resp := httptest.NewRecorder() - req := &http.Request{ - Method: "GET", - URL: u, - RemoteAddr: "test.bad.address.missing.port", - } - h := newGitHandler(context.Background(), s.cluster) - h.ServeHTTP(resp, req) - c.Check(resp.Code, check.Equals, http.StatusInternalServerError) - c.Check(resp.Body.String(), check.Equals, "") -} diff --git a/services/githttpd/gitolite_test.go b/services/githttpd/gitolite_test.go deleted file mode 100644 index d34c413c1b..0000000000 --- a/services/githttpd/gitolite_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "io/ioutil" - "os" - "os/exec" - "strings" - - "git.arvados.org/arvados.git/lib/config" - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/ctxlog" - check "gopkg.in/check.v1" -) - -var _ = check.Suite(&GitoliteSuite{}) - -// GitoliteSuite tests need an API server, an arvados-git-httpd -// server, and a repository hosted by gitolite. -type GitoliteSuite struct { - IntegrationSuite - gitoliteHome string -} - -func (s *GitoliteSuite) SetUpTest(c *check.C) { - var err error - s.gitoliteHome, err = ioutil.TempDir("", "githttp") - c.Assert(err, check.Equals, nil) - - runGitolite := func(prog string, args ...string) { - c.Log(prog, " ", args) - cmd := exec.Command(prog, args...) - cmd.Dir = s.gitoliteHome - cmd.Env = []string{"HOME=" + s.gitoliteHome} - for _, e := range os.Environ() { - if !strings.HasPrefix(e, "HOME=") { - cmd.Env = append(cmd.Env, e) - } - } - diags, err := cmd.CombinedOutput() - c.Log(string(diags)) - c.Assert(err, check.Equals, nil) - } - - runGitolite("gitolite", "setup", "--admin", "root") - - s.tmpRepoRoot = s.gitoliteHome + "/repositories" - - cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load() - c.Assert(err, check.Equals, nil) - s.cluster, err = cfg.GetCluster("") - c.Assert(err, check.Equals, nil) - - s.cluster.Services.GitHTTP.InternalURLs = map[arvados.URL]arvados.ServiceInstance{{Host: "localhost:0"}: {}} - s.cluster.TLS.Insecure = true - s.cluster.Git.GitCommand = "/usr/share/gitolite3/gitolite-shell" - s.cluster.Git.GitoliteHome = s.gitoliteHome - s.cluster.Git.Repositories = s.tmpRepoRoot - - s.IntegrationSuite.SetUpTest(c) - - // Install the gitolite hooks in the bare repo we made in - // (*IntegrationTest)SetUpTest() -- see 2.2.4 at - // http://gitolite.com/gitolite/gitolite.html - runGitolite("gitolite", "setup") -} - -func (s *GitoliteSuite) TearDownTest(c *check.C) { - // We really want Unsetenv here, but it's not worth forcing an - // upgrade to Go 1.4. - os.Setenv("GITOLITE_HTTP_HOME", "") - os.Setenv("GL_BYPASS_ACCESS_CHECKS", "") - if s.gitoliteHome != "" { - err := os.RemoveAll(s.gitoliteHome) - c.Check(err, check.Equals, nil) - } - s.IntegrationSuite.TearDownTest(c) -} - -func (s *GitoliteSuite) TestFetch(c *check.C) { - err := s.RunGit(c, activeToken, "fetch", "active/foo.git", "refs/heads/main") - c.Check(err, check.Equals, nil) -} - -func (s *GitoliteSuite) TestFetchUnreadable(c *check.C) { - err := s.RunGit(c, anonymousToken, "fetch", "active/foo.git") - c.Check(err, check.ErrorMatches, `.* not found.*`) -} - -func (s *GitoliteSuite) TestPush(c *check.C) { - err := s.RunGit(c, activeToken, "push", "active/foo.git", "main:gitolite-push") - c.Check(err, check.Equals, nil) - - // Check that the commit hash appears in the gitolite log, as - // assurance that the gitolite hooks really did run. - - sha1, err := exec.Command("git", "--git-dir", s.tmpWorkdir+"/.git", - "log", "-n1", "--format=%H").CombinedOutput() - c.Logf("git-log in workdir: %q", string(sha1)) - c.Assert(err, check.Equals, nil) - c.Assert(len(sha1), check.Equals, 41) - - gitoliteLog, err := exec.Command("grep", "-r", string(sha1[:40]), s.gitoliteHome+"/.gitolite/logs").CombinedOutput() - c.Check(err, check.Equals, nil) - c.Logf("gitolite log message: %q", string(gitoliteLog)) -} - -func (s *GitoliteSuite) TestPushUnwritable(c *check.C) { - err := s.RunGit(c, spectatorToken, "push", "active/foo.git", "main:gitolite-push-fail") - c.Check(err, check.ErrorMatches, `.*HTTP (code = )?403.*`) -} diff --git a/services/githttpd/integration_test.go b/services/githttpd/integration_test.go deleted file mode 100644 index c819272d3e..0000000000 --- a/services/githttpd/integration_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "context" - "errors" - "io/ioutil" - "os" - "os/exec" - "strings" - "testing" - - "git.arvados.org/arvados.git/lib/config" - "git.arvados.org/arvados.git/sdk/go/arvados" - "git.arvados.org/arvados.git/sdk/go/arvadostest" - "git.arvados.org/arvados.git/sdk/go/ctxlog" - "git.arvados.org/arvados.git/sdk/go/httpserver" - check "gopkg.in/check.v1" -) - -// Gocheck boilerplate -func Test(t *testing.T) { - check.TestingT(t) -} - -// IntegrationSuite tests need an API server and an arvados-git-httpd -// server. See GitSuite and GitoliteSuite. -type IntegrationSuite struct { - tmpRepoRoot string - tmpWorkdir string - testServer *httpserver.Server - cluster *arvados.Cluster -} - -func (s *IntegrationSuite) SetUpTest(c *check.C) { - arvadostest.ResetEnv() - - var err error - if s.tmpRepoRoot == "" { - s.tmpRepoRoot, err = ioutil.TempDir("", "githttp") - c.Assert(err, check.Equals, nil) - } - s.tmpWorkdir, err = ioutil.TempDir("", "githttp") - c.Assert(err, check.Equals, nil) - _, err = exec.Command("git", "init", "--bare", s.tmpRepoRoot+"/zzzzz-s0uqq-382brsig8rp3666.git").Output() - c.Assert(err, check.Equals, nil) - // we need git 2.28 to specify the initial branch with -b; Buster only has 2.20; so we do it in 2 steps - _, err = exec.Command("git", "init", s.tmpWorkdir).Output() - c.Assert(err, check.Equals, nil) - _, err = exec.Command("sh", "-c", "cd "+s.tmpWorkdir+" && git checkout -b main").Output() - c.Assert(err, check.Equals, nil) - _, err = exec.Command("sh", "-c", "cd "+s.tmpWorkdir+" && echo initial >initial && git add initial && git -c user.name=Initial -c user.email=Initial commit -am 'foo: initial commit'").CombinedOutput() - c.Assert(err, check.Equals, nil) - _, err = exec.Command("sh", "-c", "cd "+s.tmpWorkdir+" && git push "+s.tmpRepoRoot+"/zzzzz-s0uqq-382brsig8rp3666.git main:main").CombinedOutput() - c.Assert(err, check.Equals, nil) - _, err = exec.Command("sh", "-c", "cd "+s.tmpWorkdir+" && echo work >work && git add work && git -c user.name=Foo -c user.email=Foo commit -am 'workdir: test'").CombinedOutput() - c.Assert(err, check.Equals, nil) - - if s.cluster == nil { - cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load() - c.Assert(err, check.Equals, nil) - s.cluster, err = cfg.GetCluster("") - c.Assert(err, check.Equals, nil) - - s.cluster.Services.GitHTTP.InternalURLs = map[arvados.URL]arvados.ServiceInstance{{Host: "localhost:0"}: {}} - s.cluster.TLS.Insecure = true - s.cluster.Git.GitCommand = "/usr/bin/git" - s.cluster.Git.Repositories = s.tmpRepoRoot - s.cluster.ManagementToken = arvadostest.ManagementToken - } - - s.testServer = &httpserver.Server{} - s.testServer.Handler = httpserver.LogRequests(newHandler(context.Background(), s.cluster, "", nil)) - err = s.testServer.Start() - c.Assert(err, check.Equals, nil) - - _, err = exec.Command("git", "config", - "--file", s.tmpWorkdir+"/.git/config", - "credential.http://"+s.testServer.Addr+"/.helper", - "!cred(){ cat >/dev/null; if [ \"$1\" = get ]; then echo password=$ARVADOS_API_TOKEN; fi; };cred").Output() - c.Assert(err, check.Equals, nil) - _, err = exec.Command("git", "config", - "--file", s.tmpWorkdir+"/.git/config", - "credential.http://"+s.testServer.Addr+"/.username", - "none").Output() - c.Assert(err, check.Equals, nil) - - // Clear ARVADOS_API_* env vars before starting up the server, - // to make sure arvados-git-httpd doesn't use them or complain - // about them being missing. - os.Unsetenv("ARVADOS_API_HOST") - os.Unsetenv("ARVADOS_API_HOST_INSECURE") - os.Unsetenv("ARVADOS_API_TOKEN") -} - -func (s *IntegrationSuite) TearDownTest(c *check.C) { - var err error - if s.testServer != nil { - err = s.testServer.Close() - } - c.Check(err, check.Equals, nil) - s.testServer = nil - - if s.tmpRepoRoot != "" { - err = os.RemoveAll(s.tmpRepoRoot) - c.Check(err, check.Equals, nil) - } - s.tmpRepoRoot = "" - - if s.tmpWorkdir != "" { - err = os.RemoveAll(s.tmpWorkdir) - c.Check(err, check.Equals, nil) - } - s.tmpWorkdir = "" - - s.cluster = nil -} - -func (s *IntegrationSuite) RunGit(c *check.C, token, gitCmd, repo string, args ...string) error { - cwd, err := os.Getwd() - c.Assert(err, check.Equals, nil) - defer os.Chdir(cwd) - os.Chdir(s.tmpWorkdir) - - gitargs := append([]string{ - gitCmd, "http://" + s.testServer.Addr + "/" + repo, - }, args...) - cmd := exec.Command("git", gitargs...) - cmd.Env = append(os.Environ(), "ARVADOS_API_TOKEN="+token) - w, err := cmd.StdinPipe() - c.Assert(err, check.Equals, nil) - w.Close() - output, err := cmd.CombinedOutput() - c.Log("git ", gitargs, " => ", err) - c.Log(string(output)) - if err != nil && len(output) > 0 { - // If messages appeared on stderr, they are more - // helpful than the err returned by CombinedOutput(). - // - // Easier to match error strings without newlines: - err = errors.New(strings.Replace(string(output), "\n", " // ", -1)) - } - return err -} diff --git a/services/githttpd/server_test.go b/services/githttpd/server_test.go deleted file mode 100644 index 02c13a3112..0000000000 --- a/services/githttpd/server_test.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -package githttpd - -import ( - "os" - "os/exec" - - check "gopkg.in/check.v1" -) - -var _ = check.Suite(&GitSuite{}) - -const ( - spectatorToken = "zw2f4gwx8hw8cjre7yp6v1zylhrhn3m5gvjq73rtpwhmknrybu" - activeToken = "3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi" - anonymousToken = "4kg6k6lzmp9kj4cpkcoxie964cmvjahbt4fod9zru44k4jqdmi" - expiredToken = "2ym314ysp27sk7h943q6vtc378srb06se3pq6ghurylyf3pdmx" -) - -type GitSuite struct { - IntegrationSuite -} - -func (s *GitSuite) TestPathVariants(c *check.C) { - s.makeArvadosRepo(c) - for _, repo := range []string{"active/foo.git", "active/foo/.git", "arvados.git", "arvados/.git"} { - err := s.RunGit(c, spectatorToken, "fetch", repo, "refs/heads/main") - c.Assert(err, check.Equals, nil) - } -} - -func (s *GitSuite) TestReadonly(c *check.C) { - err := s.RunGit(c, spectatorToken, "fetch", "active/foo.git", "refs/heads/main") - c.Assert(err, check.Equals, nil) - err = s.RunGit(c, spectatorToken, "push", "active/foo.git", "main:newbranchfail") - c.Assert(err, check.ErrorMatches, `.*HTTP (code = )?403.*`) - _, err = os.Stat(s.tmpRepoRoot + "/zzzzz-s0uqq-382brsig8rp3666.git/refs/heads/newbranchfail") - c.Assert(err, check.FitsTypeOf, &os.PathError{}) -} - -func (s *GitSuite) TestReadwrite(c *check.C) { - err := s.RunGit(c, activeToken, "fetch", "active/foo.git", "refs/heads/main") - c.Assert(err, check.Equals, nil) - err = s.RunGit(c, activeToken, "push", "active/foo.git", "main:newbranch") - c.Assert(err, check.Equals, nil) - _, err = os.Stat(s.tmpRepoRoot + "/zzzzz-s0uqq-382brsig8rp3666.git/refs/heads/newbranch") - c.Assert(err, check.Equals, nil) -} - -func (s *GitSuite) TestNonexistent(c *check.C) { - err := s.RunGit(c, spectatorToken, "fetch", "thisrepodoesnotexist.git", "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* not found.*`) -} - -func (s *GitSuite) TestMissingGitdirReadableRepository(c *check.C) { - err := s.RunGit(c, activeToken, "fetch", "active/foo2.git", "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* not found.*`) -} - -func (s *GitSuite) TestNoPermission(c *check.C) { - for _, repo := range []string{"active/foo.git", "active/foo/.git"} { - err := s.RunGit(c, anonymousToken, "fetch", repo, "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* not found.*`) - } -} - -func (s *GitSuite) TestExpiredToken(c *check.C) { - for _, repo := range []string{"active/foo.git", "active/foo/.git"} { - err := s.RunGit(c, expiredToken, "fetch", repo, "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* (500 while accessing|requested URL returned error: 500).*`) - } -} - -func (s *GitSuite) TestInvalidToken(c *check.C) { - for _, repo := range []string{"active/foo.git", "active/foo/.git"} { - err := s.RunGit(c, "s3cr3tp@ssw0rd", "fetch", repo, "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* requested URL returned error.*`) - } -} - -func (s *GitSuite) TestShortToken(c *check.C) { - for _, repo := range []string{"active/foo.git", "active/foo/.git"} { - err := s.RunGit(c, "s3cr3t", "fetch", repo, "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.* (500 while accessing|requested URL returned error: 500).*`) - } -} - -func (s *GitSuite) TestShortTokenBadReq(c *check.C) { - for _, repo := range []string{"bogus"} { - err := s.RunGit(c, "s3cr3t", "fetch", repo, "refs/heads/main") - c.Assert(err, check.ErrorMatches, `.*not found.*`) - } -} - -// Make a bare arvados repo at {tmpRepoRoot}/arvados.git -func (s *GitSuite) makeArvadosRepo(c *check.C) { - msg, err := exec.Command("git", "init", "--bare", s.tmpRepoRoot+"/zzzzz-s0uqq-arvadosrepo0123.git").CombinedOutput() - c.Log(string(msg)) - c.Assert(err, check.Equals, nil) - msg, err = exec.Command("git", "--git-dir", s.tmpRepoRoot+"/zzzzz-s0uqq-arvadosrepo0123.git", "fetch", "../../.git", "HEAD:main").CombinedOutput() - c.Log(string(msg)) - c.Assert(err, check.Equals, nil) -} diff --git a/services/workbench2/cypress/e2e/search.cy.js b/services/workbench2/cypress/e2e/search.cy.js index 094a3f618c..4e5aa31f4d 100644 --- a/services/workbench2/cypress/e2e/search.cy.js +++ b/services/workbench2/cypress/e2e/search.cy.js @@ -215,8 +215,6 @@ describe("Search tests", function () { DispatchCloud: { ExternalURL: "" }, DispatchLSF: { ExternalURL: "" }, DispatchSLURM: { ExternalURL: "" }, - GitHTTP: { ExternalURL: "https://xxxxx.fakecluster.tld:39105/" }, - GitSSH: { ExternalURL: "" }, Health: { ExternalURL: "https://xxxxx.fakecluster.tld:42915/" }, Keepbalance: { ExternalURL: "" }, Keepproxy: { ExternalURL: "https://xxxxx.fakecluster.tld:46773/" }, diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.base b/tools/arvbox/lib/arvbox/docker/Dockerfile.base index d8b2408831..927b975f8f 100644 --- a/tools/arvbox/lib/arvbox/docker/Dockerfile.base +++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.base @@ -137,8 +137,7 @@ RUN echo arvados_version is git commit $arvados_version COPY $workdir/fuse.conf /etc/ -COPY $workdir/gitolite.rc \ - $workdir/keep-setup.sh $workdir/common.sh $workdir/createusers.sh \ +COPY $workdir/keep-setup.sh $workdir/common.sh $workdir/createusers.sh \ $workdir/logger $workdir/runsu.sh $workdir/waitforpostgres.sh \ $workdir/yml_override.py $workdir/api-setup.sh \ $workdir/go-setup.sh $workdir/devenv.sh $workdir/cluster-config.sh $workdir/edit_users.py \ diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo index 81a5369f5e..dfbeaa448c 100644 --- a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo +++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo @@ -37,7 +37,6 @@ RUN sudo -u arvbox /var/lib/arvbox/service/keep-web/run-service --only-deps RUN sudo -u arvbox /var/lib/arvbox/service/doc/run-service --only-deps 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/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 diff --git a/tools/arvbox/lib/arvbox/docker/api-setup.sh b/tools/arvbox/lib/arvbox/docker/api-setup.sh index 29cea1ecbe..b2d20a455c 100755 --- a/tools/arvbox/lib/arvbox/docker/api-setup.sh +++ b/tools/arvbox/lib/arvbox/docker/api-setup.sh @@ -38,8 +38,6 @@ $RAILS_ENV: blob_signing_key: $blob_signing_key workbench_address: "https://$localip/" websocket_address: "wss://$localip:${services[websockets-ssl]}/websocket" - git_repo_ssh_base: "git@$localip:" - git_repo_https_base: "http://$localip:${services[arv-git-httpd]}/" new_users_are_active: true auto_admin_first_user: true auto_setup_new_users: true diff --git a/tools/arvbox/lib/arvbox/docker/cluster-config.sh b/tools/arvbox/lib/arvbox/docker/cluster-config.sh index 9b55181c91..d07fc3d34d 100755 --- a/tools/arvbox/lib/arvbox/docker/cluster-config.sh +++ b/tools/arvbox/lib/arvbox/docker/cluster-config.sh @@ -87,12 +87,6 @@ Clusters: ExternalURL: "wss://$localip:${services[websockets-ssl]}/websocket" InternalURLs: "http://localhost:${services[websockets]}": {} - GitSSH: - ExternalURL: "ssh://git@$localip:" - GitHTTP: - InternalURLs: - "http://localhost:${services[arv-git-httpd]}/": {} - ExternalURL: "https://$localip:${services[arv-git-httpd-ssl]}/" WebDAV: InternalURLs: "http://localhost:${services[keep-web]}/": {} @@ -132,11 +126,6 @@ Clusters: AutoAdminFirstUser: true AutoSetupNewUsers: true AutoSetupNewUsersWithVmUUID: $vm_uuid - AutoSetupNewUsersWithRepository: true - Git: - GitCommand: /usr/share/gitolite3/gitolite-shell - GitoliteHome: $ARVADOS_CONTAINER_PATH/git - Repositories: $ARVADOS_CONTAINER_PATH/git/repositories Volumes: ${uuid_prefix}-nyw5e-000000000000000: Driver: Directory diff --git a/tools/arvbox/lib/arvbox/docker/common.sh b/tools/arvbox/lib/arvbox/docker/common.sh index 40a540ac80..2232b63c4f 100644 --- a/tools/arvbox/lib/arvbox/docker/common.sh +++ b/tools/arvbox/lib/arvbox/docker/common.sh @@ -37,8 +37,6 @@ services=( [api]=8004 [controller]=8003 [controller-ssl]=8000 - [arv-git-httpd-ssl]=9000 - [arv-git-httpd]=9001 [keep-web]=9003 [keep-web-ssl]=9002 [keep-web-dl-ssl]=9004 diff --git a/tools/arvbox/lib/arvbox/docker/gitolite.rc b/tools/arvbox/lib/arvbox/docker/gitolite.rc deleted file mode 100644 index 07a9ce0d44..0000000000 --- a/tools/arvbox/lib/arvbox/docker/gitolite.rc +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (C) The Arvados Authors. All rights reserved. -# -# SPDX-License-Identifier: AGPL-3.0 - -# This is based on the default Gitolite configuration file with the following -# changes applied as described here: -# http://doc.arvados.org/install/install-arv-git-httpd.html - -# configuration variables for gitolite - -# This file is in perl syntax. But you do NOT need to know perl to edit it -- -# just mind the commas, use single quotes unless you know what you're doing, -# and make sure the brackets and braces stay matched up! - -# (Tip: perl allows a comma after the last item in a list also!) - -# HELP for commands can be had by running the command with "-h". - -# HELP for all the other FEATURES can be found in the documentation (look for -# "list of non-core programs shipped with gitolite" in the master index) or -# directly in the corresponding source file. - -my $repo_aliases; -my $aliases_src = "$ENV{HOME}/.gitolite/arvadosaliases.pl"; -if ($ENV{HOME} && (-e $aliases_src)) { - $repo_aliases = do $aliases_src; -} -$repo_aliases ||= {}; - -%RC = ( - - REPO_ALIASES => $repo_aliases, - - # ------------------------------------------------------------------ - - # default umask gives you perms of '0700'; see the rc file docs for - # how/why you might change this - UMASK => 0022, - - # look for "git-config" in the documentation - GIT_CONFIG_KEYS => '', - - # comment out if you don't need all the extra detail in the logfile - LOG_EXTRA => 1, - # logging options - # 1. leave this section as is for 'normal' gitolite logging (default) - # 2. uncomment this line to log ONLY to syslog: - # LOG_DEST => 'syslog', - # 3. uncomment this line to log to syslog and the normal gitolite log: - # LOG_DEST => 'syslog,normal', - # 4. prefixing "repo-log," to any of the above will **also** log just the - # update records to "gl-log" in the bare repo directory: - # LOG_DEST => 'repo-log,normal', - # LOG_DEST => 'repo-log,syslog', - # LOG_DEST => 'repo-log,syslog,normal', - - # roles. add more roles (like MANAGER, TESTER, ...) here. - # WARNING: if you make changes to this hash, you MUST run 'gitolite - # compile' afterward, and possibly also 'gitolite trigger POST_COMPILE' - ROLES => { - READERS => 1, - WRITERS => 1, - }, - - # enable caching (currently only Redis). PLEASE RTFM BEFORE USING!!! - # CACHE => 'Redis', - - # ------------------------------------------------------------------ - - # rc variables used by various features - - # the 'info' command prints this as additional info, if it is set - # SITE_INFO => 'Please see http://blahblah/gitolite for more help', - - # the CpuTime feature uses these - # display user, system, and elapsed times to user after each git operation - # DISPLAY_CPU_TIME => 1, - # display a warning if total CPU times (u, s, cu, cs) crosses this limit - # CPU_TIME_WARN_LIMIT => 0.1, - - # the Mirroring feature needs this - # HOSTNAME => "foo", - - # TTL for redis cache; PLEASE SEE DOCUMENTATION BEFORE UNCOMMENTING! - # CACHE_TTL => 600, - - # ------------------------------------------------------------------ - - # suggested locations for site-local gitolite code (see cust.html) - - # this one is managed directly on the server - # LOCAL_CODE => "$ENV{HOME}/local", - - # or you can use this, which lets you put everything in a subdirectory - # called "local" in your gitolite-admin repo. For a SECURITY WARNING - # on this, see http://gitolite.com/gitolite/non-core.html#pushcode - # LOCAL_CODE => "$rc{GL_ADMIN_BASE}/local", - - # ------------------------------------------------------------------ - - # List of commands and features to enable - - ENABLE => [ - - # COMMANDS - - # These are the commands enabled by default - 'help', - 'desc', - 'info', - 'perms', - 'writable', - - # Uncomment or add new commands here. - # 'create', - # 'fork', - # 'mirror', - # 'readme', - # 'sskm', - # 'D', - - # These FEATURES are enabled by default. - - # essential (unless you're using smart-http mode) - 'ssh-authkeys', - - # creates git-config enties from gitolite.conf file entries like 'config foo.bar = baz' - 'git-config', - - # creates git-daemon-export-ok files; if you don't use git-daemon, comment this out - 'daemon', - - # creates projects.list file; if you don't use gitweb, comment this out - 'gitweb', - - # These FEATURES are disabled by default; uncomment to enable. If you - # need to add new ones, ask on the mailing list :-) - - # user-visible behaviour - - # prevent wild repos auto-create on fetch/clone - # 'no-create-on-read', - # no auto-create at all (don't forget to enable the 'create' command!) - # 'no-auto-create', - - # access a repo by another (possibly legacy) name - 'Alias', - - # give some users direct shell access. See documentation in - # sts.html for details on the following two choices. - # "Shell $ENV{HOME}/.gitolite.shell-users", - # 'Shell alice bob', - - # set default roles from lines like 'option default.roles-1 = ...', etc. - # 'set-default-roles', - - # show more detailed messages on deny - # 'expand-deny-messages', - - # show a message of the day - # 'Motd', - - # system admin stuff - - # enable mirroring (don't forget to set the HOSTNAME too!) - # 'Mirroring', - - # allow people to submit pub files with more than one key in them - # 'ssh-authkeys-split', - - # selective read control hack - # 'partial-copy', - - # manage local, gitolite-controlled, copies of read-only upstream repos - # 'upstream', - - # updates 'description' file instead of 'gitweb.description' config item - # 'cgit', - - # allow repo-specific hooks to be added - # 'repo-specific-hooks', - - # performance, logging, monitoring... - - # be nice - # 'renice 10', - - # log CPU times (user, system, cumulative user, cumulative system) - # 'CpuTime', - - # syntactic_sugar for gitolite.conf and included files - - # allow backslash-escaped continuation lines in gitolite.conf - # 'continuation-lines', - - # create implicit user groups from directory names in keydir/ - # 'keysubdirs-as-groups', - - # allow simple line-oriented macros - # 'macros', - - # Kindergarten mode - - # disallow various things that sensible people shouldn't be doing anyway - # 'Kindergarten', - ], - -); - -# ------------------------------------------------------------------------------ -# per perl rules, this should be the last line in such a file: -1; - -# Local variables: -# mode: perl -# End: -# vim: set syn=perl: diff --git a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/main/.gitstub b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/main/.gitstub deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/run b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/run deleted file mode 120000 index d6aef4a77d..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/log/run +++ /dev/null @@ -1 +0,0 @@ -/usr/local/lib/arvbox/logger \ No newline at end of file diff --git a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run deleted file mode 120000 index a388c8b67b..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run +++ /dev/null @@ -1 +0,0 @@ -/usr/local/lib/arvbox/runsu.sh \ No newline at end of file diff --git a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service deleted file mode 100755 index b598a75d89..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service +++ /dev/null @@ -1,22 +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-git-httpd) - -if test "$1" = "--only-deps" ; then - exit -fi - -flock $ARVADOS_CONTAINER_PATH/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh - -export PATH="$PATH:$ARVADOS_CONTAINER_PATH/git/bin" -cd ~git -exec /usr/local/bin/arvados-git-httpd diff --git a/tools/arvbox/lib/arvbox/docker/service/gitolite/log/main/.gitstub b/tools/arvbox/lib/arvbox/docker/service/gitolite/log/main/.gitstub deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/arvbox/lib/arvbox/docker/service/gitolite/log/run b/tools/arvbox/lib/arvbox/docker/service/gitolite/log/run deleted file mode 120000 index d6aef4a77d..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/gitolite/log/run +++ /dev/null @@ -1 +0,0 @@ -/usr/local/lib/arvbox/logger \ No newline at end of file diff --git a/tools/arvbox/lib/arvbox/docker/service/gitolite/run b/tools/arvbox/lib/arvbox/docker/service/gitolite/run deleted file mode 120000 index a388c8b67b..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/gitolite/run +++ /dev/null @@ -1 +0,0 @@ -/usr/local/lib/arvbox/runsu.sh \ No newline at end of file diff --git a/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service b/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service deleted file mode 100755 index 5f2cbc8825..0000000000 --- a/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash -# Copyright (C) The Arvados Authors. All rights reserved. -# -# SPDX-License-Identifier: AGPL-3.0 - -exec 2>&1 -set -eux -o pipefail - -. /usr/local/lib/arvbox/common.sh - -if test "$1" != "--only-deps" ; then - while [ ! -f $ARVADOS_CONTAINER_PATH/api.ready ]; do - sleep 1 - done -fi - -mkdir -p $ARVADOS_CONTAINER_PATH/git - -export ARVADOS_API_HOST=$localip:${services[controller-ssl]} -export ARVADOS_API_HOST_INSECURE=1 -export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token) - -export USER=git -export USERNAME=git -export LOGNAME=git -export HOME=$ARVADOS_CONTAINER_PATH/git - -cd ~arvbox - -mkdir -p ~arvbox/.ssh ~git/.ssh -chmod 0700 ~arvbox/.ssh ~git/.ssh - -if ! test -s ~arvbox/.ssh/id_rsa ; then - ssh-keygen -t rsa -P '' -f .ssh/id_rsa - cp ~arvbox/.ssh/id_rsa ~arvbox/.ssh/id_rsa.pub ~git/.ssh -fi - -if test -s ~arvbox/.ssh/known_hosts ; then - ssh-keygen -f ".ssh/known_hosts" -R localhost -fi - -if ! test -f $ARVADOS_CONTAINER_PATH/gitolite-setup ; then - cd ~git - - # Do a no-op login to populate known_hosts - # with the hostkey, so it won't try to ask - # about it later. - cp .ssh/id_rsa.pub .ssh/authorized_keys - ssh -o stricthostkeychecking=no git@localhost true - rm .ssh/authorized_keys - - cp /usr/local/lib/arvbox/gitolite.rc .gitolite.rc - - gitolite setup -pk .ssh/id_rsa.pub - - if ! test -d gitolite-admin ; then - git clone git@localhost:gitolite-admin - fi - - cd gitolite-admin - git config user.email arvados - git config user.name arvados - git config push.default simple - git push - - touch $ARVADOS_CONTAINER_PATH/gitolite-setup -else - # Do a no-op login to populate known_hosts - # with the hostkey, so it won't try to ask - # about it later. Don't run anything, - # get the default gitolite behavior. - ssh -o stricthostkeychecking=no git@localhost -fi - -prefix=$(arv --format=uuid user current | cut -d- -f1) - -if ! test -s $ARVADOS_CONTAINER_PATH/arvados-git-uuid ; then - repo_uuid=$(arv --format=uuid repository create --repository "{\"owner_uuid\":\"$prefix-tpzed-000000000000000\", \"name\":\"arvados\"}") - echo $repo_uuid > $ARVADOS_CONTAINER_PATH/arvados-git-uuid -fi - -repo_uuid=$(cat $ARVADOS_CONTAINER_PATH/arvados-git-uuid) - -if ! test -s $ARVADOS_CONTAINER_PATH/arvados-git-link-uuid ; then - all_users_group_uuid="$prefix-j7d0g-fffffffffffffff" - - set +e - read -rd $'\000' newlink < $ARVADOS_CONTAINER_PATH/arvados-git-link-uuid -fi - -if ! test -d $ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git ; then - git clone --bare /usr/src/arvados $ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git -else - git --git-dir=$ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git fetch -f /usr/src/arvados main:main -fi - -cd /usr/src/arvados/services/api - -if test -s $ARVADOS_CONTAINER_PATH/api_rails_env ; then - RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/api_rails_env) -else - RAILS_ENV=development -fi - -git_user_key=$(cat ~git/.ssh/id_rsa.pub) - -cat > config/arvados-clients.yml </dev/null; if [ "$1" = get ]; then echo password=$ARVADOS_API_TOKEN; fi; };cred' - /usr/local/lib/arvbox/runsu.sh $0-service cd /usr/src/arvados/services/login-sync diff --git a/tools/salt-install/config_examples/multi_host/aws/pillars/arvados.sls b/tools/salt-install/config_examples/multi_host/aws/pillars/arvados.sls index 16e686ab80..ce95a256b0 100644 --- a/tools/salt-install/config_examples/multi_host/aws/pillars/arvados.sls +++ b/tools/salt-install/config_examples/multi_host/aws/pillars/arvados.sls @@ -166,7 +166,6 @@ arvados: NewUsersAreActive: true AutoAdminFirstUser: true AutoSetupNewUsers: true - AutoSetupNewUsersWithRepository: true Services: Controller: diff --git a/tools/salt-install/config_examples/single_host/multiple_hostnames/pillars/arvados.sls b/tools/salt-install/config_examples/single_host/multiple_hostnames/pillars/arvados.sls index 271ab50290..a2bfdb19b0 100644 --- a/tools/salt-install/config_examples/single_host/multiple_hostnames/pillars/arvados.sls +++ b/tools/salt-install/config_examples/single_host/multiple_hostnames/pillars/arvados.sls @@ -128,7 +128,6 @@ arvados: NewUsersAreActive: true AutoAdminFirstUser: true AutoSetupNewUsers: true - AutoSetupNewUsersWithRepository: true Services: Controller: diff --git a/tools/salt-install/config_examples/single_host/single_hostname/pillars/arvados.sls b/tools/salt-install/config_examples/single_host/single_hostname/pillars/arvados.sls index 9e3a293110..03db62ab5d 100644 --- a/tools/salt-install/config_examples/single_host/single_hostname/pillars/arvados.sls +++ b/tools/salt-install/config_examples/single_host/single_hostname/pillars/arvados.sls @@ -131,7 +131,6 @@ arvados: NewUsersAreActive: true AutoAdminFirstUser: true AutoSetupNewUsers: true - AutoSetupNewUsersWithRepository: true Services: Controller: -- 2.39.5