func (p *AuthService) getObjectById(instanceId string, collectionName string) (data interface{}) {
	if !bson.IsObjectIdHex(instanceId) {
		logrus.Errorf("AuthService:getObjectById --- invalid instanceId")
		return nil
	}
	selector := make(bson.M)
	selector["_id"] = bson.ObjectIdHex(instanceId)

	// parse request
	// var fields bson.M = buildFields()
	data = bson.M{}
	queryStruct := dao.QueryStruct{
		CollectionName: collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	// _, _, data, err = p.Dao.HandleQuery(collectionName, selector, true, fields, 0, 1, "", "true")
	err := dao.HandleQueryOne(data, queryStruct)
	if err != nil {
		logrus.Errorf("handle query err is %v", err)
		return nil
	}
	return
}
func (p *UserService) GetUserByUserId(userId string) (user *entity.User, err error) {
	if !bson.IsObjectIdHex(userId) {
		logrus.Errorln("invalid object id for getUseerById: ", userId)
		err = errors.New("invalid object id for getUserById")
		return nil, err
	}
	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(userId)

	user = new(entity.User)
	queryStruct := dao.QueryStruct{
		CollectionName: p.userCollectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(user, queryStruct)

	if err != nil {
		logrus.Warnln("failed to get user by id %v", err)
		return
	}

	return
}
// GetRoleByName return the role by the role name.
func (p *RoleService) getRoleByName(rolename string) (role *entity.Role, err error) {
	query := strings.Join([]string{"{\"rolename\": \"", rolename, "\"}"}, "")

	selector := make(bson.M)
	err = json.Unmarshal([]byte(query), &selector)
	if err != nil {
		return
	}
	selector, err = mejson.Unmarshal(selector)
	if err != nil {
		return
	}

	role = new(entity.Role)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(role, queryStruct)

	return
}
func (p *ProviderService) QueryById(objectId string, token string) (provider entity.IaaSProvider, errorCode string, err error) {
	logrus.Infof("query provider by id[%s]", objectId)
	if !bson.IsObjectIdHex(objectId) {
		err = errors.New("invalide ObjectId.")
		errorCode = COMMON_ERROR_INVALIDATE
		return
	}

	errorCode, err = TokenValidation(token)
	if err != nil {
		logrus.Errorf("token validation failed for provider get [%v]", err)
		return
	}

	// do authorize first
	if authorized := GetAuthService().Authorize("get_provider", token, objectId, p.collectionName); !authorized {
		err = errors.New("required opertion is not authorized!")
		errorCode = COMMON_ERROR_UNAUTHORIZED
		logrus.Errorf("get provider with objectId [%v] error is %v", objectId, err)
		return
	}

	var selector = bson.M{}
	selector["_id"] = bson.ObjectIdHex(objectId)
	provider = entity.IaaSProvider{}
	err = dao.HandleQueryOne(&provider, dao.QueryStruct{p.collectionName, selector, 0, 0, ""})
	if err != nil {
		logrus.Errorf("query provider [objectId=%v] error is %v", objectId, err)
		errorCode = PROVIDER_ERROR_QUERY
	}
	return

}
func (p *TokenService) GetTokenById(token string) (currentToken *entity.Token, err error) {
	validId := bson.IsObjectIdHex(token)
	if !validId {
		return nil, errors.New("invalid token!")
	}

	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(token)

	currentToken = new(entity.Token)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(currentToken, queryStruct)
	if err != nil {
		logrus.Infoln("token does not exist! %v", err)
		return nil, err
	}

	return
}
func (p *TenantService) TenantDetail(token string, tenantId string) (ret interface{}, errorCode string, err error) {
	if !bson.IsObjectIdHex(tenantId) {
		logrus.Errorln("invalid object id for getTenantDetail: ", tenantId)
		err = errors.New("invalid object id for getTenantDetail")
		return nil, TENANT_ERROR_CREATE, err
	}
	code, err := GetTokenService().TokenValidate(token)
	if err != nil {
		return nil, code, err
	}

	if authorized := GetAuthService().Authorize("get_tenant", token, tenantId, p.collectionName); !authorized {
		logrus.Errorln("required opertion is not allowed!")
		return nil, COMMON_ERROR_UNAUTHORIZED, errors.New("Required opertion is not authorized!")
	}

	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(tenantId)

	ret = entity.Tenant{}
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(&ret, queryStruct)
	return
}
func (p *ClusterService) QueryById(objectId string, x_auth_token string) (cluster entity.Cluster,
	errorCode string, err error) {
	if !bson.IsObjectIdHex(objectId) {
		err = errors.New("invalide ObjectId.")
		errorCode = COMMON_ERROR_INVALIDATE
		return
	}

	// do authorize first
	if authorized := GetAuthService().Authorize("get_cluster", x_auth_token, objectId, p.collectionName); !authorized {
		err = errors.New("required opertion is not authorized!")
		errorCode = COMMON_ERROR_UNAUTHORIZED
		logrus.Errorf("get cluster with objectId [%v] error is %v", objectId, err)
		return
	}

	var selector = bson.M{}
	selector["_id"] = bson.ObjectIdHex(objectId)
	cluster = entity.Cluster{}
	err = dao.HandleQueryOne(&cluster, dao.QueryStruct{p.collectionName, selector, 0, 0, ""})
	if err != nil {
		logrus.Errorf("query cluster [objectId=%v] error is %v", objectId, err)
		errorCode = CLUSTER_ERROR_QUERY
	}
	return

}
func (p *UserService) GetUserById(userid string) (currentUser *entity.User, err error) {
	validId := bson.IsObjectIdHex(userid)
	if !validId {
		return nil, errors.New("invalid token!")
	}

	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(userid)

	currentUser = new(entity.User)
	queryStruct := dao.QueryStruct{
		CollectionName: p.userCollectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(currentUser, queryStruct)
	if err != nil {
		logrus.Infoln("user does not exist! %v", err)
		return nil, err
	}

	return
}
func (p *TenantService) GetTenantByTenantId(tenantId string) (tenant *entity.Tenant, err error) {
	if !bson.IsObjectIdHex(tenantId) {
		logrus.Errorln("invalid object id for getTenantById: ", tenantId)
		err = errors.New("invalid object id for getTenantById")
		return
	}
	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(tenantId)

	tenant = new(entity.Tenant)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(tenant, queryStruct)
	if err != nil {
		logrus.Warnln("failed to get tenant by id %v", err)
		return
	}

	return
}
func (p *UserService) UserDetail(token string, userId string) (ret interface{}, errorCode string, err error) {
	code, err := GetTokenService().TokenValidate(token)
	if err != nil {
		return nil, code, err
	}

	if authorized := GetAuthService().Authorize("get_user", token, userId, p.userCollectionName); !authorized {
		logrus.Errorln("required opertion is not allowed!")
		return nil, COMMON_ERROR_UNAUTHORIZED, errors.New("Required opertion is not authorized!")
	}

	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(userId)

	ret = new(entity.User)
	queryStruct := dao.QueryStruct{
		CollectionName: p.userCollectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(ret, queryStruct)
	logrus.Errorln(ret)
	return
}
func (p *UserService) UserUpdate(token string, newuser entity.User, userId string) (created bool, id string, errorCode string, err error) {
	code, err := GetTokenService().TokenValidate(token)
	if err != nil {
		return false, userId, code, err
	}

	if authorized := GetAuthService().Authorize("update_user", token, userId, p.userCollectionName); !authorized {
		logrus.Errorln("required opertion is not allowed!")
		return false, userId, COMMON_ERROR_UNAUTHORIZED, errors.New("Required opertion is not authorized!")
	}

	if !bson.IsObjectIdHex(userId) {
		logrus.Errorf("invalid user id format for user update %v", userId)
		return false, "", COMMON_ERROR_INVALIDATE, errors.New("Invalid object Id for user update")
	}

	selector := bson.M{}
	selector["_id"] = bson.ObjectIdHex(userId)

	queryStruct := dao.QueryStruct{
		CollectionName: p.userCollectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	user := new(entity.User)
	err = dao.HandleQueryOne(user, queryStruct)
	if err != nil {
		logrus.Errorf("get user by id error %v", err)
		return false, "", USER_ERROR_UPDATE, err
	}

	if len(newuser.Company) > 0 {
		user.Company = newuser.Company
	}
	if len(newuser.Email) > 0 {
		user.Email = newuser.Email
	}

	user.TimeUpdate = dao.GetCurrentTime()

	created, err = dao.HandleUpdateOne(user, queryStruct)
	return created, userId, "", nil
}
// GetTenantByName return the tenant by the given tenant name.
func (p *TenantService) getTenantByName(tenantname string) (tenant *entity.Tenant, err error) {
	selector := make(bson.M)
	selector["tenantname"] = tenantname

	tenant = new(entity.Tenant)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(tenant, queryStruct)
	if err != nil {
		logrus.Warnln("get tenant by name error %v", err)
		return
	}

	return
}
func getObjectById(instanceId string, collectionName string) (data interface{}) {
	if !bson.IsObjectIdHex(instanceId) {
		logrus.Errorln("invalid object id for getObjectById: ", instanceId)
		return nil
	}
	selector := make(bson.M)
	selector["_id"] = bson.ObjectIdHex(instanceId)

	data = bson.M{}
	queryStruct := dao.QueryStruct{
		CollectionName: collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	// _, _, data, err = p.Dao.HandleQuery(collectionName, selector, true, fields, 0, 1, "", "true")
	err := dao.HandleQueryOne(&data, queryStruct)
	if err != nil {
		logrus.Errorf("handle query err is %v", err)
		return nil
	}
	return
}
func (p *TenantService) getTenantByTenantId(tenantId string) (tenant *entity.Tenant, err error) {
	if !bson.IsObjectIdHex(tenantId) {
		err = errors.New("invalide ObjectId.")
		return
	}
	selector := make(bson.M)
	selector["_id"] = bson.ObjectIdHex(tenantId)

	tenant = new(entity.Tenant)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(tenant, queryStruct)
	if err != nil {
		logrus.Warnln("get tenant by name error %v", err)
		return
	}

	return
}
func (p *RoleService) getRoleByRoleId(roleid string) (role *entity.Role, err error) {
	if !bson.IsObjectIdHex(roleid) {
		err = errors.New("invalide ObjectId.")
		return
	}
	selector := make(bson.M)
	selector["_id"] = bson.ObjectIdHex(roleid)

	role = new(entity.Role)
	queryStruct := dao.QueryStruct{
		CollectionName: p.collectionName,
		Selector:       selector,
		Skip:           0,
		Limit:          0,
		Sort:           ""}

	err = dao.HandleQueryOne(role, queryStruct)
	if err != nil {
		logrus.Warnln("get role by name error %v", err)
		return
	}

	return
}
//terminate specified hosts of a cluster
func (p *ClusterService) TerminateHosts(clusterId string, hostIds []string, x_auth_token string) (errorCode string, err error) {
	logrus.Infof("start to decrease cluster hosts [%v]", hostIds)

	if !bson.IsObjectIdHex(clusterId) {
		err = errors.New("Invalid cluster_id")
		errorCode = COMMON_ERROR_INVALIDATE
		return
	}

	if len(hostIds) == 0 {
		errorCode = COMMON_ERROR_INVALIDATE
		err = errors.New("Empty array of host id")
		return errorCode, err
	}

	//query cluster by clusterId
	cluster := entity.Cluster{}
	clusterSelector := bson.M{}
	clusterSelector["_id"] = bson.ObjectIdHex(clusterId)
	err = dao.HandleQueryOne(&cluster, dao.QueryStruct{p.collectionName, clusterSelector, 0, 0, ""})

	_, currentHosts, errorCode, err := GetHostService().QueryHosts(clusterId, 0, 0, HOST_STATUS_RUNNING, x_auth_token)
	if err != nil {
		logrus.Errorf("get host by clusterId[%v] error [%v]", clusterId, err)
		return errorCode, err
	}

	if !deletable(currentHosts, hostIds) {
		logrus.Errorf("cluster's running node should not less than 5 nodes!")
		return CLUSTER_ERROR_DELETE_NODE_NUM, errors.New("cluster's running node should not less than 5 nodes!")
	}

	hosts := []entity.Host{}
	originStatus := make(map[string]string)
	directDeletedHosts := 0
	for _, hostId := range hostIds {
		//query host
		host, errorCode, err := GetHostService().QueryById(hostId, x_auth_token)
		if err != nil {
			return errorCode, err
		}

		//no host name means current host has not been created by docker-machine
		if len(strings.TrimSpace(host.HostName)) <= 0 {
			logrus.Warnf("host has no hostname, will be terminated directly, hostid: %s", hostId)
			_, _, err := GetHostService().UpdateStatusById(hostId, HOST_STATUS_TERMINATED, x_auth_token)
			if err != nil {
				logrus.Warnf("set no hostname host[%s] status to termianted error %v", hostId, err)
			}
			directDeletedHosts++
			continue
		}

		hosts = append(hosts, host)

		//protect master node
		if host.IsMasterNode {
			return HOST_ERROR_DELETE_MASTER, errors.New("Cannot delete master node")
		}

		originStatus[host.ObjectId.Hex()] = host.Status
		//call API to terminate host(master node cannot be deleted now)
		_, errorCode, err = GetHostService().UpdateStatusById(hostId, HOST_STATUS_TERMINATING, x_auth_token)
		if err != nil {
			logrus.Errorf("terminate host error is %s,%v", errorCode, err)
			continue
		}
	}

	if directDeletedHosts > 0 {
		logrus.Infof("update cluster instances - %d", directDeletedHosts)
		newvalue := cluster.Instances - directDeletedHosts
		selector := bson.M{}
		selector["_id"] = cluster.ObjectId

		change := bson.M{"instances": newvalue, "time_update": dao.GetCurrentTime()}
		erro := dao.HandleUpdateByQueryPartial(p.collectionName, selector, change)
		if erro != nil {
			logrus.Errorf("update cluster with objectId [%v] instances to [%d] failed, error is %v", clusterId, newvalue, erro)
		}
	}

	if len(hosts) <= 0 {
		logrus.Infof("no valid hosts will be deleted!")
		return
	}

	if IsDeploymentEnabled() {
		//call deployment module to delete nodes
		go DeleteNodes(cluster, hosts, originStatus, x_auth_token)
	}

	return
}
func (p *ClusterService) AddHosts(clusterId, numberStr string, x_auth_token string) (cluster entity.Cluster, errorCode string, err error) {
	logrus.Infof("start to add hosts")
	logrus.Infof("clusterId is %s, number is %s.", clusterId, numberStr)

	// do authorize first
	if authorized := GetAuthService().Authorize("create_host", x_auth_token, clusterId, p.collectionName); !authorized {
		err = errors.New("required opertion is not authorized!")
		errorCode = COMMON_ERROR_UNAUTHORIZED
		logrus.Errorf("authorize failure when adding hosts in cluster with id [%v] , error is %v", clusterId, err)
		return
	}
	if !bson.IsObjectIdHex(clusterId) {
		err = errors.New("Invalid cluster id.")
		errorCode = COMMON_ERROR_INVALIDATE
		return
	}

	var selector = bson.M{}
	selector["_id"] = bson.ObjectIdHex(clusterId)
	cluster = entity.Cluster{}
	err = dao.HandleQueryOne(&cluster, dao.QueryStruct{p.collectionName, selector, 0, 0, ""})
	if err != nil {
		logrus.Errorf("query cluster [objectId=%v] error is %v", clusterId, err)
		errorCode = CLUSTER_ERROR_QUERY
		return
	}

	number, err := strconv.ParseInt(numberStr, 10, 0)
	if err != nil {
		logrus.Errorf("Parse number [objectId=%v] error is %v", numberStr, err)
		errorCode = CLUSTER_ERROR_INVALID_NUMBER
		return
	}

	if number <= 0 {
		//call terminate hosts to do this
		errorCode := CLUSTER_ERROR_INVALID_NUMBER
		err = errors.New("Invalid number, it should be positive")
		return cluster, errorCode, err
	}

	newHosts := []entity.Host{}
	for i := 0; i < int(number); i++ {
		host := entity.Host{}
		host.ClusterId = clusterId
		host.ClusterName = cluster.Name
		host.Status = HOST_STATUS_DEPLOYING
		//insert info to db
		newHost, _, err := GetHostService().Create(host, x_auth_token)
		newHosts = append(newHosts, newHost)
		if err != nil {
			logrus.Errorf("creat host error is %v", err)
		}
	}

	if IsDeploymentEnabled() {
		//call deployment module to add nodes
		go AddNodes(cluster, int(number), newHosts, x_auth_token)
	}

	return
}