func main() {

	fmt.Println("at top of testswarm main")

	var err error

	//var infoResponse swarmapi.DockerInfoResponse
	_, err = swarmapi.DockerInfo()
	os.Exit(0)

	inspectReq := swarmapi.DockerInspectRequest{}
	inspectReq.ContainerName = "cpm"
	var inspectResp swarmapi.DockerInspectResponse
	inspectResp, err = swarmapi.DockerInspect(&inspectReq)
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(inspectResp.IPAddress)

	runReq := swarmapi.DockerRunRequest{}
	runReq.PGDataPath = "/var/cpm/data/pgsql/swarmtest"
	runReq.ContainerType = "cpm-node"
	runReq.ContainerName = "swarmtest"
	runReq.EnvVars = make(map[string]string)
	runReq.EnvVars["one"] = "value of one"
	runReq.EnvVars["two"] = "value of two"
	runReq.CPU = "0"
	runReq.MEM = "0"
	var runResp swarmapi.DockerRunResponse
	runResp, err = swarmapi.DockerRun(&runReq)
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(runResp.ID)
}
// GetProxyByContainerID returns a proxy node defintion for a given container
func GetProxyByContainerID(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
	}

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

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

	request := &swarmapi.DockerInspectRequest{}
	var inspectInfo swarmapi.DockerInspectResponse
	request.ContainerName = proxy.ContainerName
	inspectInfo, err = swarmapi.DockerInspect(request)
	if err != nil {
		logit.Error.Println(err.Error())
		rest.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	proxy.ServerName = inspectInfo.ServerID

	w.WriteJson(&proxy)
}
// ProvisionRestoreJob creates a docker container to orchestrate a restore job
func ProvisionRestoreJob(dbConn *sql.DB, args *TaskRequest) error {

	logit.Info.Println("task.ProvisionRestoreJob called")
	logit.Info.Println("with scheduleid=" + args.ScheduleID)
	logit.Info.Println("with containername=" + args.ContainerName)
	logit.Info.Println("with profilename=" + args.ProfileName)
	logit.Info.Println("with statusid=" + args.StatusID)

	restorecontainername := args.ContainerName + "-restore-job"

	//remove any existing container with the same name
	inspectReq := &swarmapi.DockerInspectRequest{}
	inspectReq.ContainerName = restorecontainername
	inspectResponse, err := swarmapi.DockerInspect(inspectReq)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}
	if inspectResponse.RunningState != "not-found" {
		rreq := &swarmapi.DockerRemoveRequest{}
		rreq.ContainerName = restorecontainername
		_, err = swarmapi.DockerRemove(rreq)
		if err != nil {
			logit.Error.Println(err.Error())
			return err
		}
	}

	//create the new container
	params := &swarmapi.DockerRunRequest{}
	params.Image = "cpm-restore-job"
	params.ContainerName = restorecontainername
	params.Standalone = "false"
	params.Profile = "SM"

	schedule, err := GetSchedule(dbConn, args.ScheduleID)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

	logit.Info.Println("schedule serverip is " + schedule.Serverip)

	var taskstatus TaskStatus
	taskstatus, err = GetStatus(dbConn, args.StatusID)
	if err != nil {
		logit.Error.Println(err.Error())
		return err
	}

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

	//get the docker profile settings
	var setting types.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
	setting, err = admindb.GetSetting(dbConn, "PG-DATA-PATH")
	var datapath string
	datapath = setting.Value

	//this gets mounted under /pgdata and allows us to access
	//both the backup files and the restored containers files
	params.PGDataPath = datapath

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

	params.EnvVars["RestoreServerip"] = schedule.Serverip
	params.EnvVars["RestoreBackupPath"] = taskstatus.Path
	params.EnvVars["RestorePath"] = args.ContainerName
	params.EnvVars["RestoreContainerName"] = args.ContainerName
	params.EnvVars["RestoreScheduleID"] = args.ScheduleID
	params.EnvVars["RestoreProfileName"] = args.ProfileName
	params.EnvVars["RestoreStatusID"] = args.StatusID

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

	return nil
}
// GetNode returns the container node definition
func GetNode(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("error node ID required")
		rest.Error(w, "node ID required", http.StatusBadRequest)
		return
	}

	node, err2 := admindb.GetContainer(dbConn, ID)

	if node.ID == "" {
		rest.NotFound(w, r)
		return
	}
	if err2 != nil {
		logit.Error.Println(err2.Error())
		rest.Error(w, err2.Error(), http.StatusBadRequest)
		return
	}

	var currentStatus = "UNKNOWN"

	request := &swarmapi.DockerInspectRequest{}
	var inspectInfo swarmapi.DockerInspectResponse
	request.ContainerName = node.Name
	inspectInfo, err = swarmapi.DockerInspect(request)
	if err != nil {
		logit.Error.Println(err.Error())
		currentStatus = CONTAINER_NOT_FOUND
	}

	if currentStatus != "CONTAINER NOT FOUND" {
		var pgport types.Setting
		pgport, err = admindb.GetSetting(dbConn, "PG-PORT")
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		currentStatus, err = util.FastPing(pgport.Value, node.Name)
		if err != nil {
			logit.Error.Println(err.Error())
			rest.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		//logit.Info.Println("pinging db finished")
	}

	clusternode := new(types.ClusterNode)
	clusternode.ID = node.ID
	clusternode.ClusterID = node.ClusterID
	clusternode.Name = node.Name
	clusternode.Role = node.Role
	clusternode.Image = node.Image
	clusternode.CreateDate = node.CreateDate
	clusternode.Status = currentStatus
	clusternode.ProjectID = node.ProjectID
	clusternode.ProjectName = node.ProjectName
	clusternode.ClusterName = node.ClusterName
	clusternode.ServerID = inspectInfo.ServerID
	clusternode.IPAddress = inspectInfo.IPAddress

	w.WriteJson(clusternode)
}
func provisionImpl(dbConn *sql.DB, params *swarmapi.DockerRunRequest, standby bool) (string, 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(errorStr)
		return "", errors.New(errorStr)
	}

	//get the pg data path
	var pgdatapath types.Setting
	pgdatapath, err = admindb.GetSetting(dbConn, "PG-DATA-PATH")
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}

	var infoResponse swarmapi.DockerInfoResponse
	infoResponse, err = swarmapi.DockerInfo()
	servers := make([]types.Server, len(infoResponse.Output))
	i := 0
	for i = range infoResponse.Output {
		servers[i].ID = infoResponse.Output[i]
		servers[i].Name = infoResponse.Output[i]
		servers[i].IPAddress = infoResponse.Output[i]
		i++
	}

	//for database nodes, on the target server, we need to allocate
	//a disk volume on all CPM servers for the /pgdata container volume to work with
	//this causes a volume to be created with the directory
	//named the same as the container name

	params.PGDataPath = pgdatapath.Value + "/" + params.ContainerName

	logit.Info.Println("PROFILE provisionImpl 2 about to provision volume " + params.PGDataPath)
	if params.Image != "cpm-pgpool" {
		preq := &cpmserverapi.DiskProvisionRequest{}
		preq.Path = params.PGDataPath
		var response cpmserverapi.DiskProvisionResponse
		for _, each := range servers {
			logit.Info.Println("Provision: provisionvolume on server " + each.Name)
			response, err = cpmserverapi.DiskProvisionClient(each.Name, preq)
			if err != nil {
				logit.Info.Println("Provision: provisionvolume error" + err.Error())
				logit.Error.Println(err.Error())
				return "", err
			}
			logit.Info.Println("Provision: provisionvolume call response=" + response.Status)
		}
	}
	logit.Info.Println("PROFILE provisionImpl 3 provision volume completed")

	//run docker run to create the container

	params.CPU, params.MEM, err = getDockerResourceSettings(dbConn, params.Profile)
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}

	//inspect and remove any existing container
	logit.Info.Println("PROFILE provisionImpl inspect 4")
	inspectReq := &swarmapi.DockerInspectRequest{}
	inspectReq.ContainerName = params.ContainerName
	var inspectResponse swarmapi.DockerInspectResponse
	inspectResponse, err = swarmapi.DockerInspect(inspectReq)
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}
	if inspectResponse.RunningState != "not-found" {
		logit.Info.Println("PROFILE provisionImpl remove existing container 4a")
		rreq := &swarmapi.DockerRemoveRequest{}
		rreq.ContainerName = params.ContainerName
		_, err = swarmapi.DockerRemove(rreq)
		if err != nil {
			logit.Error.Println(err.Error())
			return "", err
		}
	}

	//pass any restore env vars to the new container
	if params.RestoreJob != "" {
		if params.EnvVars == nil {
			//logit.Info.Println("making envvars map")
			params.EnvVars = make(map[string]string)
		}
		params.EnvVars["RestoreJob"] = params.RestoreJob
		params.EnvVars["RestoreRemotePath"] = params.RestoreRemotePath
		params.EnvVars["RestoreRemoteHost"] = params.RestoreRemoteHost
		params.EnvVars["RestoreRemoteUser"] = params.RestoreRemoteUser
		params.EnvVars["RestoreDbUser"] = params.RestoreDbUser
		params.EnvVars["RestoreDbPass"] = params.RestoreDbPass
		params.EnvVars["RestoreSet"] = params.RestoreSet
	}

	//
	runReq := swarmapi.DockerRunRequest{}
	runReq.PGDataPath = params.PGDataPath
	runReq.Profile = params.Profile
	runReq.Image = params.Image
	runReq.ContainerName = params.ContainerName
	runReq.EnvVars = params.EnvVars
	//logit.Info.Println("CPU=" + params.CPU)
	//logit.Info.Println("MEM=" + params.MEM)
	runReq.CPU = "0"
	runReq.MEM = "0"
	var runResp swarmapi.DockerRunResponse
	runResp, err = swarmapi.DockerRun(&runReq)
	if err != nil {
		logit.Error.Println(err.Error())
		return "", err
	}
	logit.Info.Println("PROFILE provisionImpl created container 5 " + runResp.ID)

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

	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(err.Error())
		return "", err
	}
	dbnode.ID = newid

	if params.Image != "cpm-node-proxy" {
		//register default db users on the new node
		err = createDBUsers(dbConn, dbnode)
	}

	return newid, err

}