github.com/pachyderm/pachyderm@v1.13.4/src/server/transaction/cmds/cmds.go (about) 1 package cmds 2 3 import ( 4 "fmt" 5 "os" 6 7 "github.com/gogo/protobuf/jsonpb" 8 "github.com/pachyderm/pachyderm/src/client" 9 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 10 "github.com/pachyderm/pachyderm/src/client/pkg/grpcutil" 11 "github.com/pachyderm/pachyderm/src/client/transaction" 12 "github.com/pachyderm/pachyderm/src/server/pkg/cmdutil" 13 "github.com/pachyderm/pachyderm/src/server/pkg/tabwriter" 14 "github.com/pachyderm/pachyderm/src/server/transaction/pretty" 15 "github.com/spf13/cobra" 16 "github.com/spf13/pflag" 17 ) 18 19 // Cmds returns the set of commands used for managing transactions with the 20 // Pachyderm CLI tool pachctl. 21 func Cmds() []*cobra.Command { 22 var commands []*cobra.Command 23 24 marshaller := &jsonpb.Marshaler{Indent: " "} 25 26 raw := false 27 rawFlags := pflag.NewFlagSet("", pflag.ContinueOnError) 28 rawFlags.BoolVar(&raw, "raw", false, "disable pretty printing, print raw json") 29 30 fullTimestamps := false 31 fullTimestampsFlags := pflag.NewFlagSet("", pflag.ContinueOnError) 32 fullTimestampsFlags.BoolVar(&fullTimestamps, "full-timestamps", false, "Return absolute timestamps (as opposed to the default, relative timestamps).") 33 34 transactionDocs := &cobra.Command{ 35 Short: "Docs for transactions.", 36 Long: `Transactions modify several Pachyderm objects in a single operation. 37 38 The following pachctl commands are supported in transactions: 39 create repo 40 delete repo 41 start commit 42 finish commit 43 delete commit 44 create branch 45 delete branch 46 create pipeline 47 update pipeline 48 49 A transaction can be started with 'start transaction', after which the above 50 commands will be stored in the transaction rather than immediately executed. 51 The stored commands can be executed as a single operation with 'finish 52 transaction' or cancelled with 'delete transaction'.`, 53 } 54 commands = append(commands, cmdutil.CreateDocsAlias(transactionDocs, "transaction", " transaction$")) 55 56 listTransaction := &cobra.Command{ 57 Short: "List transactions.", 58 Long: "List transactions.", 59 Run: cmdutil.RunFixedArgs(0, func([]string) error { 60 c, err := client.NewOnUserMachine("user") 61 if err != nil { 62 return err 63 } 64 defer c.Close() 65 transactions, err := c.ListTransaction() 66 if err != nil { 67 return err 68 } 69 if raw { 70 for _, transaction := range transactions { 71 if err := marshaller.Marshal(os.Stdout, transaction); err != nil { 72 return err 73 } 74 } 75 return nil 76 } 77 writer := tabwriter.NewWriter(os.Stdout, pretty.TransactionHeader) 78 for _, transaction := range transactions { 79 pretty.PrintTransactionInfo(writer, transaction, fullTimestamps) 80 } 81 return writer.Flush() 82 }), 83 } 84 listTransaction.Flags().AddFlagSet(rawFlags) 85 listTransaction.Flags().AddFlagSet(fullTimestampsFlags) 86 commands = append(commands, cmdutil.CreateAlias(listTransaction, "list transaction")) 87 88 startTransaction := &cobra.Command{ 89 Short: "Start a new transaction.", 90 Long: "Start a new transaction.", 91 Run: cmdutil.RunFixedArgs(0, func([]string) error { 92 c, err := client.NewOnUserMachine("user") 93 if err != nil { 94 return err 95 } 96 defer c.Close() 97 txn, err := getActiveTransaction() 98 if err != nil { 99 return err 100 } 101 if txn != nil { 102 return errors.Errorf("cannot start a new transaction, since transaction with ID %q already exists", txn.ID) 103 } 104 105 transaction, err := c.StartTransaction() 106 if err != nil { 107 return grpcutil.ScrubGRPC(err) 108 } 109 // TODO: use advisory locks on config so we don't have a race condition if 110 // two commands are run simultaneously 111 err = setActiveTransaction(transaction) 112 if err != nil { 113 return err 114 } 115 fmt.Printf("started new transaction: %q\n", transaction.ID) 116 return nil 117 }), 118 } 119 commands = append(commands, cmdutil.CreateAlias(startTransaction, "start transaction")) 120 121 stopTransaction := &cobra.Command{ 122 Short: "Stop modifying the current transaction.", 123 Long: "Stop modifying the current transaction.", 124 Run: cmdutil.RunFixedArgs(0, func([]string) error { 125 // TODO: use advisory locks on config so we don't have a race condition if 126 // two commands are run simultaneously 127 txn, err := requireActiveTransaction() 128 if err != nil { 129 return err 130 } 131 132 err = ClearActiveTransaction() 133 if err != nil { 134 return err 135 } 136 137 fmt.Printf("Cleared active transaction: %s\n", txn.ID) 138 return nil 139 }), 140 } 141 commands = append(commands, cmdutil.CreateAlias(stopTransaction, "stop transaction")) 142 143 finishTransaction := &cobra.Command{ 144 Use: "{{alias}} [<transaction>]", 145 Short: "Execute and clear the currently active transaction.", 146 Long: "Execute and clear the currently active transaction.", 147 Run: cmdutil.RunBoundedArgs(0, 1, func(args []string) error { 148 c, err := client.NewOnUserMachine("user") 149 if err != nil { 150 return err 151 } 152 defer c.Close() 153 154 // TODO: use advisory locks on config so we don't have a race condition if 155 // two commands are run simultaneously 156 var txn *transaction.Transaction 157 if len(args) > 0 { 158 txn = &transaction.Transaction{ID: args[0]} 159 } else { 160 txn, err = requireActiveTransaction() 161 if err != nil { 162 return err 163 } 164 } 165 166 info, err := c.FinishTransaction(txn) 167 if err != nil { 168 return grpcutil.ScrubGRPC(err) 169 } 170 171 err = ClearActiveTransaction() 172 if err != nil { 173 return err 174 } 175 176 fmt.Printf("Completed transaction with %d requests: %s\n", len(info.Responses), info.Transaction.ID) 177 return nil 178 }), 179 } 180 commands = append(commands, cmdutil.CreateAlias(finishTransaction, "finish transaction")) 181 182 deleteTransaction := &cobra.Command{ 183 Use: "{{alias}} [<transaction>]", 184 Short: "Cancel and delete an existing transaction.", 185 Long: "Cancel and delete an existing transaction.", 186 Run: cmdutil.RunBoundedArgs(0, 1, func(args []string) error { 187 c, err := client.NewOnUserMachine("user") 188 if err != nil { 189 return err 190 } 191 defer c.Close() 192 193 // TODO: use advisory locks on config so we don't have a race condition if 194 // two commands are run simultaneously 195 var txn *transaction.Transaction 196 isActive := false 197 if len(args) > 0 { 198 txn = &transaction.Transaction{ID: args[0]} 199 200 // Don't check err here, this is just a quality-of-life check to clean 201 // up the config after a successful delete 202 activeTxn, _ := requireActiveTransaction() 203 if activeTxn != nil { 204 isActive = txn.ID == activeTxn.ID 205 } 206 } else { 207 txn, err = requireActiveTransaction() 208 if err != nil { 209 return err 210 } 211 isActive = true 212 } 213 214 err = c.DeleteTransaction(txn) 215 if err != nil { 216 return grpcutil.ScrubGRPC(err) 217 } 218 if isActive { 219 // The active transaction was successfully deleted, clean it up so the 220 // user doesn't need to manually 'stop transaction' it. 221 ClearActiveTransaction() 222 } 223 return nil 224 }), 225 } 226 commands = append(commands, cmdutil.CreateAlias(deleteTransaction, "delete transaction")) 227 228 inspectTransaction := &cobra.Command{ 229 Use: "{{alias}} [<transaction>]", 230 Short: "Print information about an open transaction.", 231 Long: "Print information about an open transaction.", 232 Run: cmdutil.RunBoundedArgs(0, 1, func(args []string) error { 233 c, err := client.NewOnUserMachine("user") 234 if err != nil { 235 return err 236 } 237 defer c.Close() 238 239 var txn *transaction.Transaction 240 if len(args) > 0 { 241 txn = &transaction.Transaction{ID: args[0]} 242 } else { 243 txn, err = requireActiveTransaction() 244 if err != nil { 245 return err 246 } 247 } 248 249 info, err := c.InspectTransaction(txn) 250 if err != nil { 251 return grpcutil.ScrubGRPC(err) 252 } 253 if info == nil { 254 return errors.Errorf("transaction %s not found", txn.ID) 255 } 256 if raw { 257 return marshaller.Marshal(os.Stdout, info) 258 } 259 return pretty.PrintDetailedTransactionInfo(&pretty.PrintableTransactionInfo{ 260 TransactionInfo: info, 261 FullTimestamps: fullTimestamps, 262 }) 263 }), 264 } 265 inspectTransaction.Flags().AddFlagSet(rawFlags) 266 inspectTransaction.Flags().AddFlagSet(fullTimestampsFlags) 267 commands = append(commands, cmdutil.CreateAlias(inspectTransaction, "inspect transaction")) 268 269 resumeTransaction := &cobra.Command{ 270 Use: "{{alias}} <transaction>", 271 Short: "Set an existing transaction as active.", 272 Long: "Set an existing transaction as active.", 273 Run: cmdutil.RunFixedArgs(1, func(args []string) error { 274 c, err := client.NewOnUserMachine("user") 275 if err != nil { 276 return err 277 } 278 defer c.Close() 279 info, err := c.InspectTransaction(&transaction.Transaction{ID: args[0]}) 280 if err != nil { 281 return grpcutil.ScrubGRPC(err) 282 } 283 if info == nil { 284 return errors.Errorf("transaction %s not found", args[0]) 285 } 286 287 err = setActiveTransaction(info.Transaction) 288 if err != nil { 289 return err 290 } 291 292 fmt.Printf("Resuming existing transaction with %d requests: %s\n", len(info.Requests), info.Transaction.ID) 293 return nil 294 }), 295 } 296 commands = append(commands, cmdutil.CreateAlias(resumeTransaction, "resume transaction")) 297 298 return commands 299 }