Example #1
0
func initNodeData() {
	if memConfNodes[conf.ClientAddr] == nil {
		bs, _ := json.Marshal(memConfDataVersion)
		node := &models.Node{
			URL:            conf.ClientAddr,
			NodeURL:        conf.NodeAddr,
			Type:           conf.NodeType,
			DataVersion:    memConfDataVersion,
			DataVersionStr: string(bs),
			CreatedUTC:     utils.GetNowSecond(),
		}

		if err := models.InsertRow(nil, node); err != nil {
			log.Panicf("Failed to init node data: %s", err.Error())
		}
		memConfNodes[conf.ClientAddr] = node
	}

	node := memConfNodes[conf.ClientAddr]
	if node.Type != conf.NodeType {
		node.Type = conf.NodeType
		if err := models.UpdateDBModel(nil, node); err != nil {
			log.Panicf("Failed to update node data: %s", err.Error())
		}
	}
}
Example #2
0
func cloneConfigsFromApp(from, to, aux_info, userKey string) (*models.App, []*models.Config, error) {
	memConfMux.RLock()
	fromApp := memConfAppsByName[from]
	memConfMux.RUnlock()

	fromConfigs, err := models.GetConfigsByAppKey(nil, fromApp.Key)
	if err != nil {
		return nil, nil, err
	}

	app := &models.App{
		Key:        utils.GenerateKey(),
		Name:       to,
		UserKey:    userKey,
		AuxInfo:    aux_info,
		CreatedUTC: utils.GetNowSecond(),
		Type:       fromApp.Type,
	}

	for _, config := range fromConfigs {
		config.Key = utils.GenerateKey()
		config.CreatorKey = app.UserKey
		config.AppKey = app.Key
		config.CreatedUTC = app.CreatedUTC
	}

	if err := cloneConfigs(app, fromConfigs, userKey); err != nil {
		return nil, nil, err
	}

	return app, fromConfigs, nil
}
Example #3
0
func newUserWithNewUserData(data *newUserData, userKey, creatorKey string) (*models.User, error) {
	user := &models.User{
		Name:       data.Name,
		PassCode:   encryptUserPassCode(data.PassCode),
		CreatorKey: creatorKey,
		CreatedUTC: utils.GetNowSecond(),
		AuxInfo:    data.AuxInfo,
		Status:     models.USER_STATUS_ACTIVE,
		Key:        userKey}

	return updateUser(user, nil)
}
Example #4
0
func newConfigWithNewConfigData(data *newConfigData, userKey string) (*models.Config, error) {
	config := &models.Config{
		Key:        utils.GenerateKey(),
		AppKey:     data.AppKey,
		K:          data.K,
		V:          data.V,
		VType:      data.VType,
		CreatedUTC: utils.GetNowSecond(),
		CreatorKey: userKey,
		Des:        data.Des,
		Status:     models.CONF_STATUS_ACTIVE,
	}

	return updateConfig(config, userKey, nil, nil)
}
Example #5
0
func UpdateMasterLastDataUpdateUTC(c *gin.Context) {
	if !getServiceStatus(c) ||
		(c.Request.Method != http.MethodPost && c.Request.Method != http.MethodPut && c.Request.Method != http.MethodPatch && c.Request.Method != http.MethodDelete) {
		return
	}
	memConfMux.RLock()
	localNode := *memConfNodes[conf.ClientAddr] // must be master node
	memConfMux.RUnlock()

	// use master node's LastCheckUTC to store last update utc
	localNode.LastCheckUTC = utils.GetNowSecond()
	if models.UpdateDBModel(nil, &localNode) == nil {
		memConfMux.Lock()
		memConfNodes[localNode.URL] = &localNode
		memConfMux.Unlock()
	}
}
Example #6
0
func syncData2Slave(node *models.Node, data interface{}, dataVer *models.DataVersion, opUserKey string) error {
	kind := ""
	switch data.(type) {
	case *models.User:
		kind = NODE_REQUEST_SYNC_TYPE_USER
	case *models.App:
		kind = NODE_REQUEST_SYNC_TYPE_APP
	case *models.WebHook:
		kind = NODE_REQUEST_SYNC_TYPE_WEBHOOK
	case *models.Config:
		kind = NODE_REQUEST_SYNC_TYPE_CONFIG
	case *models.Node:
		kind = NODE_REQUEST_SYNC_TYPE_NODE
	case *cloneData:
		kind = NODE_REQUEST_SYNC_TYPE_CLONE
	default:
		log.Panicln("unknown node data sync type: ", reflect.TypeOf(data))
	}

	bs, _ := json.Marshal(data)
	syncDataString, _ := json.Marshal(&syncDataT{
		DataVersion: dataVer,
		Kind:        kind,
		Data:        string(bs),
		OpUserKey:   opUserKey,
	})

	reqData := nodeRequestDataT{
		Auth: nodeAuthString,
		Data: string(syncDataString),
	}
	_, err := nodeRequest(node.NodeURL, NODE_REQUEST_TYPE_SYNCSLAVE, reqData)

	if err == nil && kind != NODE_REQUEST_SYNC_TYPE_NODE {
		// update slave data version here
		dataVersionStr, _ := json.Marshal(dataVer)
		memConfMux.Lock()
		node.DataVersion = dataVer
		node.DataVersionStr = string(dataVersionStr)
		node.LastCheckUTC = utils.GetNowSecond()
		memConfMux.Unlock()
		updateNodeDataVersion(nil, node, dataVer)
	}

	return err
}
Example #7
0
func NewApp(c *gin.Context) {
	confWriteMux.Lock()
	defer confWriteMux.Unlock()

	var data struct {
		Name    string `json:"name" binding:"required"`
		Type    string `json:"type" binding:"required"`
		AuxInfo string `json:"aux_info"`
	}
	if err := c.BindJSON(&data); err != nil {
		Error(c, BAD_POST_DATA, err.Error())
		return
	}

	if !models.IsValidAppType(data.Type) {
		Error(c, BAD_REQUEST, "unknown app type: "+data.Type)
		return
	}

	if memConfAppsByName[data.Name] != nil {
		Error(c, BAD_REQUEST, "appname already exists: "+data.Name)
		return
	}

	app := &models.App{
		Key:        utils.GenerateKey(),
		Name:       data.Name,
		UserKey:    getOpUserKey(c),
		Type:       data.Type,
		AuxInfo:    data.AuxInfo,
		CreatedUTC: utils.GetNowSecond(),
	}
	if _, err := updateApp(app, nil, nil); err != nil {
		Error(c, SERVER_ERROR, err.Error())
		return
	}

	failedNodes := syncData2SlaveIfNeed(app, getOpUserKey(c))
	if len(failedNodes) > 0 {
		Success(c, map[string]interface{}{"failed_nodes": failedNodes})
	} else {
		Success(c, nil)
	}
}
Example #8
0
func handleSlaveCheckMaster(c *gin.Context, data string) {
	if !conf.IsMasterNode() {
		Error(c, BAD_REQUEST, "invalid req type for slave node: "+NODE_REQUEST_TYPE_CHECKMASTER)
		return
	}

	node := &models.Node{}
	if err := json.Unmarshal([]byte(data), node); err != nil {
		Error(c, BAD_REQUEST, "bad req body format")
		return
	}

	confWriteMux.Lock()
	defer confWriteMux.Unlock()

	oldNode := memConfNodes[node.URL]
	node.LastCheckUTC = utils.GetNowSecond()
	if oldNode == nil {
		if err := models.InsertRow(nil, node); err != nil {
			Error(c, SERVER_ERROR, err.Error())
			return
		}
	} else {
		if err := models.UpdateDBModel(nil, node); err != nil {
			Error(c, SERVER_ERROR, err.Error())
			return
		}
	}

	memConfMux.Lock()
	memConfNodes[node.URL] = node
	bs, _ := json.Marshal(memConfDataVersion)
	memConfMux.Unlock()

	go masterSyncNodeToSlave(node)

	Success(c, string(bs))
}
Example #9
0
func TestPubuNotifaction(t *testing.T) {
	pubuURL := `https://hooks.pubu.im/services/q2qp7wywyebgfqd`
	hostname, _ := os.Hostname()
	configHistory := &models.ConfigUpdateHistory{
		Id:         "",
		ConfigKey:  "",
		K:          "TestKey",
		OldV:       "",
		OldVType:   "",
		NewV:       "1.0",
		NewVType:   models.CONF_V_TYPE_INT,
		Kind:       models.CONFIG_UPDATE_KIND_NEW,
		UserKey:    "",
		UserName:   fmt.Sprintf("PubuTester@%s", hostname),
		CreatedUTC: utils.GetNowSecond(),
	}
	app := &models.App{
		Name: "TestApp",
	}
	sendNotificationToPubu(pubuURL, configHistory, app)
	configHistory.UserName = fmt.Sprintf("SlackTester@%s", hostname)
	sendNotificationToSlack(pubuURL, configHistory, app)
}
Example #10
0
func updateConfig(config *models.Config, userKey string, newDataVersion *models.DataVersion, ms *models.Session) (*models.Config, error) {
	var s *models.Session

	if ms != nil {
		s = ms
	} else {
		s = models.NewSession()
		defer s.Close()
		if err := s.Begin(); err != nil {
			s.Rollback()
			return nil, err
		}
	}

	isSysConf := isSysConfType(config.AppKey)

	node := *memConfNodes[conf.ClientAddr]
	oldConfig := memConfRawConfigs[config.Key]

	app, err := models.GetAppByKey(s, config.AppKey)
	if err != nil {
		return nil, err
	}

	if newDataVersion == nil {
		newDataVersion = genNewDataVersion(memConfDataVersion)
	}

	if err := updateNodeDataVersion(s, &node, newDataVersion); err != nil {
		if ms == nil {
			s.Rollback()
		}
		return nil, err
	}

	var configHistory *models.ConfigUpdateHistory

	if oldConfig == nil {
		configHistory = &models.ConfigUpdateHistory{
			Id:         utils.GenerateKey(),
			ConfigKey:  config.Key,
			K:          config.K,
			OldV:       "",
			OldVType:   "",
			NewV:       config.V,
			NewVType:   config.VType,
			Kind:       models.CONFIG_UPDATE_KIND_NEW,
			UserKey:    userKey,
			CreatedUTC: utils.GetNowSecond(),
		}
		if err := models.InsertRow(s, configHistory); err != nil {
			if ms == nil {
				s.Rollback()
			}
			return nil, err
		}

		config.LastUpdateId = configHistory.Id
		if err := models.InsertRow(s, config); err != nil {
			if ms == nil {
				s.Rollback()
			}
			return nil, err
		}

		if !isSysConf {
			app.KeyCount++
			app.LastUpdateUTC = configHistory.CreatedUTC
			app.LastUpdateId = configHistory.Id
			app.UpdateTimes++
		}

	} else {
		kind := models.CONFIG_UPDATE_KIND_UPDATE
		if config.Status != oldConfig.Status {
			if config.Status == models.CONF_STATUS_ACTIVE {
				kind = models.CONFIG_UPDATE_KIND_RECOVER
			} else {
				kind = models.CONFIG_UPDATE_KIND_HIDE
			}
		}

		configHistory = &models.ConfigUpdateHistory{
			Id:         utils.GenerateKey(),
			ConfigKey:  config.Key,
			K:          config.K,
			OldV:       oldConfig.V,
			OldVType:   oldConfig.VType,
			NewV:       config.V,
			NewVType:   config.VType,
			Kind:       kind,
			UserKey:    userKey,
			CreatedUTC: utils.GetNowSecond(),
		}
		if err := models.InsertRow(s, configHistory); err != nil {
			if ms == nil {
				s.Rollback()
			}
			return nil, err
		}

		config.UpdateTimes++
		config.LastUpdateId = configHistory.Id
		if err := models.UpdateDBModel(s, config); err != nil {
			if ms == nil {
				s.Rollback()
			}
			return nil, err
		}
		if !isSysConf {
			app.LastUpdateUTC = configHistory.CreatedUTC
			app.LastUpdateId = configHistory.Id
			app.UpdateTimes++
		}
	}

	var toUpdateApps []*models.App
	if !isSysConf {
		newDataSign := utils.GenerateKey()
		app.DataSign = newDataSign
		if err := models.UpdateDBModel(s, app); err != nil {
			if ms == nil {
				s.Rollback()
			}
			return nil, err
		}

		if app.Type == models.APP_TYPE_TEMPLATE {
			for _, _app := range memConfApps {
				if _app.Key == config.AppKey {
					continue
				}
				for _, _config := range memConfAppConfigs[_app.Key] {
					if _config.VType == models.CONF_V_TYPE_TEMPLATE && _config.V == config.AppKey {
						// this app has a config refer to this template app
						toUpdateApps = append(toUpdateApps, _app)
						break
					}
				}
			}
		}

		for _, app := range toUpdateApps {
			_app := *app
			_app.DataSign = newDataSign
			if err := models.UpdateDBModel(s, &_app); err != nil {
				if ms == nil {
					s.Rollback()
				}
				return nil, err
			}
		}
	}

	if ms == nil {
		if err := s.Commit(); err != nil {
			s.Rollback()
			return nil, err
		}

		if !isSysConf {
			go TriggerWebHooks(configHistory, app)
		} else {
			go TriggerWebHooks(configHistory, &models.App{Key: config.Key, Name: config.Key})
		}

		updateMemConf(config, newDataVersion, &node, toUpdateApps)
	}

	return config, nil
}
Example #11
0
func ClientConf(c *gin.Context) {
	clientData := &ClientData{
		AppKey:     c.Query("app_key"),
		OSType:     c.Query("os_type"),
		OSVersion:  c.Query("os_version"),
		AppVersion: c.Query("app_version"),
		Ip:         c.Query("ip"),
		Lang:       c.Query("lang"),
		DeviceId:   c.Query("device_id"),
		DataSign:   c.Query("data_sign"),
		TimeZone:   c.Query("timezone"),
		NetWork:    c.Query("network"),
	}

	if clientData.AppKey == "" {
		memConfMux.RLock()
		app := memConfAppsByName[c.Query("app")]
		memConfMux.RUnlock()

		if app != nil {
			clientData.AppKey = app.Key
			clientData.OSType = "ios"
			clientData.OSVersion = c.Query("osv")
			clientData.AppVersion = c.Query("v")
			clientData.DeviceId = c.Query("ida")
			clientData.Ip = c.Request.RemoteAddr
		}

		clientData = uniformClientParams(clientData)
		sendChanAsync(clientQueryParamCh, clientData)
		setClientData(c, clientData)

		c.JSON(http.StatusOK, getAppMatchConf(clientData.AppKey, clientData))
		return
	}

	clientData = uniformClientParams(clientData)
	sendChanAsync(clientQueryParamCh, clientData)
	setClientData(c, clientData)

	memConfMux.RLock()
	if !conf.IsMasterNode() && conf.DataExpires > 0 {
		if memConfNodes[conf.ClientAddr].LastCheckUTC < utils.GetNowSecond()-conf.DataExpires {
			memConfMux.RUnlock()
			Error(c, DATA_EXPIRED)
			return
		}
	}

	nodes := []string{}
	nodes = make([]string, len(memConfNodes))
	ix := 0
	for _, node := range memConfNodes {
		nodes[ix] = node.URL
		ix++
	}

	needConf := memConfApps[clientData.AppKey] != nil && clientData.DataSign != memConfApps[clientData.AppKey].DataSign
	memConfMux.RUnlock()

	if needConf {
		var dataSign string
		configs := getAppMatchConf(clientData.AppKey, clientData)
		if len(configs) > 0 {
			memConfMux.RLock()
			dataSign = memConfApps[clientData.AppKey].DataSign
			memConfMux.RUnlock()
		}

		Success(c, map[string]interface{}{
			"nodes":     nodes,
			"configs":   configs,
			"data_sign": dataSign,
		})
	} else {
		Success(c, map[string]interface{}{
			"data_sign": clientData.DataSign,
			"nodes":     nodes,
		})
	}

	return
}
Example #12
0
func slaveCheckMaster() error {
	confWriteMux.Lock()
	defer confWriteMux.Unlock()

	localNode := *memConfNodes[conf.ClientAddr]
	nodeString, _ := json.Marshal(localNode)
	reqData := nodeRequestDataT{
		Auth: nodeAuthString,
		Data: string(nodeString),
	}
	data, err := nodeRequest(conf.MasterAddr, NODE_REQUEST_TYPE_CHECKMASTER, reqData)
	if err != nil {
		return err
	}

	masterVersion := &models.DataVersion{}
	if err = json.Unmarshal([]byte(data.(string)), masterVersion); err != nil {
		return fmt.Errorf("bad response data format: %s < %s >", err.Error(), data.(string))
	}

	if masterVersion.Version == memConfDataVersion.Version && masterVersion.Sign == memConfDataVersion.Sign {
		localNode.LastCheckUTC = utils.GetNowSecond()
		if err = models.UpdateDBModel(nil, &localNode); err != nil {
			return err
		}

		memConfMux.Lock()
		memConfNodes[conf.ClientAddr] = &localNode
		memConfMux.Unlock()

		return nil
	}

	reqData = nodeRequestDataT{
		Auth: nodeAuthString,
		Data: "",
	}
	// slave's data_version not equals master's data_version, slave sync all data from master
	data, err = nodeRequest(conf.MasterAddr, NODE_REQUEST_TYPE_SYNCMASTER, reqData)
	if err != nil {
		return err
	}

	resData := &syncAllDataT{}
	if err = json.Unmarshal([]byte(data.(string)), resData); err != nil {
		return fmt.Errorf("bad response data format: %s < %s >", err.Error(), data.(string))
	}

	var users []*models.User
	var apps []*models.App
	var configs []*models.Config
	var nodes []*models.Node

	bs, _ := json.Marshal(resData.DataVersion)
	localNode.DataVersion = resData.DataVersion
	localNode.DataVersionStr = string(bs)
	localNode.LastCheckUTC = utils.GetNowSecond()

	// let sqlite use new db file
	models.UpdateSqliteDBEngine()

	s := models.NewSession()
	defer s.Close()
	if err = s.Begin(); err != nil {
		s.Rollback()
		return err
	}

	if err = models.ClearModeData(s); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels := make([]interface{}, 0)
	for _, node := range resData.Nodes {
		if node.URL == conf.ClientAddr {
			node.DataVersion = localNode.DataVersion
			node.DataVersionStr = localNode.DataVersionStr
			node.LastCheckUTC = localNode.LastCheckUTC
		}
		toInsertModels = append(toInsertModels, node)
		nodes = append(nodes, node)
	}
	if err := models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels = make([]interface{}, 0)
	for _, user := range resData.Users {
		users = append(users, user)
		toInsertModels = append(toInsertModels, user)
	}
	if err = models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels = make([]interface{}, 0)
	for _, app := range resData.Apps {
		toInsertModels = append(toInsertModels, app)
		apps = append(apps, app)
	}
	if err = models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels = make([]interface{}, len(resData.WebHooks))
	for ix, hook := range resData.WebHooks {
		toInsertModels[ix] = hook
	}
	if err = models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels = make([]interface{}, 0)
	for _, config := range resData.Configs {
		toInsertModels = append(toInsertModels, config)
		configs = append(configs, config)
	}
	if err = models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	toInsertModels = make([]interface{}, len(resData.ConfHistory))
	for ix, history := range resData.ConfHistory {
		toInsertModels[ix] = history
	}
	if err = models.InsertMultiRows(s, toInsertModels); err != nil {
		s.Rollback()
		return err
	}

	if err = models.UpdateDataVersion(s, resData.DataVersion); err != nil {
		s.Rollback()
		return err
	}

	if err = s.Commit(); err != nil {
		s.Rollback()
		return err
	}

	fillMemConfData(users, apps, resData.WebHooks, configs, nodes, resData.DataVersion)

	nodeString, _ = json.Marshal(&localNode)
	reqData = nodeRequestDataT{
		Auth: nodeAuthString,
		Data: string(nodeString),
	}

	nodeRequest(conf.MasterAddr, NODE_REQUEST_TYPE_CHECKMASTER, reqData)

	return nil
}