← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~julian-edwards/maas/ephemeral_proxying_bug-1116331 into lp:maas

 

Scott Moser has proposed merging lp:~julian-edwards/maas/ephemeral_proxying_bug-1116331 into lp:maas.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1116331 in MAAS: "proxy not used in ephemeral or commissioning"
  https://bugs.launchpad.net/maas/+bug/1116331

For more details, see:
https://code.launchpad.net/~julian-edwards/maas/ephemeral_proxying_bug-1116331/+merge/147668
-- 
https://code.launchpad.net/~julian-edwards/maas/ephemeral_proxying_bug-1116331/+merge/147668
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/ephemeral_proxying_bug-1116331 into lp:maas.
=== modified file 'contrib/preseeds_v2/enlist_userdata'
--- contrib/preseeds_v2/enlist_userdata	2012-11-30 17:35:04 +0000
+++ contrib/preseeds_v2/enlist_userdata	2013-02-11 14:13:23 +0000
@@ -1,7 +1,10 @@
 #cloud-config
 
-# could/should set local mirror here or proxy here
-# apt_proxy: http://{{server_host}}:8000/
+{{if http_proxy}}
+apt_proxy: http_proxy
+{{else}}
+apt_proxy: http://{{server_host}}:8000/
+{{endif}}
 
 misc_bucket:
  - &maas_enlist |

=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py	2013-01-14 22:06:12 +0000
+++ src/maasserver/models/node.py	2013-02-11 14:13:23 +0000
@@ -635,7 +635,7 @@
         from metadataserver.commissioning.user_data import generate_user_data
         from metadataserver.models import NodeCommissionResult
 
-        commissioning_user_data = generate_user_data()
+        commissioning_user_data = generate_user_data(nodegroup=self.nodegroup)
         NodeCommissionResult.objects.clear_results(self)
         self.status = NODE_STATUS.COMMISSIONING
         self.owner = user

=== modified file 'src/maasserver/preseed.py'
--- src/maasserver/preseed.py	2012-11-27 10:39:51 +0000
+++ src/maasserver/preseed.py	2013-02-11 14:13:23 +0000
@@ -15,6 +15,7 @@
     'compose_preseed_url',
     'get_enlist_preseed',
     'get_preseed',
+    'get_preseed_context',
     ]
 
 from collections import namedtuple

=== modified file 'src/maasserver/tests/test_node.py'
--- src/maasserver/tests/test_node.py	2012-12-19 12:23:48 +0000
+++ src/maasserver/tests/test_node.py	2013-02-11 14:13:23 +0000
@@ -489,6 +489,8 @@
             ).return_value = user_data
         node.start_commissioning(factory.make_admin())
         self.assertEqual(user_data, NodeUserData.objects.get_user_data(node))
+        commissioning.user_data.generate_user_data.assert_called_with(
+            nodegroup=node.nodegroup)
 
     def test_start_commissioning_clears_node_commissioning_results(self):
         node = factory.make_node(status=NODE_STATUS.DECLARED)

=== modified file 'src/metadataserver/commissioning/tests/test_user_data.py'
--- src/metadataserver/commissioning/tests/test_user_data.py	2012-12-18 12:31:47 +0000
+++ src/metadataserver/commissioning/tests/test_user_data.py	2013-02-11 14:13:23 +0000
@@ -17,6 +17,7 @@
 from maasserver.testing.factory import factory
 from maasserver.testing.testcase import TestCase
 from maastesting.matchers import ContainsAll
+from metadataserver.commissioning import user_data
 from metadataserver.commissioning.user_data import (
     generate_user_data,
     is_snippet,
@@ -24,6 +25,10 @@
     read_snippet,
     strip_name,
     )
+from mock import (
+    Mock,
+    sentinel,
+    )
 
 
 class TestUserData(TestCase):
@@ -72,3 +77,13 @@
                 'def authenticate_headers',
                 'def encode_multipart_data',
             }))
+
+    def test_nodegroup_passed_to_get_preseed_context(self):
+        # I don't care about what effect it has, I just want to know
+        # that it was passed as it can affect the contents of
+        # `server_host` in the context.
+        fake_context = dict(http_proxy=factory.getRandomString())
+        user_data.get_preseed_context = Mock(return_value=fake_context)
+        nodegroup = sentinel.nodegroup
+        generate_user_data(nodegroup)
+        user_data.get_preseed_context.assert_called_with(nodegroup=nodegroup)

=== modified file 'src/metadataserver/commissioning/user_data.py'
--- src/metadataserver/commissioning/user_data.py	2012-12-18 12:31:47 +0000
+++ src/metadataserver/commissioning/user_data.py	2013-02-11 14:13:23 +0000
@@ -24,6 +24,7 @@
 from os import listdir
 import os.path
 
+from maasserver.preseed import get_preseed_context
 import tempita
 
 
@@ -58,13 +59,12 @@
     return snippet_name.replace('.', '_')
 
 
-def generate_user_data():
+def generate_user_data(nodegroup=None):
     """Produce the main commissioning script.
 
-    The script was templated so that code snippets become easier to
-    maintain, check for lint, and ideally, unit-test.  However its
-    contents are static: there are no variables.  It's perfectly
-    cacheable.
+    The main template file contains references to so-called ``snippets''
+    which are read in here, and substituted.  In addition, the regular
+    preseed context variables are available (such as 'http_proxy').
 
     :rtype: `bytes`
     """
@@ -78,4 +78,5 @@
         strip_name(name): read_snippet(snippets_dir, name, encoding=encoding)
         for name in list_snippets(snippets_dir)
     }
+    snippets.update(get_preseed_context(nodegroup=nodegroup))
     return template.substitute(snippets).encode('utf-8')

=== modified file 'src/metadataserver/commissioning/user_data.template'
--- src/metadataserver/commissioning/user_data.template	2013-02-06 13:59:35 +0000
+++ src/metadataserver/commissioning/user_data.template	2013-02-11 14:13:23 +0000
@@ -1,356 +1,365 @@
-#!/bin/sh
-#
-# This script carries inside it multiple files.  When executed, it creates
-# the files into a temporary directory, downloads and extracts commissioning
-# scripts from the metadata service, and then processes the scripts.
-#
-# The commissioning scripts get run by a close equivalent of run-parts.
-# For each, the main script calls home to maas with maas-signal, posting
-# the script's output as a separate file.
-#
-####  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"
-
-#### script setup ######
-TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX")
-SCRIPTS_D="${TEMP_D}/commissioning.d"
-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"
-trap cleanup EXIT
-
-mkdir -p "$BIN_D" "$OUT_D" "$SCRIPTS_D" "$IPMI_CONFIG_D"
-
-### some utility functions ####
-aptget() {
-   DEBIAN_FRONTEND=noninteractive apt-get --assume-yes -q "$@" </dev/null
-}
-
-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"
-}
-cleanup() {
-   [ -n "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
-}
-
-find_creds_cfg() {
-   local config="" file="" found=""
-
-   # If the config location is set in environment variable, trust it.
-   [ -n "${COMMISSIONING_CREDENTIALS_URL}" ] &&
-      _RET="${COMMISSIONING_CREDENTIALS_URL}" && return
-
-   # Go looking for local files written by cloud-init.
-   for file in /etc/cloud/cloud.cfg.d/*cmdline*.cfg; do
-      [ -f "$file" ] && _RET="$file" && return
-   done
-
-   local opt="" cmdline=""
-   if [ -f /proc/cmdline ] && read cmdline < /proc/cmdline; then
-      # Search through /proc/cmdline arguments:
-      # cloud-config-url trumps url=
-      for opt in $cmdline; do
-         case "$opt" in
-            url=*)
-               found=${opt#url=};;
-            cloud-config-url=*)
-               _RET="${opt#*=}"
-               return 0;;
-         esac
-      done
-      [ -n "$found" ] && _RET="$found" && return 0
-   fi
-   return 1
-}
-
-# Invoke the "signal()" API call to report progress.
-# Usage: signal <status> <message>
-signal() {
-   maas-signal "--config=${CRED_CFG}" "$@"
-}
-
-# Report result of a commissioning script: output file, error output
-# file if there was any error output, and return code.
-# Usage: signal <return-value> <message> <stdout-file> <stderr-file>
-signal_result() {
-   local result=$1 message="$2" stdout="$3" stderr="$4"
-   local files="--file=$stdout"
-   if [ -f "$stderr" -a -s "$stderr" ]
-   then
-      files="$files --file=$stderr"
-   fi
-   maas-signal \
-      "--config=${CRED_CFG}" \
-      "--script-result=$result" \
-      $files \
-      WORKING "$message"
-}
-
-fail() {
-   [ -z "$CRED_CFG" ] || signal FAILED "$1"
-   echo "FAILED: $1" 1>&2;
-   exit 1
-}
-
-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
-}
-
-main() {
-   write_poweroff_job
-
-   # Install tools and load modules.
-   aptget update
-   aptget install freeipmi-tools
-   load_modules
-
-   # The main function, actually execute stuff that is written below.
-   local script total=0 creds=""
-
-   find_creds_cfg ||
-      fail "failed to find credential config"
-   creds="$_RET"
-
-   # Get remote credentials into a local file.
-   case "$creds" in
-      http://*|https://*)
-         wget "$creds" -O "${TEMP_D}/my.creds" ||
-            fail "failed to get credentials from $cred_cfg"
-         creds="${TEMP_D}/my.creds"
-         ;;
-   esac
-
-   # Use global name read by signal() and fail.
-   CRED_CFG="$creds"
-
-   # Power settings.
-   local pargs=""
-   if $IPMI_CHANGE_STATIC_TO_DHCP; then
-      pargs="--dhcp-if-static"
-   fi
-   power_settings=$(maas-ipmi-autodetect --configdir "$IPMI_CONFIG_D" ${pargs})
-   if [ ! -z "$power_settings" ]; then
-      signal "--power-type=ipmi" "--power-parameters=${power_settings}" WORKING "finished [maas-ipmi-autodetect]"
-   fi
-
-   # Download and extract commissioning scripts.  It will contain a
-   # commissioning.d directory, so this is how $SCRIPTS_D is created.
-   maas-get --config="${CRED_CFG}" maas-commissioning-scripts | tar -C "${TEMP_D}" -x
-
-   # Just get a count of how many scripts there are for progress reporting.
-   for script in "${SCRIPTS_D}/"*; do
-      [ -x "$script" -a -f "$script" ] || continue
-      total=$(($total+1))
-   done
-
-   local cur=1 numpass=0 name="" failed=""
-   for script in "${SCRIPTS_D}/"*; do
-      [ -f "$script" -a -f "$script" ] || continue
-      name=${script##*/}
-      signal WORKING "starting ${name} [$cur/$total]"
-      "$script" > "${OUT_D}/${name}.out" 2> "${OUT_D}/${name}.err"
-      ret=$?
-      signal_result \
-         "$ret" "finished $name [$cur/$total]: $ret" \
-         "${OUT_D}/${name}.out" \
-         "${OUT_D}/${name}.err"
-      if [ $ret -eq 0 ]; then
-          numpass=$(($numpass+1))
-          failed="${failed} ${name}"
-      fi
-      cur=$(($cur+1))
-   done
-
-   if [ $numpass -eq $total ]; then
-      ( cd "${OUT_D}" &&
-         signal OK "finished [$numpass/$total]" )
-      return 0
-   else
-      ( cd "${OUT_D}" &&
-         signal FAILED "failed [$numpass/$total] ($failed)" )
-      return $(($count-$numpass))
-   fi
-
-}
-
-load_modules() {
-   modprobe ipmi_msghandler
-   modprobe ipmi_devintf
-   modprobe ipmi_si ${IPMI_SI_PARAMS}
-   udevadm settle
-}
-
-### begin writing files ###
-
-add_ipmi_config "01-user-privileges.ipmi" <<"END_IPMI_USER_PRIVILEGES"
-Section User3
-	Enable_User				Yes
-	Lan_Enable_IPMI_Msgs			Yes
-	Lan_Privilege_Limit			Administrator
-EndSection
-END_IPMI_USER_PRIVILEGES
-
-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
-
-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 commit_ipmi_user_settings(user, password):
-    (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User3:Username=%s"' % user)
-    (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User3:Password=%s"' % password)
-
-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 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", default=None)
-    parser.add_argument("--dhcp-if-static", action="store_true",
-        dest="dhcp", help="specify config file", 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)
+#cloud-config-archive
+- content: |
+   #cloud-config
+   {{if http_proxy}}
+   apt_proxy: http_proxy
+   {{else}}
+   apt_proxy: http://{{server_host}}:8000/
+   {{endif}}
+- content: |
+    #!/bin/sh
+    #
+    # This script carries inside it multiple files.  When executed, it creates
+    # the files into a temporary directory, downloads and extracts commissioning
+    # scripts from the metadata service, and then processes the scripts.
+    #
+    # The commissioning scripts get run by a close equivalent of run-parts.
+    # For each, the main script calls home to maas with maas-signal, posting
+    # the script's output as a separate file.
+    #
+    ####  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"
+
+    #### script setup ######
+    TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX")
+    SCRIPTS_D="${TEMP_D}/commissioning.d"
+    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"
+    trap cleanup EXIT
+
+    mkdir -p "$BIN_D" "$OUT_D" "$SCRIPTS_D" "$IPMI_CONFIG_D"
+
+    ### some utility functions ####
+    aptget() {
+       DEBIAN_FRONTEND=noninteractive apt-get --assume-yes -q "$@" </dev/null
+    }
+
+    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"
+    }
+    cleanup() {
+       [ -n "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
+    }
+
+    find_creds_cfg() {
+       local config="" file="" found=""
+
+       # If the config location is set in environment variable, trust it.
+       [ -n "${COMMISSIONING_CREDENTIALS_URL}" ] &&
+          _RET="${COMMISSIONING_CREDENTIALS_URL}" && return
+
+       # Go looking for local files written by cloud-init.
+       for file in /etc/cloud/cloud.cfg.d/*cmdline*.cfg; do
+          [ -f "$file" ] && _RET="$file" && return
+       done
+
+       local opt="" cmdline=""
+       if [ -f /proc/cmdline ] && read cmdline < /proc/cmdline; then
+          # Search through /proc/cmdline arguments:
+          # cloud-config-url trumps url=
+          for opt in $cmdline; do
+             case "$opt" in
+                url=*)
+                   found=${opt#url=};;
+                cloud-config-url=*)
+                   _RET="${opt#*=}"
+                   return 0;;
+             esac
+          done
+          [ -n "$found" ] && _RET="$found" && return 0
+       fi
+       return 1
+    }
+
+    # Invoke the "signal()" API call to report progress.
+    # Usage: signal <status> <message>
+    signal() {
+       maas-signal "--config=${CRED_CFG}" "$@"
+    }
+
+    # Report result of a commissioning script: output file, error output
+    # file if there was any error output, and return code.
+    # Usage: signal <return-value> <message> <stdout-file> <stderr-file>
+    signal_result() {
+       local result=$1 message="$2" stdout="$3" stderr="$4"
+       local files="--file=$stdout"
+       if [ -f "$stderr" -a -s "$stderr" ]
+       then
+          files="$files --file=$stderr"
+       fi
+       maas-signal \
+          "--config=${CRED_CFG}" \
+          "--script-result=$result" \
+          $files \
+          WORKING "$message"
+    }
+
+    fail() {
+       [ -z "$CRED_CFG" ] || signal FAILED "$1"
+       echo "FAILED: $1" 1>&2;
+       exit 1
+    }
+
+    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
+    }
+
+    main() {
+       write_poweroff_job
+
+       # Install tools and load modules.
+       aptget update
+       aptget install freeipmi-tools
+       load_modules
+
+       # The main function, actually execute stuff that is written below.
+       local script total=0 creds=""
+
+       find_creds_cfg ||
+          fail "failed to find credential config"
+       creds="$_RET"
+
+       # Get remote credentials into a local file.
+       case "$creds" in
+          http://*|https://*)
+             wget "$creds" -O "${TEMP_D}/my.creds" ||
+                fail "failed to get credentials from $cred_cfg"
+             creds="${TEMP_D}/my.creds"
+             ;;
+       esac
+
+       # Use global name read by signal() and fail.
+       CRED_CFG="$creds"
+
+       # Power settings.
+       local pargs=""
+       if $IPMI_CHANGE_STATIC_TO_DHCP; then
+          pargs="--dhcp-if-static"
+       fi
+       power_settings=$(maas-ipmi-autodetect --configdir "$IPMI_CONFIG_D" ${pargs})
+       if [ ! -z "$power_settings" ]; then
+          signal "--power-type=ipmi" "--power-parameters=${power_settings}" WORKING "finished [maas-ipmi-autodetect]"
+       fi
+
+       # Download and extract commissioning scripts.  It will contain a
+       # commissioning.d directory, so this is how $SCRIPTS_D is created.
+       maas-get --config="${CRED_CFG}" maas-commissioning-scripts | tar -C "${TEMP_D}" -x
+
+       # Just get a count of how many scripts there are for progress reporting.
+       for script in "${SCRIPTS_D}/"*; do
+          [ -x "$script" -a -f "$script" ] || continue
+          total=$(($total+1))
+       done
+
+       local cur=1 numpass=0 name="" failed=""
+       for script in "${SCRIPTS_D}/"*; do
+          [ -f "$script" -a -f "$script" ] || continue
+          name=${script##*/}
+          signal WORKING "starting ${name} [$cur/$total]"
+          "$script" > "${OUT_D}/${name}.out" 2> "${OUT_D}/${name}.err"
+          ret=$?
+          signal_result \
+             "$ret" "finished $name [$cur/$total]: $ret" \
+             "${OUT_D}/${name}.out" \
+             "${OUT_D}/${name}.err"
+          if [ $ret -eq 0 ]; then
+              numpass=$(($numpass+1))
+              failed="${failed} ${name}"
+          fi
+          cur=$(($cur+1))
+       done
+
+       if [ $numpass -eq $total ]; then
+          ( cd "${OUT_D}" &&
+             signal OK "finished [$numpass/$total]" )
+          return 0
+       else
+          ( cd "${OUT_D}" &&
+             signal FAILED "failed [$numpass/$total] ($failed)" )
+          return $(($count-$numpass))
+       fi
+
+    }
+
+    load_modules() {
+       modprobe ipmi_msghandler
+       modprobe ipmi_devintf
+       modprobe ipmi_si ${IPMI_SI_PARAMS}
+       udevadm settle
+    }
+
+    ### begin writing files ###
+
+    add_ipmi_config "01-user-privileges.ipmi" <<"END_IPMI_USER_PRIVILEGES"
+    Section User3
+        Enable_User				Yes
+        Lan_Enable_IPMI_Msgs			Yes
+        Lan_Privilege_Limit			Administrator
+    EndSection
+    END_IPMI_USER_PRIVILEGES
+
+    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
+
+    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 commit_ipmi_user_settings(user, password):
+        (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User3:Username=%s"' % user)
+        (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User3:Password=%s"' % password)
+
+    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 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", default=None)
+        parser.add_argument("--dhcp-if-static", action="store_true",
+            dest="dhcp", help="specify config file", 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 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)
-
-    print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS)
-
-if __name__ == '__main__':
-    main()
-END_MAAS_IPMI_AUTODETECT
-
-add_bin "maas_api_helper.py" <<"END_MAAS_API_HELPER"
-{{maas_api_helper_py}}
-END_MAAS_API_HELPER
-
-add_bin "maas-signal" <<"END_MAAS_SIGNAL"
-{{maas_signal_py}}
-END_MAAS_SIGNAL
-
-add_bin "maas-get" <<END_MAAS_GET
-{{maas_get_py}}
-END_MAAS_GET
-
-
-main
-exit
+        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)
+
+        print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS)
+
+    if __name__ == '__main__':
+        main()
+    END_MAAS_IPMI_AUTODETECT
+
+    add_bin "maas_api_helper.py" <<"END_MAAS_API_HELPER"
+    {{maas_api_helper_py}}
+    END_MAAS_API_HELPER
+
+    add_bin "maas-signal" <<"END_MAAS_SIGNAL"
+    {{maas_signal_py}}
+    END_MAAS_SIGNAL
+
+    add_bin "maas-get" <<END_MAAS_GET
+    {{maas_get_py}}
+    END_MAAS_GET
+
+
+    main
+    exit


Follow ups