17995: Merge branch 'main'
[arvados.git] / lib / boot / helpers.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package boot
6
7 import (
8         "context"
9         "net/url"
10
11         "git.arvados.org/arvados.git/lib/controller/rpc"
12         "git.arvados.org/arvados.git/lib/service"
13         "git.arvados.org/arvados.git/sdk/go/arvados"
14         "git.arvados.org/arvados.git/sdk/go/arvadosclient"
15         "git.arvados.org/arvados.git/sdk/go/auth"
16         "git.arvados.org/arvados.git/sdk/go/ctxlog"
17         "git.arvados.org/arvados.git/sdk/go/keepclient"
18         "gopkg.in/check.v1"
19 )
20
21 // TestCluster stores a working test cluster data
22 type TestCluster struct {
23         Super         Supervisor
24         Config        arvados.Config
25         ControllerURL *url.URL
26         ClusterID     string
27 }
28
29 type logger struct {
30         loggerfunc func(...interface{})
31 }
32
33 func (l logger) Log(args ...interface{}) {
34         l.loggerfunc(args)
35 }
36
37 // NewTestCluster loads the provided configuration, and sets up a test cluster
38 // ready for being started.
39 func NewTestCluster(srcPath, clusterID string, cfg *arvados.Config, listenHost string, logWriter func(...interface{})) *TestCluster {
40         return &TestCluster{
41                 Super: Supervisor{
42                         SourcePath:           srcPath,
43                         ClusterType:          "test",
44                         ListenHost:           listenHost,
45                         ControllerAddr:       ":0",
46                         OwnTemporaryDatabase: true,
47                         Stderr: &service.LogPrefixer{
48                                 Writer: ctxlog.LogWriter(logWriter),
49                                 Prefix: []byte("[" + clusterID + "] ")},
50                 },
51                 Config:    *cfg,
52                 ClusterID: clusterID,
53         }
54 }
55
56 // Start the test cluster.
57 func (tc *TestCluster) Start() {
58         tc.Super.Start(context.Background(), &tc.Config, "-")
59 }
60
61 // WaitReady waits for all components to report healthy, and finishes setting
62 // up the TestCluster struct.
63 func (tc *TestCluster) WaitReady() bool {
64         au, ok := tc.Super.WaitReady()
65         if !ok {
66                 return ok
67         }
68         u := url.URL(*au)
69         tc.ControllerURL = &u
70         return ok
71 }
72
73 // ClientsWithToken returns Context, Arvados.Client and keepclient structs
74 // initialized to connect to the cluster with the supplied Arvados token.
75 func (tc *TestCluster) ClientsWithToken(token string) (context.Context, *arvados.Client, *keepclient.KeepClient) {
76         cl := tc.Config.Clusters[tc.ClusterID]
77         ctx := auth.NewContext(context.Background(), auth.NewCredentials(token))
78         ac, err := arvados.NewClientFromConfig(&cl)
79         if err != nil {
80                 panic(err)
81         }
82         ac.AuthToken = token
83         arv, err := arvadosclient.New(ac)
84         if err != nil {
85                 panic(err)
86         }
87         kc := keepclient.New(arv)
88         return ctx, ac, kc
89 }
90
91 // UserClients logs in as a user called "example", get the user's API token,
92 // initialize clients with the API token, set up the user and
93 // optionally activate the user.  Return client structs for
94 // communicating with the cluster on behalf of the 'example' user.
95 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) {
96         login, err := conn.UserSessionCreate(rootctx, rpc.UserSessionCreateOptions{
97                 ReturnTo: ",https://example.com",
98                 AuthInfo: rpc.UserSessionAuthInfo{
99                         Email:     authEmail,
100                         FirstName: "Example",
101                         LastName:  "User",
102                         Username:  "example",
103                 },
104         })
105         c.Assert(err, check.IsNil)
106         redirURL, err := url.Parse(login.RedirectLocation)
107         c.Assert(err, check.IsNil)
108         userToken := redirURL.Query().Get("api_token")
109         c.Logf("user token: %q", userToken)
110         ctx, ac, kc := tc.ClientsWithToken(userToken)
111         user, err := conn.UserGetCurrent(ctx, arvados.GetOptions{})
112         c.Assert(err, check.IsNil)
113         _, err = conn.UserSetup(rootctx, arvados.UserSetupOptions{UUID: user.UUID})
114         c.Assert(err, check.IsNil)
115         if activate {
116                 _, err = conn.UserActivate(rootctx, arvados.UserActivateOptions{UUID: user.UUID})
117                 c.Assert(err, check.IsNil)
118                 user, err = conn.UserGetCurrent(ctx, arvados.GetOptions{})
119                 c.Assert(err, check.IsNil)
120                 c.Logf("user UUID: %q", user.UUID)
121                 if !user.IsActive {
122                         c.Fatalf("failed to activate user -- %#v", user)
123                 }
124         }
125         return ctx, ac, kc, user
126 }
127
128 // RootClients returns Context, arvados.Client and keepclient structs initialized
129 // to communicate with the cluster as the system root user.
130 func (tc *TestCluster) RootClients() (context.Context, *arvados.Client, *keepclient.KeepClient) {
131         return tc.ClientsWithToken(tc.Config.Clusters[tc.ClusterID].SystemRootToken)
132 }
133
134 // AnonymousClients returns Context, arvados.Client and keepclient structs initialized
135 // to communicate with the cluster as the anonymous user.
136 func (tc *TestCluster) AnonymousClients() (context.Context, *arvados.Client, *keepclient.KeepClient) {
137         return tc.ClientsWithToken(tc.Config.Clusters[tc.ClusterID].Users.AnonymousUserToken)
138 }
139
140 // Conn gets rpc connection struct initialized to communicate with the
141 // specified cluster.
142 func (tc *TestCluster) Conn() *rpc.Conn {
143         return rpc.NewConn(tc.ClusterID, tc.ControllerURL, true, rpc.PassthroughTokenProvider)
144 }