#!/usr/bin/env python

# Copyright C 2002-2011 by Isilon Systems, Inc. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
# 
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
# 
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems. 
#  
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

# PROVIDE: isi_create_hardware_xml
# REQUIRE: isi_pre_network isi_dongle_init isi_vmware_init isi_hal_init

"""
Generates the HARDWARE_XML file. This script runs only after an
isi_reformat_node (formerly known as isi_reset).

This document consists of:

    - isilon node
        - drives node
        - journal node
        - journal log disk node (if journal logging enabled)
        - type node
        - network node

"""

HARDWARE_XML = '/etc/ifs/hardware.xml'

import os
import sys
import xml.dom.minidom as xmldom
import getopt

import isi.hw.hal as hal
import isi.fs.linearjournal as linearjournal

JDEV = ""

def create_drives(doc):
    global JDEV
    drives = doc.createElement('drives')

    # We only care about the drives in storage nodes
    if hal.isStorageClass() or hal.supportsCto():
        for drive in ['da', 'twed']:
            d_match = doc.createElement('drive-match')
            d_match.setAttribute('partition', 's1e')
            d_match.setAttribute('prefix', drive)
            drives.appendChild(d_match)

    ''' If journal is on disk, add it to exclude list '''
    if JDEV and (JDEV <> hal.getNvramDeviceName()):
        exclude_drv = doc.createElement('drive-exclude')
        exclude_drv.appendChild(doc.createTextNode(JDEV))
        drives.appendChild(exclude_drv)

    return drives

def create_journal(doc, force = False, jrndev = None):
    """Creates the <journal> tag."""

    global JDEV
    journal = doc.createElement('journal')

    ''' Short-circuting for now to run standard regressions '''
    if hal.hasNvram() and not force:
        journal.appendChild(doc.createTextNode('/dev/' + hal.getNvramDeviceName()))
    elif (force or (hal.isVirtualSeries and not hal.hasNvram())) and hal.isStorageClass():
        JDEV, drive = linearjournal.create_journal_device(force, jrndev)
        if drive is not None:
            journal.appendChild(doc.createTextNode(drive))

    return journal

def create_journal_log(doc, guid):
    """Creates the <journal-log> tag."""

    journal_log = doc.createElement('journal-log')
    journal_log.appendChild(doc.createTextNode(guid))

    return journal_log

def create_type(doc):
    """Creates the <type> tag."""

    dtype = doc.createElement('type')

    if hal.isAcceleratorClass():
        dtype.appendChild(doc.createTextNode('diskless'))
    elif hal.isStorageClass() or hal.supportsCto():
        dtype.appendChild(doc.createTextNode('storage'))

    return dtype

def exclude_journal_disk(doc, old_journal):
    global JDEV
    present = False
    new_journal = JDEV
    drives = doc.getElementsByTagName('drives')
    exclude_drives = doc.getElementsByTagName('drive-exclude')

    ''' See if journal disk is already in exclude-drive list
    	and remove old_journal disk from the list '''
    for exdrv in exclude_drives:
        for node in exdrv.childNodes:
            if ((node.data).strip()) in old_journal:
                drives[0].removeChild(node)
            elif new_journal in node.data:
                present = True

    ''' Add the journal disk to exclude-disk '''
    if present is not True:
        exclude_drv = doc.createElement('drive-exclude')
        exclude_drv.appendChild(doc.createTextNode(JDEV))
        drives[0].appendChild(exclude_drv)

def modify_hw_xml():
    global JDEV
    """Updates journal (disk) if changed."""
    doc = xmldom.parse(open(HARDWARE_XML))
    journal = doc.getElementsByTagName('journal')
    if journal[0].firstChild is None:
        return
    cur_journal = journal[0].firstChild.nodeValue
    if hal.getNvramDeviceName() and hal.getNvramDeviceName() not in cur_journal:
        JDEV, drive = linearjournal.get_journal_device()
        if drive not in cur_journal:
            ''' Device name of journal disk has changed upon reboot,
            update journal tag accordingly and disk in drive-exclude list '''
            journal[0].removeChild(journal[0].firstChild)
            journal[0].appendChild(doc.createTextNode(drive))
            exclude_journal_disk(doc, cur_journal)
            doc.writexml(open(HARDWARE_XML + '~', 'w'))
            os.rename(HARDWARE_XML + '~', HARDWARE_XML)
            os.chmod(HARDWARE_XML, 0640)

def create_hw_xml(guid=None, force=False, jrndev=None):
    """Creates the HARDWARE_XML document."""

    if not force and os.path.exists(HARDWARE_XML) and guid is None:
        modify_hw_xml()
        print 'Hardware configuration exists, creation skipped.'
        return

    impl = xmldom.getDOMImplementation()

    hwxml = impl.createDocument(None, "isilon", None)
    root = hwxml.documentElement
    ''' NB: Ordering is important, if journal is chosen to be
    	on 'disk', then we need to add that disk in '<drive-exclude>'
	in order for newfs_efs to ignore while formating drives '''
    root.appendChild(create_journal(hwxml, force, jrndev))
    root.appendChild(create_drives(hwxml))
    if guid is not None and guid != "jlog_disable":
        root.appendChild(create_journal_log(hwxml, guid))

    root.appendChild(create_type(hwxml))

    hwxml.writexml(open(HARDWARE_XML + '~', 'w'), '', ' ', '\n')
    os.rename(HARDWARE_XML + '~', HARDWARE_XML)
    os.chmod(HARDWARE_XML, 0640)

    print 'Hardware configuration created.'

def main(argv):
    force = False
    guid = None
    jrndev = None
    
    opts, args = getopt.getopt(sys.argv[1:], 'fd:')
    for opt, val in opts:
        if opt == '-f':
            force = True
        elif opt == '-d':
            guid = val
   
    if args:
	jrndev = args.pop() 
	if "/dev/" in jrndev:
	   jrndev = jrndev[5:]

    create_hw_xml(guid, force, jrndev)
    return 0

if __name__ == '__main__':
    sys.exit(main(sys.argv))

