//currently we define default DB users (postgres, cpmtest, pgpool)
//for all database containers
func createDBUsers(dbConn *sql.DB, dbnode admindb.Container) error {
	var err error
	var password admindb.Setting

	//get the postgres password
	password, err = admindb.GetSetting(dbConn, "POSTGRESPSW")
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}
	//register postgres user
	var user = admindb.ContainerUser{}
	user.Containername = dbnode.Name
	user.Rolname = "postgres"
	user.Passwd = password.Value
	_, err = admindb.AddContainerUser(dbConn, user)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	//cpmtest and pgpool users are created by the node-setup.sql script
	//here, we just register them when we create a new node

	//get the cpmtest password
	password, err = admindb.GetSetting(dbConn, "CPMTESTPSW")
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}
	//register cpmtest user
	user.Containername = dbnode.Name
	user.Rolname = "cpmtest"
	user.Passwd = password.Value
	_, err = admindb.AddContainerUser(dbConn, user)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	//get the pgpool password
	password, err = admindb.GetSetting(dbConn, "PGPOOLPSW")
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}
	user.Containername = dbnode.Name
	user.Rolname = "pgpool"
	user.Passwd = password.Value
	//register pgpool user
	_, err = admindb.AddContainerUser(dbConn, user)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	return err
}
func templateChange(dbConn *sql.DB, containerName string, cars []ContainerAccessRule, containerRole string) error {
	var err error

	logit.Info.Println("templateChange called")
	//create pg_hba.conf
	var mode = containerRole

	domainname, err := admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("templateChange:DOMAIN-NAME error " + err.Error())
		return err
	}

	rules := make([]template.Rule, 0)
	var ar Rule
	for i := range cars {
		logit.Info.Println("templateChange cars found")
		if cars[i].Selected == "true" {
			logit.Info.Println("templateChange cars found to be true")
			rule := template.Rule{}
			ar, err = GetAccessRule(dbConn, cars[i].AccessRuleID)
			if err != nil {
				logit.Error.Println("templateChange:get access rule error " + err.Error())
				return err
			}
			rule.Type = ar.Type
			rule.Database = ar.Database
			rule.User = ar.User
			rule.Address = ar.Address
			rule.Method = ar.Method
			rules = append(rules, rule)
		}
	}

	logit.Info.Printf("templateChange rules going to template %d\n", len(rules))
	var data string

	data, err = template.Hba(dbConn, mode, containerName, "", "", domainname.Value, rules)

	if err != nil {
		logit.Error.Println("templateChange:" + err.Error())
		return err
	}

	fqdn := containerName + "." + domainname.Value

	//place pg_hba.conf on node
	_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/pg_hba.conf", data, fqdn)
	if err != nil {
		logit.Error.Println("templateChange:" + err.Error())
		return err
	}

	return err
}
func getPort(dbConn *sql.DB) (string, error) {
	var err error
	var port admindb.Setting

	port, err = admindb.GetSetting(dbConn, "PG-PORT")
	if err != nil {
		logit.Error.Println(err.Error())
		return port.Value, err
	}
	return port.Value, nil
}
//return the CPU MEM settings
func getDockerResourceSettings(dbConn *sql.DB, size string) (string, string, error) {
	var CPU, MEM string
	var setting admindb.Setting
	var err error

	switch size {
	case "SM":
		setting, err = admindb.GetSetting(dbConn, "S-DOCKER-PROFILE-CPU")
		CPU = setting.Value
		setting, err = admindb.GetSetting(dbConn, "S-DOCKER-PROFILE-MEM")
		MEM = setting.Value
	case "MED":
		setting, err = admindb.GetSetting(dbConn, "M-DOCKER-PROFILE-CPU")
		CPU = setting.Value
		setting, err = admindb.GetSetting(dbConn, "M-DOCKER-PROFILE-MEM")
		MEM = setting.Value
	default:
		setting, err = admindb.GetSetting(dbConn, "L-DOCKER-PROFILE-CPU")
		CPU = setting.Value
		setting, err = admindb.GetSetting(dbConn, "L-DOCKER-PROFILE-MEM")
		MEM = setting.Value
	}

	return CPU, MEM, err

}
func GetPGStatus2(dbConn *sql.DB, nodename string, hostname string) (string, error) {

	//fetch cpmtest user credentials
	nodeuser, err := admindb.GetContainerUser(dbConn, nodename, "cpmtest")
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}

	logit.Info.Println("cpmtest password is " + nodeuser.Passwd)

	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(hostname, "cpmtest", pgport.Value, "cpmtest", nodeuser.Passwd)
	defer dbConn2.Close()
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}

	var value string

	err = dbConn2.QueryRow(fmt.Sprintf("select now()::text")).Scan(&value)
	switch {
	case err == sql.ErrNoRows:
		logit.Info.Println("getpgstatus 2 no rows returned")
		return "OFFLINE", nil
	case err != nil:
		logit.Info.Println("getpgstatus2 error " + err.Error())
		return "OFFLINE", nil
	default:
		logit.Info.Println("getpgstatus2 returned " + value)
	}

	return "RUNNING", nil
}
func ContainerInfoStatrepl(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("ContainerStatrepl: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

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

	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//fetch cpmtest user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	stats := make([]Statrepl, 0)
	var rows *sql.Rows

	rows, err = dbConn2.Query("SELECT pid , usesysid , usename , application_name , client_addr , coalesce(client_hostname, ' ') , client_port , to_char(backend_start, 'YYYY-MM-DD HH24:MI-SS') as backend_start , state , sent_location , write_location , flush_location , replay_location , sync_priority , sync_state from pg_stat_replication")
	if err != nil {
		logit.Error.Println("ContainerStatrepl:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer rows.Close()
	for rows.Next() {
		stat := Statrepl{}
		if err = rows.Scan(
			&stat.Pid,
			&stat.Usesysid,
			&stat.Usename,
			&stat.AppName,
			&stat.ClientAddr,
			&stat.ClientHostname,
			&stat.ClientPort,
			&stat.BackendStart,
			&stat.State,
			&stat.SentLocation,
			&stat.WriteLocation,
			&stat.FlushLocation,
			&stat.ReplayLocation,
			&stat.SyncPriority,
			&stat.SyncState,
		); err != nil {
			logit.Error.Println("ContainerStatrepl:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		stats = append(stats, stat)
	}
	if err = rows.Err(); err != nil {
		logit.Error.Println("ContainerStatrepl:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&stats)
}
func provisionImpl(dbConn *sql.DB, params *cpmserverapi.DockerRunRequest, PROFILE string, standby bool) error {
	logit.Info.Println("PROFILE: provisionImpl starts 1")

	var errorStr string
	//make sure the container name is not already taken
	_, err := admindb.GetContainerByName(dbConn, params.ContainerName)
	if err != nil {
		if err != sql.ErrNoRows {
			return err
		}
	} else {
		errorStr = "container name" + params.ContainerName + " already used can't provision"
		logit.Error.Println("Provision error" + errorStr)
		return errors.New(errorStr)
	}

	//create the container by constructing a template and calling openshift

	params.CPU, params.MEM, err = getDockerResourceSettings(dbConn, PROFILE)
	if err != nil {
		logit.Error.Println("Provision: problem in getting profiles call" + err.Error())
		return err
	}

	//remove any existing pods and services with this name
	var username = "******"
	var password = "******"
	var objectName = params.ContainerName
	var objectType = "pod"

	err = OpenshiftDelete(username, password, objectName, objectType)
	if err != nil {
		logit.Info.Println("Provision:" + err.Error())
	}

	objectName = params.ContainerName
	err = OpenshiftDelete(username, password, objectName, objectType)
	if err != nil {
		logit.Info.Println("Provision:" + err.Error())
	}

	podInfo := template.KubePodParams{
		NAME:                 params.ContainerName,
		ID:                   params.ContainerName,
		PODID:                params.ContainerName,
		CPU:                  params.CPU,
		MEM:                  params.MEM,
		IMAGE:                params.Image,
		VOLUME:               params.PGDataPath,
		PORT:                 "13000",
		BACKUP_NAME:          "",
		BACKUP_SERVERNAME:    "",
		BACKUP_SERVERIP:      "",
		BACKUP_SCHEDULEID:    "",
		BACKUP_PROFILENAME:   "",
		BACKUP_CONTAINERNAME: "",
		BACKUP_PATH:          "",
		BACKUP_HOST:          "",
		BACKUP_PORT:          "",
		BACKUP_USER:          "",
		BACKUP_SERVER_URL:    "",
	}

	//generate the pod template
	var podTemplateData []byte
	podTemplateData, err = template.KubeNodePod(podInfo)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	logit.Info.Println("pod template=" + string(podTemplateData[:]))

	//create the pod
	file, err := ioutil.TempFile("/tmp", "openshift-template")
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	defer os.Remove(file.Name())
	err = ioutil.WriteFile(file.Name(), podTemplateData, 0644)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}

	err = OpenshiftCreate(username, password, file.Name())
	if err != nil {
		logit.Info.Println("Provision:" + err.Error())
	}

	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
	if err != nil {
		logit.Error.Println("Provision:PG-PORT setting error " + err.Error())
		return err
	}

	//generate the admin service template
	serviceInfo := template.KubeServiceParams{
		SERVICENAME: params.ContainerName,
		NAME:        params.ContainerName,
		PORT:        "10001",
		DBPORT:      pgport.Value,
	}

	//create the admin service template
	var serviceTemplateData []byte
	serviceTemplateData, err = template.KubeNodeService(serviceInfo)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	logit.Info.Println("service template=" + string(serviceTemplateData[:]))

	file, err = ioutil.TempFile("/tmp", "openshift-template")
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	defer os.Remove(file.Name())
	err = ioutil.WriteFile(file.Name(), serviceTemplateData, 0644)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}

	//create the service
	err = OpenshiftCreate(username, password, file.Name())
	if err != nil {
		logit.Info.Println("Provision:" + err.Error())
	}

	dbnode := admindb.Container{}
	dbnode.ID = ""
	dbnode.Name = params.ContainerName
	dbnode.Image = params.Image
	dbnode.ClusterID = "-1"
	dbnode.ProjectID = params.ProjectID
	dbnode.ServerID = params.ServerID

	if params.Standalone == "true" {
		dbnode.Role = "standalone"
	} else {
		dbnode.Role = "unassigned"
	}

	var strid int
	strid, err = admindb.InsertContainer(dbConn, dbnode)
	newid := strconv.Itoa(strid)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	dbnode.ID = newid

	//register default db users on the new node
	err = createDBUsers(dbConn, dbnode)

	return err

}
func BackupNow(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()
	postMsg := BackupNowPost{}
	err = r.DecodeJsonPayload(&postMsg)
	if err != nil {
		logit.Error.Println("BackupNow: error in decode" + err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

	if postMsg.ServerID == "" {
		logit.Error.Println("BackupNow: error node ServerID required")
		rest.Error(w, "server ID required", 400)
		return
	}
	if postMsg.ProfileName == "" {
		logit.Error.Println("BackupNow: error node ProfileName required")
		rest.Error(w, "ProfileName required", 400)
		return
	}

	if postMsg.ScheduleID == "" {
		logit.Error.Println("BackupNow: error schedule ID required")
		rest.Error(w, "schedule ID required", 400)
		return
	}

	schedule, err2 := backup.GetSchedule(dbConn, postMsg.ScheduleID)
	if err2 != nil {
		logit.Error.Println("BackupNow: " + err2.Error())
		rest.Error(w, err2.Error(), 400)
		return
	}

	//get the server details for where the backup should be made
	server := admindb.Server{}
	server, err = admindb.GetServer(dbConn, postMsg.ServerID)
	if err != nil {
		logit.Error.Println("BackupNow: " + err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}

	//get the domain name
	//get domain name
	var domainname admindb.Setting
	domainname, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("BackupNow: DOMAIN-NAME err " + err.Error())
	}

	request := backup.BackupRequest{}
	request.ScheduleID = postMsg.ScheduleID
	request.ServerID = server.ID
	if KubeEnv {
		request.ContainerName = schedule.ContainerName + "-db"
	} else {
		request.ContainerName = schedule.ContainerName
	}
	request.ServerName = server.Name
	request.ServerIP = server.IPAddress
	request.ProfileName = postMsg.ProfileName
	backupServerURL := "cpm-backup." + domainname.Value + ":13000"
	output, err := backup.BackupNowClient(backupServerURL, request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	logit.Info.Println("output=" + output)

	w.WriteHeader(http.StatusOK)
	status := SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
func UpdateSchedule(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()

	postMsg := AddSchedulePost{}
	err = r.DecodeJsonPayload(&postMsg)
	if err != nil {
		logit.Error.Println("UpdateSchedule: error in decode" + err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

	if postMsg.ID == "" {
		logit.Error.Println("UpdateSchedule: error schedule ID required")
		rest.Error(w, "schedule ID required", 400)
		return
	}
	if postMsg.ServerID == "" {
		logit.Error.Println("UpdateSchedule: error ServerID required")
		rest.Error(w, "schedule ID required", 400)
		return
	}
	if postMsg.Enabled == "" {
		logit.Error.Println("UpdateSchedule: error Enabled required")
		rest.Error(w, "Enabled required", 400)
		return
	}
	if postMsg.Minutes == "" {
		logit.Error.Println("UpdateSchedule: error Minutes required")
		rest.Error(w, "schedule Minutes required", 400)
		return
	}
	if postMsg.Hours == "" {
		logit.Error.Println("UpdateSchedule: error Hours required")
		rest.Error(w, "schedule Hours required", 400)
		return
	}
	if postMsg.DayOfMonth == "" {
		logit.Error.Println("UpdateSchedule: error DayOfMonth required")
		rest.Error(w, "schedule DayOfMonth required", 400)
		return
	}
	if postMsg.Month == "" {
		logit.Error.Println("UpdateSchedule: error Month required")
		rest.Error(w, "schedule Month required", 400)
		return
	}
	if postMsg.DayOfWeek == "" {
		logit.Error.Println("UpdateSchedule: error DayOfWeek required")
		rest.Error(w, "schedule DayOfWeek required", 400)
		return
	}
	if postMsg.Name == "" {
		logit.Error.Println("UpdateSchedule: error Name required")
		rest.Error(w, "schedule Name required", 400)
		return
	}

	s := backup.BackupSchedule{}
	s.ID = postMsg.ID
	s.ServerID = postMsg.ServerID
	s.Minutes = postMsg.Minutes
	s.Hours = postMsg.Hours
	s.Enabled = postMsg.Enabled
	s.DayOfMonth = postMsg.DayOfMonth
	s.Month = postMsg.Month
	s.DayOfWeek = postMsg.DayOfWeek
	s.Name = postMsg.Name

	err = backup.UpdateSchedule(dbConn, s)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}

	//notify backup server to reload it's schedules

	//get the domain name
	//get domain name
	var domainname admindb.Setting
	domainname, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("BackupNow: DOMAIN-NAME err " + err.Error())
	}
	backupServerURL := "cpm-backup." + domainname.Value + ":13000"
	output, err := backup.ReloadClient(backupServerURL, s)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

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

	w.WriteHeader(http.StatusOK)
	status := SimpleStatus{}
	status.Status = "OK"
	w.WriteJson(&status)
}
func DeleteSchedule(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-backup")
	if err != nil {
		logit.Error.Println("DeleteSchedule: 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 = backup.DeleteSchedule(dbConn, ID)
	if err != nil {
		logit.Error.Println("DeleteSchedule: " + err.Error())
		rest.Error(w, err.Error(), 400)
		return
	}

	//notify backup server to reload schedules

	//get the domain name
	//get domain name
	var domainname admindb.Setting
	domainname, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("DeleteSchedule: DOMAIN-NAME err " + err.Error())
		rest.Error(w, err.Error(), 400)
		return

	}

	s := backup.BackupSchedule{}

	backupServerURL := "cpm-backup." + domainname.Value + ":13000"
	var output string
	output, err = backup.ReloadClient(backupServerURL, s)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), 400)
		return

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

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

}
func DeleteContainerUser(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-backup")
	if err != nil {
		logit.Error.Println("DeleteContainerUser: validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ContainerID := r.PathParam("ContainerID")

	if ContainerID == "" {
		rest.Error(w, "ContainerID required", 400)
		return
	}
	rolname := r.PathParam("Rolname")

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

	//get node info
	node, err := admindb.GetContainer(dbConn, ContainerID)
	if err != nil {
		logit.Error.Println("AddContainUser: "******"DeleteContainerUser: "******"-db"
	}

	//fetch cpmtest user credentials
	var cpmuser admindb.ContainerUser
	cpmuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, cpmuser.Passwd)
	defer dbConn2.Close()

	query := "drop role " + rolname

	logit.Info.Println(query)

	_, err = dbConn2.Query(query)
	if err != nil {
		logit.Error.Println("DeleteContainerUser:"******"OK"
	w.WriteJson(&status)

}
func configureCluster(dbConn *sql.DB, cluster admindb.Cluster, autocluster bool) error {
	logit.Info.Println("configureCluster:GetCluster")

	//get master node for this cluster
	master, err := admindb.GetContainerMaster(dbConn, cluster.ID)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:GetContainerMaster")

	//configure master postgresql.conf file
	var data string
	if cluster.ClusterType == "synchronous" {
		data, err = template.Postgresql("master", pgport.Value, "*")
	} else {
		data, err = template.Postgresql("master", pgport.Value, "")
	}
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:master postgresql.conf generated")

	//write master postgresql.conf file remotely
	_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/postgresql.conf", data, master.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:master postgresql.conf copied to remote")

	//get domain name
	var domainname admindb.Setting
	domainname, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("configureCluster: DOMAIN-NAME err " + err.Error())
		return err
	}

	//configure master pg_hba.conf file
	rules := make([]template.Rule, 0)
	data, err = template.Hba(dbConn, "master", master.Name, pgport.Value, cluster.ID, domainname.Value, rules)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:master pg_hba.conf generated")

	//write master pg_hba.conf file remotely
	_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/pg_hba.conf", data, master.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:master pg_hba.conf copied remotely")

	//restart postgres after the config file changes
	var stopResp cpmcontainerapi.StopPGResponse
	stopResp, err = cpmcontainerapi.StopPGClient(master.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster: master stoppg output was" + stopResp.Output)

	var startResp cpmcontainerapi.StartPGResponse
	startResp, err = cpmcontainerapi.StartPGClient(master.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster:master startpg output was" + startResp.Output)

	//sleep loop until the master's PG can respond
	var found = false
	var currentStatus string
	var masterhost = master.Name
	for i := 0; i < 20; i++ {
		currentStatus, err = GetPGStatus2(dbConn, master.Name, masterhost)
		if currentStatus == "RUNNING" {
			logit.Info.Println("master is running...continuing")
			found = true
			break
		} else {
			logit.Info.Println("sleeping 1 sec waiting on master..")
			time.Sleep(1000 * time.Millisecond)
		}
	}
	if !found {
		logit.Info.Println("configureCluster: timed out waiting on master pg to start")
		return errors.New("timeout waiting for master pg to respond")
	}

	standbynodes, err2 := admindb.GetAllStandbyContainers(dbConn, cluster.ID)
	if err2 != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	//configure all standby nodes
	var stopPGResp cpmcontainerapi.StopPGResponse
	i := 0
	for i = range standbynodes {
		if standbynodes[i].Role == STANDBY {

			//stop standby
			if !autocluster {
				stopPGResp, err = cpmcontainerapi.StopPGClient(standbynodes[i].Name)
				if err != nil {
					logit.Error.Println("configureCluster:" + err.Error())
					return err
				}
				logit.Info.Println("configureCluster:stop output was" + stopPGResp.Output)
			}

			//create base backup from master
			var backupresp cpmcontainerapi.BasebackupResponse
			backupresp, err = cpmcontainerapi.BasebackupClient(masterhost+"."+domainname.Value, standbynodes[i].Name)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:basebackup output was" + backupresp.Output)

			data, err = template.Recovery(masterhost, pgport.Value, "postgres")
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:standby recovery.conf generated")

			//write standby recovery.conf file remotely
			_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/recovery.conf", data, standbynodes[i].Name)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:standby recovery.conf copied remotely")

			data, err = template.Postgresql(STANDBY, pgport.Value, "")
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}

			//write standby postgresql.conf file remotely
			_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/postgresql.conf", data, standbynodes[i].Name)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:standby postgresql.conf copied remotely")

			//configure standby pg_hba.conf file
			data, err = template.Hba(dbConn, STANDBY, standbynodes[i].Name, pgport.Value, cluster.ID, domainname.Value, rules)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}

			logit.Info.Println("configureCluster:standby pg_hba.conf generated")

			//write standby pg_hba.conf file remotely
			_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/pg_hba.conf", data, standbynodes[i].Name)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:standby pg_hba.conf copied remotely")

			//start standby

			var stResp cpmcontainerapi.StartPGOnStandbyResponse
			stResp, err = cpmcontainerapi.StartPGOnStandbyClient(standbynodes[i].Name)
			if err != nil {
				logit.Error.Println("configureCluster:" + err.Error())
				return err
			}
			logit.Info.Println("configureCluster:standby startpg output was" + stResp.Output)
		}
		i++
	}

	logit.Info.Println("configureCluster: sleeping 5 seconds before configuring pgpool...")
	time.Sleep(5000 * time.Millisecond)

	pgpoolNode, err4 := admindb.GetContainerPgpool(dbConn, cluster.ID)
	logit.Info.Println("configureCluster: lookup pgpool node")
	if err4 != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster:" + pgpoolNode.Name)

	//configure the pgpool includes all standby nodes AND the master node
	poolnames := make([]string, len(standbynodes)+1)

	i = 0
	for i = range standbynodes {
		poolnames[i] = standbynodes[i].Name + "." + domainname.Value
		i++
	}
	poolnames[i] = master.Name + "." + domainname.Value

	//generate pgpool.conf HOST_LIST
	data, err = template.Poolconf(poolnames)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:pgpool pgpool.conf generated")

	//write pgpool.conf to remote pool node
	_, err = cpmcontainerapi.RemoteWritefileClient(util.GetBase()+"/bin/"+"pgpool.conf", data, pgpoolNode.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster:pgpool pgpool.conf copied remotely")

	//generate pool_passwd
	data, err = template.Poolpasswd()
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:pgpool pool_passwd generated")

	//write pgpool.conf to remote pool node
	_, err = cpmcontainerapi.RemoteWritefileClient(util.GetBase()+"/bin/"+"pool_passwd", data, pgpoolNode.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster:pgpool pool_passwd copied remotely")

	//generate pool_hba.conf
	data, err = template.Poolhba()
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	logit.Info.Println("configureCluster:pgpool pool_hba generated")

	//write pgpool.conf to remote pool node
	_, err = cpmcontainerapi.RemoteWritefileClient(util.GetBase()+"/bin/"+"pool_hba.conf", data, pgpoolNode.Name)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}
	logit.Info.Println("configureCluster:pgpool pool_hba copied remotely")

	//start pgpool
	var startPoolResp cpmcontainerapi.StartPgpoolResponse
	startPoolResp, err = cpmcontainerapi.StartPgpoolClient(pgpoolNode.Name)
	if err != nil {
		logit.Error.Println("configureCluster: " + err.Error())
		return err
	}
	logit.Info.Println("configureCluster: pgpool startpgpool output was" + startPoolResp.Output)

	//finally, update the cluster to show that it is
	//initialized!
	cluster.Status = "initialized"
	err = admindb.UpdateCluster(dbConn, cluster)
	if err != nil {
		logit.Error.Println("configureCluster:" + err.Error())
		return err
	}

	return nil

}
func MonitorStatements(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("MonitorStatements: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

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

	var host = container.Name
	if KubeEnv {
		host = container.Name + "-db"
	}

	//fetch cpmtest user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, container.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	//get the list of databases
	databases := make([]string, 0)
	var rows *sql.Rows

	rows, err = dbConn2.Query(
		"SELECT datname from pg_database where datname not in ('template1', 'template0') order by datname")
	if err != nil {
		logit.Error.Println("MonitorStatements:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var datname string
	for rows.Next() {
		if err = rows.Scan(
			&datname,
		); err != nil {
			logit.Error.Println("MonitorContainerSettings:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		databases = append(databases, datname)
	}
	if err = rows.Err(); err != nil {
		logit.Error.Println("MonitorStatements:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	rows.Close()

	statements := make([]PostgresStatement, 0)

	for i := range databases {
		//get a database connection to a specific database
		dbConn3, err := util.GetMonitoringConnection(host, databases[i], pgport.Value, CPMTEST_USER, nodeuser.Passwd)
		defer dbConn3.Close()

		rows, err = dbConn3.Query(
			"SELECT query, calls, total_time, rows, to_char(coalesce(100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0), -1), '999D99') AS hit_percent FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5")
		if err != nil {
			logit.Error.Println("MonitorStatements:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		defer rows.Close()
		for rows.Next() {
			stat := PostgresStatement{}
			stat.Database = databases[i]
			if err = rows.Scan(
				&stat.Query,
				&stat.Calls,
				&stat.TotalTime,
				&stat.Rows,
				&stat.HitPercent,
			); err != nil {
				logit.Error.Println("MonitorContainerSettings:" + err.Error())
				rest.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			statements = append(statements, stat)
		}
		if err = rows.Err(); err != nil {
			logit.Error.Println("MonitorStatements:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&statements)
}
func MonitorContainerSettings(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("MonitorContainerSettings: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

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

	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//fetch cpmtest user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	logit.Info.Println("cpmtest password is " + nodeuser.Passwd)

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	settings := make([]PostgresSetting, 0)
	var rows *sql.Rows

	rows, err = dbConn2.Query("select name, current_setting(name), source from pg_settings where source not in ('default','override')")
	if err != nil {
		logit.Error.Println("MonitorContainerSettings:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer rows.Close()
	for rows.Next() {
		setting := PostgresSetting{}
		if err = rows.Scan(
			&setting.Name,
			&setting.CurrentSetting,
			&setting.Source,
		); err != nil {
			logit.Error.Println("MonitorContainerSettings:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		settings = append(settings, setting)
	}
	if err = rows.Err(); err != nil {
		logit.Error.Println("MonitorContainerSettings:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&settings)
}
func provisionImplInit(dbConn *sql.DB, params *cpmserverapi.DockerRunRequest, PROFILE string, standby bool) error {
	//go get the domain name from the settings
	var domainname admindb.Setting
	var pgport admindb.Setting
	var err error

	domainname, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("Provision:DOMAIN-NAME setting error " + err.Error())
		return err
	}
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
	if err != nil {
		logit.Error.Println("Provision:PG-PORT setting error " + err.Error())
		return err
	}

	fqdn := params.ContainerName + "." + domainname.Value

	//we are depending on a DNS entry being created shortly after
	//creating the node in Docker
	//you might need to wait here until you can reach the new node's agent
	logit.Info.Println("PROFILE waiting till DNS ready")
	err = waitTillReady(fqdn)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	logit.Info.Println("checkpt 1")

	if standby {
		logit.Info.Println("standby node being created, will not initdb")
	} else {
		//initdb on the new node

		logit.Info.Println("PROFILE running initdb on the node")
		var resp cpmcontainerapi.InitdbResponse

		logit.Info.Println("checkpt 2")
		resp, err = cpmcontainerapi.InitdbClient(fqdn)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		logit.Info.Println("checkpt 3")
		logit.Info.Println("initdb output was" + resp.Output)
		logit.Info.Println("PROFILE initdb completed")
		//create postgresql.conf
		var data string
		var mode = "standalone"

		data, err = template.Postgresql(mode, pgport.Value, "")

		//place postgresql.conf on new node
		_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/"+params.ContainerName+"/postgresql.conf", data, fqdn)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		//create pg_hba.conf
		rules := make([]template.Rule, 0)
		data, err = template.Hba(dbConn, mode, params.ContainerName, pgport.Value, "", domainname.Value, rules)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		//place pg_hba.conf on new node
		_, err = cpmcontainerapi.RemoteWritefileClient("/pgdata/"+params.ContainerName+"/pg_hba.conf", data, fqdn)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		logit.Info.Println("PROFILE templates all built and copied to node")
		//start pg on new node
		var startResp cpmcontainerapi.StartPGResponse
		startResp, err = cpmcontainerapi.StartPGClient(fqdn)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		logit.Info.Println("startpg output was" + startResp.Output)

		//seed database with initial objects
		var seedResp cpmcontainerapi.SeedResponse
		seedResp, err = cpmcontainerapi.SeedClient(fqdn)
		if err != nil {
			logit.Error.Println("Provision:" + err.Error())
			return err
		}
		logit.Info.Println("seed output was" + seedResp.Output)
	}
	logit.Info.Println("PROFILE node provisioning completed")

	return nil
}
func ContainerInfoStatdatabase(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("ContainerStatdatabase: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

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

	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//get password
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	stats := make([]Statdatabase, 0)
	var rows *sql.Rows

	rows, err = dbConn2.Query("SELECT datname, blks_read::text, tup_returned::text, tup_fetched::text, tup_inserted::text, tup_updated::text, tup_deleted::text, coalesce(to_char(stats_reset, 'YYYY-MM-DD HH24:MI:SS'), ' ') as stats_reset from pg_stat_database")
	if err != nil {
		logit.Error.Println("ContainerStatdatabase:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer rows.Close()
	for rows.Next() {
		stat := Statdatabase{}
		if err = rows.Scan(
			&stat.Datname,
			&stat.BlksRead,
			&stat.TupReturned,
			&stat.TupFetched,
			&stat.TupInserted,
			&stat.TupUpdated,
			&stat.TupDeleted,
			&stat.StatsReset,
		); err != nil {
			logit.Error.Println("ContainerStatdatabase:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		stats = append(stats, stat)
	}
	if err = rows.Err(); err != nil {
		logit.Error.Println("ContainerStatdatabase:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&stats)
}
func ContainerInfoBgwriter(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("ContainerBgwriter: authorize error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

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

	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//get password
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println("ContainerBgwriter:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	var dbConn2 *sql.DB
	dbConn2, err = util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	info := Bgwriter{}
	err = dbConn2.QueryRow("SELECT to_char(now(), 'mm/dd/yy HH12:MI:SS') now, to_char(block_size::numeric * buffers_alloc / (1024 * 1024 * seconds), 'FM999999999999D9999') AS alloc_mbps, to_char(block_size::numeric * buffers_checkpoint / (1024 * 1024 * seconds), 'FM999999999999D9999') AS checkpoint_mbps, to_char(block_size::numeric * buffers_clean / (1024 * 1024 * seconds), 'FM999999999999D9999') AS clean_mbps, to_char(block_size::numeric * buffers_backend/ (1024 * 1024 * seconds), 'FM999999999999D9999') AS backend_mbps, to_char(block_size::numeric * (buffers_checkpoint + buffers_clean + buffers_backend) / (1024 * 1024 * seconds), 'FM999999999999D9999') AS write_mbps FROM ( SELECT now() AS sample,now() - stats_reset AS uptime,EXTRACT(EPOCH FROM now()) - extract(EPOCH FROM stats_reset) AS seconds, b.*,p.setting::integer AS block_size FROM pg_stat_bgwriter b,pg_settings p WHERE p.name='block_size') bgw").Scan(&info.Now, &info.AllocMbps, &info.CheckpointMbps, &info.CleanMbps, &info.BackendMbps, &info.WriteMbps)
	switch {
	case err == sql.ErrNoRows:
		logit.Error.Println("ContainerBgwriter:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	case err != nil:
		logit.Error.Println("ContainerBgwriter:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&info)
}
func GetContainerUser(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("GetContainerUser: validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	ContainerID := r.PathParam("ContainerID")
	if ContainerID == "" {
		rest.Error(w, "ContainerID required", 400)
		return
	}

	Rolname := r.PathParam("Rolname")
	if Rolname == "" {
		rest.Error(w, "Rolname required", 400)
		return
	}

	//get container info
	node, err := admindb.GetContainer(dbConn, ContainerID)
	if err != nil {
		logit.Error.Println("AddContainUser: "******"-db"
	}

	//fetch  user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, Rolname)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//fetch cpmtest user credentials
	var cpmuser admindb.ContainerUser
	cpmuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	dbConn2, err := util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, cpmuser.Passwd)
	defer dbConn2.Close()

	query := "select rolname::text, rolsuper::text, rolinherit::text, rolcreaterole::text, rolcreatedb::text, rolcatupdate::text, rolcanlogin::text, rolreplication::text from pg_roles where rolname = '" + Rolname + "' order by rolname"

	logit.Info.Println(query)

	err = dbConn2.QueryRow(query).Scan(
		&nodeuser.Rolname,
		&nodeuser.Rolsuper,
		&nodeuser.Rolinherit,
		&nodeuser.Rolcreaterole,
		&nodeuser.Rolcreatedb,
		&nodeuser.Rolcatupdate,
		&nodeuser.Rolcanlogin,
		&nodeuser.Rolreplication)
	if err != nil {
		logit.Error.Println("GetContainerUser:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteJson(&nodeuser)

}
func UpdateContainerUser(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()

	postMsg := NodeUser{}
	err = r.DecodeJsonPayload(&postMsg)
	if err != nil {
		logit.Error.Println("UpdateContainerUser: error in decode" + err.Error())
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = secimpl.Authorize(dbConn, postMsg.Token, "perm-user")
	if err != nil {
		logit.Error.Println("UpdateContainerUser: validate token error " + err.Error())
		rest.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	if postMsg.ID == "" {
		logit.Error.Println("UpdateContainerUser: error node ID required")
		rest.Error(w, "ID required", 400)
		return
	}

	if postMsg.Rolname == "" {
		logit.Error.Println("UpdateContainerUser: error node Rolname required")
		rest.Error(w, "Rolname required", 400)
		return
	}

	//create user on the container
	//get container info
	var node admindb.Container
	node, err = admindb.GetContainer(dbConn, postMsg.ID)
	if err != nil {
		logit.Error.Println("AddContainUser: "******"" {
	} else {
		//update the password
	}

	//get connection to container's database
	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//fetch cpmtest user credentials
	var cpmuser admindb.ContainerUser
	cpmuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
	var dbConn2 *sql.DB

	dbConn2, err = util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, cpmuser.Passwd)
	defer dbConn2.Close()

	var SUPERUSER = "******"
	var INHERIT = "INHERIT"
	var CREATEROLE = "CREATEROLE"
	var CREATEDB = "CREATEDB"
	var LOGIN = "******"
	var REPLICATION = "REPLICATION"

	logit.Info.Println("Rolsuper is " + strconv.FormatBool(postMsg.Rolsuper))
	if !postMsg.Rolsuper {
		SUPERUSER = "******"
	}

	if !postMsg.Rolinherit {
		INHERIT = "NOINHERIT"
	}

	if !postMsg.Rolcreaterole {
		CREATEROLE = "NOCREATEROLE"
	}
	if !postMsg.Rolcreatedb {
		CREATEDB = "NOCREATEDB"
	}

	if !postMsg.Rollogin {
		LOGIN = "******"
	}
	if !postMsg.Rolreplication {
		REPLICATION = "NOREPLICATION"
	}

	query := "alter user " + postMsg.Rolname + " " +
		SUPERUSER + " " +
		INHERIT + " " +
		CREATEROLE + " " +
		CREATEDB + " " +
		LOGIN + " " +
		REPLICATION + " "

	if postMsg.Passwd != "" {
		query = query + " PASSWORD '" + postMsg.Passwd + "'"
	}

	logit.Info.Println(query)

	_, err = dbConn2.Query(query)
	if err != nil {
		logit.Error.Println("UpdateContainerUser:"******"" {
		//update user's password
		dbuser := admindb.ContainerUser{}
		dbuser.Containername = node.Name
		dbuser.Passwd = postMsg.Passwd
		dbuser.Rolname = postMsg.Rolname

		err = admindb.UpdateContainerUser(dbConn, dbuser)
		if err != nil {
			logit.Error.Println("UpdateContainerUser: "******"OK"
	w.WriteJson(&status)
}
func GetAllUsersForContainer(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("GetAllUsersForContainer: 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
	}

	//get container info
	var node admindb.Container
	node, err = admindb.GetContainer(dbConn, ID)
	if err != nil {
		logit.Error.Println("GetAllUsersForContainer: " + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	//get connection to container's database
	var host = node.Name
	if KubeEnv {
		host = node.Name + "-db"
	}

	//fetch cpmtest user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, node.Name, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	logit.Info.Println("cpmtest password is " + nodeuser.Passwd)

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
	var dbConn2 *sql.DB
	dbConn2, err = util.GetMonitoringConnection(host, CPMTEST_DB, pgport.Value, CPMTEST_USER, nodeuser.Passwd)
	defer dbConn2.Close()

	users := make([]admindb.ContainerUser, 0)

	//query results
	var rows *sql.Rows

	rows, err = dbConn2.Query("select rolname::text, rolsuper::text, rolinherit::text, rolcreaterole::text, rolcreatedb::text, rolcatupdate::text, rolcanlogin::text, rolreplication::text from pg_roles order by rolname")
	if err != nil {
		logit.Error.Println("GetAllUsersForContainer:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer rows.Close()

	for rows.Next() {
		user := admindb.ContainerUser{}
		if err = rows.Scan(
			&user.Rolname,
			&user.Rolsuper,
			&user.Rolinherit,
			&user.Rolcreaterole,
			&user.Rolcreatedb,
			&user.Rolcatupdate,
			&user.Rolcanlogin,
			&user.Rolreplication,
		); err != nil {
			logit.Error.Println("GetAllUsersForContainer:" + err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		user.Containername = node.Name
		user.ContainerID = node.ID
		users = append(users, user)
	}
	if err = rows.Err(); err != nil {
		logit.Error.Println("GetAllUsersForContainer:" + err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.WriteJson(&users)

}
func loadtest(dbConn *sql.DB, nodename string, host string, writes int) ([]Loadtestresults, error) {
	var err error
	var name string
	var query string
	var id int
	var i int
	var dbConn2 *sql.DB
	var results = make([]Loadtestresults, 4)

	//get port
	var pgport admindb.Setting
	pgport, err = admindb.GetSetting(dbConn, "PG-PORT")

	//fetch cpmtest user credentials
	var nodeuser admindb.ContainerUser
	nodeuser, err = admindb.GetContainerUser(dbConn, nodename, CPMTEST_USER)
	if err != nil {
		logit.Error.Println(err.Error())
		return results, err
	}

	//get db connection
	dbConn2, err = util.GetMonitoringConnection(host, CPMTEST_USER, pgport.Value, CPMTEST_DB, nodeuser.Passwd)
	if err != nil {
		logit.Error.Println("loadtest connection error:" + err.Error())
		return results, err
	}
	defer dbConn2.Close()

	start := time.Now()

	//inserts
	results[0].Operation = "inserts"
	results[0].Count = writes
	for i = 0; i < writes; i++ {
		query = fmt.Sprintf("insert into loadtest ( id, name ) values ( %d, 'this is a row for load test') returning id ", i)
		err = dbConn2.QueryRow(query).Scan(&id)
		switch {
		case err != nil:
			logit.Error.Println("loadtest insert error:" + err.Error())
			return results, err
		}
	}

	results[0].Results = time.Since(start).String()

	start = time.Now()

	//selects
	results[1].Operation = "selects"
	results[1].Count = writes
	for i = 0; i < writes; i++ {
		err = dbConn2.QueryRow(fmt.Sprintf("select name from loadtest where id=%d", i)).Scan(&name)
		switch {
		case err == sql.ErrNoRows:
			logit.Error.Println("no row with that id")
			return results, err
		case err != nil:
			logit.Error.Println(err.Error())
			return results, err
		}
	}

	results[1].Results = time.Since(start).String()

	start = time.Now()

	//updates
	results[2].Operation = "updates"
	results[2].Count = writes
	for i = 0; i < writes; i++ {
		query = fmt.Sprintf("update loadtest set ( name ) = ('howdy' ) where id = %d returning id", i)
		err = dbConn2.QueryRow(query).Scan(&id)
		switch {
		case err != nil:
			return results, err
		}
	}

	results[2].Results = time.Since(start).String()

	start = time.Now()

	//deletes
	results[3].Operation = "deletes"
	results[3].Count = writes
	for i = 0; i < writes; i++ {
		query = fmt.Sprintf("delete from loadtest where id=%d returning id", i)
		err := dbConn2.QueryRow(query).Scan(&id)
		switch {
		case err != nil:
			return results, err
		}

	}

	results[3].Results = time.Since(start).String()

	return results, nil
}
func ProvisionBackupJob(dbConn *sql.DB, args *BackupRequest) error {

	logit.Info.Println("backup.Provision called")
	logit.Info.Println("with scheduleid=" + args.ScheduleID)
	logit.Info.Println("with serverid=" + args.ServerID)
	logit.Info.Println("with servername=" + args.ServerName)
	logit.Info.Println("with serverip=" + args.ServerIP)
	logit.Info.Println("with containername=" + args.ContainerName)
	logit.Info.Println("with profilename=" + args.ProfileName)

	params := &cpmserverapi.DockerRunRequest{}
	params.Image = "crunchydata/cpm-backup-job"
	params.ServerID = args.ServerID
	backupcontainername := args.ContainerName + "-backup"
	params.ContainerName = backupcontainername
	params.Standalone = "false"

	//get server info
	server, err := admindb.GetServer(dbConn, params.ServerID)
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}

	params.PGDataPath = server.PGDataPath + "/" + backupcontainername + "/" + getFormattedDate()

	//get the docker profile settings
	var setting admindb.Setting
	setting, err = admindb.GetSetting(dbConn, "S-DOCKER-PROFILE-CPU")
	params.CPU = setting.Value
	setting, err = admindb.GetSetting(dbConn, "S-DOCKER-PROFILE-MEM")
	params.MEM = setting.Value

	params.EnvVars = make(map[string]string)

	setting, err = admindb.GetSetting(dbConn, "DOMAIN-NAME")
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	var domain = setting.Value

	params.EnvVars["BACKUP_NAME"] = backupcontainername
	params.EnvVars["BACKUP_SERVERNAME"] = server.Name
	params.EnvVars["BACKUP_SERVERIP"] = server.IPAddress
	params.EnvVars["BACKUP_SCHEDULEID"] = args.ScheduleID
	params.EnvVars["BACKUP_PROFILENAME"] = args.ProfileName
	params.EnvVars["BACKUP_CONTAINERNAME"] = args.ContainerName
	params.EnvVars["BACKUP_PATH"] = params.PGDataPath
	params.EnvVars["BACKUP_HOST"] = args.ContainerName + "." + setting.Value

	setting, err = admindb.GetSetting(dbConn, "PG-PORT")
	if err != nil {
		logit.Error.Println("Provision:" + err.Error())
		return err
	}
	params.EnvVars["BACKUP_PORT"] = setting.Value
	params.EnvVars["BACKUP_USER"] = "******"
	params.EnvVars["BACKUP_SERVER_URL"] = "cpm-backup" + "." + domain + ":" + "13000"

	//provision the volume
	request := &cpmserverapi.DiskProvisionRequest{"/tmp/foo"}
	request.Path = params.PGDataPath
	var url = "http://" + server.IPAddress + ":10001"
	_, err = cpmserverapi.DiskProvisionClient(url, request)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	//run the container
	params.CommandPath = "docker-run-backup.sh"
	var response cpmserverapi.DockerRunResponse
	url = "http://" + server.IPAddress + ":10001"
	response, err = cpmserverapi.DockerRunClient(url, params)
	if err != nil {
		logit.Error.Println("Provision: " + response.Output)
		return err
	}
	logit.Info.Println("docker-run-backup.sh output=" + response.Output)

	return nil
}