-
Notifications
You must be signed in to change notification settings - Fork 567
/
cmds.go
351 lines (319 loc) · 12.7 KB
/
cmds.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
package cmds
import (
"context"
"fmt"
"github.com/pachyderm/pachyderm/v2/src/admin"
"github.com/pachyderm/pachyderm/v2/src/enterprise"
"github.com/pachyderm/pachyderm/v2/src/internal/cmdutil"
"github.com/pachyderm/pachyderm/v2/src/internal/config"
"github.com/pachyderm/pachyderm/v2/src/internal/errors"
"github.com/pachyderm/pachyderm/v2/src/internal/pachctl"
"github.com/pachyderm/pachyderm/v2/src/license"
"github.com/pachyderm/pachyderm/v2/src/version"
"github.com/spf13/cobra"
)
func getIsActiveContextEnterpriseServer() (bool, error) {
cfg, err := config.Read(false, true)
if err != nil {
return false, errors.Wrapf(err, "could not read config")
}
_, ctx, err := cfg.ActiveEnterpriseContext(true)
if err != nil {
return false, errors.Wrapf(err, "could not retrieve the enterprise context from the config")
}
return ctx.EnterpriseServer, nil
}
// DeactivateCmd returns a cobra.Command to deactivate the enterprise service.
func DeactivateCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
deactivate := &cobra.Command{
Use: "{{alias}}",
Short: "Deactivate the enterprise service",
Long: "This command deactivates the enterprise service.",
Run: cmdutil.RunFixedArgs(0, func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, false)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
// Deactivate the enterprise server
req := &enterprise.DeactivateRequest{}
if _, err := c.Enterprise.Deactivate(c.Ctx(), req); err != nil {
return errors.EnsureStack(err)
}
return nil
}),
}
return cmdutil.CreateAlias(deactivate, "enterprise deactivate")
}
// RegisterCmd returns a cobra.Command that registers this cluster with a remote Enterprise Server.
func RegisterCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
var id, pachdAddr, pachdUsrAddr, enterpriseAddr, clusterId string
register := &cobra.Command{
Use: "{{alias}}",
Short: "Register the cluster with an enterprise license server",
Long: "This command registers a given cluster with an enterprise license server. Enterprise servers also handle IdP authentication for the clusters registered to it.",
Example: "\t- {{alias}} \n" +
"\t- {{alias}} --id my-cluster-id \n" +
"\t- {{alias}} --id my-cluster-id --pachd-address <pachd-ip>:650 \n" +
"\t- {{alias}} --id my-cluster-id --pachd-enterprise-server-address <pach-enterprise-IP>:650 \n",
Run: cmdutil.RunFixedArgs(0, func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, false)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
ec, err := pachctlCfg.NewOnUserMachine(ctx, true)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer ec.Close()
if pachdUsrAddr == "" {
pachdUsrAddr = c.GetAddress().Qualified()
}
if pachdAddr == "" {
pachdAddr = c.GetAddress().Qualified()
}
if enterpriseAddr == "" {
enterpriseAddr = ec.GetAddress().Qualified()
}
if clusterId == "" {
clusterInfo, inspectErr := c.AdminAPIClient.InspectCluster(c.Ctx(), &admin.InspectClusterRequest{
ClientVersion: version.Version,
})
if inspectErr != nil {
return errors.Wrapf(inspectErr, "could not inspect cluster")
}
clusterId = clusterInfo.DeploymentId
}
enterpriseServer, err := getIsActiveContextEnterpriseServer()
if err != nil {
return err
}
// Register the pachd with the license server
resp, err := ec.License.AddCluster(ec.Ctx(),
&license.AddClusterRequest{
Id: id,
Address: pachdAddr,
UserAddress: pachdUsrAddr,
ClusterDeploymentId: clusterId,
EnterpriseServer: enterpriseServer,
})
if err != nil {
return errors.Wrapf(err, "could not register pachd with the license service")
}
// activate the Enterprise service
_, err = c.Enterprise.Activate(c.Ctx(),
&enterprise.ActivateRequest{
Id: id,
Secret: resp.Secret,
LicenseServer: enterpriseAddr,
})
if err != nil {
err = errors.Wrapf(err, "could not register with the license server.")
_, deleteErr := ec.License.DeleteCluster(ec.Ctx(), &license.DeleteClusterRequest{Id: id})
if deleteErr != nil {
deleteErr := errors.Wrapf(deleteErr, "also failed to rollback creation of cluster with ID, %v."+
"To retry enterprise registration, first delete this cluster with 'pachctl license delete-cluster --id %v'.: %v",
id, id, deleteErr.Error())
return errors.Wrap(err, deleteErr.Error())
}
return err
}
return nil
}),
}
register.PersistentFlags().StringVar(&id, "id", "", "Set the ID for this cluster.")
register.PersistentFlags().StringVar(&pachdAddr, "pachd-address", "", "Set the address for the enterprise server to reach this pachd.")
register.PersistentFlags().StringVar(&pachdUsrAddr, "pachd-user-address", "", "Set the address for a user to reach this pachd.")
register.PersistentFlags().StringVar(&enterpriseAddr, "enterprise-server-address", "", "Set the address for the pachd to reach the enterprise server.")
register.PersistentFlags().StringVar(&clusterId, "cluster-deployment-id", "", "Set the deployment id of the cluster being registered.")
return cmdutil.CreateAlias(register, "enterprise register")
}
// GetStateCmd returns a cobra.Command to activate the enterprise features of
// Pachyderm within a Pachyderm cluster. All repos will go from
// publicly-accessible to accessible only by the owner, who can subsequently add
// users
func GetStateCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
var isEnterprise bool
getState := &cobra.Command{
Short: "Check whether the Pachyderm cluster has an active enterprise license.",
Long: "This command checks whether the Pachyderm cluster has an active enterprise license; If so, it also returns the expiration date of the license.",
Run: cmdutil.Run(func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, isEnterprise)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
resp, err := c.Enterprise.GetState(c.Ctx(), &enterprise.GetStateRequest{})
if err != nil {
return errors.EnsureStack(err)
}
if resp.State == enterprise.State_NONE {
fmt.Println("No Pachyderm Enterprise token was found")
return nil
}
ts := resp.Info.Expires.AsTime()
fmt.Printf("Pachyderm Enterprise token state: %s\nExpiration: %s\n",
resp.State.String(), ts.String())
return nil
}),
}
getState.PersistentFlags().BoolVar(&isEnterprise, "enterprise", false, "Activate auth on the active enterprise context")
return cmdutil.CreateAlias(getState, "enterprise get-state")
}
func SyncContextsCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
syncContexts := &cobra.Command{
Short: "Pull all available Pachyderm Cluster contexts into your pachctl config",
Long: "This command pulls all available Pachyderm Cluster contexts into your pachctl config.",
Run: cmdutil.Run(func(args []string) error {
cfg, err := config.Read(false, false)
if err != nil {
return err
}
ec, err := pachctlCfg.NewOnUserMachine(ctx, true)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer ec.Close()
resp, err := ec.License.ListUserClusters(ec.Ctx(), &license.ListUserClustersRequest{})
if err != nil {
return errors.EnsureStack(err)
}
// update the pach_address of all existing contexts, and add the rest as well.
for _, cluster := range resp.Clusters {
if context, ok := cfg.V2.Contexts[cluster.Id]; ok {
// reset the session token if the context is pointing to a new cluster deployment
if cluster.ClusterDeploymentId != context.ClusterDeploymentId {
context.ClusterDeploymentId = cluster.ClusterDeploymentId
context.SessionToken = ""
}
context.PachdAddress = cluster.Address
context.EnterpriseServer = cluster.EnterpriseServer
} else {
cfg.V2.Contexts[cluster.Id] = &config.Context{
ClusterDeploymentId: cluster.ClusterDeploymentId,
PachdAddress: cluster.Address,
Source: config.ContextSource_IMPORTED,
EnterpriseServer: cluster.EnterpriseServer,
}
}
}
err = cfg.Write()
if err != nil {
return err
}
return nil
}),
}
return cmdutil.CreateAlias(syncContexts, "enterprise sync-contexts")
}
// HeartbeatCmd triggers an explicit heartbeat to the license server
func HeartbeatCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
var isEnterprise bool
heartbeat := &cobra.Command{
Short: "Sync the enterprise state with the license server immediately.",
Long: "This command syncs the enterprise state with the license server immediately. \n\n" +
"This means that if there is an active enterprise license associated with the enterprise server, the cluster will also have access to enterprise features.",
Run: cmdutil.Run(func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, isEnterprise)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
_, err = c.Enterprise.Heartbeat(c.Ctx(), &enterprise.HeartbeatRequest{})
if err != nil {
return errors.Wrapf(err, "could not sync with license server")
}
return nil
}),
}
heartbeat.PersistentFlags().BoolVar(&isEnterprise, "enterprise", false, "Make the enterprise server refresh its state")
return cmdutil.CreateAlias(heartbeat, "enterprise heartbeat")
}
// PauseCmd pauses the cluster.
func PauseCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
pause := &cobra.Command{
Short: "Pause the cluster.",
Long: "This command pauses the cluster.",
Run: cmdutil.Run(func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, true)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
_, err = c.Enterprise.Pause(c.Ctx(), &enterprise.PauseRequest{})
if err != nil {
return errors.Wrapf(err, "could not pause cluster")
}
return nil
}),
}
return cmdutil.CreateAlias(pause, "enterprise pause")
}
// UnpauseCmd pauses the cluster.
func UnpauseCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
unpause := &cobra.Command{
Short: "Unpause the cluster.",
Long: "This command unpauses the cluster.",
Run: cmdutil.Run(func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, true)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
_, err = c.Enterprise.Unpause(c.Ctx(), &enterprise.UnpauseRequest{})
if err != nil {
return errors.Wrapf(err, "could not unpause cluster")
}
return nil
}),
}
return cmdutil.CreateAlias(unpause, "enterprise unpause")
}
// PauseStatusCmd returns the pause status of the cluster: unpaused; partially
// paused; or completely paused.
func PauseStatusCmd(ctx context.Context, pachctlCfg *pachctl.Config) *cobra.Command {
pauseStatus := &cobra.Command{
Short: "Get the pause status of the cluster.",
Long: "This command returns the pause state of the cluster: `normal`, `partially-paused` or `paused`.",
Run: cmdutil.Run(func(args []string) error {
c, err := pachctlCfg.NewOnUserMachine(ctx, true)
if err != nil {
return errors.Wrapf(err, "could not connect")
}
defer c.Close()
resp, err := c.Enterprise.PauseStatus(c.Ctx(), &enterprise.PauseStatusRequest{})
if err != nil {
return errors.Wrapf(err, "could not get pause status")
}
switch resp.Status {
case enterprise.PauseStatusResponse_UNPAUSED:
fmt.Println("unpaused")
case enterprise.PauseStatusResponse_PARTIALLY_PAUSED:
fmt.Println("partially-paused")
case enterprise.PauseStatusResponse_PAUSED:
fmt.Println("paused")
}
return nil
}),
}
return cmdutil.CreateAlias(pauseStatus, "enterprise pause-status")
}
// Cmds returns pachctl commands related to Pachyderm Enterprise
func Cmds(mainCtx context.Context, pachctlCfg *pachctl.Config) []*cobra.Command {
var commands []*cobra.Command
enterprise := &cobra.Command{
Short: "Enterprise commands enable Pachyderm Enterprise features",
Long: "Enterprise commands enable Pachyderm Enterprise features",
}
commands = append(commands, cmdutil.CreateAlias(enterprise, "enterprise"))
commands = append(commands, RegisterCmd(mainCtx, pachctlCfg))
commands = append(commands, DeactivateCmd(mainCtx, pachctlCfg))
commands = append(commands, GetStateCmd(mainCtx, pachctlCfg))
commands = append(commands, SyncContextsCmd(mainCtx, pachctlCfg))
commands = append(commands, HeartbeatCmd(mainCtx, pachctlCfg))
commands = append(commands, PauseCmd(mainCtx, pachctlCfg))
commands = append(commands, UnpauseCmd(mainCtx, pachctlCfg))
commands = append(commands, PauseStatusCmd(mainCtx, pachctlCfg))
return commands
}