//NewServer returns new GohanAPIServer func NewServer(configFile string) (*Server, error) { manager := schema.GetManager() config := util.GetConfig() err := config.ReadConfig(configFile) err = os.Chdir(path.Dir(configFile)) if err != nil { return nil, fmt.Errorf("Config load error: %s", err) } err = l.SetUpLogging(config) if err != nil { return nil, fmt.Errorf("Logging setup error: %s", err) } log.Info("logging initialized") server := &Server{} m := martini.Classic() m.Handlers() m.Use(middleware.Logging()) m.Use(martini.Recovery()) m.Use(middleware.JSONURLs()) m.Use(middleware.WithContext()) server.martini = m server.address = config.GetString("address", ":9091") if config.GetBool("tls/enabled", false) { log.Info("TLS enabled") server.tls = &tls{ KeyFile: config.GetString("tls/key_file", "./etc/key.pem"), CertFile: config.GetString("tls/cert_file", "./etc/cert.pem"), } } server.connectDB() schemaFiles := config.GetStringList("schemas", nil) if schemaFiles == nil { log.Fatal("No schema specified in configuraion") } else { err = manager.LoadSchemasFromFiles(schemaFiles...) if err != nil { return nil, fmt.Errorf("invalid schema: %s", err) } } server.initDB() etcdServers := config.GetStringList("etcd", nil) log.Info("etcd servers: %s", etcdServers) server.sync = etcd.NewSync(etcdServers) if config.GetList("database/initial_data", nil) != nil { initialDataList := config.GetList("database/initial_data", nil) for _, initialData := range initialDataList { initialDataConfig := initialData.(map[string]interface{}) inType := initialDataConfig["type"].(string) inConnection := initialDataConfig["connection"].(string) log.Info("Importing data from %s ...", inConnection) inDB, err := db.ConnectDB(inType, inConnection) if err != nil { log.Fatal(err) } db.CopyDBResources(inDB, server.db) } } if config.GetBool("keystone/use_keystone", false) { //TODO remove this if config.GetBool("keystone/fake", false) { server.keystoneIdentity = &middleware.FakeIdentity{} //TODO(marcin) requests to fake server also get authenticated // we need a separate routing Group log.Info("Debug Mode with Fake Keystone Server") middleware.FakeKeystone(server.martini) } else { log.Info("Keystone backend server configured") server.keystoneIdentity, err = cloud.NewKeystoneIdentity( config.GetString("keystone/auth_url", "http://localhost:35357/v3"), config.GetString("keystone/user_name", "admin"), config.GetString("keystone/password", "password"), config.GetString("keystone/domain_name", "Default"), config.GetString("keystone/tenant_name", "admin"), config.GetString("keystone/version", ""), ) if err != nil { log.Fatal(err) } } m.MapTo(server.keystoneIdentity, (*middleware.IdentityService)(nil)) m.Use(middleware.Authentication()) //m.Use(Authorization()) } if err != nil { return nil, fmt.Errorf("invalid base dir: %s", err) } server.addOptionsRoute() cors := config.GetString("cors", "") if cors != "" { log.Info("Enabling CORS for %s", cors) if cors == "*" { log.Warning("cors for * have security issue") } server.martini.Use(func(rw http.ResponseWriter, r *http.Request) { rw.Header().Add("Access-Control-Allow-Origin", cors) rw.Header().Add("Access-Control-Allow-Headers", "X-Auth-Token, Content-Type") rw.Header().Add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE") }) } documentRoot := config.GetString("document_root", "./") log.Info("Static file serving from %s", documentRoot) documentRootABS, err := filepath.Abs(documentRoot) server.martini.Use(martini.Static(documentRootABS)) server.mapRoutes() return server, nil }
func httpServer(stmt *gohanscript.Stmt) (func(*gohanscript.Context) (interface{}, error), error) { return func(globalContext *gohanscript.Context) (interface{}, error) { m := martini.Classic() var mutex = &sync.Mutex{} history := []interface{}{} server := map[string]interface{}{ "history": history, } m.Handlers() m.Use(middleware.Logging()) m.Use(martini.Recovery()) rawBody := util.MaybeMap(stmt.RawData["http_server"]) paths := util.MaybeMap(rawBody["paths"]) middlewareCode := util.MaybeString(rawBody["middleware"]) if middlewareCode != "" { vm := gohanscript.NewVM() err := vm.LoadString(stmt.File, middlewareCode) if err != nil { return nil, err } m.Use(func(w http.ResponseWriter, r *http.Request) { context := globalContext.Extend(nil) fillInContext(context.Data(), r, w, nil) reqData, _ := ioutil.ReadAll(r.Body) buff := ioutil.NopCloser(bytes.NewBuffer(reqData)) r.Body = buff var data interface{} if reqData != nil { json.Unmarshal(reqData, &data) } context.Set("request", data) vm.Run(context.Data()) }) } m.Use(func(w http.ResponseWriter, r *http.Request) { reqData, _ := ioutil.ReadAll(r.Body) buff := ioutil.NopCloser(bytes.NewBuffer(reqData)) r.Body = buff var data interface{} if reqData != nil { json.Unmarshal(reqData, &data) } mutex.Lock() server["history"] = append(server["history"].([]interface{}), map[string]interface{}{ "method": r.Method, "path": r.URL.String(), "data": data, }) mutex.Unlock() }) for path, body := range paths { methods, ok := body.(map[string]interface{}) if !ok { continue } for method, rawRouteBody := range methods { routeBody, ok := rawRouteBody.(map[string]interface{}) if !ok { continue } code := util.MaybeString(routeBody["code"]) vm := gohanscript.NewVM() err := vm.LoadString(stmt.File, code) if err != nil { return nil, err } switch method { case "get": m.Get(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) { context := globalContext.Extend(nil) fillInContext(context.Data(), r, w, p) vm.Run(context.Data()) serveResponse(w, context.Data()) }) case "post": m.Post(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) { context := globalContext.Extend(nil) fillInContext(context.Data(), r, w, p) requestData, _ := middleware.ReadJSON(r) context.Set("request", requestData) vm.Run(context.Data()) serveResponse(w, context.Data()) }) case "put": m.Put(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) { context := globalContext.Extend(nil) fillInContext(context.Data(), r, w, p) requestData, _ := middleware.ReadJSON(r) context.Set("request", requestData) vm.Run(context.Data()) serveResponse(w, context.Data()) }) case "delete": m.Delete(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) { context := globalContext.Extend(nil) fillInContext(context.Data(), r, w, p) vm.Run(context.Data()) serveResponse(w, context.Data()) }) } } } testMode := stmt.Args["test"].Value(globalContext).(bool) if testMode { ts := httptest.NewServer(m) server["server"] = ts return server, nil } m.RunOnAddr(stmt.Args["address"].Value(globalContext).(string)) return nil, nil }, nil }
//NewServer returns new GohanAPIServer func NewServer(configFile string) (*Server, error) { manager := schema.GetManager() config := util.GetConfig() err := config.ReadConfig(configFile) err = os.Chdir(path.Dir(configFile)) if err != nil { return nil, fmt.Errorf("Config load error: %s", err) } err = l.SetUpLogging(config) if err != nil { return nil, fmt.Errorf("Logging setup error: %s", err) } log.Info("logging initialized") server := &Server{} m := martini.Classic() m.Handlers() m.Use(middleware.Logging()) m.Use(martini.Recovery()) m.Use(middleware.JSONURLs()) m.Use(middleware.WithContext()) server.martini = m port := os.Getenv("PORT") if port == "" { port = "9091" } setupEditor(server) server.timelimit = config.GetInt("extension/timelimit", 30) server.extensions = config.GetStringList("extension/use", []string{ "javascript", "gohanscript", "go", }) schema.DefaultExtension = config.GetString("extension/default", "javascript") server.address = config.GetString("address", ":"+port) if config.GetBool("tls/enabled", false) { log.Info("TLS enabled") server.tls = &tlsConfig{ KeyFile: config.GetString("tls/key_file", "./etc/key.pem"), CertFile: config.GetString("tls/cert_file", "./etc/cert.pem"), } } etcdServers := config.GetStringList("etcd", nil) if etcdServers != nil { log.Info("etcd servers: %s", etcdServers) server.sync = etcd.NewSync(etcdServers) } server.connectDB() schemaFiles := config.GetStringList("schemas", nil) if schemaFiles == nil { log.Fatal("No schema specified in configuraion") } else { err = manager.LoadSchemasFromFiles(schemaFiles...) if err != nil { return nil, fmt.Errorf("invalid schema: %s", err) } } if !config.GetBool("database/no_init", false) { server.initDB() } if config.GetList("database/initial_data", nil) != nil { initialDataList := config.GetList("database/initial_data", nil) for _, initialData := range initialDataList { initialDataConfig := initialData.(map[string]interface{}) inType := initialDataConfig["type"].(string) inConnection := initialDataConfig["connection"].(string) log.Info("Importing data from %s ...", inConnection) inDB, err := db.ConnectDB(inType, inConnection, db.DefaultMaxOpenConn) if err != nil { log.Fatal(err) } db.CopyDBResources(inDB, server.db, false) } } if config.GetBool("keystone/use_keystone", false) { //TODO remove this if config.GetBool("keystone/fake", false) { server.keystoneIdentity = &middleware.FakeIdentity{} //TODO(marcin) requests to fake server also get authenticated // we need a separate routing Group log.Info("Debug Mode with Fake Keystone Server") } else { log.Info("Keystone backend server configured") server.keystoneIdentity, err = cloud.NewKeystoneIdentity( config.GetString("keystone/auth_url", "http://localhost:35357/v3"), config.GetString("keystone/user_name", "admin"), config.GetString("keystone/password", "password"), config.GetString("keystone/domain_name", "Default"), config.GetString("keystone/tenant_name", "admin"), config.GetString("keystone/version", ""), ) if err != nil { log.Fatal(err) } } m.MapTo(server.keystoneIdentity, (*middleware.IdentityService)(nil)) m.Use(middleware.Authentication()) //m.Use(Authorization()) } else { m.MapTo(&middleware.NoIdentityService{}, (*middleware.IdentityService)(nil)) m.Map(schema.NewAuthorization("admin", "admin", "admin_token", []string{"admin"}, nil)) } if err != nil { return nil, fmt.Errorf("invalid base dir: %s", err) } server.addOptionsRoute() cors := config.GetString("cors", "") if cors != "" { log.Info("Enabling CORS for %s", cors) if cors == "*" { log.Warning("cors for * have security issue") } server.martini.Use(func(rw http.ResponseWriter, r *http.Request) { rw.Header().Add("Access-Control-Allow-Origin", cors) rw.Header().Add("Access-Control-Allow-Headers", "X-Auth-Token, Content-Type") rw.Header().Add("Access-Control-Expose-Headers", "X-Total-Count") rw.Header().Add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE") }) } documentRoot := config.GetString("document_root", "embed") if config.GetBool("webui_config/enabled", false) { m.Use(func(res http.ResponseWriter, req *http.Request, c martini.Context) { if req.URL.Path != "/webui/config.json" { c.Next() return } address := config.GetString("webui_config/address", server.address) if address[0] == ':' { address = "__HOST__" + address } baseURL := "http://" + address authURL := "http://" + address + "/v2.0" if config.GetBool("webui_config/tls", config.GetBool("tls/enabled", false)) { baseURL = "https://" + address authURL = "https://" + address + "/v2.0" } authURL = config.GetString("webui_config/auth_url", authURL) webUIConfig := map[string]interface{}{ "authUrl": authURL, "gohan": map[string]interface{}{ "schema": "/gohan/v0.1/schemas", "url": baseURL, }, } routes.ServeJson(res, webUIConfig) }) } if documentRoot == "embed" { m.Use(staticbin.Static("public", util.Asset, staticbin.Options{ SkipLogging: true, })) } else { log.Info("Static file serving from %s", documentRoot) documentRootABS, err := filepath.Abs(documentRoot) if err != nil { return nil, err } server.martini.Use(martini.Static(documentRootABS, martini.StaticOptions{ SkipLogging: true, })) } server.mapRoutes() maxWorkerCount := config.GetInt("workers", 100) server.queue = job.NewQueue(uint(maxWorkerCount)) return server, nil }