Merge branch '15583-no-count'
authorEric Biagiotti <ebiagiotti@veritasgenetics.com>
Wed, 28 Aug 2019 19:59:39 +0000 (15:59 -0400)
committerEric Biagiotti <ebiagiotti@veritasgenetics.com>
Wed, 28 Aug 2019 19:59:39 +0000 (15:59 -0400)
refs #15583

Arvados-DCO-1.1-Signed-off-by: Eric Biagiotti <ebiagiotti@veritasgenetics.com>

26 files changed:
doc/admin/config-migration.html.textile.liquid
doc/admin/upgrading.html.textile.liquid
doc/install/install-arv-git-httpd.html.textile.liquid
doc/install/install-keepproxy.html.textile.liquid
lib/config/config.default.yml
lib/config/deprecated.go
lib/config/deprecated_test.go
lib/config/generated_config.go
lib/config/load.go
sdk/go/arvados/config.go
sdk/python/arvados/util.py
sdk/python/tests/run_test_server.py
services/arv-git-httpd/arvados-git-httpd.service
services/arv-git-httpd/auth_handler.go
services/arv-git-httpd/auth_handler_test.go
services/arv-git-httpd/git_handler.go
services/arv-git-httpd/git_handler_test.go
services/arv-git-httpd/gitolite_test.go
services/arv-git-httpd/integration_test.go
services/arv-git-httpd/main.go
services/arv-git-httpd/server.go
services/arv-git-httpd/usage.go [deleted file]
tools/arvbox/lib/arvbox/docker/cluster-config.sh
tools/arvbox/lib/arvbox/docker/common.sh
tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service
tools/arvbox/lib/arvbox/docker/service/nginx/run

index 556e20dd08ac5817643a024f01949d4b68070dd9..4e2fd81afc8ec2cd6d7eb588939d31e3c325ad57 100644 (file)
@@ -66,6 +66,11 @@ h2(#keepproxy). keepproxy
 
 The legacy keepproxy config (loaded from @/etc/arvados/keepproxy/keepproxy.yml@ or a different location specified via -legacy-keepproxy-config command line argument) takes precedence over the centralized config. After you migrate everything from the legacy config to the centralized config, you should delete @/etc/arvados/keepproxy/keepproxy.yml@ and stop using the -legacy-keepproxy-config argument.
 
+h2(#arv-git-httpd). arv-git-httpd
+
+The legacy arv-git-httpd config (loaded from @/etc/arvados/git-httpd/git-httpd.yml@ or a different location specified via -legacy-git-httpd-config command line argument) takes precedence over the centralized config. After you migrate everything from the legacy config to the centralized config, you should delete @/etc/arvados/git-httpd/git-httpd.yml@ and stop using the -legacy-git-httpd-config argument.
+
+
 h2. arvados-controller
 
 Already uses centralized config exclusively.  No migration needed.
index 079a41d2f38797031498473b200ab8619f02d08b..e1e29ed128fb77ae4d238c6c12911fd35a9b081e 100644 (file)
@@ -41,6 +41,10 @@ table(table table-bordered table-condensed).
 
 h3(#master). development master (as of 2019-08-12)
 
+h4. Arv-git-httpd configuration migration
+
+(feature "#14712":https://dev.arvados.org/issues/14712 ) The arv-git-httpd package can now be configured using the centralized configuration file at @/etc/arvados/config.yml@. Configuration via individual command line arguments is no longer available. Please see "arv-git-httpd's config migration guide":{{site.baseurl}}/admin/config-migration.html#arv-git-httpd for more details.
+
 h4. Keep-web dropped support on command line flags configuration
 
 As we're migrating to a central cluster configuration file, the already deprecated way of getting configurations via environment variables and command line flags isn't valid anymore. Current keep-web supports both the now legacy @keep-web.yml@ config format (used by Arvados 1.4) and the new cluster config file format. Please check "keep-web's install guide":{{site.baseurl}}/install/install-keep-web.html for more details.
index 7fc332177dcf812a1f44f3f5554d9d8583844952..c25fdee1dd3267eb00c038973c945bf41e735c5a 100644 (file)
@@ -212,10 +212,14 @@ Otherwise, create @/etc/cron.d/arvados-git-sync@ with the following content:
 
 h3. Configure the API server to advertise the correct SSH URLs
 
-In your API server's @application.yml@ file, add the following entry:
+Edit the cluster config at @/etc/arvados/config.yml@ and set @Services.GitSSH.ExternalURL@. Replace @uuid_prefix@ with your cluster id.
 
 <notextile>
-<pre><code>git_repo_ssh_base: "git@git.<span class="userinput">uuid_prefix.your.domain</span>:"
+<pre><code>Clusters:
+  <span class="userinput">uuid_prefix</span>:
+    Services:
+      GitSSH:
+        ExternalURL: <span class="userinput">git@git.uuid_prefix.your.domain:</span>
 </code></pre>
 </notextile>
 
@@ -267,21 +271,28 @@ The arvados-git-httpd package includes configuration files for systemd.  If you'
 
 {% include 'notebox_end' %}
 
-Create the configuration file @/etc/arvados/git-httpd/git-httpd.yml@. Run @arvados-git-httpd -h@ to learn more about configuration entries.
+Edit the cluster config at @/etc/arvados/config.yml@ and set the following values. Replace @uuid_prefix@ with your cluster id.
 
 <notextile>
-<pre><code>Client:
-  APIHost: <b>uuid_prefix.your.domain</b>
-  Insecure: false
-GitCommand: /var/lib/arvados/git/gitolite/src/gitolite-shell
-GitoliteHome: /var/lib/arvados/git
-Listen: :9001
-RepoRoot: /var/lib/arvados/git/repositories
+<pre><code>Clusters:
+  <span class="userinput">uuid_prefix</span>:
+    Services:
+      GitHTTP:
+        ExternalURL: <span class="userinput">https://git.uuid_prefix.your.domain/</span>
+        InternalURLs:
+         <span class="userinput">"http://localhost:9001": {}</span>
+    Git:
+      GitCommand: <span class="userinput">/var/lib/arvados/git/gitolite/src/gitolite-shell</span>
+      GitoliteHome: <span class="userinput">/var/lib/arvados/git</span>
+      Repositories: <span class="userinput">/var/lib/arvados/git/repositories</span>
 </code></pre>
 </notextile>
 
+Make sure to include the trailing slash for @Services.GitHTTP.ExternalURL@.
+
 Restart the systemd service to ensure the new configuration is used.
 
+
 <notextile>
 <pre><code>~$ <span class="userinput">sudo systemctl restart arvados-git-httpd</span>
 </code></pre>
@@ -320,17 +331,6 @@ server {
 </code></pre>
 </notextile>
 
-h3. Configure the API server to advertise the correct HTTPS URLs
-
-In your API server's @application.yml@ file, add the following entry:
-
-<notextile>
-<pre><code>git_repo_https_base: https://git.<span class="userinput">uuid_prefix.your.domain</span>/
-</code></pre>
-</notextile>
-
-Make sure to include the trailing slash.
-
 h2. Restart Nginx
 
 Restart Nginx to make the Nginx and API server configuration changes take effect.
index 910e47e0e8f90666b625a0a28f504b827759d3e8..d3a60ad0f3dda62fd8fcf270e70e745fd3e9ad49 100644 (file)
@@ -57,16 +57,16 @@ Usage of keepproxy:
 
 h3. Update the cluster config
 
-Edit the cluster config at @/etc/arvados/config.yml@ and set @Services.Keepproxy.ExternalURL@ and @Services.Keepproxy.InternalURLs@.  Replace @zzzzz@ with your cluster id.
+Edit the cluster config at @/etc/arvados/config.yml@ and set @Services.Keepproxy.ExternalURL@ and @Services.Keepproxy.InternalURLs@.  Replace @uuid_prefix@ with your cluster id.
 
 <notextile>
 <pre><code>Clusters:
   <span class="userinput">uuid_prefix</span>:
     Services:
-      <span class="userinput">Keepproxy:
-        ExternalURL: https://keep.uuid_prefix.your.domain
+      Keepproxy:
+        ExternalURL: <span class="userinput">https://keep.uuid_prefix.your.domain</span>
         InternalURLs:
-         "http://localhost:25107": {}
+         <span class="userinput">"http://localhost:25107": {}</span>
 </span></code></pre>
 </notextile>
 
index 163cd87ec5107ee826e1b971eac94fc4f8b1892d..24b2e450eb8c927388ec5add94299fb931163ccf 100644 (file)
@@ -419,6 +419,17 @@ Clusters:
       ProviderAppID: ""
 
     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
index df872111db2adf8ff1bc504fd0a5b2f31f2b14a6..9eb8c40c18d9455693a9ce18d24d890c528f6d25 100644 (file)
@@ -468,3 +468,44 @@ func (ldr *Loader) loadOldKeepWebConfig(cfg *arvados.Config) error {
        cfg.Clusters[cluster.ClusterID] = *cluster
        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("arv-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)
+
+       cluster.Services.GitHTTP.InternalURLs[arvados.URL{Host: oc.Listen}] = arvados.ServiceInstance{}
+       cluster.TLS.Insecure = oc.Client.Insecure
+       cluster.ManagementToken = oc.ManagementToken
+       cluster.Git.GitCommand = oc.GitCommand
+       cluster.Git.GitoliteHome = oc.GitoliteHome
+       cluster.Git.Repositories = oc.RepoRoot
+
+       cfg.Clusters[cluster.ClusterID] = *cluster
+       return nil
+}
index 76313ebb1615885298b3c8109ea73515fcfa8f2f..5dda0ba94457eb0dd5c76a85a22f38a798011de2 100644 (file)
@@ -187,3 +187,32 @@ 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.Check(err, check.IsNil)
+       c.Check(cluster, check.NotNil)
+       c.Check(cluster.Services.Controller.ExternalURL, check.Equals, arvados.URL{Scheme: "https", Host: "example.com"})
+       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{})
+}
index 1eae24d84e540ccc597cc0dcf8f048fadf19514e..8a5b4610c2b9b3ec88dd7029eed52bc7de4ce704 100644 (file)
@@ -425,6 +425,17 @@ Clusters:
       ProviderAppID: ""
 
     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
index 84de9b60e991de1672ddb4c448faf860d8ee64fb..7e48493939cd67a8322e67fe9f14bf357f26cd76 100644 (file)
@@ -35,6 +35,7 @@ type Loader struct {
        CrunchDispatchSlurmPath string
        WebsocketPath           string
        KeepproxyPath           string
+       GitHttpdPath            string
 
        configdata []byte
 }
@@ -66,6 +67,7 @@ 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 arv-git-httpd configuration `file`")
        flagset.BoolVar(&ldr.SkipLegacy, "skip-legacy", false, "Don't load legacy config files")
 }
 
@@ -143,6 +145,9 @@ func (ldr *Loader) MungeLegacyConfigArgs(lgr logrus.FieldLogger, args []string,
        if legacyConfigArg != "-legacy-keepproxy-config" {
                ldr.KeepproxyPath = ""
        }
+       if legacyConfigArg != "-legacy-git-httpd-config" {
+               ldr.GitHttpdPath = ""
+       }
 
        return munged
 }
@@ -244,6 +249,7 @@ func (ldr *Loader) Load() (*arvados.Config, error) {
                        ldr.loadOldCrunchDispatchSlurmConfig(&cfg),
                        ldr.loadOldWebsocketConfig(&cfg),
                        ldr.loadOldKeepproxyConfig(&cfg),
+                       ldr.loadOldGitHttpdConfig(&cfg),
                } {
                        if err != nil {
                                return nil, err
index 93f52f3c809bb003c3bb506574d42e140728960c..5a18972f5232127466a1590c023915deef354935 100644 (file)
@@ -114,6 +114,8 @@ type Cluster struct {
                WebDAVCache WebDAVCacheConfig
        }
        Git struct {
+               GitCommand   string
+               GitoliteHome string
                Repositories string
        }
        Login struct {
index 66da2d12af2082689179bbf1b89dd6285c1edbd9..fd29a3dc1d46938d2ea9e5c661bea2cbf20659be 100644 (file)
@@ -19,6 +19,9 @@ import arvados
 from arvados.collection import CollectionReader
 
 HEX_RE = re.compile(r'^[0-9a-fA-F]+$')
+CR_UNCOMMITTED = 'Uncommitted'
+CR_COMMITTED = 'Committed'
+CR_FINAL = 'Final'
 
 keep_locator_pattern = re.compile(r'[0-9a-f]{32}\+\d+(\+\S+)*')
 signed_locator_pattern = re.compile(r'[0-9a-f]{32}\+\d+(\+\S+)*\+A\S+(\+\S+)*')
index e79b4843a268049e117d60e59a37a8de62e61fbb..34342059f3062820313127514c47e0061f080a77 100644 (file)
@@ -578,16 +578,11 @@ def run_arv_git_httpd():
         return
     stop_arv_git_httpd()
 
-    gitdir = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'git')
     gitport = internal_port_from_config("GitHTTP")
     env = os.environ.copy()
     env.pop('ARVADOS_API_TOKEN', None)
     logf = open(_logfilename('arv-git-httpd'), 'a')
-    agh = subprocess.Popen(
-        ['arv-git-httpd',
-         '-repo-root='+gitdir+'/test',
-         '-management-token=e687950a23c3a9bceec28c6223a06c79',
-         '-address=:'+str(gitport)],
+    agh = subprocess.Popen(['arv-git-httpd'],
         env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
     with open(_pidfile('arv-git-httpd'), 'w') as f:
         f.write(str(agh.pid))
@@ -747,6 +742,9 @@ def setup_config():
                 },
                 "Collections": {
                     "TrustAllContent": True
+                },
+                "Git": {
+                    "Repositories": "%s/test" % os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'git')
                 }
             }
         }
index 6f8cca856b595498b7f6b8ee387e956e838666a2..7ac160eea33da990b976910de4693f87d97bdbda 100644 (file)
@@ -6,7 +6,6 @@
 Description=Arvados git server
 Documentation=https://doc.arvados.org/
 After=network.target
-AssertPathExists=/etc/arvados/git-httpd/git-httpd.yml
 
 # systemd==229 (ubuntu:xenial) obeys StartLimitInterval in the [Unit] section
 StartLimitInterval=0
index 3b3032afda5d9707616ce474c431e10d2e629e37..6c618189474912bab9fa45062739acff6862ddad 100644 (file)
@@ -14,6 +14,7 @@ import (
        "sync"
        "time"
 
+       "git.curoverse.com/arvados.git/sdk/go/arvados"
        "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
        "git.curoverse.com/arvados.git/sdk/go/auth"
        "git.curoverse.com/arvados.git/sdk/go/httpserver"
@@ -22,14 +23,21 @@ import (
 type authHandler struct {
        handler    http.Handler
        clientPool *arvadosclient.ClientPool
+       cluster    *arvados.Cluster
        setupOnce  sync.Once
 }
 
 func (h *authHandler) setup() {
-       ac, err := arvadosclient.New(&theConfig.Client)
+       client, err := arvados.NewClientFromConfig(h.cluster)
        if err != nil {
                log.Fatal(err)
        }
+
+       ac, err := arvadosclient.New(client)
+       if err != nil {
+               log.Fatalf("Error setting up arvados client prototype %v", err)
+       }
+
        h.clientPool = &arvadosclient.ClientPool{Prototype: ac}
 }
 
@@ -161,7 +169,7 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) {
                "/" + repoName + "/.git",
        }
        for _, dir := range tryDirs {
-               if fileInfo, err := os.Stat(theConfig.RepoRoot + dir); err != nil {
+               if fileInfo, err := os.Stat(h.cluster.Git.Repositories + dir); err != nil {
                        if !os.IsNotExist(err) {
                                statusCode, statusText = http.StatusInternalServerError, err.Error()
                                return
@@ -173,7 +181,7 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) {
        }
        if rewrittenPath == "" {
                log.Println("WARNING:", repoUUID,
-                       "git directory not found in", theConfig.RepoRoot, tryDirs)
+                       "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"
index 05fde03e72c7366ebafdf7e1fc04209e86c5868e..568570942e1f143c0f89725bc20cf372512d8983 100644 (file)
@@ -13,6 +13,7 @@ import (
        "path/filepath"
        "strings"
 
+       "git.curoverse.com/arvados.git/lib/config"
        "git.curoverse.com/arvados.git/sdk/go/arvados"
        "git.curoverse.com/arvados.git/sdk/go/arvadostest"
        check "gopkg.in/check.v1"
@@ -20,7 +21,9 @@ import (
 
 var _ = check.Suite(&AuthHandlerSuite{})
 
-type AuthHandlerSuite struct{}
+type AuthHandlerSuite struct {
+       cluster *arvados.Cluster
+}
 
 func (s *AuthHandlerSuite) SetUpSuite(c *check.C) {
        arvadostest.StartAPI()
@@ -34,23 +37,23 @@ func (s *AuthHandlerSuite) SetUpTest(c *check.C) {
        arvadostest.ResetEnv()
        repoRoot, err := filepath.Abs("../api/tmp/git/test")
        c.Assert(err, check.IsNil)
-       theConfig = &Config{
-               Client: arvados.Client{
-                       APIHost:  arvadostest.APIHost(),
-                       Insecure: true,
-               },
-               Listen:          ":0",
-               GitCommand:      "/usr/bin/git",
-               RepoRoot:        repoRoot,
-               ManagementToken: arvadostest.ManagementToken,
-       }
+
+       cfg, err := config.NewLoader(nil, nil).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{arvados.URL{Host: "localhost:0"}: arvados.ServiceInstance{}}
+       s.cluster.TLS.Insecure = true
+       s.cluster.Git.GitCommand = "/usr/bin/git"
+       s.cluster.Git.Repositories = repoRoot
 }
 
 func (s *AuthHandlerSuite) TestPermission(c *check.C) {
        h := &authHandler{handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                log.Printf("%v", r.URL)
                io.WriteString(w, r.URL.Path)
-       })}
+       }), cluster: s.cluster}
        baseURL, err := url.Parse("http://git.example/")
        c.Assert(err, check.IsNil)
        for _, trial := range []struct {
@@ -133,7 +136,7 @@ func (s *AuthHandlerSuite) TestPermission(c *check.C) {
 }
 
 func (s *AuthHandlerSuite) TestCORS(c *check.C) {
-       h := &authHandler{}
+       h := &authHandler{cluster: s.cluster}
 
        // CORS preflight
        resp := httptest.NewRecorder()
index d9b08a995b3ab1baee6b3a5b33a3f3f9d084e2b6..0b14e81d54107fb97ff68747bffa58a4ff63de5c 100644 (file)
@@ -10,6 +10,8 @@ import (
        "net/http"
        "net/http/cgi"
        "os"
+
+       "git.curoverse.com/arvados.git/sdk/go/arvados"
 )
 
 // gitHandler is an http.Handler that invokes git-http-backend (or
@@ -20,29 +22,34 @@ type gitHandler struct {
        cgi.Handler
 }
 
-func newGitHandler() http.Handler {
+func newGitHandler(cluster *arvados.Cluster) http.Handler {
        const glBypass = "GL_BYPASS_ACCESS_CHECKS"
        const glHome = "GITOLITE_HTTP_HOME"
        var env []string
        path := os.Getenv("PATH")
-       if theConfig.GitoliteHome != "" {
+       if cluster.Git.GitoliteHome != "" {
                env = append(env,
-                       glHome+"="+theConfig.GitoliteHome,
+                       glHome+"="+cluster.Git.GitoliteHome,
                        glBypass+"=1")
-               path = path + ":" + theConfig.GitoliteHome + "/bin"
+               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)
                log.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="+theConfig.RepoRoot,
+               "GIT_PROJECT_ROOT="+cluster.Git.Repositories,
                "GIT_HTTP_EXPORT_ALL=",
-               "SERVER_ADDR="+theConfig.Listen,
+               "SERVER_ADDR="+listen.Host,
                "PATH="+path)
        return &gitHandler{
                Handler: cgi.Handler{
-                       Path: theConfig.GitCommand,
-                       Dir:  theConfig.RepoRoot,
+                       Path: cluster.Git.GitCommand,
+                       Dir:  cluster.Git.Repositories,
                        Env:  env,
                        Args: []string{"http-backend"},
                },
index 0cf7de4e22c229545bde64edaa03aa9dcb2612a6..d5cb275fd8fea3613584ff809095a5c8094407c5 100644 (file)
@@ -10,18 +10,29 @@ import (
        "net/url"
        "regexp"
 
+       "git.curoverse.com/arvados.git/lib/config"
+       "git.curoverse.com/arvados.git/sdk/go/arvados"
        check "gopkg.in/check.v1"
 )
 
 var _ = check.Suite(&GitHandlerSuite{})
 
-type GitHandlerSuite struct{}
+type GitHandlerSuite struct {
+       cluster *arvados.Cluster
+}
 
-func (s *GitHandlerSuite) TestEnvVars(c *check.C) {
-       theConfig = defaultConfig()
-       theConfig.RepoRoot = "/"
-       theConfig.GitoliteHome = "/test/ghh"
+func (s *GitHandlerSuite) SetUpTest(c *check.C) {
+       cfg, err := config.NewLoader(nil, nil).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{arvados.URL{Host: "localhost:80"}: arvados.ServiceInstance{}}
+       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()
@@ -30,7 +41,7 @@ func (s *GitHandlerSuite) TestEnvVars(c *check.C) {
                URL:        u,
                RemoteAddr: "[::1]:12345",
        }
-       h := newGitHandler()
+       h := newGitHandler(s.cluster)
        h.(*gitHandler).Path = "/bin/sh"
        h.(*gitHandler).Args = []string{"-c", "printf 'Content-Type: text/plain\r\n\r\n'; env"}
 
@@ -43,7 +54,7 @@ func (s *GitHandlerSuite) TestEnvVars(c *check.C) {
        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(theConfig.Listen)+`$.*`)
+       c.Check(body, check.Matches, `(?ms).*^SERVER_ADDR=`+regexp.QuoteMeta("localhost:80")+`$.*`)
 }
 
 func (s *GitHandlerSuite) TestCGIErrorOnSplitHostPortError(c *check.C) {
@@ -55,7 +66,7 @@ func (s *GitHandlerSuite) TestCGIErrorOnSplitHostPortError(c *check.C) {
                URL:        u,
                RemoteAddr: "test.bad.address.missing.port",
        }
-       h := newGitHandler()
+       h := newGitHandler(s.cluster)
        h.ServeHTTP(resp, req)
        c.Check(resp.Code, check.Equals, http.StatusInternalServerError)
        c.Check(resp.Body.String(), check.Equals, "")
index 88cd221cbf8aaed87e4f91a6289e8dd02458cd90..eaa7b55f8381f0b4097d751b2aad39866babe355 100644 (file)
@@ -10,8 +10,8 @@ import (
        "os/exec"
        "strings"
 
+       "git.curoverse.com/arvados.git/lib/config"
        "git.curoverse.com/arvados.git/sdk/go/arvados"
-       "git.curoverse.com/arvados.git/sdk/go/arvadostest"
        check "gopkg.in/check.v1"
 )
 
@@ -47,16 +47,18 @@ func (s *GitoliteSuite) SetUpTest(c *check.C) {
        runGitolite("gitolite", "setup", "--admin", "root")
 
        s.tmpRepoRoot = s.gitoliteHome + "/repositories"
-       s.Config = &Config{
-               Client: arvados.Client{
-                       APIHost:  arvadostest.APIHost(),
-                       Insecure: true,
-               },
-               Listen:       "localhost:0",
-               GitCommand:   "/usr/share/gitolite3/gitolite-shell",
-               GitoliteHome: s.gitoliteHome,
-               RepoRoot:     s.tmpRepoRoot,
-       }
+
+       cfg, err := config.NewLoader(nil, nil).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{arvados.URL{Host: "localhost:0"}: arvados.ServiceInstance{}}
+       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
index 53b636dc0e577e75bf5577e66a54059628be8774..46bf8329c2dce429178071a6da72cfb6b90bb8b5 100644 (file)
@@ -12,6 +12,7 @@ import (
        "strings"
        "testing"
 
+       "git.curoverse.com/arvados.git/lib/config"
        "git.curoverse.com/arvados.git/sdk/go/arvados"
        "git.curoverse.com/arvados.git/sdk/go/arvadostest"
        check "gopkg.in/check.v1"
@@ -28,7 +29,7 @@ type IntegrationSuite struct {
        tmpRepoRoot string
        tmpWorkdir  string
        testServer  *server
-       Config      *Config
+       cluster     *arvados.Cluster
 }
 
 func (s *IntegrationSuite) SetUpSuite(c *check.C) {
@@ -41,7 +42,7 @@ func (s *IntegrationSuite) TearDownSuite(c *check.C) {
 
 func (s *IntegrationSuite) SetUpTest(c *check.C) {
        arvadostest.ResetEnv()
-       s.testServer = &server{}
+
        var err error
        if s.tmpRepoRoot == "" {
                s.tmpRepoRoot, err = ioutil.TempDir("", "arv-git-httpd")
@@ -60,6 +61,23 @@ func (s *IntegrationSuite) SetUpTest(c *check.C) {
        _, 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, nil).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{arvados.URL{Host: "localhost:0"}: arvados.ServiceInstance{}}
+               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 = &server{cluster: s.cluster}
+       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",
@@ -71,29 +89,12 @@ func (s *IntegrationSuite) SetUpTest(c *check.C) {
                "none").Output()
        c.Assert(err, check.Equals, nil)
 
-       if s.Config == nil {
-               s.Config = &Config{
-                       Client: arvados.Client{
-                               APIHost:  arvadostest.APIHost(),
-                               Insecure: true,
-                       },
-                       Listen:          "localhost:0",
-                       GitCommand:      "/usr/bin/git",
-                       RepoRoot:        s.tmpRepoRoot,
-                       ManagementToken: arvadostest.ManagementToken,
-               }
-       }
-
        // Clear ARVADOS_API_* env vars before starting up the server,
        // to make sure arv-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")
-
-       theConfig = s.Config
-       err = s.testServer.Start()
-       c.Assert(err, check.Equals, nil)
 }
 
 func (s *IntegrationSuite) TearDownTest(c *check.C) {
@@ -116,9 +117,7 @@ func (s *IntegrationSuite) TearDownTest(c *check.C) {
        }
        s.tmpWorkdir = ""
 
-       s.Config = nil
-
-       theConfig = defaultConfig()
+       s.cluster = nil
 }
 
 func (s *IntegrationSuite) RunGit(c *check.C, token, gitCmd, repo string, args ...string) error {
index 74ac7ae55eea05aa396f9ff337a8dbed74505079..3edfcf4ca68454418e62dd29739a16c07f68c242 100644 (file)
@@ -5,89 +5,62 @@
 package main
 
 import (
-       "encoding/json"
        "flag"
        "fmt"
-       "log"
        "os"
-       "regexp"
 
-       "git.curoverse.com/arvados.git/sdk/go/arvados"
-       "git.curoverse.com/arvados.git/sdk/go/config"
+       "git.curoverse.com/arvados.git/lib/config"
        "github.com/coreos/go-systemd/daemon"
+       "github.com/ghodss/yaml"
+       log "github.com/sirupsen/logrus"
 )
 
 var version = "dev"
 
-// Server configuration
-type Config struct {
-       Client          arvados.Client
-       Listen          string
-       GitCommand      string
-       RepoRoot        string
-       GitoliteHome    string
-       ManagementToken string
-}
-
-var theConfig = defaultConfig()
-
-func defaultConfig() *Config {
-       return &Config{
-               Listen:     ":80",
-               GitCommand: "/usr/bin/git",
-               RepoRoot:   "/var/lib/arvados/git/repositories",
-       }
-}
-
 func main() {
-       const defaultCfgPath = "/etc/arvados/git-httpd/git-httpd.yml"
-       const deprecated = " (DEPRECATED -- use config file instead)"
-       flag.StringVar(&theConfig.Listen, "address", theConfig.Listen,
-               "Address to listen on, \"host:port\" or \":port\"."+deprecated)
-       flag.StringVar(&theConfig.GitCommand, "git-command", theConfig.GitCommand,
-               "Path to git or gitolite-shell executable. Each authenticated request will execute this program with a single argument, \"http-backend\"."+deprecated)
-       flag.StringVar(&theConfig.RepoRoot, "repo-root", theConfig.RepoRoot,
-               "Path to git repositories."+deprecated)
-       flag.StringVar(&theConfig.GitoliteHome, "gitolite-home", theConfig.GitoliteHome,
-               "Value for GITOLITE_HTTP_HOME environment variable. If not empty, GL_BYPASS_ACCESS_CHECKS=1 will also be set."+deprecated)
+       logger := log.New()
+       log.SetFormatter(&log.JSONFormatter{
+               TimestampFormat: "2006-01-02T15:04:05.000000000Z07:00",
+       })
 
-       cfgPath := flag.String("config", defaultCfgPath, "Configuration file `path`.")
-       dumpConfig := flag.Bool("dump-config", false, "write current configuration to stdout and exit (useful for migrating from command line flags to config file)")
-       getVersion := flag.Bool("version", false, "print version information and exit.")
+       flags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+       loader := config.NewLoader(os.Stdin, logger)
+       loader.SetupFlags(flags)
 
-       flag.StringVar(&theConfig.ManagementToken, "management-token", theConfig.ManagementToken,
-               "Authorization token to be included in all health check requests.")
+       dumpConfig := flags.Bool("dump-config", false, "write current configuration to stdout and exit (useful for migrating from command line flags to config file)")
+       getVersion := flags.Bool("version", false, "print version information and exit.")
 
-       flag.Usage = usage
-       flag.Parse()
+       args := loader.MungeLegacyConfigArgs(logger, os.Args[1:], "-legacy-git-httpd-config")
+       flags.Parse(args)
 
-       // Print version information if requested
        if *getVersion {
                fmt.Printf("arv-git-httpd %s\n", version)
                return
        }
 
-       err := config.LoadFile(theConfig, *cfgPath)
+       cfg, err := loader.Load()
        if err != nil {
-               h := os.Getenv("ARVADOS_API_HOST")
-               if h == "" || !os.IsNotExist(err) || *cfgPath != defaultCfgPath {
-                       log.Fatal(err)
-               }
-               log.Print("DEPRECATED: No config file found, but ARVADOS_API_HOST environment variable is set. Please use a config file instead.")
-               theConfig.Client.APIHost = h
-               if regexp.MustCompile("^(?i:1|yes|true)$").MatchString(os.Getenv("ARVADOS_API_HOST_INSECURE")) {
-                       theConfig.Client.Insecure = true
-               }
-               if j, err := json.MarshalIndent(theConfig, "", "    "); err == nil {
-                       log.Print("Current configuration:\n", string(j))
-               }
+               log.Fatal(err)
+       }
+
+       cluster, err := cfg.GetCluster("")
+       if err != nil {
+               log.Fatal(err)
        }
 
        if *dumpConfig {
-               log.Fatal(config.DumpAndExit(theConfig))
+               out, err := yaml.Marshal(cfg)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               _, err = os.Stdout.Write(out)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               return
        }
 
-       srv := &server{}
+       srv := &server{cluster: cluster}
        if err := srv.Start(); err != nil {
                log.Fatal(err)
        }
@@ -96,7 +69,7 @@ func main() {
        }
        log.Printf("arv-git-httpd %s started", version)
        log.Println("Listening at", srv.Addr)
-       log.Println("Repository root", theConfig.RepoRoot)
+       log.Println("Repository root", cluster.Git.Repositories)
        if err := srv.Wait(); err != nil {
                log.Fatal(err)
        }
index 8f0d90f89e29cad0a0d8d590b66e412b02195ad2..56c9765b56947959792b1ac3e046cfdf5afa2652 100644 (file)
@@ -7,22 +7,30 @@ package main
 import (
        "net/http"
 
+       "git.curoverse.com/arvados.git/sdk/go/arvados"
        "git.curoverse.com/arvados.git/sdk/go/health"
        "git.curoverse.com/arvados.git/sdk/go/httpserver"
 )
 
 type server struct {
        httpserver.Server
+       cluster *arvados.Cluster
 }
 
 func (srv *server) Start() error {
        mux := http.NewServeMux()
-       mux.Handle("/", &authHandler{handler: newGitHandler()})
+       mux.Handle("/", &authHandler{handler: newGitHandler(srv.cluster), cluster: srv.cluster})
        mux.Handle("/_health/", &health.Handler{
-               Token:  theConfig.ManagementToken,
+               Token:  srv.cluster.ManagementToken,
                Prefix: "/_health/",
        })
+
+       var listen arvados.URL
+       for listen = range srv.cluster.Services.GitHTTP.InternalURLs {
+               break
+       }
+
        srv.Handler = mux
-       srv.Addr = theConfig.Listen
+       srv.Addr = listen.Host
        return srv.Server.Start()
 }
diff --git a/services/arv-git-httpd/usage.go b/services/arv-git-httpd/usage.go
deleted file mode 100644 (file)
index 8863da6..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-// arvados-git-httpd provides authenticated access to Arvados-hosted
-// git repositories.
-//
-// See http://doc.arvados.org/install/install-arv-git-httpd.html.
-package main
-
-import (
-       "flag"
-       "fmt"
-       "os"
-
-       "github.com/ghodss/yaml"
-)
-
-func usage() {
-       c := defaultConfig()
-       c.Client.APIHost = "zzzzz.arvadosapi.com:443"
-       exampleConfigFile, err := yaml.Marshal(c)
-       if err != nil {
-               panic(err)
-       }
-       fmt.Fprintf(os.Stderr, `
-
-arvados-git-httpd provides authenticated access to Arvados-hosted git
-repositories.
-
-See http://doc.arvados.org/install/install-arv-git-httpd.html.
-
-Usage: arvados-git-httpd [-config path/to/arvados/git-httpd.yml]
-
-Options:
-`)
-       flag.PrintDefaults()
-       fmt.Fprintf(os.Stderr, `
-Example config file:
-
-%s
-
-Client.APIHost:
-
-    Address (or address:port) of the Arvados API endpoint.
-
-Client.AuthToken:
-
-    Unused. Normally empty, or omitted entirely.
-
-Client.Insecure:
-
-    True if your Arvados API endpoint uses an unverifiable SSL/TLS
-    certificate.
-
-GitCommand:
-
-    Path to git or gitolite-shell executable. Each authenticated
-    request will execute this program with the single argument
-    "http-backend".
-
-GitoliteHome:
-
-    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.
-
-Listen:
-
-    Local port to listen on. Can be "address:port" or ":port", where
-    "address" is a host IP address or name and "port" is a port number
-    or name.
-
-RepoRoot:
-
-    Path to git repositories.
-
-`, exampleConfigFile)
-}
index 34a0c2d75221b0466c23870ead2a996b929987da..951b592ea69d1893b6c030f539ce8e8d8bcf925e 100755 (executable)
@@ -90,7 +90,9 @@ Clusters:
       GitSSH:
         ExternalURL: "ssh://git@$localip:"
       GitHTTP:
-        ExternalURL: "http://$localip:${services[arv-git-httpd]}/"
+        InternalURLs:
+          "http://localhost:${services[arv-git-httpd]}/": {}
+        ExternalURL: "https://$localip:${services[arv-git-httpd-ssl]}/"
       WebDAV:
         InternalURLs:
           "http://localhost:${services[keep-web]}/": {}
@@ -143,6 +145,10 @@ Clusters:
     Workbench:
       SecretKeyBase: $workbench_secret_key_base
       ArvadosDocsite: http://$localip:${services[doc]}/
+    Git:
+      GitCommand: /usr/share/gitolite3/gitolite-shell
+      GitoliteHome: /var/lib/arvados/git
+      Repositories: /var/lib/arvados/git/repositories
 EOF
 
 /usr/local/lib/arvbox/yml_override.py /var/lib/arvados/cluster_config.yml
index 21872749575cbcb2a4fb03ee7c97e0114046f56d..9d29eb9f143e8be2d9b88857e093524c73ee3c99 100644 (file)
@@ -33,6 +33,7 @@ services=(
   [controller-ssl]=8000
   [sso]=8900
   [composer]=4200
+  [arv-git-httpd-ssl]=9000
   [arv-git-httpd]=9001
   [keep-web]=9003
   [keep-web-ssl]=9002
index 9339f2328c6a9ee8a5e3058e537cb212ddbd0c00..38522a714c5b905563a6c35e0d855c5fda2d95ca 100755 (executable)
@@ -21,8 +21,4 @@ export ARVADOS_API_HOST_INSECURE=1
 export PATH="$PATH:/var/lib/arvados/git/bin"
 cd ~git
 
-exec /usr/local/bin/arv-git-httpd \
-    -address=:${services[arv-git-httpd]} \
-    -git-command=/usr/share/gitolite3/gitolite-shell \
-    -gitolite-home=/var/lib/arvados/git \
-    -repo-root=/var/lib/arvados/git/repositories
+exec /usr/local/bin/arv-git-httpd
index 04a1b539526f31547011d02d4db18ae508434883..0d60e74128365605a49194b27cb2cf9c09af9618 100755 (executable)
@@ -143,6 +143,29 @@ server {
     }
   }
 
+  upstream arvados-git-httpd {
+    server localhost:${services[arv-git-httpd]};
+  }
+  server {
+    listen *:${services[arv-git-httpd-ssl]} ssl default_server;
+    server_name arvados-git-httpd;
+    proxy_connect_timeout 90s;
+    proxy_read_timeout 300s;
+
+    ssl on;
+    ssl_certificate "${server_cert}";
+    ssl_certificate_key "${server_cert_key}";
+    client_max_body_size 50m;
+
+    location  / {
+      proxy_pass http://arvados-git-httpd;
+      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;
+    }
+  }
+
 }
 
 EOF