github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/cmd/bacalhau/root.go (about) 1 package bacalhau 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/signal" 8 "strconv" 9 "strings" 10 11 "github.com/filecoin-project/bacalhau/pkg/config" 12 "github.com/filecoin-project/bacalhau/pkg/logger" 13 "github.com/filecoin-project/bacalhau/pkg/system" 14 "github.com/filecoin-project/bacalhau/pkg/telemetry" 15 "github.com/filecoin-project/bacalhau/pkg/version" 16 "github.com/rs/zerolog/log" 17 "github.com/spf13/cobra" 18 "github.com/spf13/viper" 19 "go.opentelemetry.io/otel/trace" 20 ) 21 22 var apiHost string 23 var apiPort int 24 var doNotTrack bool 25 26 var loggingMode = logger.LogModeDefault 27 28 var Fatal = FatalErrorHandler 29 30 var defaultAPIHost string 31 var defaultAPIPort int 32 33 func init() { //nolint:gochecknoinits 34 defaultAPIHost = system.Envs[system.GetEnvironment()].APIHost 35 defaultAPIPort = system.Envs[system.GetEnvironment()].APIPort 36 37 if config.GetAPIHost() != "" { 38 defaultAPIHost = config.GetAPIHost() 39 } 40 41 if config.GetAPIPort() != "" { 42 intPort, err := strconv.Atoi(config.GetAPIPort()) 43 if err == nil { 44 defaultAPIPort = intPort 45 } 46 } 47 48 if logtype, set := os.LookupEnv("LOG_TYPE"); set { 49 loggingMode = logger.LogMode(strings.ToLower(logtype)) 50 } 51 52 // Force cobra to set apiHost & apiPort 53 NewRootCmd() 54 } 55 56 func NewRootCmd() *cobra.Command { 57 RootCmd := &cobra.Command{ 58 Use: getCommandLineExecutable(), 59 Short: "Compute over data", 60 Long: `Compute over data`, 61 PersistentPreRun: func(cmd *cobra.Command, args []string) { 62 ctx := cmd.Context() 63 64 logger.ConfigureLogging(loggingMode) 65 66 cm := system.NewCleanupManager() 67 cm.RegisterCallback(telemetry.Cleanup) 68 ctx = context.WithValue(ctx, systemManagerKey, cm) 69 70 var names []string 71 root := cmd 72 for ; root.HasParent(); root = root.Parent() { 73 names = append([]string{root.Name()}, names...) 74 } 75 name := fmt.Sprintf("bacalhau.%s", strings.Join(names, ".")) 76 ctx, span := system.NewRootSpan(ctx, system.GetTracer(), name) 77 ctx = context.WithValue(ctx, spanKey, span) 78 79 cmd.SetContext(ctx) 80 }, 81 PersistentPostRun: func(cmd *cobra.Command, args []string) { 82 ctx := cmd.Context() 83 ctx.Value(spanKey).(trace.Span).End() 84 ctx.Value(systemManagerKey).(*system.CleanupManager).Cleanup(ctx) 85 }, 86 } 87 // ====== Start a job 88 89 // Create job from file 90 RootCmd.AddCommand(newCreateCmd()) 91 92 // Plumbing commands (advanced usage) 93 RootCmd.AddCommand(newDockerCmd()) 94 RootCmd.AddCommand(newWasmCmd()) 95 96 // Porcelain commands (language specific easy to use commands) 97 RootCmd.AddCommand(newRunCmd()) 98 99 RootCmd.AddCommand(newValidateCmd()) 100 101 RootCmd.AddCommand(newVersionCmd()) 102 103 // ====== Get information or results about a job 104 // Describe a job 105 RootCmd.AddCommand(newDescribeCmd()) 106 107 // Get the results of a job 108 RootCmd.AddCommand(newGetCmd()) 109 110 // Cancel a job 111 RootCmd.AddCommand(newCancelCmd()) 112 113 // List jobs 114 RootCmd.AddCommand(newListCmd()) 115 116 // ====== Run a server 117 118 // Serve commands 119 RootCmd.AddCommand(newServeCmd()) 120 RootCmd.AddCommand(newSimulatorCmd()) 121 RootCmd.AddCommand(newIDCmd()) 122 RootCmd.AddCommand(newDevStackCmd()) 123 124 RootCmd.PersistentFlags().StringVar( 125 &apiHost, "api-host", defaultAPIHost, 126 `The host for the client and server to communicate on (via REST). 127 Ignored if BACALHAU_API_HOST environment variable is set.`, 128 ) 129 RootCmd.PersistentFlags().IntVar( 130 &apiPort, "api-port", defaultAPIPort, 131 `The port for the client and server to communicate on (via REST). 132 Ignored if BACALHAU_API_PORT environment variable is set.`, 133 ) 134 RootCmd.PersistentFlags().Var( 135 LoggingFlag(&loggingMode), "log-mode", 136 `Log format: 'default','station','json','combined','event'`, 137 ) 138 return RootCmd 139 } 140 141 func Execute() { 142 rootCmd := NewRootCmd() 143 144 // Ensure commands are able to stop cleanly if someone presses ctrl+c 145 ctx, cancel := signal.NotifyContext(context.Background(), ShutdownSignals...) 146 defer cancel() 147 rootCmd.SetContext(ctx) 148 149 doNotTrack = false 150 if doNotTrackValue, foundDoNotTrack := os.LookupEnv("DO_NOT_TRACK"); foundDoNotTrack { 151 doNotTrackInt, err := strconv.Atoi(doNotTrackValue) 152 if err == nil && doNotTrackInt == 1 { 153 doNotTrack = true 154 } 155 } 156 157 viper.SetEnvPrefix("BACALHAU") 158 159 if err := viper.BindEnv("API_HOST"); err != nil { 160 log.Ctx(ctx).Fatal().Msgf("API_HOST was set, but could not bind.") 161 } 162 163 if err := viper.BindEnv("API_PORT"); err != nil { 164 log.Ctx(ctx).Fatal().Msgf("API_PORT was set, but could not bind.") 165 } 166 167 viper.AutomaticEnv() 168 169 if envAPIHost := viper.GetString("API_HOST"); envAPIHost != "" { 170 apiHost = envAPIHost 171 } 172 173 if envAPIPort := viper.GetString("API_PORT"); envAPIPort != "" { 174 var parseErr error 175 apiPort, parseErr = strconv.Atoi(envAPIPort) 176 if parseErr != nil { 177 log.Ctx(ctx).Fatal().Msgf("could not parse API_PORT into an int. %s", envAPIPort) 178 } 179 } 180 181 // Use stdout, not stderr for cmd.Print output, so that 182 // e.g. ID=$(bacalhau run) works 183 rootCmd.SetOut(system.Stdout) 184 // TODO this is from fixing a deprecation warning for SetOutput. Shouldn't this be system.Stderr? 185 rootCmd.SetErr(system.Stdout) 186 187 if err := rootCmd.Execute(); err != nil { 188 Fatal(rootCmd, err.Error(), 1) 189 } 190 } 191 192 type contextKey struct { 193 name string 194 } 195 196 var systemManagerKey = contextKey{name: "context key for storing the system manager"} 197 var spanKey = contextKey{name: "context key for storing the root span"} 198 199 func checkVersion(cmd *cobra.Command, args []string) error { 200 ctx := cmd.Context() 201 202 // corba doesn't do PersistentPreRun{,E} chaining yet 203 // https://github.com/spf13/cobra/issues/252 204 root := cmd 205 for ; root.HasParent(); root = root.Parent() { 206 } 207 root.PersistentPreRun(cmd, args) 208 209 // Check that the server version is compatible with the client version 210 serverVersion, _ := GetAPIClient().Version(ctx) // Ok if this fails, version validation will skip 211 if err := ensureValidVersion(ctx, version.Get(), serverVersion); err != nil { 212 Fatal(cmd, fmt.Sprintf("version validation failed: %s", err), 1) 213 return err 214 } 215 216 return nil 217 }