// 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
}
Exemple #2
0
// 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
}
Exemple #3
0
// 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
}
Exemple #4
0
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
}
Exemple #5
0
// 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)
}