// Login perform a login using passed credentials and return a token if successful
func Login(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	ID := r.PathParam("ID")
	PSW := r.PathParam("PSW")
	if ID == "" || PSW == "" {
		logit.Error.Println("Login: ID or PSW not supplied")
		rest.Error(w, "ID or PSW not supplied", http.StatusBadRequest)
	}

	//logit.Info.Println("Login: called")

	tokenContents, err := secimpl.Login(dbConn, ID, PSW)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	//w.WriteHeader(http.StatusOK)
	token := LoginToken{tokenContents}
	logit.Info.Println("sending back token " + token.Contents)
	w.WriteJson(&token)
}
// DeleteRole delete a CPM role
func DeleteRole(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-user")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	if r.PathParam("ID") == "" {
		logit.Error.Println("DeleteRole: error ID required")
		rest.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	err = secimpl.DeleteRole(dbConn, r.PathParam("ID"))
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
// GetAllUsers return all CPM users
func GetAllUsers(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	usersList, err := secimpl.GetAllUsers(dbConn)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//for i := range usersList {
	//logit.Info.Println("GetAllUsers: secimpl.GetAllUsers userName=" + usersList[i].Name)
	//}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&usersList)
}
// GetAllSettings return all settings
func GetAllSettings(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	results, err := admindb.GetAllSettings(dbConn)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
	}
	settings := make([]types.Setting, len(results))
	i := 0
	for i = range results {
		settings[i].Name = results[i].Name
		settings[i].Value = results[i].Value
		settings[i].Description = results[i].Description
		settings[i].UpdateDate = results[i].UpdateDate
		i++
	}

	w.WriteJson(&settings)
}
// GetRole return a role
func GetRole(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	Name := r.PathParam("Name")
	if Name == "" {
		logit.Error.Println("GetRole: error Name required")
		rest.Error(w, "Name required", http.StatusBadRequest)
		return
	}

	var role sec.Role
	role, err = secimpl.GetRole(dbConn, Name)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)
	w.WriteJson(&role)
}
// RulesGetAll returns all the access rule definitions
func RulesGetAll(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	rules, err := GetAllRules(dbConn)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&rules)
}
// GetHealthCheck returns the latest health check metrics that have been collected
func GetHealthCheck(w rest.ResponseWriter, r *rest.Request) {

	dbConn, err := util.GetConnection("clusteradmin")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	var results []types.HealthCheck

	results, err = admindb.GetHealthCheck(dbConn)
	if err != nil {
		logit.Error.Println(err.Error())
		w.WriteJson(&results)
		return
	}

	w.WriteJson(&results)

}
// Logout perform a logout based on a given token
func Logout(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	token := r.PathParam("Token")
	if token == "" {
		logit.Error.Println("Logout: Token not supplied")
		rest.Error(w, "Token not supplied", http.StatusBadRequest)
	}

	err = secimpl.Logout(dbConn, token)
	if err != nil {
		logit.Error.Println("Logout: error secimpl call" + err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
// StartCluster starts all nodes in a cluster
func StartCluster(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-cluster")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ID := r.PathParam("ID")
	if ID == "" {
		logit.Error.Println("StartCluster: error cluster ID required")
		rest.Error(w, "cluster ID required", http.StatusBadRequest)
		return
	}

	cluster, err := admindb.GetCluster(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
	}

	//start docker containers
	containers, err := admindb.GetAllContainersForCluster(dbConn, cluster.ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
	}

	i := 0

	i = 0
	var response swarmapi.DockerStartResponse
	for i = range containers {

		req := &swarmapi.DockerStartRequest{}
		req.ContainerName = containers[i].Name
		logit.Info.Println("will attempt to start container " + req.ContainerName)
		response, err = swarmapi.DockerStart(req)
		if err != nil {
			logit.Error.Println("StartCluster: error when trying to start container" + err.Error())
		}
		logit.Info.Println("StartCluster: started " + response.Output)

		i++
	}

	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteHeader(http.StatusOK)
	w.WriteJson(&status)
}
// StatusUpdate called by backup jobs as they execute
func StatusUpdate(w rest.ResponseWriter, r *rest.Request) {

	request := TaskStatus{}
	err := r.DecodeJsonPayload(&request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var dbConn *sql.DB
	dbConn, err = util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return

	}
	defer dbConn.Close()

	//logit.Info.Println("StatusUpdate called")

	err = UpdateStatus(dbConn, &request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	response := StatusUpdateResponse{}
	response.Output = "ok"
	w.WriteJson(&response)
}
// ContainerAccessRuleGetAll returns all the rules selected for a container
func ContainerAccessRuleGetAll(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println("BackupNow: error " + err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println("ContainerRulesGetAll: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ContainerID := r.PathParam("ID")
	if ContainerID == "" {
		rest.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	cars, err := GetAllContainerAccessRule(dbConn, ContainerID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&cars)
}
// GetCluster returns a given cluster definition
func GetCluster(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ID := r.PathParam("ID")
	results, err := admindb.GetCluster(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
	}
	cluster := types.Cluster{}
	cluster.ID = results.ID
	cluster.ProjectID = results.ProjectID
	cluster.Name = results.Name
	cluster.ClusterType = results.ClusterType
	cluster.Status = results.Status
	cluster.CreateDate = results.CreateDate
	cluster.Containers = results.Containers
	//logit.Info.Println("GetCluser:db call results=" + results.ID)

	w.WriteJson(&cluster)
}
// RulesDelete deletes a given rule
func RulesDelete(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ID := r.PathParam("ID")
	if ID == "" {
		rest.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	err = DeleteRule(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteHeader(http.StatusOK)
	w.WriteJson(&status)
}
// PostCluster updates or inserts a new cluster definition
func PostCluster(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	//logit.Info.Println("PostCluster: in PostCluster")
	cluster := types.Cluster{}
	err = r.DecodeJsonPayload(&cluster)
	if err != nil {
		logit.Error.Println("error in decode" + err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = secimpl.Authorize(dbConn, cluster.Token, "perm-cluster")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	if cluster.Name == "" {
		logit.Error.Println("PostCluster: error in Name")
		rest.Error(w, "cluster name required", http.StatusBadRequest)
		return
	}

	//logit.Info.Println("PostCluster: have ID=" + cluster.ID + " Name=" + cluster.Name + " type=" + cluster.ClusterType + " status=" + cluster.Status)
	dbcluster := types.Cluster{}
	dbcluster.ID = cluster.ID
	dbcluster.ProjectID = cluster.ProjectID
	dbcluster.Name = cluster.Name
	dbcluster.ClusterType = cluster.ClusterType
	dbcluster.Status = cluster.Status
	dbcluster.Containers = cluster.Containers
	if cluster.ID == "" {
		strid, err := admindb.InsertCluster(dbConn, dbcluster)
		newid := strconv.Itoa(strid)
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		cluster.ID = newid
	} else {
		//logit.Info.Println("PostCluster: about to call UpdateCluster")
		err2 := admindb.UpdateCluster(dbConn, dbcluster)
		if err2 != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}

	w.WriteJson(&cluster)
}
// GetStatus returns the status of a given task schedule
func GetStatus(w rest.ResponseWriter, r *rest.Request) {
	Token := r.PathParam("Token")
	if Token == "" {
		rest.Error(w, "Token required", 400)
		return
	}
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	err = secimpl.Authorize(dbConn, Token, "perm-read")
	if err != nil {
		logit.Error.Println("validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ID := r.PathParam("ID")
	if ID == "" {
		rest.Error(w, "ID required", 400)
		return
	}
	stat, err := task.GetStatus(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(stat)
}
// GetSchedule returns a task schedule
func GetSchedule(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println("validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ID := r.PathParam("ID")

	if ID == "" {
		rest.Error(w, "ID required", 400)
		return
	}

	result, err := task.GetSchedule(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}
	//logit.Info.Println("GetSchedule api returns serverip of " + result.Serverip)

	w.WriteJson(result)

}
// StatusAdd called by backup jobs as they execute to write new status info
func StatusAdd(w rest.ResponseWriter, r *rest.Request) {

	//logit.Info.Println("StatusAdd called")

	request := TaskStatus{}
	err := r.DecodeJsonPayload(&request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return

	}

	defer dbConn.Close()

	var id string
	id, err = AddStatus(dbConn, &request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
	}

	response := StatusAddResponse{}
	response.ID = id
	w.WriteJson(&response)
}
// GetServer return a server definition
func GetServer(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ID := r.PathParam("ID")
	//logit.Info.Println("in GetServer with ID=" + ID)

	//currently no state about a server is maintained other than IP and port number
	//which we use for the ID, Name, and IPAddress values

	server := types.Server{ID, ID, ID, ID, "", "", ""}

	w.WriteJson(&server)
}
// GetAllNodesForServer returns a list of all nodes on a given server
func GetAllNodesForServer(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	serverID := r.PathParam("ServerID")
	if serverID == "" {
		logit.Error.Println("GetAllNodesForServer: error serverID required")
		rest.Error(w, "serverID required", http.StatusBadRequest)
		return
	}

	serverIPAddress := strings.Replace(serverID, "_", ".", -1)

	results, err := swarmapi.DockerPs(serverIPAddress)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	nodes := make([]types.ClusterNode, len(results.Output))
	i := 0
	var container types.Container

	for _, each := range results.Output {
		logit.Info.Println("got back Name:" + each.Name + " Status:" + each.Status + " Image:" + each.Image)
		nodes[i].Name = each.Name
		container, err = admindb.GetContainerByName(dbConn, each.Name)
		if err != nil {
			logit.Error.Println(err.Error())
			nodes[i].ID = "unknown"
			nodes[i].ProjectID = "unknown"
		} else {
			nodes[i].ID = container.ID
			nodes[i].ProjectID = container.ProjectID
		}

		nodes[i].Status = each.Status
		nodes[i].Image = each.Image
		i++
	}

	w.WriteJson(&nodes)

}
// ChangePassword change  a user password
func ChangePassword(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	//logit.Info.Println("ChangePassword: in ChangePassword")
	changePass := ChgPassword{}
	err = r.DecodeJsonPayload(&changePass)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = secimpl.Authorize(dbConn, changePass.Token, "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	var sameUser bool
	sameUser, err = secimpl.CompareUserToToken(dbConn, changePass.Username, changePass.Token)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//enforce perm-user if the username is not the same as the token's
	//username (e.g. bob tries to change larry's password)
	if !sameUser {
		err = secimpl.Authorize(dbConn, changePass.Token, "perm-user")
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusUnauthorized)
			return
		}
	}

	err = secimpl.ChangePassword(dbConn, changePass.Username, changePass.Password)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
// ExecuteNow called by admin do perform an adhoc task
func ExecuteNow(w rest.ResponseWriter, r *rest.Request) {
	request := TaskRequest{}
	err := r.DecodeJsonPayload(&request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var dbConn *sql.DB
	dbConn, err = util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return

	}
	defer dbConn.Close()
	log.Println("-log- ExecuteNow.impl called profile=" + request.ProfileName)
	fmt.Println("-fmt- ExecuteNow.impl called profile=" + request.ProfileName)
	//logit.Info.Println("-logit- ExecuteNow.impl called profile=" + request.ProfileName)

	if request.ProfileName == "pg_basebackup" {
		err = ProvisionBackupJob(dbConn, &request)
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else if request.ProfileName == "pg_backrest_restore" {
		logit.Info.Println("doing pg_backrest_restore job on...")
		err = ProvisionBackrestRestoreJob(dbConn, &request)
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else if request.ProfileName == "restore" {
		logit.Info.Println("doing restore job on...")
		err = ProvisionRestoreJob(dbConn, &request)
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else {
		err = errors.New("invalid profile name found:" + request.ProfileName)
		logit.Error.Println(err)
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	logit.Info.Println("ExecuteNow.impl completed")

	response := ExecuteNowResponse{}
	response.Output = "ok"
	w.WriteJson(&response)
}
// AdminStartNode starts a container
func AdminStartNode(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ID := r.PathParam("ID")
	if ID == "" {
		logit.Error.Println("AdminStartNode: error ID required")
		rest.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	node, err := admindb.GetContainer(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	/**
	server := types.Server{}
	server, err = admindb.GetServer(dbConn, node.ServerID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	*/

	var response swarmapi.DockerStartResponse
	request := &swarmapi.DockerStartRequest{}
	request.ContainerName = node.Name
	response, err = swarmapi.DockerStart(request)
	if err != nil {
		logit.Error.Println(err.Error())
		logit.Error.Println(response.Output)
	}
	//logit.Info.Println(response.Output)

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)

}
// Run this is the func that implements the cron Job interface
func (t DefaultJob) Run() {
	logit.Info.Println("running ScheduleID:" + t.request.ScheduleID)
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
	}
	defer dbConn.Close()

	ProvisionBackupJob(dbConn, &t.request)
}
// AdminStopServerContainers stops all containers on a given server
func AdminStopServerContainers(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	//serverID
	serverid := r.PathParam("ID")
	if serverid == "" {
		logit.Error.Println("AdminStopoServerContainers: error ID required")
		rest.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	cleanIP := strings.Replace(serverid, "_", ".", -1)

	containers, err := swarmapi.DockerPs(cleanIP)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//for each, get server, stop container
	for _, each := range containers.Output {

		if strings.HasPrefix(each.Status, "Up") {
			//stop container
			request := &swarmapi.DockerStopRequest{}
			request.ContainerName = each.Name
			logit.Info.Println("stopping " + request.ContainerName)
			_, err = swarmapi.DockerStop(request)
			if err != nil {
				logit.Error.Println("AdminStopServerContainers: error when trying to start container " + err.Error())
			}
		}
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)

}
// LoadSchedules loads the initial set of task schedules
func LoadSchedules() error {

	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		return err

	}
	defer dbConn.Close()

	//logit.Info.Println("LoadSchedules called")

	var schedules []TaskSchedule
	schedules, err = GetSchedules(dbConn)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	if CRONInstance != nil {
		logit.Info.Println("stopping current cron instance...")
		CRONInstance.Stop()
	}

	//kill off the old cron, garbage collect it
	CRONInstance = nil

	//create a new cron
	logit.Info.Println("creating cron instance...")
	CRONInstance = cron.New()

	var cronexp string
	for i := 0; i < len(schedules); i++ {
		cronexp = getCron(schedules[i])
		logit.Info.Println("would have loaded schedule..." + cronexp)
		if schedules[i].Enabled == "YES" {
			logit.Info.Println("schedule " + schedules[i].ID + " was enabled so adding it")
			x := DefaultJob{}
			x.request = TaskRequest{}
			x.request.ScheduleID = schedules[i].ID
			x.request.ContainerName = schedules[i].ContainerName
			x.request.ProfileName = schedules[i].ProfileName

			CRONInstance.AddJob(cronexp, x)
		} else {
			logit.Info.Println("schedule " + schedules[i].ID + " NOT enabled so dropping it")
		}

	}

	logit.Info.Println("starting new CRONInstance")
	CRONInstance.Start()

	return err
}
// AdminStoppg stops a postgres database on a given container
func AdminStoppg(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-cluster")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	//logit.Info.Println("AdminStoppg:called")
	ID := r.PathParam("ID")
	if ID == "" {
		logit.Error.Println("AdminStoppg:ID not found error")
		rest.Error(w, "node ID required", http.StatusBadRequest)
		return
	}

	var dbNode types.Container
	dbNode, err = admindb.GetContainer(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	//logit.Info.Println("AdminStoppg: in stop with dbnode")

	if dbNode.Role == "pgpool" {
		var stoppoolResp cpmcontainerapi.StopPgpoolResponse
		stoppoolResp, err = cpmcontainerapi.StopPgpoolClient(dbNode.Name)
		logit.Info.Println("AdminStoppg:" + stoppoolResp.Output)
	} else {
		var stoppgResp cpmcontainerapi.StopPGResponse
		stoppgResp, err = cpmcontainerapi.StopPGClient(dbNode.Name)
		logit.Info.Println("AdminStoppg:" + stoppgResp.Output)
	}
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
// ProxyUpdate updates a proxy node definition
func ProxyUpdate(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	req := ProxyRequest{}
	err = r.DecodeJsonPayload(&req)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	//logit.Info.Println("ID=" + req.ID)
	//logit.Info.Println("Port" + req.Port)
	//logit.Info.Println("Host" + req.Host)
	//logit.Info.Println("Database" + req.Database)
	//logit.Info.Println("Usename" + req.Usename)
	//logit.Info.Println("Passwd" + req.Passwd)
	//encrypt the password...passwords at rest are encrypted
	var encrypted string
	encrypted, err = sec.EncryptPassword(req.Passwd)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	queryStr := fmt.Sprintf("update proxy set ( port, host, usename, passwd, databasename, updatedt) = ( '%s', '%s', '%s', '%s', '%s', now()) where id = %s returning id",
		req.Port, req.Host, req.Usename, encrypted, req.Database, req.ID)

	logit.Info.Println("UpdateProxy:" + queryStr)
	var proxyid int
	err = dbConn.QueryRow(queryStr).Scan(&proxyid)
	switch {
	case err != nil:
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	default:
		logit.Info.Println("UpdateProxy: update " + strconv.Itoa(proxyid))
	}

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
// RulesUpdate updates a given rule
func RulesUpdate(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	//logit.Info.Println("RulesUpdate: in RulesUpdate")
	rule := Rule{}
	err = r.DecodeJsonPayload(&rule)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = secimpl.Authorize(dbConn, rule.Token, "perm-container")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	if rule.ID == "" {
		logit.Error.Println("RulesUpdate: error in ID")
		rest.Error(w, "rule ID required", http.StatusBadRequest)
		return
	}

	if rule.Name == "" {
		logit.Error.Println("RulesUpdate: error in Name")
		rest.Error(w, "rule name required", http.StatusBadRequest)
		return
	}

	err = UpdateRule(dbConn, rule)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteHeader(http.StatusOK)
	w.WriteJson(&status)

}
// GetAllNodesForCluster returns a list of nodes for a given cluster
func GetAllNodesForCluster(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()

	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-read")
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	ClusterID := r.PathParam("ClusterID")
	if ClusterID == "" {
		logit.Error.Println("ClusterID required")
		rest.Error(w, "node ClusterID required", http.StatusBadRequest)
		return
	}

	results, err := admindb.GetAllContainersForCluster(dbConn, ClusterID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
	}
	nodes := make([]types.ClusterNode, len(results))
	i := 0
	for i = range results {
		nodes[i].ID = results[i].ID
		nodes[i].Name = results[i].Name
		nodes[i].ClusterID = results[i].ClusterID
		nodes[i].Role = results[i].Role
		nodes[i].Image = results[i].Image
		nodes[i].CreateDate = results[i].CreateDate
		nodes[i].ProjectID = results[i].ProjectID
		nodes[i].ProjectName = results[i].ProjectName
		nodes[i].ClusterName = results[i].ClusterName
		//nodes[i].Status = "UNKNOWN"
		i++
	}

	w.WriteJson(&nodes)

}
// DeleteSchedule deletes an existing task schedule
func DeleteSchedule(w rest.ResponseWriter, r *rest.Request) {
	dbConn, err := util.GetConnection(CLUSTERADMIN_DB)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	defer dbConn.Close()
	err = secimpl.Authorize(dbConn, r.PathParam("Token"), "perm-backup")
	if err != nil {
		logit.Error.Println("validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ID := r.PathParam("ID")

	if ID == "" {
		rest.Error(w, "schedule ID required", 400)
		return
	}

	err = task.DeleteSchedule(dbConn, ID)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}

	//notify task server to reload schedules

	var output task.ReloadResponse
	output, err = task.ReloadClient()
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}
	logit.Info.Println("reload output=" + output.Output)

	w.WriteHeader(http.StatusOK)
	status := types.SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)

}