// WriteTask writes a task to a ResponseWriter. func WriteTask( ctx types.Context, config gofig.Config, w http.ResponseWriter, store types.Store, task *types.Task, okStatus int) error { if store.GetBool("async") { WriteJSON(w, http.StatusAccepted, task) return nil } exeTimeoutDur, err := time.ParseDuration( config.GetString(types.ConfigServerTasksExeTimeout)) if err != nil { exeTimeoutDur = time.Duration(time.Second * 60) } exeTimeout := time.NewTimer(exeTimeoutDur) select { case <-services.TaskWaitC(ctx, task.ID): if task.Error != nil { return task.Error } WriteJSON(w, okStatus, task.Result) case <-exeTimeout.C: WriteJSON(w, http.StatusRequestTimeout, task) } return nil }
// initDefaultLibStorageServices initializes the config object with a default // libStorage service if one is not present. // // TODO Move this into libStorage in libStorage 0.1.2 func initDefaultLibStorageServices( ctx apitypes.Context, config gofig.Config) error { if config.IsSet(apitypes.ConfigServices) { ctx.Debug( "libStorage auto service mode disabled; services defined") return nil } serviceName := config.GetString(apitypes.ConfigService) if serviceName == "" { ctx.Debug( "libStorage auto service mode disabled; service name empty") return nil } ctx.WithField("driver", serviceName).Info( "libStorage auto service mode enabled") buf := &bytes.Buffer{} fmt.Fprintf(buf, defaultServiceConfigFormat, serviceName) if err := config.ReadConfig(buf); err != nil { return err } return nil }
// UpdateLogLevel updates the log level based on the config. func UpdateLogLevel(config gofig.Config) { ll, err := log.ParseLevel(config.GetString(types.ConfigLogLevel)) if err != nil { return } log.SetLevel(ll) }
// ActivateLibStorage activates libStorage and returns a possibly mutated // context. func ActivateLibStorage( ctx apitypes.Context, config gofig.Config) (apitypes.Context, gofig.Config, <-chan error, error) { config = config.Scope("rexray") // set the `libstorage.service` property to the value of // `rexray.storageDrivers` if the former is not defined and the // latter is if !config.IsSet(apitypes.ConfigService) && config.IsSet("rexray.storageDrivers") { if sd := config.GetStringSlice("rexray.storageDrivers"); len(sd) > 0 { config.Set(apitypes.ConfigService, sd[0]) } else if sd := config.GetString("rexray.storageDrivers"); sd != "" { config.Set(apitypes.ConfigService, sd) } } if !config.IsSet(apitypes.ConfigIgVolOpsMountPath) { config.Set(apitypes.ConfigIgVolOpsMountPath, LibFilePath("volumes")) } var ( err error errs <-chan error ) ctx, config, errs, err = activateLibStorage(ctx, config) if err != nil { return ctx, config, errs, err } return ctx, config, errs, nil }
func startTimeout(config gofig.Config) time.Duration { dur, err := time.ParseDuration( config.GetString("rexray.module.startTimeout")) if err != nil { return time.Duration(10) * time.Second } return dur }
func activateLibStorage( ctx apitypes.Context, config gofig.Config) (apitypes.Context, gofig.Config, <-chan error, error) { var ( host string isRunning bool ) if host = config.GetString(apitypes.ConfigHost); host == "" { if host, isRunning = IsLocalServerActive(ctx, config); isRunning { ctx = setHost(ctx, config, host) } } if host == "" && !isRunning { return ctx, config, nil, errors.New("libStorage host config missing") } return ctx, config, nil, nil }
func getString( config gofig.Config, key string, roots ...string) string { var val string for _, r := range roots { rk := strings.Replace(key, "libstorage.", fmt.Sprintf("%s.", r), 1) if val = config.GetString(rk); val != "" { return val } } val = config.GetString(key) if val != "" { return val } return "" }
func assertString(t *testing.T, c types.Config, key, expected string) { v := c.GetString(key) if v != expected { t.Fatalf("%s != %s; == %v", key, expected, v) } }
// DeviceAttachTimeout gets the configured device attach timeout. func DeviceAttachTimeout(config gofig.Config) time.Duration { return utils.DeviceAttachTimeout( config.GetString(types.ConfigDeviceAttachTimeout)) }
// RootDir returns the path to the VFS root directory. func RootDir(config gofig.Config) string { return config.GetString("vfs.root") }
// IsLocalServerActive returns a flag indicating whether or not a local // libStorage is already running. func IsLocalServerActive( ctx apitypes.Context, config gofig.Config) (host string, running bool) { var ( isLocal bool specFile = SpecFilePath() ) if gotil.FileExists(specFile) { if h, _ := ReadSpecFile(); h != "" { host = h logHostSpec(ctx, host, "read spec file") defer func() { if running || !isLocal { return } host = "" os.RemoveAll(specFile) ctx.WithField("specFile", specFile).Info( "removed invalid spec file") }() } } if host == "" { host = config.GetString(apitypes.ConfigHost) } if host == "" { return "", false } proto, addr, err := gotil.ParseAddress(host) if err != nil { return "", false } switch proto { case "unix": isLocal = true ctx.WithField("sock", addr).Debug("is local unix server active") var sockExists, isActive bool if sockExists = gotil.FileExists(addr); sockExists { if isActive = IsAddressActive(proto, addr); !isActive { os.RemoveAll(addr) ctx.WithField("sockFile", addr).Info( "removed invalid sock file") } } return host, isActive case "tcp": m := localHostRX.FindStringSubmatch(addr) if len(m) < 3 { return "", false } isLocal = true port, err := strconv.Atoi(m[2]) if err != nil { return "", false } ctx.WithField("port", port).Debug("is local tcp server active") return host, IsAddressActive(proto, addr) } return "", false }
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 }
// 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 (d *driver) Init(ctx types.Context, config gofig.Config) error { logFields := log.Fields{} addr := config.GetString(types.ConfigHost) d.ctx = ctx.WithValue(context.HostKey, addr) d.ctx.Debug("got configured host address") proto, lAddr, err := gotil.ParseAddress(addr) if err != nil { return err } tlsConfig, err := utils.ParseTLSConfig( config, logFields, "libstorage.client") if err != nil { return err } host := getHost(proto, lAddr, tlsConfig) lsxPath := config.GetString(types.ConfigExecutorPath) cliType := types.ParseClientType(config.GetString(types.ConfigClientType)) disableKeepAlive := config.GetBool(types.ConfigHTTPDisableKeepAlive) logFields["host"] = host logFields["lsxPath"] = lsxPath logFields["clientType"] = cliType logFields["disableKeepAlive"] = disableKeepAlive httpTransport := &http.Transport{ Dial: func(string, string) (net.Conn, error) { if tlsConfig == nil { return net.Dial(proto, lAddr) } return tls.Dial(proto, lAddr, tlsConfig) }, DisableKeepAlives: disableKeepAlive, } apiClient := apiclient.New(host, httpTransport) logReq := config.GetBool(types.ConfigLogHTTPRequests) logRes := config.GetBool(types.ConfigLogHTTPResponses) apiClient.LogRequests(logReq) apiClient.LogResponses(logRes) logFields["enableInstanceIDHeaders"] = EnableInstanceIDHeaders logFields["enableLocalDevicesHeaders"] = EnableLocalDevicesHeaders logFields["logRequests"] = logReq logFields["logResponses"] = logRes d.client = client{ APIClient: apiClient, ctx: ctx, config: config, clientType: cliType, serviceCache: &lss{Store: utils.NewStore()}, } if d.clientType == types.IntegrationClient { newIIDCache := utils.NewStore dur, err := time.ParseDuration( config.GetString(types.ConfigClientCacheInstanceID)) if err != nil { logFields["iidCacheDuration"] = dur.String() newIIDCache = func() types.Store { return utils.NewTTLStore(dur, true) } } d.lsxCache = &lss{Store: utils.NewStore()} d.supportedCache = utils.NewStore() d.instanceIDCache = &lss{Store: newIIDCache()} } d.ctx.WithFields(logFields).Info("created libStorage client") if err := d.dial(ctx); err != nil { return err } d.ctx.Info("successefully dialed libStorage server") return nil }
func activateLibStorage( ctx apitypes.Context, config gofig.Config) (apitypes.Context, gofig.Config, <-chan error, error) { apiserver.DisableStartupInfo = true var ( host string err error isRunning bool errs chan error serverErrChan <-chan error server apitypes.Server ) if host = config.GetString(apitypes.ConfigHost); host != "" { if !config.GetBool(apitypes.ConfigEmbedded) { ctx.WithField( "host", host, ).Debug("not starting embedded server; embedded mode disabled") return ctx, config, nil, nil } } if host, isRunning = IsLocalServerActive(ctx, config); isRunning { ctx = setHost(ctx, config, host) ctx.WithField("host", host).Debug( "not starting embedded server; already running") return ctx, config, nil, nil } // if no host was specified then see if a set of default services need to // be initialized if host == "" { ctx.Debug("host is empty; initiliazing default services") if err = initDefaultLibStorageServices(ctx, config); err != nil { ctx.WithError(err).Error("error initializing default services") return ctx, config, nil, err } } ctx.Debug("starting embedded libStorage server") if server, serverErrChan, err = apiserver.Serve(ctx, config); err != nil { ctx.WithError(err).Error("error starting libStorage server") return ctx, config, nil, err } if host == "" { host = server.Addrs()[0] ctx.WithField("host", host).Debug("got host from new server address") } ctx = setHost(ctx, config, host) errs = make(chan error) go func() { for err := range serverErrChan { if err != nil { errs <- err } } if err := os.RemoveAll(SpecFilePath()); err == nil { logHostSpec(ctx, host, "removed spec file") } close(errs) }() // write the host to the spec file so that other rex-ray invocations can // find it, even if running as an embedded libStorage server if err := WriteSpecFile(host); err != nil { specFile := SpecFilePath() if os.IsPermission(err) { ctx.WithError(err).Errorf( "user does not have write permissions for %s", specFile) } else { ctx.WithError(err).Errorf( "error writing spec file at %s", specFile) } //WaitUntilLibStorageStopped(ctx, serverErrChan) return ctx, config, errs, err } logHostSpec(ctx, host, "created spec file") return ctx, config, errs, nil }