// Start starts the daemon. func Start( ctx apitypes.Context, config gofig.Config, host string, stop <-chan os.Signal) (<-chan error, error) { var ( err error errs = make(chan error) daemonErrChan <-chan error ) if daemonErrChan, err = start(ctx, config, host, stop); err != nil { ctx.WithError(err).Error("daemon failed to initialize") return nil, err } ctx.Info("service successfully initialized, waiting on stop signal") go func() { sig := <-stop ctx.WithField("signal", sig).Info("service received stop signal") util.WaitUntilLibStorageStopped(ctx, daemonErrChan) close(errs) }() return errs, nil }
func (d *driver) findMachineByNameOrID( ctx types.Context, nameOrID string) (*vboxc.Machine, error) { ctx.WithField("nameOrID", nameOrID).Debug("finding local machine") m, err := d.vbox.FindMachine(nameOrID) if err != nil { return nil, err } if m == nil { return nil, goof.New("could not find machine") } if id, err := m.GetID(); err == nil { m.ID = id } else { return nil, err } if name, err := m.GetName(); err == nil { m.Name = name } else { return nil, err } return m, nil }
func (s *server) handleWithMiddleware( ctx types.Context, route types.Route) types.APIFunc { /*if route.GetMethod() == "HEAD" { return route.GetHandler() }*/ handler := route.GetHandler() middlewaresForRouteName, ok := s.routeHandlers[route.GetName()] if !ok { ctx.Warn("no middlewares for route") } else { for h := range reverse(middlewaresForRouteName) { handler = h.Handler(handler) ctx.WithField( "middleware", h.Name()).Debug("added route middleware") } } // add the global handlers for h := range reverse(s.globalHandlers) { handler = h.Handler(handler) ctx.WithField( "middleware", h.Name()).Debug("added global middleware") } return handler }
func (c *client) getExecutorChecksum(ctx types.Context) (string, error) { if c.isController() { return "", utils.NewUnsupportedForClientTypeError( c.clientType, "getExecutorChecksum") } ctx.Debug("getting executor checksum") f, err := os.Open(types.LSX.String()) if err != nil { return "", err } defer f.Close() h := md5.New() buf := make([]byte, 1024) for { n, err := f.Read(buf) if err == io.EOF { break } if err != nil { return "", err } if _, err := h.Write(buf[:n]); err != nil { return "", err } } sum := fmt.Sprintf("%x", h.Sum(nil)) ctx.WithField("localChecksum", sum).Debug("got local executor checksum") return sum, nil }
func (c *client) downloadExecutor(ctx types.Context) error { if c.isController() { return utils.NewUnsupportedForClientTypeError( c.clientType, "downloadExecutor") } ctx.Debug("downloading executor") f, err := os.OpenFile( types.LSX.String(), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0755) if err != nil { return err } defer f.Close() rdr, err := c.APIClient.ExecutorGet(ctx, types.LSX.Name()) n, err := io.Copy(f, rdr) if err != nil { return err } if err := f.Sync(); err != nil { return err } ctx.WithField("bytes", n).Debug("downloaded executor") 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 }
func (d *driver) Init(ctx types.Context, config gofig.Config) error { d.ctx = ctx d.config = config d.volPath = vfs.VolumesDirPath(config) d.snapPath = vfs.SnapshotsDirPath(config) ctx.WithField("vfs.root.path", vfs.RootDir(config)).Info("vfs.root") os.MkdirAll(d.volPath, 0755) os.MkdirAll(d.snapPath, 0755) d.volJSONGlobPatt = fmt.Sprintf("%s/*.json", d.volPath) d.snapJSONGlobPatt = fmt.Sprintf("%s/*.json", d.snapPath) volJSONPaths, err := d.getVolJSONs() if err != nil { return nil } d.volCount = int64(len(volJSONPaths)) - 1 snapJSONPaths, err := d.getSnapJSONs() if err != nil { return nil } d.snapCount = int64(len(snapJSONPaths)) - 1 return nil }
func (s *storageService) initStorageDriver(ctx types.Context) error { driverName := s.config.GetString("driver") if driverName == "" { driverName = s.config.GetString("libstorage.driver") if driverName == "" { driverName = s.config.GetString("libstorage.storage.driver") if driverName == "" { return goof.WithField( "service", s.name, "error getting driver name") } } } ctx.WithField("driverName", driverName).Debug("got driver name") driver, err := registry.NewStorageDriver(driverName) if err != nil { return err } ctx = ctx.WithValue(context.DriverKey, driver) if err := driver.Init(ctx, s.config); err != nil { return err } s.driver = driver return nil }
func setHost( ctx apitypes.Context, config gofig.Config, host string) apitypes.Context { ctx = ctx.WithValue(context.HostKey, host) ctx.WithField("host", host).Debug("set host in context") config.Set(apitypes.ConfigHost, host) ctx.WithField("host", host).Debug("set host in config") return ctx }
func (d *driver) createVolume( ctx types.Context, name string, size int64) (*vboxc.Medium, error) { if name == "" { return nil, goof.New("name is empty") } path := filepath.Join(d.volumePath(), name) ctx.WithField("path", path).Debug("creating vmdk") return d.vbox.CreateMedium("vmdk", path, size) }
// VolumeAttach attaches a volume and provides a token clients can use // to validate that device has appeared locally. func (d *driver) VolumeAttach( ctx types.Context, volumeID string, opts *types.VolumeAttachOpts) (*types.Volume, string, error) { svc := mustSession(ctx) vol, err := d.VolumeInspect(ctx, volumeID, &types.VolumeInspectOpts{Attachments: types.VolAttReqTrue}) if err != nil { return nil, "", err } iid := context.MustInstanceID(ctx) var ma *types.VolumeAttachment for _, att := range vol.Attachments { if att.InstanceID.ID == iid.ID { ma = att break } } // No mount targets were found if ma == nil { secGrpIDs := d.secGroups if v, ok := iid.Fields[efs.InstanceIDFieldSecurityGroups]; ok { iSecGrpIDs := strings.Split(v, ";") ctx.WithField("secGrpIDs", iSecGrpIDs).Debug( "using instance security group IDs") secGrpIDs = iSecGrpIDs } if len(secGrpIDs) == 0 { return nil, "", errInvalidSecGroups } request := &awsefs.CreateMountTargetInput{ FileSystemId: aws.String(vol.ID), SubnetId: aws.String(iid.ID), SecurityGroups: aws.StringSlice(secGrpIDs), } // TODO(mhrabovcin): Should we block here until MountTarget is in // "available" LifeCycleState? Otherwise mount could fail until creation // is completed. _, err = svc.CreateMountTarget(request) // Failed to create mount target if err != nil { return nil, "", err } } return vol, "", err }
func (c *client) dial(ctx types.Context) error { ctx.WithField("path", lsxMutex).Info("lsx lock file path") svcInfos, err := c.Services(ctx) if err != nil { return err } // controller clients do not have any additional dialer logic if c.isController() { return nil } store := utils.NewStore() c.ctx = c.ctx.WithValue(context.ServerKey, c.ServerName()) if !c.config.GetBool(types.ConfigExecutorNoDownload) { ctx.Info("initializing executors cache") if _, err := c.Executors(ctx); err != nil { return err } if err := c.updateExecutor(ctx); err != nil { return err } } for service, _ := range svcInfos { ctx := c.ctx.WithValue(context.ServiceKey, service) ctx.Info("initializing supported cache") supported, err := c.Supported(ctx, store) if err != nil { return goof.WithError("error initializing supported cache", err) } if !supported { ctx.Warn("executor not supported") continue } ctx.Info("initializing instance ID cache") if _, err := c.InstanceID(ctx, store); err != nil { if err == types.ErrNotImplemented { ctx.WithError(err).Warn("cannot get instance ID") continue } return goof.WithError("error initializing instance ID cache", err) } } return nil }
// Init initializes the service. func (s *globalTaskService) Init(ctx types.Context, config gofig.Config) error { s.tasks = map[int]*task{} s.config = config s.resultSchemaValidationEnabled = config.GetBool( types.ConfigSchemaResponseValidationEnabled) ctx.WithField("enabled", s.resultSchemaValidationEnabled).Debug( "configured result schema validation") return nil }
// InitializeDefaultModules initializes the default modules. func InitializeDefaultModules( ctx apitypes.Context, config gofig.Config) (<-chan error, error) { modTypesRwl.RLock() defer modTypesRwl.RUnlock() var ( err error mod *Instance errs <-chan error ) // enable path caching for the modules config.Set(apitypes.ConfigIgVolOpsPathCacheEnabled, true) ctx, config, errs, err = util.ActivateLibStorage(ctx, config) if err != nil { return nil, err } modConfigs, err := getConfiguredModules(ctx, config) if err != nil { return nil, err } ctx.WithField("len(modConfigs)", len(modConfigs)).Debug( "got configured modules") for _, mc := range modConfigs { ctx.WithField("name", mc.Name).Debug( "creating libStorage client for module instance") if mc.Client, err = util.NewClient(ctx, mc.Config); err != nil { panic(err) } if mod, err = InitializeModule(ctx, mc); err != nil { return nil, err } modInstances[mod.Name] = mod } return errs, nil }
func unmarshalLocalDevices( ctx types.Context, out []byte) (*types.LocalDevices, error) { ld := &types.LocalDevices{} if err := ld.UnmarshalText(out); err != nil { return nil, err } // remove any local devices that has no mapped volume information for k, v := range ld.DeviceMap { if len(v) == 0 { ctx.WithField("deviceID", k).Warn( "removing local device w/ invalid volume id") delete(ld.DeviceMap, k) } } return ld, nil }
// InitializeModule initializes a module. func InitializeModule( ctx apitypes.Context, modConfig *Config) (*Instance, error) { modInstancesRwl.Lock() defer modInstancesRwl.Unlock() ctx.WithField("name", modConfig.Name).Debug("initializing module instance") typeName := strings.ToLower(modConfig.Type) lf := log.Fields{ "typeName": typeName, "address": modConfig.Address, } mt, modTypeExists := modTypes[typeName] if !modTypeExists { return nil, goof.WithFields(lf, "unknown module type") } mod, initErr := mt.InitFunc(ctx, modConfig) if initErr != nil { return nil, initErr } modName := mod.Name() modInst := &Instance{ Type: mt, TypeName: typeName, Inst: mod, Name: modName, Config: modConfig, Description: mod.Description(), } modInstances[modName] = modInst lf["name"] = modName ctx.WithFields(lf).Info("initialized module instance") return modInst, nil }
// Handle is the type's Handler function. func (h *instanceIDHandler) Handle( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { headers := req.Header[types.InstanceIDHeader] ctx.WithField(types.InstanceIDHeader, headers).Debug("http header") valMap := types.InstanceIDMap{} for _, h := range headers { val := &types.InstanceID{} if err := val.UnmarshalText([]byte(h)); err != nil { return err } valMap[strings.ToLower(val.Driver)] = val } ctx = ctx.WithValue(context.AllInstanceIDsKey, valMap) return h.handler(ctx, w, req, store) }
func (d *idm) initPathCache(ctx types.Context) { if !d.pathCacheEnabled() { ctx.Info("path cache initializion disabled") return } if name, ok := context.ServiceName(ctx); !ok || name == "" { ctx.Info("path cache initializion disabled; no service name in ctx") return } f := func(async bool) { ctx.WithField("async", async).Info("initializing the path cache") _, err := d.List(ctx, apiutils.NewStoreWithData(initPathCacheMap)) if err != nil { ctx.WithField("async", async).WithError(err).Error( "error initializing the path cache") } else { ctx.WithField("async", async).Debug("initialized the path cache") } } if d.pathCacheAsync() { go f(true) } else { f(false) } }
func (c *client) Supported( ctx types.Context, opts types.Store) (bool, error) { if c.isController() { return false, utils.NewUnsupportedForClientTypeError( c.clientType, "Supported") } ctx = context.RequireTX(ctx.Join(c.ctx)) serviceName, ok := context.ServiceName(ctx) if !ok { return false, goof.New("missing service name") } si, err := c.getServiceInfo(serviceName) if err != nil { return false, err } driverName := strings.ToLower(si.Driver.Name) // check to see if the driver's executor is supported on this host if ok := c.supportedCache.IsSet(driverName); ok { return c.supportedCache.GetBool(driverName), nil } out, err := c.runExecutor(ctx, driverName, types.LSXCmdSupported) if err != nil { if err == types.ErrNotImplemented { ctx.WithField("serviceDriver", driverName).Warn( "supported cmd not implemented") c.supportedCache.Set(driverName, true) ctx.WithField("supported", true).Debug("cached supported flag") return true, nil } return false, err } if len(out) == 0 { return false, nil } out = bytes.TrimSpace(out) b, err := strconv.ParseBool(string(out)) if err != nil { return false, err } c.supportedCache.Set(driverName, b) ctx.WithField("supported", b).Debug("cached supported flag") return b, nil }
func getConfiguredModules( ctx apitypes.Context, c gofig.Config) ([]*Config, error) { mods := c.Get("rexray.modules") modMap, ok := mods.(map[string]interface{}) if !ok { return nil, goof.New("invalid format rexray.modules") } ctx.WithField("count", len(modMap)).Debug("got modules map") modConfigs := []*Config{} for name := range modMap { name = strings.ToLower(name) ctx.WithField("name", name).Debug("processing module config") sc := c.Scope(fmt.Sprintf("rexray.modules.%s", name)) if disabled := sc.GetBool("disabled"); disabled { ctx.WithField("name", name).Debug("ignoring disabled module config") continue } mc := &Config{ Name: name, Type: strings.ToLower(sc.GetString("type")), Description: sc.GetString("desc"), Address: sc.GetString("host"), Config: sc, } ctx.WithFields(log.Fields{ "name": mc.Name, "type": mc.Type, "desc": mc.Description, "addr": mc.Address, }).Info("created new mod config") modConfigs = append(modConfigs, mc) } return modConfigs, nil }
// Unmount will unmount the specified volume by volumeName or volumeID. func (d *driver) Unmount( ctx types.Context, volumeID, volumeName string, opts types.Store) (*types.Volume, error) { ctx.WithFields(log.Fields{ "volumeName": volumeName, "volumeID": volumeID, "opts": opts}).Info("unmounting volume") if volumeName == "" && volumeID == "" { return nil, goof.New("missing volume name or ID") } vol, err := d.volumeInspectByIDOrName( ctx, volumeID, volumeName, types.VolAttReqWithDevMapOnlyVolsAttachedToInstance, opts) if err != nil { return nil, err } if len(vol.Attachments) == 0 { return nil, nil } client := context.MustClient(ctx) inst, err := client.Storage().InstanceInspect(ctx, utils.NewStore()) if err != nil { return nil, goof.New("problem getting instance ID") } var ma *types.VolumeAttachment for _, att := range vol.Attachments { if att.InstanceID.ID == inst.InstanceID.ID { ma = att break } } if ma == nil { return nil, goof.New("no attachment found for instance") } if ma.DeviceName == "" { return nil, goof.New("no device name found for attachment") } mounts, err := client.OS().Mounts( ctx, ma.DeviceName, "", opts) if err != nil { return nil, err } for _, mount := range mounts { ctx.WithField("mount", mount).Debug("retrieved mount") } if len(mounts) > 0 { for _, mount := range mounts { ctx.WithField("mount", mount).Debug("unmounting mount point") err = client.OS().Unmount(ctx, mount.MountPoint, opts) if err != nil { return nil, err } } } vol, err = client.Storage().VolumeDetach(ctx, vol.ID, &types.VolumeDetachOpts{ Force: opts.GetBool("force"), Opts: utils.NewStore(), }) if err != nil { return nil, err } ctx.WithFields(log.Fields{ "vol": vol}).Info("unmounted and detached volume") return vol, 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 }
func getFilteredVolumes( ctx types.Context, req *http.Request, store types.Store, storSvc types.StorageService, opts *types.VolumesOpts, filter *types.Filter) (types.VolumeMap, error) { var ( filterOp types.FilterOperator filterLeft string filterRight string objMap = types.VolumeMap{} ) iid, iidOK := context.InstanceID(ctx) if opts.Attachments.RequiresInstanceID() && !iidOK { return nil, utils.NewMissingInstanceIDError(storSvc.Name()) } ctx.WithField("attachments", opts.Attachments).Debug("querying volumes") objs, err := storSvc.Driver().Volumes(ctx, opts) if err != nil { return nil, err } if filter != nil { filterOp = filter.Op filterLeft = strings.ToLower(filter.Left) filterRight = strings.ToLower(filter.Right) } for _, obj := range objs { lf := log.Fields{ "attachments": opts.Attachments, "volumeID": obj.ID, "volumeName": obj.Name, } if filterOp == types.FilterEqualityMatch && filterLeft == "name" { ctx.WithFields(lf).Debug("checking name filter") if !strings.EqualFold(obj.Name, filterRight) { ctx.WithFields(lf).Debug("omitted volume due to name filter") continue } } if !handleVolAttachments(ctx, lf, iid, obj, opts.Attachments) { continue } if OnVolume != nil { ctx.WithFields(lf).Debug("invoking OnVolume handler") ok, err := OnVolume(ctx, req, store, obj) if err != nil { return nil, err } if !ok { continue } } objMap[obj.ID] = obj } return objMap, nil }
func (d *driver) findMachineByMacAddrs( ctx types.Context, macAddrs []string) (*vboxc.Machine, error) { ctx.WithField("macAddrs", macAddrs).Debug("finding local machine") macMap := make(map[string]bool) for _, mac := range macAddrs { macUp := mac macMap[macUp] = true } machines, err := d.vbox.GetMachines() if err != nil { return nil, err } sp, err := d.vbox.GetSystemProperties() if err != nil { return nil, err } defer sp.Release() for _, m := range machines { defer m.Release() chipset, err := m.GetChipsetType() if err != nil { return nil, err } mna, err := sp.GetMaxNetworkAdapters(chipset) if err != nil { return nil, err } for i := uint32(0); i < mna; i++ { na, err := m.GetNetworkAdapter(i) if err != nil { return nil, err } mac, err := na.GetMACAddress() if err != nil { return nil, err } if _, ok := macMap[mac]; ok { id, err := m.GetID() if err != nil { return nil, err } m.ID = id name, err := m.GetName() if err != nil { return nil, err } m.Name = name return m, nil } } } return nil, goof.New("unable to find machine") }
// 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 (d *driver) Login(ctx types.Context) (interface{}, error) { sessionsL.Lock() defer sessionsL.Unlock() var ( endpoint *string ckey string hkey = md5.New() akey = d.accessKey region = d.mustRegion(ctx) ) if region != nil && d.endpointFormat != "" { szEndpoint := fmt.Sprintf(d.endpointFormat, *region) endpoint = &szEndpoint } else { endpoint = d.endpoint } if !d.disableSessionCache { writeHkey(hkey, region) writeHkey(hkey, endpoint) writeHkey(hkey, &akey) ckey = fmt.Sprintf("%x", hkey.Sum(nil)) // if the session is cached then return it if svc, ok := sessions[ckey]; ok { ctx.WithField(cacheKeyC, ckey).Debug("using cached efs service") return svc, nil } } var ( skey = d.getSecretKey() fields = map[string]interface{}{ efs.AccessKey: akey, efs.Tag: d.tag, cacheKeyC: ckey, } ) if skey == "" { fields[efs.SecretKey] = "" } else { fields[efs.SecretKey] = "******" } if region != nil { fields[efs.Region] = *region } if endpoint != nil { fields[efs.Endpoint] = *endpoint } ctx.WithFields(fields).Debug("efs service connetion attempt") sess := session.New() var ( awsLogger = &awsLogger{ctx: ctx} awsLogLevel = aws.LogOff ) if ll, ok := context.GetLogLevel(ctx); ok { switch ll { case log.DebugLevel: awsLogger.lvl = log.DebugLevel awsLogLevel = aws.LogDebugWithHTTPBody case log.InfoLevel: awsLogger.lvl = log.InfoLevel awsLogLevel = aws.LogDebug } } svc := awsefs.New(sess, &aws.Config{ Region: region, Endpoint: endpoint, MaxRetries: d.maxRetries, Credentials: credentials.NewChainCredentials( []credentials.Provider{ &credentials.StaticProvider{ Value: credentials.Value{ AccessKeyID: akey, SecretAccessKey: skey, }, }, &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{}, &ec2rolecreds.EC2RoleProvider{ Client: ec2metadata.New(sess), }, }, ), Logger: awsLogger, LogLevel: aws.LogLevel(awsLogLevel), }) ctx.WithFields(fields).Info("efs service connection created") if !d.disableSessionCache { sessions[ckey] = svc ctx.WithFields(fields).Info("efs service connection cached") } return svc, nil }