#!/bin/sh

set -e

if [ -z "${OCI_API_URL}" ] ; then
	echo "Please add: export OCI_API_URL=\"http(s)://<url-or-IP-of-your-oci-server>/oci/api.php?\""
	echo "to your .bashrc in order to use "$(basename $0)
	echo "You may as well want to set OCI_LOGIN and OCI_PASS to be authenticated."
	exit 1
fi

usage (){
	echo $(basename $0)": configure your baremetal cluster through the OCI API."
	echo ""
	echo $(basename $0)" <action>"
	echo ""
	echo "Actions are:"
	echo "  machine-list"
	echo "  machine-show <machine_serial>"
	echo "  machine-set <machine_serial> --use_ceph_if_available <yes/no>"
	echo "  machine-add <machine_serial> <cluster_name> <role_name> <location_name>: add a machine to a cluster"
	echo "  machine-remove <machine_serial>: remove a machine from a cluster"
	echo "  machine-destroy: completely remove a machine from OCI's db"
	echo "  machine-reboot-on-hdd <serial>"
	echo "  machine-reboot-on-live <serial>"
	echo "  machine-ipmi-reboot-on-hdd <serial>"
	echo "  machine-ipmi-reboot-on-live <serial>"
	echo "  machine-install-os <serial>"
	echo "  machine-install-log <serial>"
	echo "  machine-set-ipmi <serial> <use-ipmi:yes/no> <ipmi-ip-addr> <ipmi-port> <ipmi-username> <ipmi-password>"
	echo ""
	echo "  location-list"
	echo "  location-create <name> <swiftregion>"
	echo "  location-delete <name>"
	echo ""
	echo "  network-create <name> <ip> <cidr_mask> <location> <is-public:yes/no>"
	echo "  network-list"
	echo "  network-delete <name>"
	echo "  network-add <network_name> <cluster_name> <role_name> <iface1> <iface2>"
	echo "  network-remove <network_name>"
	echo ""
	echo "  cluster-list"
	echo "  cluster-create <name> <domaine-name.com>"
	echo "  cluster-delete <name>"
	echo "  cluster-show-networks <cluster-name>"
	echo "  cluster-show-machines <cluster-name>"
	echo "  cluster-show-ips <cluster-name>"
	echo ""
	echo "  swift-region-list"
	echo "  swift-region-create <name>"
	echo "  swift-region-delete <name>"
	echo ""
	echo "  swift-calculate-ring <cluster-name>"
	exit 0
}

# Parameter: $1 = URL param
# return: API_RESPONSE_FILE
# The function exits printing API message if status != success
ocicli_call (){
	local STATUS MESSAGE URL_PARAM
	if [ -z "${1}" ] ; then
		echo "Missing URL_PARAM when calling ocicli_call()"
		exit 1
	fi
	URL_PARAM="${1}"

	if [ -n "${OCI_LOGIN}" ] && [ -n "${OCI_PASS}" ] ; then
		URL_PARAM="${URL_PARAM}&oci_login=${OCI_LOGIN}&oci_pass=${OCI_PASS}"
	fi

	API_RESPONSE_FILE=$(mktemp -t oci-poc-install-cluster.XXXXXX)
	if [ "${DEBUG}" = "on" ] ; then
		echo "curl -s \"${OCI_API_URL}${URL_PARAM}\""
	fi
	curl -s ${OCI_API_URL}${URL_PARAM} >${API_RESPONSE_FILE}
	STATUS=$(cat ${API_RESPONSE_FILE} | jq -r '.["status"]')
	if ! [ "${STATUS}" = "success" ] ; then
		echo "Could not query API:"
		MESSAGE=$(cat ${API_RESPONSE_FILE} | jq -r '.["message"]')
		echo $MESSAGE
		rm ${API_RESPONSE_FILE}
		exit 1
	fi
}

ocicli_machine_list (){
	ocicli_call "action=machine_list"
	echo "serial,Cur_ip,memory,status,lastseen,cluster,ladvd,product_name,BIOSver,IPMIver,IPMI_IP,hostname,notes"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.product_name,.serial)|.["data"][] | "\(.serial),\(.ipaddr),\(.memory),\(.status),\(.lastseen),\(.cluster),\(.ladvd_report),\(.product_name),\(.bios_version),\(.ipmi_firmware_version),\(.ipmi_detected_ip),\(.hostname),\(.notes)"'
}

ocicli_machine_show (){
	ocicli_call "action=machine_show&machine_serial=${1}"
	echo "Attribute,value"
	# Normal attributes
	OCICLI_MACHINE_SHOW_SERIAL=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.serial)"')
	OCICLI_MACHINE_SHOW_IPADDR=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipaddr)"')
	OCICLI_MACHINE_SHOW_MEMORY=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.memory)"')
	OCICLI_MACHINE_SHOW_STATUS=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.status)"')
	OCICLI_MACHINE_SHOW_LASTSEEN=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.lastseen)"')
	OCICLI_MACHINE_SHOW_ROLE=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.role)"')
	OCICLI_MACHINE_SHOW_LADVD=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ladvd_report)"')
	OCICLI_MACHINE_SHOW_PRODUCT=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.product_name)"')
	OCICLI_MACHINE_SHOW_BIOS_VER=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.bios_version)"')

	OCICLI_MACHINE_SHOW_IPMI_VER=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_firmware_version)"')
	OCICLI_MACHINE_SHOW_IPMI_DETECTED_IP=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_detected_ip)"')
	OCICLI_MACHINE_SHOW_USE_IPMI=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_use)"')
	OCICLI_MACHINE_SHOW_CALL_IPMI_BOOTDEV=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_call_chassis_bootdev)"')
	OCICLI_MACHINE_SHOW_IPMI_ADDR=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_addr)"')
	OCICLI_MACHINE_SHOW_IPMI_PORT=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_port)"')
	OCICLI_MACHINE_SHOW_IPMI_USERNAME=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_username)"')
	OCICLI_MACHINE_SHOW_IPMI_PASSWORD=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.ipmi_password)"')

	OCICLI_MACHINE_SHOW_HOSTNAME=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.hostname)"')
	OCICLI_MACHINE_SHOW_NOTES=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.notes)"')
	OCICLI_MACHINE_SHOW_USE_CEPH=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.use_ceph_if_available)"')

	# From cluster
	OCICLI_MACHINE_SHOW_CLUSTER_NAME=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.machine_cluster.name)"')

	echo "Serial:,${OCICLI_MACHINE_SHOW_SERIAL}"
	echo "Role:,${OCICLI_MACHINE_SHOW_ROLE}"
	if [ "${OCICLI_MACHINE_SHOW_ROLE}" = "compute" ] ; then
		echo "Use Ceph if available:,${OCICLI_MACHINE_SHOW_USE_CEPH}"
	fi
	echo "Hostname:,${OCICLI_MACHINE_SHOW_HOSTNAME}"
	echo "Status:,${OCICLI_MACHINE_SHOW_STATUS}"
	echo "Product name:,${OCICLI_MACHINE_SHOW_PRODUCT}"
	echo "Memory:,${OCICLI_MACHINE_SHOW_MEMORY}"
	echo "Last seen:,${OCICLI_MACHINE_SHOW_LASTSEEN}"
	echo "Cluster name:,${OCICLI_MACHINE_SHOW_CLUSTER_NAME}"
	echo "Current IP address:,${OCICLI_MACHINE_SHOW_IPADDR}"

	echo "IPMI firmware:,${OCICLI_MACHINE_SHOW_IPMI_VER}"
	echo "Detected IPMI IP:,${OCICLI_MACHINE_SHOW_IPMI_DETECTED_IP}"
	echo "Use IPMI:,${OCICLI_MACHINE_SHOW_USE_IPMI}"
	echo "Call IPMI bootdev:,${OCICLI_MACHINE_SHOW_CALL_IPMI_BOOTDEV}"
	echo "IPMI addr:,${OCICLI_MACHINE_SHOW_IPMI_ADDR}",
	echo "IPMI port:,${OCICLI_MACHINE_SHOW_IPMI_PORT}",
	echo "IPMI username:,${OCICLI_MACHINE_SHOW_IPMI_USERNAME}"
	echo "IPMI password:,${OCICLI_MACHINE_SHOW_IPMI_PASSWORD}"

	echo -n "IPs:,"
	for i in $(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.machine_ips)"' | jq -r '.[].ipaddr') ; do
		echo -n "${i} "
	done
	echo ""

	echo -n "Block devices:,"
	for i in $(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.machine_blockdevices)"' | jq -r '.[].name') ; do
		SIZE_MB=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]["machine_blockdevices"][] | select(.name == "'${i}'") | .["size_mb"]')
		SIZE_GB=$((${SIZE_MB} / 1024))
		echo -n "${i}:${SIZE_GB}G "
	done
	echo ""

	echo -n "Interfaces:,"
	for i in $(cat ${API_RESPONSE_FILE} | jq -r '.["data"]| "\(.machine_ifs)"' | jq -r '.[].name') ; do
		SPEED=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]["machine_ifs"][] | select(.name == "'${i}'") | .["max_speed"]')
		MACADDR=$(cat ${API_RESPONSE_FILE} | jq -r '.["data"]["machine_ifs"][] | select(.name == "'${i}'") | .["macaddr"]')
		case "${SPEED}" in
		10)
			H_SPEED="10Mb/s"
		;;
		100)
			H_SPEED="100Mb/s"
		;;
		1000)
			H_SPEED="1Gb/s"
		;;
		10000)
			H_SPEED="10Gb/s"
		;;
		*)
			H_SPEED=${SPEED}
		esac

		echo -n "${i}:${MACADDR}:${H_SPEED} "
	done
	echo ""

}

ocicli_machine_set (){
	SERIAL=${1}
	shift
	for i in $@ ; do
		case "${1}" in
		"--use_ceph_if_available")
			USE_CEPH=${2}
			shift
			shift
		;;
		*)
		;;
		esac
	done
	COMMAND="action=machine_set&machine_serial=${SERIAL}"
	if [ -n "${USE_CEPH}" ] ; then
		COMMAND="${COMMAND}&use_ceph=${USE_CEPH}"
	fi
	ocicli_call ${COMMAND}
	ocicli_display_status
}

ocicli_location_list (){
	ocicli_call "action=location_list"
	echo "id,name,swiftregion"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"][] | "\(.id),\(.name),\(.swiftregion)"'
}


ocicli_network_list (){
	ocicli_call "action=network_list"
	echo "name,ip,cidr,is_public,cluster,role,iface1,iface2,location_id"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.name)|.["data"][] | "\(.name),\(.ip),\(.cidr),\(.is_public),\(.cluster),\(.role),\(.iface1),\(.iface2),\(.location_id)"'
}

ocicli_cluster_list (){
	ocicli_call "action=cluster_list"
	echo "id,name,domain"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.name)|.["data"][] | "\(.id),\(.name),\(.domain)"'
}

ocicli_swiftregion_list () {
	ocicli_call "action=swiftregion_list"
	echo "id,name"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.name)|.["data"][] | "\(.id),\(.name)"'
}

ocicli_cluster_show_networks (){
	ocicli_call "action=cluster_show_networks&cluster_name=${1}"
	echo "name,ip,cidr,is_public,cluster,role,iface1,iface2,location_id"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.name)|.["data"][] | "\(.name),\(.ip),\(.cidr),\(.is_public),\(.cluster),\(.role),\(.iface1),\(.iface2),\(.location_id)"'
}

ocicli_cluster_show_machines (){
	ocicli_call "action=cluster_show_machines&cluster_name=${1}"
	echo "serial,ipaddr,memory,status,lastseen,hostname"
	cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.serial)|.["data"][] | "\(.serial),\(.ipaddr),\(.memory),\(.status),\(.lastseen),\(.hostname)"'
}

ocicli_display_status (){
	STATUS=$(cat ${API_RESPONSE_FILE} | jq -r '.["status"]')
	if [ "${STATUS}" = 'success' ] ; then
		echo "Ok."
	else
		echo "Status not ok:"
		cat ${API_RESPONSE_FILE} | jq -r '.["message"]'
	fi
}

#########################
### Parameter parsing ###
#########################

if [ -z "${1}" ] ; then
	usage
fi

if [ "${1}" = -d ] ; then
	DEBUG=on
	MINUS_D="-d"
	shift
fi

# If using -csv, procress as normal
if [ "${1}" = -csv ] ; then
	shift
else
	# If not, (and not for all commands...), we call ourself with -csv and filter the CSV output through the column program
	case ${1} in
	"machine-install-os")
		echo -n ""
	;;
	"machine-install-log")
		echo -n ""
	;;
	"swift-calculate-ring")
		echo -n ""
	;;
	*)
		$0 ${MINUS_D} -csv $@ | column -t -s $','
		exit 0
	;;
	esac
fi

ACTION=${1}
shift

case "${ACTION}" in
	"machine-list")
		ocicli_machine_list
	;;
	"machine-show")
		ocicli_machine_show ${1}
	;;
	"machine-set")
		ocicli_machine_set $@
	;;
	# Add a machine to a cluster
	"machine-add")
		ocicli_call "action=machine_add&machine_serial=${1}&cluster_name=${2}&role_name=${3}&location_name=${4}"  
		ocicli_display_status
	;;
	"machine-remove")
		ocicli_call "action=machine_remove&machine_serial=${1}"
		ocicli_display_status
	;;
	"machine-destroy")
		ocicli_call "action=machine_destroy&machine_serial=${1}"
		ocicli_display_status
	;;
	"machine-show-from-hostname")
		ocicli_call "action=machine_show_from_hostname&hostname=${1}"
		echo "serial,ipaddr,memory,status,lastseen,hostname"
		cat ${API_RESPONSE_FILE} | jq -r '.["data"] | "\(.serial),\(.ipaddr),\(.memory),\(.status),\(.lastseen),\(.hostname)"'
	;;
	"machine-reboot-on-hdd")
		ocicli_call "action=machine_reboot_on_hdd&serial=${1}"
		ocicli_display_status
	;;
	"machine-reboot-on-live")
		ocicli_call "action=machine_reboot_on_live&serial=${1}"
		ocicli_display_status
	;;
	"machine-ipmi-reboot-on-hdd")
		ocicli_call "action=ipmi_reboot_on_hdd&serial=${1}"
		ocicli_display_status
	;;
	"machine-ipmi-reboot-on-live")
		ocicli_call "action=ipmi_reboot_on_live&serial=${1}"
		ocicli_display_status
	;;
	"machine-install-os")
		ocicli_call "action=machine_install_os&serial=${1}"
		cat ${API_RESPONSE_FILE} | jq -r '.["data"]'
	;;
	"machine-install-log")
		ocicli_call "action=machine_install_log&serial=${1}"
		cat ${API_RESPONSE_FILE} | jq -r '.["data"]'
	;;
	"machine-set-ipmi")
		ocicli_call "action=machine_set_ipmi&serial=${1}&ipmi_use=${2}&ipmi_addr=${3}&ipmi_port=${4}&ipmi_username=${5}&ipmi_password=${6}"
		ocicli_display_status
	;;

	"location-list")
		ocicli_location_list
	;;
	"location-create")
		ocicli_call "action=location_create&name=${1}&swiftregion=${2}"
		ocicli_display_status
	;;
	"location-delete")
		ocicli_call "action=location_delete&name=${1}"  
		ocicli_display_status
	;;

	"network-create")
		ocicli_call "action=new_network&name=${1}&ipaddr=${2}&cidr_mask=${3}&location=${4}&is_public=${5}"
		ocicli_display_status
	;;
	"network-list")
		ocicli_network_list
	;;
	"network-delete")
		ocicli_call "action=network_delete&name=${1}"
		ocicli_display_status
	;;
	# Add a network to a cluster
	"network-add")
		ocicli_call "action=network_add&network_name=${1}&cluster_name=${2}&role_name=${3}&iface1=${4}&iface2=${5}"
		ocicli_display_status
	;;
	# Remove a network from a cluster
	"network-remove")
		ocicli_call "action=network_remove&network_name=${1}"
		ocicli_display_status
	;;

	"cluster-list")
		ocicli_cluster_list
	;;
	"cluster-create")
		ocicli_call "action=cluster_create&name=${1}&domain=${2}"
		ocicli_display_status
	;;
	"cluster-delete")
		ocicli_call "action=cluster_delete&name=${1}"
		ocicli_display_status
	;;
	"cluster-show-networks")
		ocicli_cluster_show_networks $@
	;;
	"cluster-show-machines")
		ocicli_cluster_show_machines $@
	;;
	"cluster-show-ips")
		ocicli_call "action=cluster_show_ips&name=${1}"
		echo "hostname,ip"
		cat ${API_RESPONSE_FILE} | jq -r '.["data"]|=sort_by(.hostname)|.["data"][] | "\(.hostname),\(.ipaddr)"'
	;;

	"swift-region-list")
		ocicli_swiftregion_list
	;;
	"swift-region-create")
		ocicli_call "action=swiftregion_create&name=${1}"
		ocicli_display_status
	;;
	"swift-region-delete")
		ocicli_call "action=swiftregion_delete&name=${1}"
		ocicli_display_status
	;;
	"swift-calculate-ring")
		ocicli_call "action=swift_caculate_ring&cluster_name=${1}"
		echo "Output for the job:"
		cat ${API_RESPONSE_FILE} | jq -r '.["data"]'
	;;

	*)
		usage
	;;
esac
