#!/usr/bin/python2.7

import os
import sys
import subprocess
import glob
import time
import getopt
import sqlite3
import ssl
import urllib2
from xml.dom import minidom
import json

def fmt_date():
  return time.strftime("%Y%m%d")

# get all of the installed software types by checking the SR urls
# return a list, and run routine on all of them
def discover_software():
  conn = sqlite3.connect("/opt/slapos/slapproxy.db")
  cur = conn.cursor()
  qry = cur.execute("SELECT DISTINCT software_release FROM partition11")
  return [row[0] for row in qry if row[0]]

def get_connection_information(software_release):
  conn = sqlite3.connect("/opt/slapos/slapproxy.db")
  cur = conn.cursor()
  qry = cur.execute("SELECT connection_xml FROM partition11 WHERE connection_xml IS NOT NULL AND software_release=?", (software_release,) )
  xml = None
  for row in qry:
    xml = str(row[0])
    break 

  if xml is None:
    print software_release
    return (None, None)

  instance = minidom.parseString(xml)

  try:
    el = instance.getElementsByTagName('parameter')[0]
    value = el.childNodes[0].nodeValue
  except:
    return "error"
  if not value.startswith("{"):
    value = "\"" + value + "\""
  json_text = json.loads(value)

  if 'family-admin' in json_text:
    return (json_text['family-admin'], json_text['inituser-password'])
  elif 'insecure' in json_text:
    return (json_text, None)
  else:
    return (None, None)

def check_tables():
  conn = sqlite3.connect("/opt/slapos/slapproxy.db")
  cur = conn.cursor()
  qry = cur.execute("SELECT CASE WHEN tbl_name = 'partition11' THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = 'partition11' AND type = 'table'")

  if qry is None:
    print "tables aren't ready yet, your build may have failed, check logs in /opt/slapos/log/"
    sys.exit(0)

def get_build_status():
  try:
    f = open("/opt/slapos/log/slapos-node-software-" + fmt_date() + ".log")
  except:
    f = open("/opt/slapos/log/slapos-node-software.log")
  lines = f.readlines()
  if "Finished software releases" not in lines[-1]:
    return False
  if "ERROR" in lines[-3]:
    return "error"
  return True

# Check if the last two lines show the software finished building.
# If an error came just before this, we'll report failure.
# Otherwise it passed and we can move on.
# We want to open today's log, as it is most up to date

def status(software_release):
  build = get_build_status()
  if build:
    zope_ip, pw = get_connection_information(software_release)
    print ("Build successful, connect to:\n"
           "  " + zope_ip)
    if pw is not None:
      print (" with\n"
             "  username: zope  password: " + pw)
  elif not build:
    print "Your software is still building, be patient it can take awhile"
    sys.exit(2)
  elif build == "error":
    print "An error occurred while building, check /opt/slapos/log/slapos-node-software-" + \
          fmt_date() + ".log for details"
    sys.exit(2)

  ipv6 = None
  # check if the services are actually running (run slapos node and parse output)
  if pw is None:
    zope_ip = "https://" + zope_ip[zope_ip.index("@")+1:]
  
  original_zope_ip = zope_ip
  if "[" in zope_ip and "]" in zope_ip:
    ipv6 = zope_ip[zope_ip.index("[")+1:zope_ip.index("]")]
    with open("/etc/hosts", "ra+") as f:
      if " erp5-instance" not in f.read():
        f.write("\n%s   erp5-instance\n" % ipv6)
    zope_ip = zope_ip.replace("[" + ipv6 + "]", "erp5-instance")

  ctx = ssl.create_default_context()
  ctx.check_hostname = False
  ctx.verify_mode = ssl.CERT_NONE

  try:
    r1 = urllib2.urlopen(zope_ip, context=ctx)
  except urllib2.URLError, e:
    print "At least one of your services isn't running! Check with slapos node"
    print "restart a service with slapos node restart slappart:service"
    print ""
    print "DEBUG information: %s" % e
    sys.exit(2)
  
  if r1.getcode() != 200:
    print "At least one of your services isn't running! Check with slapos node"
    print "restart a service with slapos node restart slappart:service"
    sys.exit(2)

  if ipv6:
    print ""
    print "The URL above may require extra configuration if you want to access it"
    print "from another machine. You can install an apache locally and include the"
    print "the follow rewrite rule (http version):"
    print """ 
  RewriteRule ^/(.*) %s/VirtualHostBase/http/%%{HTTP_HOST}/VirtualHostRoot/$1 [L,P]

or (https version):

  RewriteRule ^/(.*) %s/VirtualHostBase/https/%%{HTTP_HOST}/VirtualHostRoot/$1 [L,P]

""" % (original_zope_ip, original_zope_ip) 


def info(software_release):
  if get_build_status():
    print get_connection_information(software_release)
  else:
    print "Information unavailable at this time, run " + sys.argv[0] + " -s for details"

def usage():
  print ("Get the status and information of your ERP5 build\n"
         "Usage:")
  print ("  --help    (-h):  Print this message and exit\n"
         "  --status  (-s):  Print the status of the build\n"
         "  --info    (-i):  Print the partition tables\n"
         "  --dump    (-d):  Dump the entire database (alias for slapos proxy show)\n") 

def dump():
  subprocess.call(["slapos", "proxy", "show", "-u", "/opt/slapos/slapproxy.db"])

def main(argv):
  # parse command line options
  try:
    opts, args = getopt.getopt(argv, "sihd", ["status", "info", "help", "dump"])
  except getopt.error, msg:
    usage()
    sys.exit(2)
  if len(opts) == 0:
    usage()
    sys.exit(2)
  # process arguments
  for opt, arg in opts:
    if opt in ("-h", "--help"):
       usage()
       sys.exit()
    elif opt in ("-s", "--status"):
      check_tables()
      for sr in discover_software():
        status(sr)
    elif opt in ("-i", "--info"):
      check_tables()
      for sr in discover_software():
        info(sr)
    elif opt in ("-d", "--dump"):
      dump()
 
if __name__ == "__main__":
  main(sys.argv[1:])
