// serve starts the libStorage server, blocking the current thread until the // server is shutdown. // // char* host the golang network-style address. if no value is provided // then a random TCP port bound to localhost is used // // short argc the length of the argv array // // void* argv a pointer to an array of char* strings that represent the // drivers and corresponding service names to load. if the // array is odd-numbered then the service for the trailing // driver takes the name of the driver // // char* serve(char* host, int argc, void* argv); //export serve func serve( host *C.char, argc C.int, argv unsafe.Pointer) *C.char { iargc := int(argc) args := make([]string, iargc) pargv := argv for x := 0; x < iargc; x++ { gostr := C.GoString((*C.char)(pargv)) log.WithFields(log.Fields{ "x": x, "gostr": gostr, }).Info("parsed gostr") args[x] = gostr pargv = unsafe.Pointer(uintptr(pargv) + unsafe.Sizeof(gostr)) } szHost := C.GoString(host) log.WithFields(log.Fields{ "host": szHost, "args": args, }).Info("serving") config, err := apicfg.NewConfig() if err != nil { return C.CString(err.Error()) } if len(szHost) > 0 { os.Setenv("LIBSTORAGE_HOST", szHost) } _, errs, err := server.Serve(nil, config) if err != nil { return C.CString(err.Error()) } <-errs return nil }
// Run the server. func Run() { server.CloseOnAbort() flag.Usage = printUsage flag.Parse() if flagVersion != nil && *flagVersion { _, _, thisExeAbsPath := gotil.GetThisPathParts() fmt.Fprintf(os.Stdout, "Binary: %s\n", thisExeAbsPath) fmt.Fprint(os.Stdout, api.Version.String()) os.Exit(0) } if flagEnv != nil && *flagEnv { for _, v := range os.Environ() { fmt.Fprintf(os.Stdout, "%s\n", v) } os.Exit(0) } // if a config is specified then do not care about any other options if flagConfig != nil && gotil.FileExists(*flagConfig) { config = gofigCore.New() if err := config.ReadConfigFile(*flagConfig); err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } if flagPrintConfig != nil && *flagPrintConfig { jstr, err := config.ToJSON() if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } fmt.Fprintln(os.Stdout, jstr) os.Exit(0) } s, errs, err := server.Serve(nil, config) if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } err = <-errs if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } s.Close() os.Exit(0) } cfg, err := apiconfig.NewConfig() if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } config = cfg for _, fs := range config.FlagSets() { flag.CommandLine.AddFlagSet(fs) } if flagHelp != nil && *flagHelp { flag.Usage() } if len(flag.Args()) == 0 { flag.Usage() } if flagHost != nil { os.Setenv("LIBSTORAGE_HOST", *flagHost) } if flagLogLvl != nil { os.Setenv("LIBSTORAGE_LOGGING_LEVEL", *flagLogLvl) } if lvl, err := log.ParseLevel( config.GetString(apitypes.ConfigLogLevel)); err == nil { log.SetLevel(lvl) } if flagPrintConfig != nil && *flagPrintConfig { jstr, err := config.ToJSON() if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } fmt.Fprintln(os.Stdout, jstr) os.Exit(0) } buf := &bytes.Buffer{} fmt.Fprintf(buf, "libstorage:\n server:\n services:\n") for _, ds := range flag.Args() { dsp := strings.Split(ds, ":") dn := dsp[0] sn := dsp[0] if len(dsp) > 1 { sn = dsp[1] } fmt.Fprintf(buf, " %s:\n driver: %s\n", sn, dn) } if err := config.ReadConfig(buf); err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } server.CloseOnAbort() _, errs, err := server.Serve(nil, config) if err != nil { fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) os.Exit(1) } <-errs }
// New returns a new libStorage client. func New(goCtx gocontext.Context, config gofig.Config) (types.Client, error) { if config == nil { var err error if config, err = apicnfg.NewConfig(); err != nil { return nil, err } } config = config.Scope(types.ConfigClient) types.BackCompat(config) var ( c *client err error ) c = &client{ctx: context.New(goCtx), config: config} c.ctx = c.ctx.WithValue(context.ClientKey, c) logFields := log.Fields{} logConfig, err := utils.ParseLoggingConfig( config, logFields, "libstorage.client") if err != nil { return nil, err } // always update the server context's log level context.SetLogLevel(c.ctx, logConfig.Level) c.ctx.WithFields(logFields).Info("configured logging") if config.IsSet(types.ConfigService) { c.ctx = c.ctx.WithValue( context.ServiceKey, config.GetString(types.ConfigService)) } storDriverName := config.GetString(types.ConfigStorageDriver) if storDriverName == "" { c.ctx.Warn("no storage driver found") } else { if c.sd, err = registry.NewStorageDriver(storDriverName); err != nil { return nil, err } if err = c.sd.Init(c.ctx, config); err != nil { return nil, err } if papi, ok := c.sd.(types.ProvidesAPIClient); ok { c.api = papi.API() } if pxli, pxliOk := c.sd.(types.ProvidesStorageExecutorCLI); pxliOk { c.xli = pxli.XCLI() } c.ctx.Info("storage driver initialized") } // if the API or XLI are nil, then the storage driver is not the libStorage // storage driver, and we should jump avoid any more initialization if c.api == nil || c.xli == nil { c.ctx.Info("created libStorage client") return c, nil } osDriverName := config.GetString(types.ConfigOSDriver) if osDriverName == "" { c.ctx.Warn("no os driver found") } else { if c.od, err = registry.NewOSDriver(osDriverName); err != nil { return nil, err } if err = c.od.Init(c.ctx, config); err != nil { return nil, err } c.ctx.Info("os driver initialized") } intDriverName := config.GetString(types.ConfigIntegrationDriver) if intDriverName == "" { c.ctx.Warn("no integration driver found") } else { if c.id, err = registry.NewIntegrationDriver( intDriverName); err != nil { return nil, err } if err := c.id.Init(c.ctx, config); err != nil { return nil, err } c.ctx.Info("integration driver initialized") } c.ctx.Info("created libStorage client") return c, nil }
func newServer(goCtx gocontext.Context, config gofig.Config) (*server, error) { adminTokenUUID, err := types.NewUUID() if err != nil { return nil, err } adminToken := adminTokenUUID.String() serverName := randomServerName() ctx := context.New(goCtx) ctx = ctx.WithValue(context.ServerKey, serverName) ctx = ctx.WithValue(context.AdminTokenKey, adminToken) if lvl, ok := context.GetLogLevel(ctx); ok { switch lvl { case log.DebugLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.DebugLevel) case log.InfoLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.InfoLevel) case log.WarnLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.WarnLevel) case log.ErrorLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.ErrorLevel) case log.FatalLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.FatalLevel) case log.PanicLevel: ctx = context.WithValue( ctx, gournal.LevelKey(), gournal.PanicLevel) } } if logger, ok := ctx.Value(context.LoggerKey).(*log.Logger); ok { ctx = context.WithValue( ctx, gournal.AppenderKey(), glogrus.NewWithOptions( logger.Out, logger.Level, logger.Formatter)) } if config == nil { var err error if config, err = apicnfg.NewConfig(); err != nil { return nil, err } } config = config.Scope(types.ConfigServer) s := &server{ ctx: ctx, name: serverName, adminToken: adminToken, config: config, closeSignal: make(chan int), closedSignal: make(chan int), closeOnce: &sync.Once{}, } if logger, ok := s.ctx.Value(context.LoggerKey).(*log.Logger); ok { s.PrintServerStartupHeader(logger.Out) } else { s.PrintServerStartupHeader(os.Stdout) } if lvl, err := log.ParseLevel( config.GetString(types.ConfigLogLevel)); err == nil { context.SetLogLevel(s.ctx, lvl) } logFields := log.Fields{} logConfig, err := utils.ParseLoggingConfig( config, logFields, "libstorage.server") if err != nil { return nil, err } // always update the server context's log level context.SetLogLevel(s.ctx, logConfig.Level) s.ctx.WithFields(logFields).Info("configured logging") s.ctx.Info("initializing server") if err := s.initEndpoints(s.ctx); err != nil { return nil, err } s.ctx.Info("initialized endpoints") if err := services.Init(s.ctx, s.config); err != nil { return nil, err } s.ctx.Info("initialized services") if logConfig.HTTPRequests || logConfig.HTTPResponses { s.logHTTPEnabled = true s.logHTTPRequests = logConfig.HTTPRequests s.logHTTPResponses = logConfig.HTTPResponses s.stdOut = getLogIO(logConfig.Stdout, types.ConfigLogStdout) s.stdErr = getLogIO(logConfig.Stderr, types.ConfigLogStderr) } s.initGlobalMiddleware() if err := s.initRouters(); err != nil { return nil, err } servers = append(servers, s) return s, nil }
// Run runs the executor CLI. func Run() { args := os.Args if len(args) < 3 { printUsageAndExit() } d, err := registry.NewStorageExecutor(args[1]) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } driverName := strings.ToLower(d.Name()) config, err := apiconfig.NewConfig() if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } apiconfig.UpdateLogLevel(config) ctx := context.Background() if err := d.Init(ctx, config); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } cmd := cmdRx.FindString(args[2]) if cmd == "" { printUsageAndExit() } store := utils.NewStore() var ( result interface{} op string exitCode int ) if strings.EqualFold(cmd, apitypes.LSXCmdSupported) { op = "supported" if dws, ok := d.(apitypes.StorageExecutorWithSupported); ok { opResult, opErr := dws.Supported(ctx, store) if opErr != nil { err = opErr } else { result = opResult } } else { err = apitypes.ErrNotImplemented } } else if strings.EqualFold(cmd, apitypes.LSXCmdInstanceID) { op = "instance ID" opResult, opErr := d.InstanceID(ctx, store) if opErr != nil { err = opErr } else { opResult.Driver = driverName result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdNextDevice) { op = "next device" opResult, opErr := d.NextDevice(ctx, store) if opErr != nil && opErr != apitypes.ErrNotImplemented { err = opErr } else { result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdLocalDevices) { if len(args) < 4 { printUsageAndExit() } op = "local devices" opResult, opErr := d.LocalDevices(ctx, &apitypes.LocalDevicesOpts{ ScanType: apitypes.ParseDeviceScanType(args[3]), Opts: store, }) opResult.Driver = driverName if opErr != nil { err = opErr } else { result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdWaitForDevice) { if len(args) < 5 { printUsageAndExit() } op = "wait" opts := &apitypes.WaitForDeviceOpts{ LocalDevicesOpts: apitypes.LocalDevicesOpts{ ScanType: apitypes.ParseDeviceScanType(args[3]), Opts: store, }, Token: strings.ToLower(args[4]), Timeout: utils.DeviceAttachTimeout(args[5]), } ldl := func() (bool, *apitypes.LocalDevices, error) { ldm, err := d.LocalDevices(ctx, &opts.LocalDevicesOpts) if err != nil { return false, nil, err } for k := range ldm.DeviceMap { if strings.ToLower(k) == opts.Token { return true, ldm, nil } } return false, ldm, nil } var ( found bool opErr error opResult *apitypes.LocalDevices timeoutC = time.After(opts.Timeout) tick = time.Tick(500 * time.Millisecond) ) TimeoutLoop: for { select { case <-timeoutC: exitCode = apitypes.LSXExitCodeTimedOut break TimeoutLoop case <-tick: if found, opResult, opErr = ldl(); found || opErr != nil { break TimeoutLoop } } } if opErr != nil { err = opErr } else { opResult.Driver = driverName result = opResult } } if err != nil { // if the function is not implemented then exit with // apitypes.LSXExitCodeNotImplemented to let callers // know that the function is unsupported on this system exitCode = 1 if strings.EqualFold(err.Error(), apitypes.ErrNotImplemented.Error()) { exitCode = apitypes.LSXExitCodeNotImplemented } fmt.Fprintf(os.Stderr, "error: error getting %s: %v\n", op, err) os.Exit(exitCode) } switch tr := result.(type) { case bool: fmt.Fprintf(os.Stdout, "%v", result) case string: fmt.Fprintln(os.Stdout, result) case encoding.TextMarshaler: buf, err := tr.MarshalText() if err != nil { fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err) os.Exit(1) } os.Stdout.Write(buf) default: buf, err := json.Marshal(result) if err != nil { fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err) os.Exit(1) } if isNullBuf(buf) { os.Stdout.Write(emptyJSONBuff) } else { os.Stdout.Write(buf) } } os.Exit(exitCode) }