#cloud-config

# could/should set local mirror here or proxy here
# apt_proxy: http://{{server_host}}:8000/

misc_bucket:
 - &maas_enlist |
   ####  IPMI setup  ######
   # If IPMI network settings have been configured statically, you can
   # make them DHCP. If 'true', the IPMI network source will be changed
   # to DHCP.
   IPMI_CHANGE_STATIC_TO_DHCP="false"

   # In certain hardware, the parameters for the ipmi_si kernel module
   # might need to be specified. If you wish to send parameters, uncomment
   # the following line.
   #IPMI_SI_PARAMS="type=kcs ports=0xca2"

   TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX")
   IPMI_CONFIG_D="${TEMP_D}/ipmi.d"
   BIN_D="${TEMP_D}/bin"
   OUT_D="${TEMP_D}/out"
   PATH="$BIN_D:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

   mkdir -p "$BIN_D" "$OUT_D" "$IPMI_CONFIG_D"

   load_modules() {
      modprobe ipmi_msghandler
      modprobe ipmi_devintf
      modprobe ipmi_si ${IPMI_SI_PARAMS}
      udevadm settle
   }

   add_bin() {
      cat > "${BIN_D}/$1"
      chmod "${2:-755}" "${BIN_D}/$1"
   }
   add_ipmi_config() {
      cat > "${IPMI_CONFIG_D}/$1"
      chmod "${2:-644}" "${IPMI_CONFIG_D}/$1"
   }

   add_ipmi_config "02-global-config.ipmi" <<"END_IPMI_CONFIG"
   Section Lan_Channel
        Volatile_Access_Mode                    Always_Available
        Volatile_Enable_User_Level_Auth         Yes
        Volatile_Channel_Privilege_Limit        Administrator
        Non_Volatile_Access_Mode                Always_Available
        Non_Volatile_Enable_User_Level_Auth     Yes
        Non_Volatile_Channel_Privilege_Limit    Administrator
   EndSection
   END_IPMI_CONFIG

   add_bin "maas-ipmi-autodetect" <<"END_MAAS_IPMI_AUTODETECT"
   #!/usr/bin/python
   import os
   import commands
   import glob
   import re
   import string
   import random
   import time
   import json

   def detect_ipmi():
       # TODO: Detection could be improved.
       (status, output) = commands.getstatusoutput('ipmi-locate')
       show_re = re.compile('(IPMI\ Version:) (\d\.\d)')
       res = show_re.search(output)
       if res == None:
           found = glob.glob("/dev/ipmi[0-9]")
           if len(found):
               return (True, "UNKNOWN: %s" % " ".join(found))
           return (False, "")
       return (True, res.group(2))

   def is_ipmi_dhcp():
       (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address_Source"')
       show_re = re.compile('IP_Address_Source\s+Use_DHCP')
       res = show_re.search(output)
       if res == None:
           return False
       return True

   def set_ipmi_network_source(source):
       (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="Lan_Conf:IP_Address_Source=%s"' % source)

   def get_ipmi_ip_address():
       (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address"')
       show_re = re.compile('([0-9]{1,3}[.]?){4}')
       res = show_re.search(output)
       return res.group()

   def get_ipmi_user_number(user):
       for i in range(1, 17):
           ipmi_user_number = "User%s" % i
           (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="%s:Username"' % ipmi_user_number)
           if user in output:
               return ipmi_user_number
       return None

   def commit_ipmi_user_settings(user, password):
       ipmi_user_number = get_ipmi_user_number(user)
       if ipmi_user_number is None:
           (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User10:Username=%s"' % user)
           ipmi_user_number = get_ipmi_user_number(user)
       (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Password=%s"' % (ipmi_user_number, password))
       (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Enable_User=Yes"' % ipmi_user_number)
       (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Enable_IPMI_Msgs=Yes"' % ipmi_user_number)
       (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Privilege_Limit=Administrator"' % ipmi_user_number)

   def commit_ipmi_settings(config):
       (status, output) = commands.getstatusoutput('bmc-config --commit --filename %s' % config)

   def get_maas_power_settings(user, password, ipaddress):
       return "%s,%s,%s" % (user, password, ipaddress)

   def get_maas_power_settings_json(user, password, ipaddress):
       power_params = {"power_address": ipaddress, "power_pass": password, "power_user": user}
       return json.dumps(power_params) 

   def generate_random_password(min=8,max=15):
       length=random.randint(min,max)
       letters=string.ascii_letters+string.digits
       return ''.join([random.choice(letters) for _ in range(length)])

   def main():

       import argparse

       parser = argparse.ArgumentParser(
           description='send config file to modify IPMI settings with')
       parser.add_argument("--configdir", metavar="folder",
           help="specify config file directory", default=None)
       parser.add_argument("--dhcp-if-static", action="store_true",
           dest="dhcp", help="set network source to DHCP if Static", default=False)
       parser.add_argument("--commission-creds", action="store_true",
           dest="commission_creds", help="Create IPMI temporary credentials", default=False)

       args = parser.parse_args()

       # Check whether IPMI exists or not.
       (status, ipmi_version) = detect_ipmi()
       if status != True:
           # if False, then failed to detect ipmi
           exit(1)

       # Check whether IPMI is being set to DHCP. If it is not, and
       # '--dhcp-if-static' has been passed,  Set it to IPMI to DHCP.
       if not is_ipmi_dhcp() and args.dhcp:
           set_ipmi_network_source("Use_DHCP")
           # allow IPMI 120 seconds to obtain an IP address
           time.sleep(120)

       # create user/pass
       IPMI_MAAS_USER="maas"
       IPMI_MAAS_PASSWORD=generate_random_password()

       # Configure IPMI user/password
       commit_ipmi_user_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD)

       # Commit other IPMI settings
       if args.configdir:
           for file in os.listdir(args.configdir):
               commit_ipmi_settings(os.path.join(args.configdir, file))

       # get the IP address
       IPMI_IP_ADDRESS = get_ipmi_ip_address()
       if IPMI_IP_ADDRESS == "0.0.0.0":
           # if IPMI_IP_ADDRESS is 0.0.0.0, wait 60 seconds and retry.
           set_ipmi_network_source("Static")
           time.sleep(2)
           set_ipmi_network_source("Use_DHCP")
           time.sleep(60)
           IPMI_IP_ADDRESS = get_ipmi_ip_address()

       if IPMI_IP_ADDRESS is None or IPMI_IP_ADDRESS == "0.0.0.0":
           # Exit (to not set power params in MAAS) if no IPMI_IP_ADDRESS
           # has been detected
           exit(1)

       if args.commission_creds:
           print get_maas_power_settings_json(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS)
       else:
           print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS)

   if __name__ == '__main__':
       main()
   END_MAAS_IPMI_AUTODETECT

   # we could obtain the interface that booted from the kernel cmdline
   # thanks to 'IPAPPEND' (http://www.syslinux.org/wiki/index.php/SYSLINUX)
   url="{{server_url}}"
   host=""
   ip=$(ifconfig eth0 | awk '$1 == "inet" { sub("addr:","",$2); print $2; }') &&
     [ -n "${ip}" ] && host=$(dig +short -x $ip)  && host=${host%.}
   # load ipmi modules
   load_modules
   pargs=""
   if $IPMI_CHANGE_STATIC_TO_DHCP; then
      pargs="--dhcp-if-static"
   fi
   power_params=$(maas-ipmi-autodetect --configdir "$IPMI_CONFIG_D" ${pargs} --commission-creds) &&
     [ -n "${power_params}" ] && power_params=${power_params%.} && power_type=ipmi
   # Try maas-enlist without power parameters on failure for older versions of
   # maas-enlist without power parameter support
   maas-enlist --serverurl "$url" ${host:+--hostname "${host}"} ${power_params:+--power-params "${power_params}" --power-type "${power_type}"}>/tmp/enlist.out ||\
      maas-enlist --serverurl "$url" ${host:+--hostname "${host}"} >/tmp/enlist.out
   if [ $? -eq 0 ]; then
      msg="successfully enlisted to '$url'"
      [ -n "$host" ] && msg="$msg with hostname '$host'" ||
         msg="$msg without hostname"
      echo
      echo "=== $(date -R): $msg"
      cat  /tmp/enlist.out
      echo =============================================
      sleep 10
   else
      user="ubuntu"
      pass="ubuntu"

      echo "$user:$pass" | chpasswd
      bfile="/tmp/block-poweroff"
      { echo "#!/bin/sh"; echo "touch $bfile"; } > /etc/profile.d/A01-block.sh
      chmod 755 /etc/profile.d/A01-block.sh
      echo
      echo =============================================
      echo "failed to enlist system maas server '$host'"
      echo "sleeping 60 seconds then poweroff"
      echo
      echo "login with '$user:$pass' to debug and disable poweroff"
      echo 
      cat /tmp/enlist.out
      echo =============================================
      sleep 60
      [ -e $bfile ] && exit 0
   fi
 - &write_poweroff_job |
   cat >/etc/init/maas-poweroff.conf <<EOF
   description "poweroff when maas task is done"
   start on stopped cloud-final
   console output
   task
   script
     [ ! -e /tmp/block-poweroff ] || exit 0
     poweroff
   end script
   EOF
   # reload required due to lack of inotify in overlayfs (LP: #882147)
   initctl reload-configuration


packages: [ maas-enlist, freeipmi-tools ]
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
 - [ sh, -c, *maas_enlist ]
 - [ sh, -c, *write_poweroff_job ]
