[ARVADOS] updated: 2.3.2-64-g45a8b5916

Git user git at public.arvados.org
Tue Mar 8 19:19:46 UTC 2022


Summary of changes:

  discards  136d118b7cef35d9ed79aa8e69e929fc3a602f0b (commit)
  discards  a6f31f1b41199852a66e533230e3199c3d33062d (commit)
  discards  5e06c0972f36d35e45c69bc71efc82c15aefed8f (commit)
       via  45a8b5916a6704894df668d79ba70a2c65c2e159 (commit)
       via  b2979dd1e28a1e094842980f6dbe703f86ae9d2e (commit)
       via  1c68563901bc41137825196064b845ae77ea1cde (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (136d118b7cef35d9ed79aa8e69e929fc3a602f0b)
            \
             N -- N -- N (45a8b5916a6704894df668d79ba70a2c65c2e159)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 45a8b5916a6704894df668d79ba70a2c65c2e159
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Tue Mar 8 13:43:08 2022 -0500

    Update versions on installer/arvbox/docs refs #18733
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/doc/install/arvbox.html.textile.liquid b/doc/install/arvbox.html.textile.liquid
index 5c4548d65..9945d4861 100644
--- a/doc/install/arvbox.html.textile.liquid
+++ b/doc/install/arvbox.html.textile.liquid
@@ -16,7 +16,7 @@ h2. Quick start
 <pre>
 $ curl -O https://git.arvados.org/arvados.git/blob_plain/refs/heads/2.3-release:/tools/arvbox/bin/arvbox
 $ chmod +x arvbox
-$ ./arvbox start localdemo 2.3.0
+$ ./arvbox start localdemo 2.3.3
 $ ./arvbox adduser demouser demo at example.com
 </pre>
 
diff --git a/tools/arvbox/bin/arvbox b/tools/arvbox/bin/arvbox
index 70e5b6fa9..9cfab9bf3 100755
--- a/tools/arvbox/bin/arvbox
+++ b/tools/arvbox/bin/arvbox
@@ -61,7 +61,7 @@ if test -z "$WORKBENCH2_BRANCH" ; then
 fi
 
 # Update this to the docker tag for the version on releases.
-DEFAULT_TAG=2.3.2
+DEFAULT_TAG=2.3.3
 
 PG_DATA="$ARVBOX_DATA/postgres"
 VAR_DATA="$ARVBOX_DATA/var"
diff --git a/tools/salt-install/provision.sh b/tools/salt-install/provision.sh
index 630eb6695..ff25403e5 100755
--- a/tools/salt-install/provision.sh
+++ b/tools/salt-install/provision.sh
@@ -195,7 +195,7 @@ CUSTOM_CERTS_DIR="${SCRIPT_DIR}/certs"
 # The "local.params.example.*" files already set "RELEASE=production"
 # to deploy  production-ready packages
 RELEASE="production"
-VERSION="2.3.2-1"
+VERSION="2.3.3-1"
 
 # These are arvados-formula-related parameters
 # An arvados-formula tag. For a stable release, this should be a

commit b2979dd1e28a1e094842980f6dbe703f86ae9d2e
Author: Tom Clegg <tom at curii.com>
Date:   Mon Mar 7 14:19:14 2022 -0500

    Merge branch '18808-new-token-race' to 2.3-release
    
    cherry-pick d05b16ce4d4eea6841bf105081191f9964b485b7 + resolve merge
    conflict
    
    refs #18808
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curii.com>

diff --git a/lib/controller/localdb/login_oidc.go b/lib/controller/localdb/login_oidc.go
index 6182469ac..77f607d3f 100644
--- a/lib/controller/localdb/login_oidc.go
+++ b/lib/controller/localdb/login_oidc.go
@@ -31,6 +31,7 @@ import (
 	"github.com/coreos/go-oidc"
 	lru "github.com/hashicorp/golang-lru"
 	"github.com/jmoiron/sqlx"
+	"github.com/lib/pq"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/oauth2"
 	"google.golang.org/api/option"
@@ -43,6 +44,7 @@ var (
 	tokenCacheNegativeTTL = time.Minute * 5
 	tokenCacheTTL         = time.Minute * 10
 	tokenCacheRaceWindow  = time.Minute
+	pqCodeUniqueViolation = pq.ErrorCode("23505")
 )
 
 type oidcLoginController struct {
@@ -482,7 +484,6 @@ func (ta *oidcTokenAuthorizer) registerToken(ctx context.Context, tok string) er
 	// it's expiring.
 	exp := time.Now().UTC().Add(tokenCacheTTL + tokenCacheRaceWindow)
 
-	var aca arvados.APIClientAuthorization
 	if updating {
 		_, err = tx.ExecContext(ctx, `update api_client_authorizations set expires_at=$1 where api_token=$2`, exp, hmac)
 		if err != nil {
@@ -490,23 +491,44 @@ func (ta *oidcTokenAuthorizer) registerToken(ctx context.Context, tok string) er
 		}
 		ctxlog.FromContext(ctx).WithField("HMAC", hmac).Debug("(*oidcTokenAuthorizer)registerToken: updated api_client_authorizations row")
 	} else {
-		aca, err = ta.ctrl.Parent.CreateAPIClientAuthorization(ctx, ta.ctrl.Cluster.SystemRootToken, *authinfo)
+		aca, err := ta.ctrl.Parent.CreateAPIClientAuthorization(ctx, ta.ctrl.Cluster.SystemRootToken, *authinfo)
 		if err != nil {
 			return err
 		}
-		_, err = tx.ExecContext(ctx, `update api_client_authorizations set api_token=$1, expires_at=$2 where uuid=$3`, hmac, exp, aca.UUID)
+		_, err = tx.ExecContext(ctx, `savepoint upd`)
 		if err != nil {
+			return err
+		}
+		_, err = tx.ExecContext(ctx, `update api_client_authorizations set api_token=$1, expires_at=$2 where uuid=$3`, hmac, exp, aca.UUID)
+		if e, ok := err.(*pq.Error); ok && e.Code == pqCodeUniqueViolation {
+			// unique_violation, given that the above
+			// query did not find a row with matching
+			// api_token, means another thread/process
+			// also received this same token and won the
+			// race to insert it -- in which case this
+			// thread doesn't need to update the database.
+			// Discard the redundant row.
+			_, err = tx.ExecContext(ctx, `rollback to savepoint upd`)
+			if err != nil {
+				return err
+			}
+			_, err = tx.ExecContext(ctx, `delete from api_client_authorizations where uuid=$1`, aca.UUID)
+			if err != nil {
+				return err
+			}
+			ctxlog.FromContext(ctx).WithField("HMAC", hmac).Debug("(*oidcTokenAuthorizer)registerToken: api_client_authorizations row inserted by another thread")
+		} else if err != nil {
+			ctxlog.FromContext(ctx).Errorf("%#v", err)
 			return fmt.Errorf("error adding OIDC access token to database: %w", err)
+		} else {
+			ctxlog.FromContext(ctx).WithFields(logrus.Fields{"UUID": aca.UUID, "HMAC": hmac}).Debug("(*oidcTokenAuthorizer)registerToken: inserted api_client_authorizations row")
 		}
-		aca.APIToken = hmac
-		ctxlog.FromContext(ctx).WithFields(logrus.Fields{"UUID": aca.UUID, "HMAC": hmac}).Debug("(*oidcTokenAuthorizer)registerToken: inserted api_client_authorizations row")
 	}
 	err = tx.Commit()
 	if err != nil {
 		return err
 	}
-	aca.ExpiresAt = exp.Format(time.RFC3339Nano)
-	ta.cache.Add(tok, aca)
+	ta.cache.Add(tok, arvados.APIClientAuthorization{ExpiresAt: exp.Format(time.RFC3339Nano)})
 	return nil
 }
 
diff --git a/lib/controller/localdb/login_oidc_test.go b/lib/controller/localdb/login_oidc_test.go
index 4778e45f5..b9f0f56e0 100644
--- a/lib/controller/localdb/login_oidc_test.go
+++ b/lib/controller/localdb/login_oidc_test.go
@@ -17,6 +17,7 @@ import (
 	"net/url"
 	"sort"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 
@@ -236,18 +237,49 @@ func (s *OIDCLoginSuite) TestOIDCAuthorizer(c *check.C) {
 
 	ctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{accessToken}})
 	var exp1 time.Time
-	oidcAuthorizer.WrapCalls(func(ctx context.Context, opts interface{}) (interface{}, error) {
-		creds, ok := auth.FromContext(ctx)
-		c.Assert(ok, check.Equals, true)
-		c.Assert(creds.Tokens, check.HasLen, 1)
-		c.Check(creds.Tokens[0], check.Equals, accessToken)
 
-		err := db.QueryRowContext(ctx, `select expires_at at time zone 'UTC' from api_client_authorizations where api_token=$1`, apiToken).Scan(&exp1)
-		c.Check(err, check.IsNil)
-		c.Check(exp1.Sub(time.Now()) > -time.Second, check.Equals, true)
-		c.Check(exp1.Sub(time.Now()) < time.Second, check.Equals, true)
-		return nil, nil
-	})(ctx, nil)
+	concurrent := 4
+	s.fakeProvider.HoldUserInfo = make(chan *http.Request)
+	s.fakeProvider.ReleaseUserInfo = make(chan struct{})
+	go func() {
+		for i := 0; ; i++ {
+			if i == concurrent {
+				close(s.fakeProvider.ReleaseUserInfo)
+			}
+			<-s.fakeProvider.HoldUserInfo
+		}
+	}()
+	var wg sync.WaitGroup
+	for i := 0; i < concurrent; i++ {
+		i := i
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			_, err := oidcAuthorizer.WrapCalls(func(ctx context.Context, opts interface{}) (interface{}, error) {
+				c.Logf("concurrent req %d/%d", i, concurrent)
+				var exp time.Time
+
+				creds, ok := auth.FromContext(ctx)
+				c.Assert(ok, check.Equals, true)
+				c.Assert(creds.Tokens, check.HasLen, 1)
+				c.Check(creds.Tokens[0], check.Equals, accessToken)
+
+				err := db.QueryRowContext(ctx, `select expires_at at time zone 'UTC' from api_client_authorizations where api_token=$1`, apiToken).Scan(&exp)
+				c.Check(err, check.IsNil)
+				c.Check(exp.Sub(time.Now()) > -time.Second, check.Equals, true)
+				c.Check(exp.Sub(time.Now()) < time.Second, check.Equals, true)
+				if i == 0 {
+					exp1 = exp
+				}
+				return nil, nil
+			})(ctx, nil)
+			c.Check(err, check.IsNil)
+		}()
+	}
+	wg.Wait()
+	if c.Failed() {
+		c.Fatal("giving up")
+	}
 
 	// If the token is used again after the in-memory cache
 	// expires, oidcAuthorizer must re-check the token and update
@@ -257,8 +289,8 @@ func (s *OIDCLoginSuite) TestOIDCAuthorizer(c *check.C) {
 		var exp time.Time
 		err := db.QueryRowContext(ctx, `select expires_at at time zone 'UTC' from api_client_authorizations where api_token=$1`, apiToken).Scan(&exp)
 		c.Check(err, check.IsNil)
-		c.Check(exp.Sub(exp1) > 0, check.Equals, true)
-		c.Check(exp.Sub(exp1) < time.Second, check.Equals, true)
+		c.Check(exp.Sub(exp1) > 0, check.Equals, true, check.Commentf("expect %v > 0", exp.Sub(exp1)))
+		c.Check(exp.Sub(exp1) < time.Second, check.Equals, true, check.Commentf("expect %v < 1s", exp.Sub(exp1)))
 		return nil, nil
 	})(ctx, nil)
 
diff --git a/sdk/go/arvadostest/oidc_provider.go b/sdk/go/arvadostest/oidc_provider.go
index fa5e55c42..087adc4b2 100644
--- a/sdk/go/arvadostest/oidc_provider.go
+++ b/sdk/go/arvadostest/oidc_provider.go
@@ -35,6 +35,12 @@ type OIDCProvider struct {
 
 	PeopleAPIResponse map[string]interface{}
 
+	// send incoming /userinfo requests to HoldUserInfo (if not
+	// nil), then receive from ReleaseUserInfo (if not nil),
+	// before responding (these are used to set up races)
+	HoldUserInfo    chan *http.Request
+	ReleaseUserInfo chan struct{}
+
 	key       *rsa.PrivateKey
 	Issuer    *httptest.Server
 	PeopleAPI *httptest.Server
@@ -126,6 +132,12 @@ func (p *OIDCProvider) serveOIDC(w http.ResponseWriter, req *http.Request) {
 	case "/auth":
 		w.WriteHeader(http.StatusInternalServerError)
 	case "/userinfo":
+		if p.HoldUserInfo != nil {
+			p.HoldUserInfo <- req
+		}
+		if p.ReleaseUserInfo != nil {
+			<-p.ReleaseUserInfo
+		}
 		authhdr := req.Header.Get("Authorization")
 		if _, err := jwt.ParseSigned(strings.TrimPrefix(authhdr, "Bearer ")); err != nil {
 			p.c.Logf("OIDCProvider: bad auth %q", authhdr)

commit 1c68563901bc41137825196064b845ae77ea1cde
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Mar 4 17:03:06 2022 -0500

    Fix python2-ism
    
    refs #18835
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/python/arvados/commands/run.py b/sdk/python/arvados/commands/run.py
index 1e64eeb1d..0fe05da22 100644
--- a/sdk/python/arvados/commands/run.py
+++ b/sdk/python/arvados/commands/run.py
@@ -65,7 +65,7 @@ def is_in_collection(root, branch):
             return (None, None)
         fn = os.path.join(root, ".arvados#collection")
         if os.path.exists(fn):
-            with file(fn, 'r') as f:
+            with open(fn, 'r') as f:
                 c = json.load(f)
             return (c["portable_data_hash"], branch)
         else:

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list