// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 package boot import ( "context" "net/url" "git.arvados.org/arvados.git/lib/controller/rpc" "git.arvados.org/arvados.git/lib/service" "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/ctxlog" "git.arvados.org/arvados.git/sdk/go/keepclient" "gopkg.in/check.v1" ) // TestCluster stores a working test cluster data type TestCluster struct { Super Supervisor Config arvados.Config ControllerURL *url.URL ClusterID string } type logger struct { loggerfunc func(...interface{}) } func (l logger) Log(args ...interface{}) { l.loggerfunc(args) } // NewTestCluster loads the provided configuration, and sets up a test cluster // ready for being started. func NewTestCluster(srcPath, clusterID string, cfg *arvados.Config, listenHost string, logWriter func(...interface{})) *TestCluster { return &TestCluster{ Super: Supervisor{ SourcePath: srcPath, ClusterType: "test", ListenHost: listenHost, ControllerAddr: ":0", OwnTemporaryDatabase: true, Stderr: &service.LogPrefixer{ Writer: ctxlog.LogWriter(logWriter), Prefix: []byte("[" + clusterID + "] ")}, }, Config: *cfg, ClusterID: clusterID, } } // Start the test cluster. func (tc *TestCluster) Start() { tc.Super.Start(context.Background(), &tc.Config, "-") } // WaitReady waits for all components to report healthy, and finishes setting // up the TestCluster struct. func (tc *TestCluster) WaitReady() bool { au, ok := tc.Super.WaitReady() if !ok { return ok } u := url.URL(*au) tc.ControllerURL = &u return ok } // ClientsWithToken returns Context, Arvados.Client and keepclient structs // initialized to connect to the cluster with the supplied Arvados token. func (tc *TestCluster) ClientsWithToken(token string) (context.Context, *arvados.Client, *keepclient.KeepClient) { cl := tc.Config.Clusters[tc.ClusterID] ctx := auth.NewContext(context.Background(), auth.NewCredentials(token)) ac, err := arvados.NewClientFromConfig(&cl) if err != nil { panic(err) } ac.AuthToken = token arv, err := arvadosclient.New(ac) if err != nil { panic(err) } kc := keepclient.New(arv) return ctx, ac, kc } // UserClients logs in as a user called "example", get the user's API token, // initialize clients with the API token, set up the user and // optionally activate the user. Return client structs for // communicating with the cluster on behalf of the 'example' user. func (tc *TestCluster) UserClients(rootctx context.Context, c *check.C, conn *rpc.Conn, authEmail string, activate bool) (context.Context, *arvados.Client, *keepclient.KeepClient, arvados.User) { login, err := conn.UserSessionCreate(rootctx, rpc.UserSessionCreateOptions{ ReturnTo: ",https://example.com", AuthInfo: rpc.UserSessionAuthInfo{ Email: authEmail, FirstName: "Example", LastName: "User", Username: "example", }, }) c.Assert(err, check.IsNil) redirURL, err := url.Parse(login.RedirectLocation) c.Assert(err, check.IsNil) userToken := redirURL.Query().Get("api_token") c.Logf("user token: %q", userToken) ctx, ac, kc := tc.ClientsWithToken(userToken) user, err := conn.UserGetCurrent(ctx, arvados.GetOptions{}) c.Assert(err, check.IsNil) _, err = conn.UserSetup(rootctx, arvados.UserSetupOptions{UUID: user.UUID}) c.Assert(err, check.IsNil) if activate { _, err = conn.UserActivate(rootctx, arvados.UserActivateOptions{UUID: user.UUID}) c.Assert(err, check.IsNil) user, err = conn.UserGetCurrent(ctx, arvados.GetOptions{}) c.Assert(err, check.IsNil) c.Logf("user UUID: %q", user.UUID) if !user.IsActive { c.Fatalf("failed to activate user -- %#v", user) } } return ctx, ac, kc, user } // RootClients returns Context, arvados.Client and keepclient structs initialized // to communicate with the cluster as the system root user. func (tc *TestCluster) RootClients() (context.Context, *arvados.Client, *keepclient.KeepClient) { return tc.ClientsWithToken(tc.Config.Clusters[tc.ClusterID].SystemRootToken) } // AnonymousClients returns Context, arvados.Client and keepclient structs initialized // to communicate with the cluster as the anonymous user. func (tc *TestCluster) AnonymousClients() (context.Context, *arvados.Client, *keepclient.KeepClient) { return tc.ClientsWithToken(tc.Config.Clusters[tc.ClusterID].Users.AnonymousUserToken) } // Conn gets rpc connection struct initialized to communicate with the // specified cluster. func (tc *TestCluster) Conn() *rpc.Conn { return rpc.NewConn(tc.ClusterID, tc.ControllerURL, true, rpc.PassthroughTokenProvider) }