예제 #1
0
파일: framework.go 프로젝트: cloudwan/gohan
// TestExtensions runs extension tests when invoked from Gohan CLI
func TestExtensions(c *cli.Context) {
	buflog.SetUpDefaultLogging()

	var config *util.Config
	configFilePath := c.String("config-file")

	if configFilePath != "" && !c.Bool("verbose") {
		config = util.GetConfig()
		err := config.ReadConfig(configFilePath)
		if err != nil {
			log.Error(fmt.Sprintf("Failed to read config from path %s: %v", configFilePath, err))
			os.Exit(1)
		}

		err = gohan_log.SetUpLogging(config)
		if err != nil {
			log.Error(fmt.Sprintf("Failed to set up logging: %v", err))
			os.Exit(1)
		}
	}

	testFiles := getTestFiles(c.Args())

	//logging from config is a limited printAllLogs option
	returnCode := RunTests(testFiles, c.Bool("verbose") || config != nil, c.String("run-test"))
	os.Exit(returnCode)
}
예제 #2
0
파일: sync.go 프로젝트: vozhyk-/gohan
//Sync Watch Process
func startSyncWatchProcess(server *Server) {
	config := util.GetConfig()
	watch := config.GetStringList("watch/keys", nil)
	events := config.GetStringList("watch/events", nil)
	if watch == nil {
		return
	}
	extensions := map[string]extension.Environment{}
	for _, event := range events {
		path := "sync://" + event
		env, err := server.NewEnvironmentForPath("sync."+event, path)
		if err != nil {
			log.Fatal(err.Error())
		}
		extensions[event] = env
	}
	responseChan := make(chan *gohan_sync.Event)
	stopChan := make(chan bool)
	for _, path := range watch {
		go func(path string) {
			defer util.LogFatalPanic(log)
			for server.running {
				lockKey := lockPath + "watch"
				err := server.sync.Lock(lockKey, true)
				if err != nil {
					log.Warning("Can't start watch process due to lock", err)
					time.Sleep(5 * time.Second)
					continue
				}
				defer func() {
					server.sync.Unlock(lockKey)
				}()
				err = server.sync.Watch(path, responseChan, stopChan)
				if err != nil {
					log.Error(fmt.Sprintf("sync watch error: %s", err))
				}
			}
		}(path)
	}
	//main response lisnter process
	go func() {
		defer util.LogFatalPanic(log)
		for server.running {
			response := <-responseChan
			server.queue.Add(job.NewJob(
				func() {
					defer util.LogPanic(log)
					for _, event := range events {
						//match extensions
						if strings.HasPrefix(response.Key, "/"+event) {
							env := extensions[event]
							runExtensionOnSync(server, response, env.Clone())
							return
						}
					}
				}))
		}
	}()

}
예제 #3
0
파일: cli.go 프로젝트: vozhyk-/gohan
func getGraceServerCommand() cli.Command {
	return cli.Command{
		Name:        "glace-server",
		ShortName:   "gsrv",
		Usage:       "Run API Server with graceful restart support",
		Description: "Run Gohan API server with graceful restart support",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "config-file", Value: defaultConfigFile, Usage: "Server config File"},
		},
		Action: func(c *cli.Context) {
			configFile := c.String("config-file")
			loadConfig(configFile)
			opts := &options{OptInterval: -1}
			opts.OptCommand = os.Args[0]
			config := util.GetConfig()
			opts.OptPorts = []string{config.GetString("address", ":9091")}
			opts.OptArgs = []string{"server", "--config-file", configFile}
			s, err := starter.NewStarter(opts)
			if err != nil {
				fmt.Fprintf(os.Stderr, "error: %s\n", err)
				return
			}
			s.Run()
		},
	}
}
예제 #4
0
//AMQP Process
func startAMQPProcess(server *Server) {
	config := util.GetConfig()
	enableAMQP := config.GetParam("amqp", nil)
	if enableAMQP == nil {
		return
	}
	listenAMQP(server)
}
예제 #5
0
파일: snmp.go 프로젝트: masaki-saeki/gohan
//SNMP Process
//Experimental
func startSNMPProcess(server *Server) {
	manager := schema.GetManager()
	config := util.GetConfig()
	enabled := config.GetParam("snmp", nil)
	if enabled == nil {
		return
	}
	host := config.GetString("snmp/address", "localhost:162")

	path := "snmp://"
	env := newEnvironment(server.db, server.keystoneIdentity, server.timelimit)
	err := env.LoadExtensionsForPath(manager.Extensions, path)
	if err != nil {
		log.Fatal(fmt.Sprintf("Extensions parsing error: %v", err))
	}

	addr, err := net.ResolveUDPAddr("udp", host)
	if err != nil {
		log.Fatal(err)
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Fatal(err)
	}

	buf := make([]byte, 1024)
	go func() {
		defer conn.Close()
		for server.running {
			rlen, remote, err := conn.ReadFromUDP(buf)
			if err != nil {
				log.Error(fmt.Sprintf("[SNMP] failed read bytes %s", err))
				return
			}
			decoded, err := wapsnmp.DecodeSequence(buf[:rlen])
			if err != nil {
				log.Error(fmt.Sprintf("[SNMP] failed decode bytes %s", err))
				continue
			}
			infos := decoded[3].([]interface{})[4].([]interface{})[1:]
			trap := map[string]string{}
			for _, info := range infos {
				listInfo := info.([]interface{})
				oid := listInfo[1].(wapsnmp.Oid)
				trap[oid.String()] = fmt.Sprintf("%v", listInfo[2])
			}

			context := map[string]interface{}{
				"trap":   trap,
				"remote": remote,
			}
			if err := env.HandleEvent("notification", context); err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
			}
		}
	}()
}
예제 #6
0
파일: server.go 프로젝트: vozhyk-/gohan
func (server *Server) connectDB() error {
	config := util.GetConfig()
	dbType, dbConnection, _, _ := server.getDatabaseConfig()
	maxConn := config.GetInt("database/max_open_conn", db.DefaultMaxOpenConn)
	dbConn, err := db.ConnectDB(dbType, dbConnection, maxConn)
	if server.sync == nil {
		server.db = dbConn
	} else {
		server.db = &DbSyncWrapper{dbConn}
	}
	return err
}
예제 #7
0
파일: cron.go 프로젝트: nati/gohan
//CRON Process
func startCRONProcess(server *Server) {
	manager := schema.GetManager()
	config := util.GetConfig()
	jobList := config.GetParam("cron", nil)
	if jobList == nil {
		return
	}
	log.Info("Started CRON process")
	c := cron.New()
	for _, rawJob := range jobList.([]interface{}) {
		job := rawJob.(map[string]interface{})
		path := job["path"].(string)
		timing := job["timing"].(string)
		env := newEnvironment(server.db, server.keystoneIdentity)
		err := env.LoadExtensionsForPath(manager.Extensions, path)
		if err != nil {
			log.Fatal(fmt.Sprintf("Extensions parsing error: %v", err))
		}
		log.Info("New job for %s / %s", path, timing)
		c.AddFunc(timing, func() {
			lockKey := lockPath + "/" + path
			err := server.sync.Lock(lockKey, false)
			if err != nil {
				return
			}
			defer func() {
				server.sync.Unlock(lockKey)
			}()
			tx, err := server.db.Begin()
			defer tx.Close()
			context := map[string]interface{}{
				"path": path,
			}
			if err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
				return
			}
			if err := env.HandleEvent("notification", context); err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
				return
			}
			err = tx.Commit()
			if err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
				return
			}
			return
		})
	}
	c.Start()
}
예제 #8
0
func (server *Server) getDatabaseConfig() (string, string, bool, bool) {
	config := util.GetConfig()
	databaseType := config.GetString("database/type", "sqlite3")
	if databaseType == "json" || databaseType == "yaml" {
		log.Fatal("json or yaml isn't supported as main db backend")
	}
	databaseConnection := config.GetString("database/connection", "")
	if databaseConnection == "" {
		log.Fatal("no database connection specified in the configuraion file.")
	}
	databaseDropOnCreate := config.GetBool("database/drop_on_create", false)
	databaseCascade := config.GetBool("database/cascade_delete", false)
	return databaseType, databaseConnection, databaseDropOnCreate, databaseCascade
}
예제 #9
0
파일: server.go 프로젝트: nati/gohan
func (server *Server) mapRoutes() {
	config := util.GetConfig()
	schemaManager := schema.GetManager()
	MapNamespacesRoutes(server.martini)
	MapRouteBySchemas(server, server.db)

	tx, err := server.db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	defer tx.Close()
	coreSchema, _ := schemaManager.Schema("schema")
	if coreSchema == nil {
		log.Fatal("Gohan core schema not found")
		return
	}

	policySchema, _ := schemaManager.Schema("policy")
	policyList, _, err := tx.List(policySchema, nil, nil)
	if err != nil {
		log.Info(err.Error())
	}
	schemaManager.LoadPolicies(policyList)

	extensionSchema, _ := schemaManager.Schema("extension")
	extensionList, _, err := tx.List(extensionSchema, nil, nil)
	if err != nil {
		log.Info(err.Error())
	}
	schemaManager.LoadExtensions(extensionList)

	namespaceSchema, _ := schemaManager.Schema("namespace")
	if namespaceSchema == nil {
		log.Error("No gohan schema. Disabling schema editing mode")
		return
	}
	namespaceList, _, err := tx.List(namespaceSchema, nil, nil)
	if err != nil {
		log.Info(err.Error())
	}
	err = tx.Commit()
	if err != nil {
		log.Info(err.Error())
	}
	schemaManager.LoadNamespaces(namespaceList)

	if config.GetBool("keystone/fake", false) {
		middleware.FakeKeystone(server.martini)
	}
}
예제 #10
0
파일: cron.go 프로젝트: cloudwan/gohan
//CRON Process
func startCRONProcess(server *Server) {
	config := util.GetConfig()
	jobList := config.GetParam("cron", nil)
	if jobList == nil {
		return
	}
	if server.sync == nil {
		log.Fatalf(fmt.Sprintf("Could not start CRON process because of sync backend misconfiguration."))
		util.LogFatalPanic(log)
	}
	log.Info("Started CRON process")
	c := cron.New()
	for _, rawJob := range jobList.([]interface{}) {
		job := rawJob.(map[string]interface{})
		path := job["path"].(string)
		timing := job["timing"].(string)
		name := strings.TrimPrefix(path, "cron://")
		env, err := server.NewEnvironmentForPath(name, path)
		if err != nil {
			log.Fatal(err.Error())
		}
		log.Info("New job for %s / %s", path, timing)
		c.AddFunc(timing, func() {
			lockKey := lockPath + "/" + path
			err := server.sync.Lock(lockKey, false)
			if err != nil {
				return
			}
			defer func() {
				server.sync.Unlock(lockKey)
			}()
			context := map[string]interface{}{
				"path": path,
			}
			if err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
				return
			}
			if err := env.HandleEvent("notification", context); err != nil {
				log.Warning(fmt.Sprintf("extension error: %s", err))
				return
			}
			return
		})
	}
	c.Start()
}
예제 #11
0
파일: template.go 프로젝트: vozhyk-/gohan
func doTemplate(c *cli.Context) {
	template := c.String("template")
	manager := schema.GetManager()
	configFile := c.String("config-file")
	config := util.GetConfig()
	err := config.ReadConfig(configFile)
	if err != nil {
		util.ExitFatal(err)
		return
	}
	templateCode, err := util.GetContent(template)
	if err != nil {
		util.ExitFatal(err)
		return
	}
	pwd, _ := os.Getwd()
	os.Chdir(path.Dir(configFile))
	schemaFiles := config.GetStringList("schemas", nil)
	if schemaFiles == nil {
		util.ExitFatal("No schema specified in configuraion")
	} else {
		err = manager.LoadSchemasFromFiles(schemaFiles...)
		if err != nil {
			util.ExitFatal(err)
			return
		}
	}
	schemas := manager.OrderedSchemas()

	if err != nil {
		util.ExitFatal(err)
		return
	}
	tpl, err := pongo2.FromString(string(templateCode))
	if err != nil {
		util.ExitFatal(err)
		return
	}
	output, err := tpl.Execute(pongo2.Context{"schemas": schemas})
	if err != nil {
		util.ExitFatal(err)
		return
	}
	os.Chdir(pwd)
	fmt.Println(output)
}
예제 #12
0
파일: gohan_core.go 프로젝트: vozhyk-/gohan
func loadNPMModules() {
	config := util.GetConfig()
	npmPath := config.GetString("extension/npm_path", ".")
	files, _ := ioutil.ReadDir(npmPath + "/node_modules/")
	for _, f := range files {
		if f.IsDir() && !strings.HasPrefix(f.Name(), ".") {
			module, err := motto.FindFileModule(f.Name(), npmPath, nil)
			if err != nil {
				log.Error("Finding module failed %s in %s", err, f.Name())
				break
			}
			if !strings.HasSuffix(module, ".js") {
				module = module + "/index.js"
			}
			loader := motto.CreateLoaderFromFile(module)
			motto.AddModule(f.Name(), loader)
		}
	}
}
예제 #13
0
파일: cli.go 프로젝트: vozhyk-/gohan
func loadConfig(configFile string) {
	if configFile == "" {
		return
	}
	config := util.GetConfig()
	err := config.ReadConfig(configFile)
	if err != nil {
		if configFile != defaultConfigFile {
			fmt.Println(err)
			os.Exit(1)
		}
		return
	}
	err = l.SetUpLogging(config)
	if err != nil {
		fmt.Printf("Logging setup error: %s\n", err)
		os.Exit(1)
		return
	}
	log.Info("logging initialized")
}
예제 #14
0
		}
	}
	return nil
}

func TestOttoExtension(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Otto Extension Suite")
}

var _ = Describe("Suite set up and tear down", func() {
	var _ = BeforeSuite(func() {
		var err error
		Expect(os.Chdir(configDir)).To(Succeed())
		testDB, err = db.ConnectDB(dbType, dbFile, db.DefaultMaxOpenConn)
		Expect(err).ToNot(HaveOccurred(), "Failed to connect database.")
		manager := schema.GetManager()
		config := util.GetConfig()
		Expect(config.ReadConfig(configFile)).To(Succeed())
		schemaFiles := config.GetStringList("schemas", nil)
		Expect(schemaFiles).NotTo(BeNil())
		Expect(manager.LoadSchemasFromFiles(schemaFiles...)).To(Succeed())
		Expect(db.InitDBWithSchemas(dbType, dbFile, false, false)).To(Succeed())
	})

	var _ = AfterSuite(func() {
		schema.ClearManager()
		os.Remove(dbFile)
	})
})
예제 #15
0
파일: editor.go 프로젝트: vozhyk-/gohan
func setupEditor(server *Server) {
	manager := schema.GetManager()
	config := util.GetConfig()
	editableSchemaFile := config.GetString("editable_schema", "")
	golang.RegisterGoCallback("handle_schema",
		func(event string, context map[string]interface{}) error {
			auth := context["auth"].(schema.Authorization)
			if event == "pre_list" {
				list := []interface{}{}
				total := 0
				for _, currentSchema := range manager.OrderedSchemas() {
					trimmedSchema, err := GetSchema(currentSchema, auth)
					if err != nil {
						return err
					}
					if trimmedSchema != nil {
						s := trimmedSchema.Data()
						s["url"] = currentSchema.URL
						list = append(list, s)
						total = total + 1
					}
				}
				context["total"] = total
				context["response"] = map[string]interface{}{
					"schemas": list,
				}
				return nil
			} else if event == "pre_show" {
				ID := context["id"].(string)
				currentSchema, _ := manager.Schema(ID)
				object, _ := GetSchema(currentSchema, auth)
				s := object.Data()
				s["url"] = currentSchema.URL
				context["response"] = map[string]interface{}{
					"schema": s,
				}
				return nil
			}
			if event != "pre_create" && event != "pre_update" && event != "pre_delete" {
				return nil
			}

			if editableSchemaFile == "" {
				return nil
			}

			ID := context["id"].(string)

			schemasInFile, err := util.LoadMap(editableSchemaFile)
			if err != nil {
				return nil
			}
			schemas := schemasInFile["schemas"].([]interface{})
			updatedSchemas := []interface{}{}
			var existingSchema map[string]interface{}
			for _, rawSchema := range schemas {
				s := rawSchema.(map[string]interface{})
				if s["id"] == ID {
					existingSchema = s
				} else {
					updatedSchemas = append(updatedSchemas, s)
				}
			}

			if event == "pre_create" {
				if existingSchema != nil {
					return fmt.Errorf("ID has been taken")
				}
				newSchema := context["resource"].(map[string]interface{})
				_, err := schema.NewSchemaFromObj(newSchema)
				if err != nil {
					return err
				}
				schemasInFile["schemas"] = append(updatedSchemas, context["resource"].(map[string]interface{}))
				context["response"] = map[string]interface{}{
					"schema": context["resource"],
				}
				context["exception"] = map[string]interface{}{
					"name":    "CustomException",
					"message": context["response"],
					"code":    201,
				}
			} else if event == "pre_update" {
				if existingSchema == nil {
					return fmt.Errorf("Not found or Update isn't supported for this schema")
				}
				for key, value := range context["resource"].(map[string]interface{}) {
					existingSchema[key] = value
				}
				_, err := schema.NewSchemaFromObj(existingSchema)
				if err != nil {
					return err
				}
				schemasInFile["schemas"] = append(updatedSchemas, existingSchema)
				context["response"] = map[string]interface{}{
					"schema": context["resource"],
				}
				context["exception"] = map[string]interface{}{
					"name":    "CustomException",
					"message": context["response"],
					"code":    200,
				}

			} else if event == "pre_delete" {
				if existingSchema == nil {
					return fmt.Errorf("Not found or Delete isn't supported for this schema")
				}
				schemasInFile["schemas"] = updatedSchemas
				deletedSchema, ok := manager.Schema(ID)
				if ok {
					manager.UnRegisterSchema(deletedSchema)
				}
				context["exception"] = map[string]interface{}{
					"name":    "CustomException",
					"message": map[string]interface{}{"result": "deleted"},
					"code":    204,
				}
			}
			util.SaveFile(editableSchemaFile, schemasInFile)
			err = manager.LoadSchemaFromFile(editableSchemaFile)
			if err != nil {
				return err
			}
			server.initDB()
			server.resetRouter()
			server.mapRoutes()
			return nil
		})
}
예제 #16
0
func listenAMQP(server *Server) {

	hostname, _ := os.Hostname()
	processID := hostname + uuid.NewV4().String()
	config := util.GetConfig()
	connection := config.GetString("amqp/connection", "amqp://*****:*****@127.0.0.1:5672/")
	queues := config.GetStringList("amqp/queues", []string{"notifications.info", "notifications.error"})
	events := config.GetStringList("amqp/events", []string{})
	extensions := map[string]extension.Environment{}
	for _, event := range events {
		path := "amqp://" + event
		env, err := server.NewEnvironmentForPath("amqp."+event, path)
		if err != nil {
			log.Fatal(err.Error())
		}
		extensions[event] = env
	}

	for _, queue := range queues {
		go func(queue string) {
			defer util.LogPanic(log)
			for server.running {
				conn, err := amqp.Dial(connection)
				if err != nil {
					log.Error(fmt.Sprintf("[AMQP] connection error: %s", err))
					time.Sleep(connectionWait)
					continue
				}
				defer conn.Close()

				ch, err := conn.Channel()
				if err != nil {
					log.Error(fmt.Sprintf("[AMQP] channel: %s", err))
					return
				}
				defer ch.Close()
				q, err := ch.QueueDeclare(
					queue, // name
					false, // durable
					false, // delete when usused
					false, // exclusive
					false, // no-wait
					nil,   // arguments
				)
				if err != nil {
					log.Error(fmt.Sprintf("[AMQP] queue declare error: %s", err))
					return
				}

				for server.running {
					msgs, err := ch.Consume(
						q.Name, // queue
						"gohan-"+processID+"-"+queue, // consumer
						true,  // auto-ack
						false, // exclusive
						false, // no-local
						false, // no-wait
						nil,   // args
					)

					if err != nil {
						log.Error(fmt.Sprintf("[AMQP] consume queue error: %s", err))
						break
					}
					for d := range msgs {
						var message map[string]interface{}
						err = json.Unmarshal(d.Body, &message)
						log.Debug(fmt.Sprintf("Received a message: %s %s", queue, d.Body))
						if err != nil {
							log.Error(fmt.Sprintf("[AMQP] json decode error: %s", err))
							continue
						}
						eventType, ok := message["event_type"].(string)
						if !ok {
							log.Error("[AMQP] wrong event type")
							continue
						}
						for _, event := range events {
							if strings.HasPrefix(eventType, event) {
								env := extensions[event]

								context := map[string]interface{}{
									"event": message,
								}
								if err := env.HandleEvent("notification", context); err != nil {
									log.Warning(fmt.Sprintf("extension error: %s", err))
								}
							}
						}
					}
				}
			}
		}(queue)
	}
}
예제 #17
0
//ReadConfig reads configuraion from file.
func ReadConfig(path string) error {
	config := util.GetConfig()
	err := config.ReadConfig(path)
	return err
}
예제 #18
0
파일: sync.go 프로젝트: gitter-badger/gohan
//Sync Watch Process
func startSyncWatchProcess(server *Server) {
	manager := schema.GetManager()
	config := util.GetConfig()
	watch := config.GetStringList("watch/keys", nil)
	events := config.GetStringList("watch/events", nil)
	maxWorkerCount := config.GetParam("watch/worker_count", 0).(int)
	if watch == nil {
		return
	}
	extensions := map[string]extension.Environment{}
	for _, event := range events {
		path := "sync://" + event
		env := newEnvironment(server.db, server.keystoneIdentity)
		err := env.LoadExtensionsForPath(manager.Extensions, path)
		if err != nil {
			log.Fatal(fmt.Sprintf("Extensions parsing error: %v", err))
		}
		extensions[event] = env
	}
	responseChan := make(chan *gohan_sync.Event)
	stopChan := make(chan bool)
	for _, path := range watch {
		go func(path string) {
			for server.running {
				err := server.sync.Watch(path, responseChan, stopChan)
				if err != nil {
					log.Error(fmt.Sprintf("sync watch error: %s", err))
				}
				time.Sleep(5 * time.Second)
			}
		}(path)
	}
	//main response lisnter process
	go func() {
		var wg sync.WaitGroup
		workerCount := 0
		for server.running {
			response := <-responseChan
			wg.Add(1)
			workerCount++
			//spawn workers up to max worker count
			go func() {
				defer func() {
					workerCount--
					wg.Done()
				}()
				for _, event := range events {
					//match extensions
					if strings.HasPrefix(response.Key, "/"+event) {
						env := extensions[event]
						runExtensionOnSync(server, response, env)
						return
					}
				}
			}()
			// Wait if worker pool is full
			if workerCount > maxWorkerCount {
				wg.Wait()
			}
		}
		stopChan <- true
	}()

}
예제 #19
0
//GetConfig returns config by key.
func GetConfig(key string, defaultValue interface{}) interface{} {
	config := util.GetConfig()
	return config.GetParam(key, defaultValue)
}
예제 #20
0
파일: server.go 프로젝트: vozhyk-/gohan
//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
}
예제 #21
0
//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
}
예제 #22
0
//SetUp sets up vm to with environment
func init() {
	gohanRemoteInit := func(env *Environment) {
		vm := env.VM

		builtins := map[string]interface{}{
			"gohan_netconf_open": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 2 {
					panic("Wrong number of arguments in gohan_netconf_open call.")
				}
				rawHost, _ := call.Argument(0).Export()
				host, ok := rawHost.(string)
				if !ok {
					return otto.NullValue()
				}
				rawUserName, _ := call.Argument(1).Export()
				userName, ok := rawUserName.(string)
				if !ok {
					return otto.NullValue()
				}
				config := util.GetConfig()
				publicKeyFile := config.GetString("ssh/key_file", "")
				if publicKeyFile == "" {
					return otto.NullValue()
				}
				sshConfig := &ssh.ClientConfig{
					User: userName,
					Auth: []ssh.AuthMethod{
						util.PublicKeyFile(publicKeyFile),
					},
				}
				s, err := netconf.DialSSH(host, sshConfig)

				if err != nil {
					ThrowOttoException(&call, "Error during gohan_netconf_open: %s", err.Error())
				}
				value, _ := vm.ToValue(s)
				return value
			},
			"gohan_netconf_close": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 1 {
					panic("Wrong number of arguments in gohan_netconf_close call.")
				}
				rawSession, _ := call.Argument(0).Export()
				s, ok := rawSession.(*netconf.Session)
				if !ok {
					ThrowOttoException(&call, "Error during gohan_netconf_close")
				}
				s.Close()
				return otto.NullValue()
			},
			"gohan_netconf_exec": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 2 {
					panic("Wrong number of arguments in gohan_netconf_exec call.")
				}
				rawSession, _ := call.Argument(0).Export()
				s, ok := rawSession.(*netconf.Session)
				if !ok {
					return otto.NullValue()
				}
				rawCommand, _ := call.Argument(1).Export()
				command, ok := rawCommand.(string)
				if !ok {
					return otto.NullValue()
				}
				reply, err := s.Exec(netconf.RawMethod(command))
				resp := map[string]interface{}{}
				if err != nil {
					resp["status"] = "error"
					resp["output"] = err.Error()
				} else {
					resp["status"] = "success"
					resp["output"] = reply
				}
				value, _ := vm.ToValue(resp)
				return value
			},
			"gohan_ssh_open": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 2 {
					panic("Wrong number of arguments in gohan_netconf_open call.")
				}
				rawHost, _ := call.Argument(0).Export()
				host, ok := rawHost.(string)
				if !ok {
					return otto.NullValue()
				}
				rawUserName, _ := call.Argument(1).Export()
				userName, ok := rawUserName.(string)
				if !ok {
					return otto.NullValue()
				}
				config := util.GetConfig()
				publicKeyFile := config.GetString("ssh/key_file", "")
				if publicKeyFile == "" {
					return otto.NullValue()
				}
				sshConfig := &ssh.ClientConfig{
					User: userName,
					Auth: []ssh.AuthMethod{
						util.PublicKeyFile(publicKeyFile),
					},
				}
				conn, err := ssh.Dial("tcp", host, sshConfig)
				if err != nil {
					ThrowOttoException(&call, "Error during gohan_ssh_open %s", err)
				}
				session, err := conn.NewSession()
				if err != nil {
					ThrowOttoException(&call, "Error during gohan_ssh_open %s", err)
				}
				value, _ := vm.ToValue(session)
				return value
			},
			"gohan_ssh_close": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 1 {
					panic("Wrong number of arguments in gohan_netconf_close call.")
				}
				rawSession, _ := call.Argument(0).Export()
				s, ok := rawSession.(*ssh.Session)
				if !ok {
					ThrowOttoException(&call, "Error during gohan_ssh_close")
				}
				s.Close()
				return otto.NullValue()
			},
			"gohan_ssh_exec": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) != 2 {
					panic("Wrong number of arguments in gohan_netconf_exec call.")
				}
				rawSession, _ := call.Argument(0).Export()
				s, ok := rawSession.(*ssh.Session)
				if !ok {
					return otto.NullValue()
				}
				rawCommand, _ := call.Argument(1).Export()
				command, ok := rawCommand.(string)
				if !ok {
					return otto.NullValue()
				}
				var stdoutBuf bytes.Buffer
				s.Stdout = &stdoutBuf
				err := s.Run(command)
				resp := map[string]interface{}{}
				if err != nil {
					resp["status"] = "error"
					resp["output"] = err.Error()
				} else {
					resp["status"] = "success"
					resp["output"] = stdoutBuf.String()
				}
				value, _ := vm.ToValue(resp)
				return value
			},
		}
		for name, object := range builtins {
			vm.Set(name, object)
		}
	}
	RegistInit(gohanRemoteInit)
}
예제 #23
0
func init() {
	gohanUtilInit := func(env *Environment) {
		vm := env.VM
		builtins := map[string]interface{}{
			"gohan_http": func(call otto.FunctionCall) otto.Value {
				if len(call.ArgumentList) == 4 {
					defaultOpaque, _ := otto.ToValue(false)
					call.ArgumentList = append(call.ArgumentList, defaultOpaque)
				}
				VerifyCallArguments(&call, "gohan_http", 5)
				method, err := GetString(call.Argument(0))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				url, err := GetString(call.Argument(1))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				rawHeaders, err := GetMap(call.Argument(2))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				// A string or a map[string]interface{}
				data := ConvertOttoToGo(call.Argument(3))
				opaque, err := GetBool(call.Argument(4))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				log.Debug("gohan_http  [%s] %s %s %s", method, rawHeaders, url, opaque)
				code, headers, body, err := gohanHTTP(method, url, rawHeaders, data, opaque)
				log.Debug("response code %d", code)
				resp := map[string]interface{}{}
				if err != nil {
					resp["status"] = "err"
					resp["error"] = err.Error()
				} else {
					resp["status"] = "success"
					resp["status_code"] = fmt.Sprint(code)
					resp["body"] = body
					resp["headers"] = headers
				}
				log.Debug("response code %d", code)
				value, _ := vm.ToValue(resp)
				return value
			},
			"gohan_schemas": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_schemas", 0)
				manager := schema.GetManager()
				response := []interface{}{}
				for _, schema := range manager.OrderedSchemas() {
					response = append(response, schema)
				}
				value, _ := vm.ToValue(response)
				return value
			},
			"gohan_schema_url": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_schema_url", 1)
				schemaID, err := GetString(call.Argument(0))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				schema, err := getSchema(schemaID)
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				value, _ := vm.ToValue(schema.URL)
				return value
			},
			"gohan_policies": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_policies", 0)
				manager := schema.GetManager()
				response := []interface{}{}
				for _, policy := range manager.Policies() {
					response = append(response, policy.RawData)
				}
				value, _ := vm.ToValue(response)
				return value
			},
			"gohan_uuid": func(call otto.FunctionCall) otto.Value {
				value, _ := vm.ToValue(uuid.NewV4().String())
				return value
			},
			"gohan_sleep": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_sleep", 1)
				rawSleep, _ := call.Argument(0).Export()
				var sleep time.Duration
				switch rawSleep.(type) {
				case int:
					sleep = time.Duration(rawSleep.(int))
				case int64:
					sleep = time.Duration(rawSleep.(int64))
				}
				time.Sleep(sleep * time.Millisecond)
				return otto.NullValue()
			},
			"gohan_template": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_template", 2)
				templateString, err := GetString(call.Argument(0))
				if err != nil {
					return call.Argument(0)
				}
				data := ConvertOttoToGo(call.Argument(1))
				t := template.Must(template.New("tmpl").Parse(templateString))
				b := bytes.NewBuffer(make([]byte, 0, 100))
				t.Execute(b, data)
				value, _ := vm.ToValue(b.String())
				return value
			},
			"gohan_exec": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_exec", 2)
				command, err := GetString(call.Argument(0))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				stringArgs, err := GetStringList(call.Argument(1))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				out, err := exec.Command(command, stringArgs...).Output()
				resp := map[string]string{}
				if err != nil {
					resp["status"] = "error"
					resp["output"] = err.Error()
				} else {
					resp["status"] = "success"
					resp["output"] = string(out)
				}
				value, _ := vm.ToValue(resp)
				return value
			},
			"gohan_config": func(call otto.FunctionCall) otto.Value {
				VerifyCallArguments(&call, "gohan_exec", 2)
				configKey, err := GetString(call.Argument(0))
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				defaultValue, err := call.Argument(1).Export()
				if err != nil {
					ThrowOttoException(&call, err.Error())
				}
				config := util.GetConfig()
				result := config.GetParam(configKey, defaultValue)
				value, _ := vm.ToValue(result)
				return value
			},
		}

		for name, object := range builtins {
			vm.Set(name, object)
		}

	}
	RegisterInit(gohanUtilInit)
}