maas-enlist-0.4+bzr38.orig/avahi-discover/0000755000000000000000000000000012276326714016541 5ustar 00000000000000maas-enlist-0.4+bzr38.orig/bin/0000755000000000000000000000000012276326714014405 5ustar 00000000000000maas-enlist-0.4+bzr38.orig/man/0000755000000000000000000000000012276326714014410 5ustar 00000000000000maas-enlist-0.4+bzr38.orig/sbin/0000755000000000000000000000000012276326714014570 5ustar 00000000000000maas-enlist-0.4+bzr38.orig/avahi-discover/Makefile0000644000000000000000000000043312276326714020201 0ustar 00000000000000CFLAGS := $(shell pkg-config --cflags avahi-core) -g -Wall LDFLAGS := $(shell pkg-config --libs avahi-core) -ldebian-installer all: maas_find_component maas_find_component: $(CC) $(CFLAGS) maas-avahi-discover.c -o maas-avahi-discover $(LDFLAGS) clean: rm -f maas-avahi-discover maas-enlist-0.4+bzr38.orig/avahi-discover/maas-avahi-discover.c0000644000000000000000000001772312276326714022542 0ustar 00000000000000/* $Id$ */ /*** This file is based on an example that is part of avahi, which is copyright: Lennart Poettering Trent Lloyd Sebastien Estienne Jakub Stachowski James Willcox Collabora Ltd. Modifications for mass-enlist-udeb are copyright 2009-2012 Canonical Ltd. avahi is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. avahi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with avahi; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include static AvahiSimplePoll *simple_poll = NULL; static AvahiServer *server = NULL; static di_hash_table *resolver_hash = NULL; static int debug = 0; static void quiet_logger(AvahiLogLevel level, const char *txt) { } static bool resolver_equal_func(const void *key1, const void *key2) { return !strcmp((const char *) key1, (const char *) key2); } static uint32_t resolver_hash_func(const void *key) { /* save reimplementing our own hash algorithm ... */ di_rstring rstring; rstring.string = (char *) key; rstring.size = strlen(key); return di_rstring_hash(&rstring); } static void resolve_callback( AvahiSServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, AVAHI_GCC_UNUSED void* userdata) { assert(r); /* Called whenever a service has been resolved successfully or timed out */ switch (event) { case AVAHI_RESOLVER_FAILURE: if (debug) fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server))); break; case AVAHI_RESOLVER_FOUND: { char *human_address = avahi_malloc0(AVAHI_ADDRESS_STR_MAX); char *key = NULL; if (avahi_address_snprint(human_address, AVAHI_ADDRESS_STR_MAX, address)) { if (address->proto == AVAHI_PROTO_INET6) key = avahi_strdup_printf("[%s]:%u", human_address, port); else if (strncmp(human_address, "169.254.169.254", 15) == 0) key = avahi_strdup_printf("%s:%u", name, port); else key = avahi_strdup_printf("%s:%u", human_address, port); } else { if (debug) fprintf(stderr, "(Resolver) failed to resolve %s to IP address/port\n", key); } avahi_free(human_address); if (di_hash_table_lookup(resolver_hash, key)) { if (debug) fprintf(stderr, "(Resolver) Already seen %s\n", key); free(key); } else { di_hash_table_insert(resolver_hash, key, ""); if (debug) fprintf(stderr, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain); printf("%s|%s\n", name, key); } /* don't free key; di_hash_table_insert doesn't copy it */ } } avahi_s_service_resolver_free(r); } static void browse_callback( AvahiSServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { AvahiServer *s = userdata; assert(b); /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ switch (event) { case AVAHI_BROWSER_FAILURE: fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server))); avahi_simple_poll_quit(simple_poll); return; case AVAHI_BROWSER_NEW: if (debug) fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); /* We ignore the returned resolver object. In the callback function we free it. If the server is terminated before the callback function is called the server will free the resolver for us. */ if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET, 0, resolve_callback, s))) fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s))); break; case AVAHI_BROWSER_REMOVE: if (debug) fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); break; case AVAHI_BROWSER_ALL_FOR_NOW: if (debug) fprintf(stderr, "(Browser) %s\n", "ALL_FOR_NOW"); exit(0); break; case AVAHI_BROWSER_CACHE_EXHAUSTED: if (debug) fprintf(stderr, "(Browser) %s\n", "CACHE_EXHAUSTED"); break; } } int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) { AvahiServerConfig config; AvahiSServiceBrowser *sb = NULL; int error; int ret = 1; if (getenv("MAAS_ENLIST_DEBUG")) debug = 1; /* Initialize the pseudo-RNG */ srand(time(NULL)); if (!debug) avahi_set_log_function(quiet_logger); /* Allocate main loop object */ if (!(simple_poll = avahi_simple_poll_new())) { fprintf(stderr, "Failed to create simple poll object.\n"); goto fail; } /* Do not publish any local records */ avahi_server_config_init(&config); config.publish_hinfo = 0; config.publish_addresses = 0; config.publish_workstation = 0; config.publish_domain = 0; /* Allocate a new server */ server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error); /* Free the configuration data */ avahi_server_config_free(&config); /* Check whether creating the server object succeeded */ if (!server) { fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error)); goto fail; } /* Create the service browser */ if (!(sb = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_maas._tcp", NULL, 0, browse_callback, server))) { fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server))); goto fail; } /* Create a hash table so we can uniquify resolver results */ resolver_hash = di_hash_table_new_full(resolver_hash_func, resolver_equal_func, avahi_free, NULL); /* Run the main loop */ avahi_simple_poll_loop(simple_poll); ret = 0; fail: if (resolver_hash) di_hash_table_destroy (resolver_hash); /* Cleanup things */ if (sb) avahi_s_service_browser_free(sb); if (server) avahi_server_free(server); if (simple_poll) avahi_simple_poll_free(simple_poll); return ret; } maas-enlist-0.4+bzr38.orig/bin/maas-enlist0000755000000000000000000001265612276326714016562 0ustar 00000000000000#!/bin/sh # # maas-enlist: MAAS Enlistment Tool # # Copyright (C) 2012 Canonical Ltd. # # Authors: Andres Rodriguez # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . get_mac_addresses() { macs=`ip addr | egrep 'link/ether' | cut -d' ' -f6` for i in $macs; do if [ -z "$mac_address" ]; then mac_address="$i"; else mac_address="$mac_address,$i" fi done echo "$mac_address" } get_mac_address_by_interface() { iface="$1" mac=`ip addr sh "$iface" | egrep -m1 'link/ether' | cut -d' ' -f6` echo "$mac" } get_mac_address_curl_parms() { local args="" input_string="$1" OIFS=$IFS; IFS=","; set -- $input_string; IFS=$OIFS for i in "$@"; do args="${args} --data-urlencode mac_addresses=${i}" #mac_address="$mac_address""&mac_addresses=""${i}"; done echo "${args# }" } get_host_architecture() { if grep "flags" /proc/cpuinfo | grep -qs "\ lm\ "; then # if /proc/cpuinfo Flags has 'lm', it is x86_64 arch="amd64" else arch=`archdetect | cut -d'/' -f1` fi echo "$arch" } get_host_subarchitecture() { local arch=$1 case $arch in i386|amd64) # Skip the call to archdetect as that's what # get_host_architecture does echo generic ;; *) archdetect | cut -d'/' -f2 ;; esac } get_server_name() { local servername="$1"; _RET=${servername#*://}; _RET=${_RET%%/*}; echo "$_RET"; } enlist_node() { serverurl="${1}" mac="${2}" arch="${3}" subarch="${4}" hostname="${5}" power_type="${6}" power_params="${7}" local macparms="" macparms=$(get_mac_address_curl_parms "$mac") curl \ --data-urlencode "op=new" \ --data-urlencode "autodetect_nodegroup=1" \ --data-urlencode "hostname=${hostname}" \ --data-urlencode "architecture=${arch}" \ --data-urlencode "subarchitecture=${subarch}" \ --data-urlencode "after_commissioning_action=0" \ --data-urlencode "power_type=${power_type}" \ --data-urlencode "power_parameters=${power_params}" \ ${macparms} \ "${serverurl}" } Error () { echo "ERROR: $1" exit 1 } Usage() { cat <&2; [ $# -eq 0 ] || Error "$@"; exit 1; } short_opts="hs:n:i:a:t:p:" long_opts="help,serverurl:,hostname:,interface:,arch:,subarch:,power-type:,power-params:" getopt_out=$(getopt --name "${0##*/}" \ --options "${short_opts}" --long "${long_opts}" -- "$@") && eval set -- "${getopt_out}" || bad_Usage while [ $# -ne 0 ]; do cur=${1}; next=${2}; case "$cur" in -h|--help) Usage ; exit 0;; -s|--serverurl) serverurl=${2}; shift;; -n|--hostname) hostname=${2}; shift;; -i|--interface) iface=${2}; shift;; -a|--arch) arch=${2}; shift;; --subarch) subarch=${2}; shift;; -t|--power-type) power_type=${2}; shift;; -p|--power-params) power_parameters=${2}; shift;; --) shift; break;; esac shift; done ## check arguments here #[ $# -eq 0 ] && bad_Usage # If no interface is specified. obtain the MAC from all interfaces if [ -z "$iface" ]; then mac_addrs=$(get_mac_addresses) else mac_addrs=$(get_mac_address_by_interface "$iface") fi protocol= servername=$(get_server_name "$serverurl") if echo "$serverurl" | egrep -q '^[a-z]+://' ; then protocol=`echo "$serverurl" | sed 's#^\([a-z]\+\)://.*#\\1#'` else protocol="http" fi if [ "$protocol" != "http" ] && [ "$protocol" != "https" ]; then Error "Invalid protocol '$protocol'" fi if [ -z "$servername" ]; then serverurl="maas.local" servername="$serverurl" fi if echo "$serverurl" | egrep -q '(^[a-z]+://|^)[a-z0-9\.]+($|/$)'; then api_url="MAAS/api/1.0/nodes/" else api_url=`echo $serverurl | sed 's#^\(\|[a-z]\+://\)[a-zA-Z0-9\.]\+\(\|\:[0-9]\+\)/##'` fi #TODO: Auto-detect hostname? if [ -z "$hostname" ]; then continue #Error "No hostname has been provided" fi if [ -z "$arch" ]; then arch=$(get_host_architecture) fi if [ -z "$subarch" ]; then subarch=$(get_host_subarchitecture $arch) fi if [ -n "$power_type" ]; then case $power_type in ipmi) continue ;; virsh) continue ;; etherwake) continue ;; moonshot) continue ;; *) Error "Invalid power type: [$power_type]" esac fi enlist_node "$protocol://$servername/$api_url" "${mac_addrs}" "$arch" "$subarch" "$hostname" "$power_type" "$power_parameters" maas-enlist-0.4+bzr38.orig/bin/maas-signal0000755000000000000000000002064312276326714016534 0ustar 00000000000000#!/usr/bin/python from email.utils import parsedate import mimetypes import oauth.oauth as oauth import os.path import random import string import sys import time import urllib2 import yaml import json MD_VERSION = "2012-03-01" VALID_STATUS = ("OK", "FAILED", "WORKING") POWER_TYPES = ("ipmi", "virsh", "ether_wake") def _encode_field(field_name, data, boundary): return ('--' + boundary, 'Content-Disposition: form-data; name="%s"' % field_name, '', str(data)) def _encode_file(name, fileObj, boundary): return ('--' + boundary, 'Content-Disposition: form-data; name="%s"; filename="%s"' % (name, name), 'Content-Type: %s' % _get_content_type(name), '', fileObj.read()) def _random_string(length): return ''.join(random.choice(string.letters) for ii in range(length + 1)) def _get_content_type(filename): return mimetypes.guess_type(filename)[0] or 'application/octet-stream' def encode_multipart_data(data, files): """Create a MIME multipart payload from L{data} and L{files}. @param data: A mapping of names (ASCII strings) to data (byte string). @param files: A mapping of names (ASCII strings) to file objects ready to be read. @return: A 2-tuple of C{(body, headers)}, where C{body} is a a byte string and C{headers} is a dict of headers to add to the enclosing request in which this payload will travel. """ boundary = _random_string(30) lines = [] for name in data: lines.extend(_encode_field(name, data[name], boundary)) for name in files: lines.extend(_encode_file(name, files[name], boundary)) lines.extend(('--%s--' % boundary, '')) body = '\r\n'.join(lines) headers = {'content-type': 'multipart/form-data; boundary=' + boundary, 'content-length': str(len(body))} return body, headers def oauth_headers(url, consumer_key, token_key, token_secret, consumer_secret, clockskew=0): consumer = oauth.OAuthConsumer(consumer_key, consumer_secret) token = oauth.OAuthToken(token_key, token_secret) timestamp = int(time.time()) + clockskew params = { 'oauth_version': "1.0", 'oauth_nonce': oauth.generate_nonce(), 'oauth_timestamp': timestamp, 'oauth_token': token.key, 'oauth_consumer_key': consumer.key, } req = oauth.OAuthRequest(http_url=url, parameters=params) req.sign_request(oauth.OAuthSignatureMethod_PLAINTEXT(), consumer, token) return(req.to_header()) def geturl(url, creds, headers=None, data=None): # Takes a dict of creds to be passed through to oauth_headers, # so it should have consumer_key, token_key, ... if headers is None: headers = {} else: headers = dict(headers) clockskew = 0 def warn(msg): sys.stderr.write(msg + "\n") exc = Exception("Unexpected Error") for naptime in (1, 1, 2, 4, 8, 16, 32): if creds.get('consumer_key', None) != None: headers.update(oauth_headers(url, consumer_key=creds['consumer_key'], token_key=creds['token_key'], token_secret=creds['token_secret'], consumer_secret=creds['consumer_secret'], clockskew=clockskew)) try: req = urllib2.Request(url=url, data=data, headers=headers) return(urllib2.urlopen(req).read()) except urllib2.HTTPError as exc: if 'date' not in exc.headers: warn("date field not in %d headers" % exc.code) pass elif (exc.code == 401 or exc.code == 403): date = exc.headers['date'] try: ret_time = time.mktime(parsedate(date)) clockskew = int(ret_time - time.time()) warn("updated clock skew to %d" % clockskew) except: warn("failed to convert date '%s'" % date) except Exception as exc: pass warn("request to %s failed. sleeping %d.: %s" % (url, naptime, exc)) time.sleep(naptime) raise exc def read_config(url, creds): if url.startswith("http://") or url.startswith("https://"): cfg_str = urllib2.urlopen(urllib2.Request(url=url)) else: if url.startswith("file://"): url = url[7:] cfg_str = open(url,"r").read() cfg = yaml.safe_load(cfg_str) # Support reading cloud-init config for MAAS datasource. if 'datasource' in cfg: cfg = cfg['datasource']['MAAS'] for key in creds.keys(): if key in cfg and creds[key] == None: creds[key] = cfg[key] def fail(msg): sys.stderr.write("FAIL: %s" % msg) sys.exit(1) def main(): """ Call with single argument of directory or http or https url. If url is given additional arguments are allowed, which will be interpreted as consumer_key, token_key, token_secret, consumer_secret. """ import argparse import pprint parser = argparse.ArgumentParser( description='Send signal operation and optionally post files to MAAS') parser.add_argument("--config", metavar="file", help="Specify config file", default=None) parser.add_argument("--ckey", metavar="key", help="The consumer key to auth with", default=None) parser.add_argument("--tkey", metavar="key", help="The token key to auth with", default=None) parser.add_argument("--csec", metavar="secret", help="The consumer secret (likely '')", default="") parser.add_argument("--tsec", metavar="secret", help="The token secret to auth with", default=None) parser.add_argument("--apiver", metavar="version", help="The apiver to use ("" can be used)", default=MD_VERSION) parser.add_argument("--url", metavar="url", help="The data source to query", default=None) parser.add_argument("--file", dest='files', help="File to post", action='append', default=[]) parser.add_argument("--post", dest='posts', help="name=value pairs to post", action='append', default=[]) parser.add_argument("--power-type", dest='power_type', help="Power type.", choices=POWER_TYPES, default=None) parser.add_argument("--power-parameters", dest='power_parms', help="Power parameters.", default=None) parser.add_argument("status", help="Status", choices=VALID_STATUS, action='store') parser.add_argument("message", help="Optional message", default="", nargs='?') args = parser.parse_args() creds = {'consumer_key': args.ckey, 'token_key': args.tkey, 'token_secret': args.tsec, 'consumer_secret': args.csec, 'metadata_url': args.url} if args.config: read_config(args.config, creds) url = creds.get('metadata_url', None) if not url: fail("URL must be provided either in --url or in config\n") url = "%s/%s/" % (url, args.apiver) params = { "op": "signal", "status": args.status, "error": args.message} for ent in args.posts: try: (key, val) = ent.split("=", 2) except ValueError: sys.stderr.write("'%s' had no '='" % ent) sys.exit(1) params[key] = val if args.power_parms is not None: params["power_type"] = args.power_type power_parms = dict( power_user=args.power_parms.split(",")[0], power_pass=args.power_parms.split(",")[1], power_address=args.power_parms.split(",")[2] ) params["power_parameters"] = json.dumps(power_parms) files = {} for fpath in args.files: files[os.path.basename(fpath)] = open(fpath, "r") data, headers = encode_multipart_data(params, files) exc = None msg = "" try: payload = geturl(url, creds=creds, headers=headers, data=data) if payload != "OK": raise TypeError("Unexpected result from call: %s" % payload) else: msg = "Success" except urllib2.HTTPError as exc: msg = "http error [%s]" % exc.code except urllib2.URLError as exc: msg = "url error [%s]" % exc.reason except socket.timeout as exc: msg = "socket timeout [%s]" % exc except TypeError as exc: msg = exc.message except Exception as exc: msg = "unexpected error [%s]" % exc sys.stderr.write("%s\n" % msg) sys.exit((exc is None)) if __name__ == '__main__': main() maas-enlist-0.4+bzr38.orig/man/maas-enlist.10000644000000000000000000000204212276326714016705 0ustar 00000000000000.TH USAGE: "1" "maas-enlist" .SH NAME maas-enlist -- MaaS Enlistment tool, for enlisting with a MaaS server over a network .SH SYNOPSIS .B maas-enlist --serverurl=[protocol://]127.0.0.1 --hostname=test-node --mac-address=AA:BB:CC:DD:EE:FF,AA:BB:CC:DD:EE:F1 .SH DESCRIPTION .IP : maas\-enlist .PP Parameters: .TP \fB\-s\fR, \fB\-\-serverurl\fR \fB\-\-\fR resolvable IP or hostname of the MaaS server. May optionally prefix http:// or https:// to explicitly set the protocol. If unspecified, the protocol is http://. .TP \fB\-n\fR, \fB\-\-hostname\fR \fB\-\-\fR hostname to assign the node .TP \fB\-i\fR, \fB\-\-interface\fR \fB\-\-\fR network interface to register .TP \fB\-a\fR, \fB\-\-arch\fR \fB\-\-\fR architecture to register the node with .HP \fB\-\-interface\fR is optional; if not specified, all network interfaces will be registered .IP all other parameters are required .SH "WARNING" When using http:// as the protocol, all traffic sent unencrypted. It is strongly recommended that http:// only be used in a trusted network segment. maas-enlist-0.4+bzr38.orig/sbin/maas-ipmi-autodetect0000755000000000000000000000736712276326714020547 0ustar 00000000000000#!/usr/bin/python import os import commands 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: 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 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("--comission-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 60 seconds to obtain an IP address time.sleep(60) # create user/pass if args.commission_creds: IPMI_MAAS_USER="maas-commissioning" else: 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 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()