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 }
// TrapSignals tells the process to trap incoming process signals. func TrapSignals(ctx apitypes.Context) { context.RegisterCustomKey(signalContextKey, context.CustomLoggerKey) sigc := make(chan os.Signal, 1) signal.Notify(sigc) go func() { for s := range sigc { ctx := ctx.WithValue(signalContextKey, s.String()) if ok, graceful := IsExitSignal(s); ok && !graceful { ctx.Error("received signal; aborting") os.Exit(1) } func() { sigHandlersRWL.RLock() defer sigHandlersRWL.RUnlock() // execute the signal handlers in reverse order. the first // one registered should be executed last as it was registered // the earliest for i := len(sigHandlers) - 1; i >= 0; i-- { sigHandlers[i](ctx, s) } }() if ok, graceful := IsExitSignal(s); ok && graceful { ctx.Error("received signal; shutting down") os.Exit(0) } } }() }
func (c *client) withAllLocalDevices(ctx types.Context) (types.Context, error) { if c.isController() { return ctx, nil } ldm := types.LocalDevicesMap{} hit := map[string]bool{} for _, service := range c.serviceCache.Keys() { si := c.serviceCache.GetServiceInfo(service) dn := strings.ToLower(si.Driver.Name) if _, ok := hit[dn]; ok { continue } ctx := ctx.WithValue(context.ServiceKey, service) ld, err := c.LocalDevices(ctx, &types.LocalDevicesOpts{}) if err != nil { if err == errExecutorNotSupported || err == types.ErrNotImplemented { ctx.WithError(err).Warn("cannot get local deviecs") continue } return nil, err } hit[dn] = true ldm[dn] = ld } return ctx.WithValue(context.AllLocalDevicesKey, ldm), nil }
func (s *server) createMux(ctx types.Context) *mux.Router { m := mux.NewRouter() for _, apiRouter := range s.routers { for _, r := range apiRouter.Routes() { ctx := ctx.WithValue(context.RouteKey, r) f := s.makeHTTPHandler(ctx, r) mr := m.Path(r.GetPath()) mr = mr.Name(r.GetName()) mr = mr.Methods(r.GetMethod()) mr = mr.Queries(r.GetQueries()...) mr.Handler(f) if l, ok := context.GetLogLevel(ctx); ok && l >= log.DebugLevel { ctx.WithFields(log.Fields{ "path": r.GetPath(), "method": r.GetMethod(), "queries": r.GetQueries(), "len(queries)": len(r.GetQueries()), }).Debug("registered route") } else { ctx.Info("registered route") } } } return m }
func (s *server) makeHTTPHandler( ctx types.Context, route types.Route) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { w.Header().Set(types.ServerNameHeader, s.name) ctx := context.WithRequestRoute(ctx, req, route) if req.TLS != nil { if len(req.TLS.PeerCertificates) > 0 { userName := req.TLS.PeerCertificates[0].Subject.CommonName ctx = ctx.WithValue(context.UserKey, userName) } } ctx.Info("http request") vars := mux.Vars(req) if vars == nil { vars = map[string]string{} } store := utils.NewStoreWithVars(vars) handlerFunc := s.handleWithMiddleware(ctx, route) if err := handlerFunc(ctx, w, req, store); err != nil { ctx.Error(err) http.Error(w, err.Error(), http.StatusInternalServerError) } } }
func (c *client) InstanceInspect( ctx types.Context, service string) (*types.Instance, error) { si, err := c.ServiceInspect( ctx.WithValue(ctxInstanceForSvc, &ctxInstanceForSvcT{}), service) if err != nil { return nil, err } return si.Instance, 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 (c *client) Instances( ctx types.Context) (map[string]*types.Instance, error) { sis, err := c.Services( ctx.WithValue(ctxInstanceForSvc, &ctxInstanceForSvcT{})) if err != nil { return nil, err } instances := map[string]*types.Instance{} for service, si := range sis { instances[service] = si.Instance } return instances, nil }
func (c *client) withAllInstanceIDs(ctx types.Context) types.Context { if c.isController() { return ctx } iidm := types.InstanceIDMap{} for _, k := range c.instanceIDCache.Keys() { iidm[k] = c.instanceIDCache.GetInstanceID(k) } if len(iidm) == 0 { return ctx } return ctx.WithValue(context.AllInstanceIDsKey, iidm) }
func (c *client) withInstanceID( ctx types.Context, service string) types.Context { ctx = ctx.WithValue(context.ServiceKey, service) if c.isController() { return ctx } si := c.serviceCache.GetServiceInfo(service) if si == nil { return ctx } if !c.instanceIDCache.IsSet(si.Driver.Name) { return ctx } iid := c.instanceIDCache.GetInstanceID(si.Driver.Name) return ctx.WithValue(context.InstanceIDKey, iid) }
// 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 (s *globalTaskService) taskTrack(ctx types.Context) *task { now := time.Now().Unix() s.RLock() taskID := len(s.tasks) s.RUnlock() t := &task{ Task: types.Task{ ID: taskID, QueueTime: now, }, resultSchemaValidationEnabled: s.resultSchemaValidationEnabled, ctx: ctx.WithValue(context.TaskKey, fmt.Sprintf("%d", taskID)), } s.Lock() s.tasks[taskID] = t s.Unlock() return t }
// Handle is the type's Handler function. func (h *schemaValidator) Handle( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { reqBody, err := ioutil.ReadAll(req.Body) if err != nil { return fmt.Errorf("validate req schema: read req error: %v", err) } // do the request validation if h.reqSchema != nil { err = schema.Validate(ctx, h.reqSchema, reqBody) if err != nil { return fmt.Errorf("validate req schema: validation error: %v", err) } } // create the object for the request payload if there is a function for it if h.newReqObjFunc != nil { reqObj := h.newReqObjFunc() if len(reqBody) > 0 { if err = json.Unmarshal(reqBody, reqObj); err != nil { return fmt.Errorf( "validate req schema: unmarshal error: %v", err) } } ctx = ctx.WithValue("reqObj", reqObj) } // if there's not response schema then just return the result of the next // handler if DisableResponseValidation || h.resSchema == nil { return h.handler(ctx, w, req, store) } // at this point we know there's going to be response validation, so // we need to record the result of the next handler in order to intercept // the response payload to validate it rec := httptest.NewRecorder() // invoke the next handler with a recorder err = h.handler(ctx, rec, req, store) if err != nil { return err } // do the response validation resBody := rec.Body.Bytes() err = schema.Validate(ctx, h.resSchema, resBody) if err != nil { return err } // write the recorded result of the next handler to the resposne writer w.WriteHeader(rec.Code) for k, v := range rec.HeaderMap { w.Header()[k] = v } if _, err = w.Write(resBody); err != nil { return err } return nil }
func (c *client) httpDo( ctx types.Context, method, path string, payload, reply interface{}) (*http.Response, error) { reqBody, err := encPayload(payload) if err != nil { return nil, err } url := fmt.Sprintf("http://%s%s", c.host, path) req, err := http.NewRequest(method, url, reqBody) if err != nil { return nil, err } ctx = context.RequireTX(ctx) tx := context.MustTransaction(ctx) ctx = ctx.WithValue(transactionHeaderKey, tx) if iid, ok := context.InstanceID(ctx); ok { ctx = ctx.WithValue(instanceIDHeaderKey, iid) } else if iidMap, ok := ctx.Value( context.AllInstanceIDsKey).(types.InstanceIDMap); ok { if len(iidMap) > 0 { var iids []fmt.Stringer for _, iid := range iidMap { iids = append(iids, iid) } ctx = ctx.WithValue(instanceIDHeaderKey, iids) } } if lds, ok := context.LocalDevices(ctx); ok { ctx = ctx.WithValue(localDevicesHeaderKey, lds) } else if ldsMap, ok := ctx.Value( context.AllLocalDevicesKey).(types.LocalDevicesMap); ok { if len(ldsMap) > 0 { var ldsess []fmt.Stringer for _, lds := range ldsMap { ldsess = append(ldsess, lds) } ctx = ctx.WithValue(localDevicesHeaderKey, ldsess) } } for key := range context.CustomHeaderKeys() { var headerName string switch tk := key.(type) { case string: headerName = tk case fmt.Stringer: headerName = tk.String() default: headerName = fmt.Sprintf("%v", key) } if headerName == "" { continue } val := ctx.Value(key) switch tv := val.(type) { case string: req.Header.Add(headerName, tv) case fmt.Stringer: req.Header.Add(headerName, tv.String()) case []string: for _, sv := range tv { req.Header.Add(headerName, sv) } case []fmt.Stringer: for _, sv := range tv { req.Header.Add(headerName, sv.String()) } default: if val != nil { req.Header.Add(headerName, fmt.Sprintf("%v", val)) } } } c.logRequest(req) res, err := ctxhttp.Do(ctx, &c.Client, req) if err != nil { return nil, err } defer c.setServerName(res) c.logResponse(res) if res.StatusCode > 299 { httpErr, err := goof.DecodeHTTPError(res.Body) if err != nil { return res, goof.WithField("status", res.StatusCode, "http error") } return res, httpErr } if req.Method != http.MethodHead && reply != nil { if err := decRes(res.Body, reply); err != nil { return nil, err } } return res, 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 (c *client) InstanceID( ctx types.Context, opts types.Store) (*types.InstanceID, error) { if c.isController() { return nil, utils.NewUnsupportedForClientTypeError( c.clientType, "InstanceID") } if supported, _ := c.Supported(ctx, opts); !supported { return nil, errExecutorNotSupported } ctx = context.RequireTX(ctx.Join(c.ctx)) serviceName, ok := context.ServiceName(ctx) if !ok { return nil, goof.New("missing service name") } si, err := c.getServiceInfo(serviceName) if err != nil { return nil, err } driverName := strings.ToLower(si.Driver.Name) // check to see if the driver's instance ID is cached if iid := c.instanceIDCache.GetInstanceID(driverName); iid != nil { return iid, nil } out, err := c.runExecutor(ctx, driverName, types.LSXCmdInstanceID) if err != nil { return nil, err } iid := &types.InstanceID{} if err := iid.UnmarshalText(out); err != nil { return nil, err } ctx = ctx.WithValue(context.InstanceIDKey, iid) if iid.HasMetadata() { ctx.Debug("sending instanceID in API.InstanceInspect call") instance, err := c.InstanceInspect(ctx, serviceName) if err != nil { return nil, err } ctx.Debug("received instanceID from API.InstanceInspect call") iid.ID = instance.InstanceID.ID iid.Fields = instance.InstanceID.Fields iid.DeleteMetadata() } c.instanceIDCache.Set(driverName, iid) ctx.Debug("cached instanceID") ctx.Debug("xli instanceID success") return iid, nil }