<commit_before>#!/bin/bash
#
# Copyright (c) 2013, Joyent, Inc., All rights reserved.
#
# These upgrade hooks are called from headnode.sh during the first boot
# after we initiated the upgrade in order to complete the upgrade steps.
#
# Usage:
#       ${SDC_UPGRADE_DIR}/upgrade_hooks.sh HOOK [ZONENAME]
#
# The "pre" and "post" hooks are called before headnode does any setup
# and after the setup is complete.
#
# The role-specific hooks are called after each zone role has been setup.
#

unset LD_LIBRARY_PATH
PATH=/usr/bin:/usr/sbin:/opt/smartdc/bin:/smartdc/bin
export PATH

BASH_XTRACEFD=4
export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -o xtrace

. /lib/sdc/config.sh



#---- globals

# time to wait for each zone to setup (in seconds)
ZONE_SETUP_TIMEOUT=180

SDC_UPGRADE_DIR=/var/upgrade_headnode

# We have to install the extra zones in dependency order
EXTRA_ZONES="sdcsso cloudapi"



#---- setup state support
# "/var/lib/setup.json" support is duplicated in headnode.sh and
# upgrade_hooks.sh. These must be kept in sync.
# TODO: share these somewhere

SETUP_FILE=/var/lib/setup.json

function update_setup_state
{
    STATE=$1

    chmod 600 $SETUP_FILE
    cat "$SETUP_FILE" | json -e \
        "this.current_state = '$STATE';
         this.last_updated = new Date().toISOString();
         this.seen_states.push('$STATE');" \
        | tee ${SETUP_FILE}.new
    mv ${SETUP_FILE}.new $SETUP_FILE
    chmod 400 $SETUP_FILE
}

function mark_as_setup
{
    chmod 600 $SETUP_FILE
    # Update the setup state file with the new value
    cat "$SETUP_FILE" | json -e "this.complete = true;
         this.current_state = 'setup_complete';
         this.seen_states.push('setup_complete');
         this.last_updated = new Date().toISOString();" \
        | tee ${SETUP_FILE}.new
    mv ${SETUP_FILE}.new $SETUP_FILE
    chmod 400 $SETUP_FILE
    sysinfo -u
}


#---- support functions

saw_err()
{
    echo "    $1" >> ${SDC_UPGRADE_DIR}/error_finalize.txt
}

shutdown_zone()
{
	zlogin $1 /usr/sbin/shutdown -y -g 0 -i 5 1>&4 2>&1

	# Check for zone being down and halt it forcefully if needed
	local cnt=0
	while [[ $cnt -lt 18 ]]; do
		sleep 5
		local zstate=`zoneadm -z $1 list -p | cut -f3 -d:`
		[[ "$zstate" == "installed" ]] && break
		cnt=$(($cnt + 1))
	done

	# After 90 seconds, shutdown harder
	[[ $cnt == 18 ]] && zoneadm -z $1 halt
}

print_log()
{
    echo "$@" | tee -a /tmp/upgrade_progress >/dev/console
}

create_extra_zones()
{
    declare -A existing_zones=()

    for i in `sdc-role list | nawk '{if ($6 != "ROLE") print $6}'`
    do
        existing_zones[$i]=1
    done

    local new_uuid=
    local loops=
    local zonepath=
    local ext_ip=
    local ext_ip_arg=
    local res=
    local hn_uuid=$(sysinfo | json UUID)

    for i in $EXTRA_ZONES
    do
        [[ ${existing_zones[$i]} == 1 ]] && continue

        print_log "creating zone $i..."

        ext_ip=`nawk -v role=$i '{if ($1 == role) print $2 }' \
            ${SDC_UPGRADE_DIR}/ext_addrs.txt`
        ext_ip_arg=""
        [ -n "$ext_ip" ] && ext_ip_arg="-o external_ip=$ext_ip"

        sdc-role create $ext_ip_arg $hn_uuid $i 1>/tmp/role.out.$$ 2>&1
        res=$?
        cat /tmp/role.out.$$ 1>&4
        if [ $res != 0 ]; then
            saw_err "Error creating $i zone"
            mv /tmp/payload.* ${SDC_UPGRADE_DIR}
            mv /tmp/provision.* ${SDC_UPGRADE_DIR}

            # Capture the job info into the log
            local job=`nawk '/Job is/{print $NF}' /tmp/role.out.$$`
            [ -n "$job" ] && \
                curl -i -s \
                    http://${CONFIG_vmapi_admin_ips}/${job} | json 1>&4 2>&1

            rm -f /tmp/role.out.$$
            continue
        fi
        rm -f /tmp/role.out.$$

        new_uuid=`sdc-role list | nawk -v role=$i '{if ($6 == role) print $3}'`
        if [[ -z "$new_uuid" ]]; then
            saw_err "Error creating $i zone: not found"
            continue
        fi

        zonepath=$(vmadm get ${new_uuid} | json zonepath)
        if [[ -z ${zonepath} ]]; then
            saw_err "Error creating $i zone: no zonepath"
            continue
        fi

        loops=0
        while [[ ! -f ${zonepath}/root/var/svc/setup_complete \
            && ! -f ${zonepath}/root/var/svc/setup_failed \
            && $loops -lt ${ZONE_SETUP_TIMEOUT} ]]
        do
            sleep 1
            loops=$((${loops} + 1))
        done

        if [[ ${loops} -lt ${ZONE_SETUP_TIMEOUT} && \
            -f ${zonepath}/root/var/svc/setup_complete ]]; then

            # Got here and complete, now just wait for services.
            while [[ -n $(svcs -xz ${new_uuid}) && \
                $loops -lt ${ZONE_SETUP_TIMEOUT} ]]
            do
                sleep 1
                loops=$((${loops} + 1))
            done
        fi

        if [[ ${loops} -ge ${ZONE_SETUP_TIMEOUT} ]]; then
            saw_err "Error creating $i zone: setup timed out"
        elif [[ -f ${zonepath}/root/var/svc/setup_failed ]]; then
            saw_err "Error creating $i zone: setup failed"
        elif [[ -n $(svcs -xz ${new_uuid}) ]]; then
            saw_err "Error creating $i zone: svcs error"
        else
            # Zone is setup ok, run the post-setup hook
            print_log "upgrading zone $i..."
            ${SDC_UPGRADE_DIR}/upgrade_hooks.sh $i ${new_uuid} \
              4>${SDC_UPGRADE_DIR}/finish_${i}.log
        fi
    done
}

convert_portal_zone()
{
    zoneadm -z portal list -p >/dev/null 2>&1
    [ $? -ne 0 ] && return

    local uuid=`zonecfg -z portal info uuid | cut -d' ' -f2`

    if [ -z "$uuid" ]; then
        saw_err "Error: portal zone is missing a UUID"
        return
    fi

    zoneadm -z portal move /zones/$uuid
    zonecfg -z portal set zonename=$uuid
    vmadm update $uuid alias=portal0
    echo '{"set_tags": {"smartdc_role": "portal"}}' | vmadm update $uuid
    zoneadm -z $uuid boot
}

pre_tasks()
{
    # If pre-existing portal zone, shut it down for now.
    zoneadm -z portal halt >/dev/null 2>&1

    # The following img setup code duplicates the imgadm setup behavior from
    # joysetup.sh. That work is done on initial install of the HN, but
    # joysetup.sh is not run when we upgrade a installed HN.

    if [[ ! -f /var/db/imgadm/sources.list ]]; then
        # For now we initialize with the global one since we don't have a local
        # imgapi yet.
        mkdir -p /var/db/imgadm
        echo "https://datasets.joyent.com/datasets/" \
            > /var/db/imgadm/sources.list
        imgadm update
    fi

    if [[ ! -f /var/imgadm/imgadm.conf ]]; then
        # pickup config
        load_sdc_config

        mkdir -p /var/imgadm
        imgapi_url=http://$(echo $CONFIG_imgapi_admin_ips | cut -d, -f1)
        echo '{}' | /usr/bin/json -e "this.sources=[{\"url\": \"$imgapi_url\", \"type\": \"imgapi\"}]" \
            > /var/imgadm/imgadm.conf
    fi

    # Now create the install progress status file that is required by
    # headnode.sh. This is normally done in joysetup.sh, but again, we don't
    # run that on upgrade.
    if [[ -e /var/lib/setup.json ]]; then
        chmod +w /var/lib/setup.json
    fi
    echo "{" \
        "\"node_type\": \"headnode\"," \
        "\"start_time\": \"$(date "+%Y-%m-%dT%H:%M:%SZ")\"," \
        "\"current_state\": \"imgadm_setup\"," \
        "\"seen_states\": [" \
        "\"zpool_created\"," \
        "\"filesystems_setup\"," \
        "\"imgadm_setup\"" \
        "]," \
        "\"complete\": false," \
        "\"last_updated\": \"$(date "+%Y-%m-%dT%H:%M:%SZ")\"" \
        "}" >/var/lib/setup.json
    chmod 400 /var/lib/setup.json

    print_log \
        "If an unrecoverable error occurs, use sdc-rollback to return to 6.5"
}

post_tasks()
{
    # Need to wait for all svcs to be up before we can create additional zones
    # Give headnode.sh a second to emit all of its messages.
    sleep 1
    print_log "Upgrade: waiting for all svcs to be ready..."
    loops=0
    while [[ -n $(svcs -x) && $loops -lt ${ZONE_SETUP_TIMEOUT} ]]<commit_msg>HEAD-1467 changes for HEAD-1463 needed in upgrade too<commit_after>#!/bin/bash
#
# Copyright (c) 2013, Joyent, Inc., All rights reserved.
#
# These upgrade hooks are called from headnode.sh during the first boot
# after we initiated the upgrade in order to complete the upgrade steps.
#
# Usage:
#       ${SDC_UPGRADE_DIR}/upgrade_hooks.sh HOOK [ZONENAME]
#
# The "pre" and "post" hooks are called before headnode does any setup
# and after the setup is complete.
#
# The role-specific hooks are called after each zone role has been setup.
#

unset LD_LIBRARY_PATH
PATH=/usr/bin:/usr/sbin:/opt/smartdc/bin:/smartdc/bin
export PATH

BASH_XTRACEFD=4
export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -o xtrace

. /lib/sdc/config.sh



#---- globals

# time to wait for each zone to setup (in seconds)
ZONE_SETUP_TIMEOUT=180

SDC_UPGRADE_DIR=/var/upgrade_headnode

# We have to install the extra zones in dependency order
EXTRA_ZONES="sdcsso cloudapi"



#---- setup state support
# "/var/lib/setup.json" support is duplicated in headnode.sh and
# upgrade_hooks.sh. These must be kept in sync.
# TODO: share these somewhere

SETUP_FILE=/var/lib/setup.json

function update_setup_state
{
    STATE=$1

    chmod 600 $SETUP_FILE
    cat "$SETUP_FILE" | json -e \
        "this.current_state = '$STATE';
         this.last_updated = new Date().toISOString();
         this.seen_states.push('$STATE');" \
        | tee ${SETUP_FILE}.new
    mv ${SETUP_FILE}.new $SETUP_FILE
    chmod 400 $SETUP_FILE
}

function mark_as_setup
{
    chmod 600 $SETUP_FILE
    # Update the setup state file with the new value
    cat "$SETUP_FILE" | json -e "this.complete = true;
         this.current_state = 'setup_complete';
         this.seen_states.push('setup_complete');
         this.last_updated = new Date().toISOString();" \
        | tee ${SETUP_FILE}.new
    mv ${SETUP_FILE}.new $SETUP_FILE
    chmod 400 $SETUP_FILE
    sysinfo -u
}


#---- support functions

saw_err()
{
    echo "    $1" >> ${SDC_UPGRADE_DIR}/error_finalize.txt
}

shutdown_zone()
{
	zlogin $1 /usr/sbin/shutdown -y -g 0 -i 5 1>&4 2>&1

	# Check for zone being down and halt it forcefully if needed
	local cnt=0
	while [[ $cnt -lt 18 ]]; do
		sleep 5
		local zstate=`zoneadm -z $1 list -p | cut -f3 -d:`
		[[ "$zstate" == "installed" ]] && break
		cnt=$(($cnt + 1))
	done

	# After 90 seconds, shutdown harder
	[[ $cnt == 18 ]] && zoneadm -z $1 halt
}

print_log()
{
    echo "$@" | tee -a /tmp/upgrade_progress >/dev/console
}

create_extra_zones()
{
    declare -A existing_zones=()

    for i in `sdc-role list | nawk '{if ($6 != "ROLE") print $6}'`
    do
        existing_zones[$i]=1
    done

    local new_uuid=
    local loops=
    local zonepath=
    local ext_ip=
    local ext_ip_arg=
    local res=
    local hn_uuid=$(sysinfo | json UUID)

    for i in $EXTRA_ZONES
    do
        [[ ${existing_zones[$i]} == 1 ]] && continue

        print_log "creating zone $i..."

        ext_ip=`nawk -v role=$i '{if ($1 == role) print $2 }' \
            ${SDC_UPGRADE_DIR}/ext_addrs.txt`
        ext_ip_arg=""
        [ -n "$ext_ip" ] && ext_ip_arg="-o external_ip=$ext_ip"

        sdc-role create $ext_ip_arg $hn_uuid $i 1>/tmp/role.out.$$ 2>&1
        res=$?
        cat /tmp/role.out.$$ 1>&4
        if [ $res != 0 ]; then
            saw_err "Error creating $i zone"
            mv /tmp/payload.* ${SDC_UPGRADE_DIR}
            mv /tmp/provision.* ${SDC_UPGRADE_DIR}

            # Capture the job info into the log
            local job=`nawk '/Job is/{print $NF}' /tmp/role.out.$$`
            [ -n "$job" ] && \
                curl -i -s \
                    http://${CONFIG_vmapi_admin_ips}/${job} | json 1>&4 2>&1

            rm -f /tmp/role.out.$$
            continue
        fi
        rm -f /tmp/role.out.$$

        new_uuid=`sdc-role list | nawk -v role=$i '{if ($6 == role) print $3}'`
        if [[ -z "$new_uuid" ]]; then
            saw_err "Error creating $i zone: not found"
            continue
        fi

        zonepath=$(vmadm get ${new_uuid} | json zonepath)
        if [[ -z ${zonepath} ]]; then
            saw_err "Error creating $i zone: no zonepath"
            continue
        fi

        loops=0
        while [[ ! -f ${zonepath}/root/var/svc/setup_complete \
            && ! -f ${zonepath}/root/var/svc/setup_failed \
            && $loops -lt ${ZONE_SETUP_TIMEOUT} ]]
        do
            sleep 1
            loops=$((${loops} + 1))
        done

        if [[ ${loops} -lt ${ZONE_SETUP_TIMEOUT} && \
            -f ${zonepath}/root/var/svc/setup_complete ]]; then

            # Got here and complete, now just wait for services.
            while [[ -n $(svcs -xz ${new_uuid}) && \
                $loops -lt ${ZONE_SETUP_TIMEOUT} ]]
            do
                sleep 1
                loops=$((${loops} + 1))
            done
        fi

        if [[ ${loops} -ge ${ZONE_SETUP_TIMEOUT} ]]; then
            saw_err "Error creating $i zone: setup timed out"
        elif [[ -f ${zonepath}/root/var/svc/setup_failed ]]; then
            saw_err "Error creating $i zone: setup failed"
        elif [[ -n $(svcs -xz ${new_uuid}) ]]; then
            saw_err "Error creating $i zone: svcs error"
        else
            # Zone is setup ok, run the post-setup hook
            print_log "upgrading zone $i..."
            ${SDC_UPGRADE_DIR}/upgrade_hooks.sh $i ${new_uuid} \
              4>${SDC_UPGRADE_DIR}/finish_${i}.log
        fi
    done
}

convert_portal_zone()
{
    zoneadm -z portal list -p >/dev/null 2>&1
    [ $? -ne 0 ] && return

    local uuid=`zonecfg -z portal info uuid | cut -d' ' -f2`

    if [ -z "$uuid" ]; then
        saw_err "Error: portal zone is missing a UUID"
        return
    fi

    zoneadm -z portal move /zones/$uuid
    zonecfg -z portal set zonename=$uuid
    vmadm update $uuid alias=portal0
    echo '{"set_tags": {"smartdc_role": "portal"}}' | vmadm update $uuid
    zoneadm -z $uuid boot
}

pre_tasks()
{
    # If pre-existing portal zone, shut it down for now.
    zoneadm -z portal halt >/dev/null 2>&1

    # The following img setup code duplicates the imgadm setup behavior from
    # joysetup.sh. That work is done on initial install of the HN, but
    # joysetup.sh is not run when we upgrade a installed HN.

    # imgadm setup to use the IMGAPI in this DC.
    if [[ ! -f /var/imgadm/imgadm.conf ]]; then
        mkdir -p /var/imgadm
        echo '{}' > /var/imgadm/imgadm.conf
    fi
    if [[ -z "$(json -f /var/imgadm/imgadm.conf sources)" ]]; then
        # pickup config
        load_sdc_config

        imgapi_url=http://$(echo $CONFIG_imgapi_admin_ips | cut -d, -f1)
        imgadm sources -f -a $imgapi_url
    fi

    # Now create the install progress status file that is required by
    # headnode.sh. This is normally done in joysetup.sh, but again, we don't
    # run that on upgrade.
    if [[ -e /var/lib/setup.json ]]; then
        chmod +w /var/lib/setup.json
    fi
    echo "{" \
        "\"node_type\": \"headnode\"," \
        "\"start_time\": \"$(date "+%Y-%m-%dT%H:%M:%SZ")\"," \
        "\"current_state\": \"imgadm_setup\"," \
        "\"seen_states\": [" \
        "\"zpool_created\"," \
        "\"filesystems_setup\"," \
        "\"imgadm_setup\"" \
        "]," \
        "\"complete\": false," \
        "\"last_updated\": \"$(date "+%Y-%m-%dT%H:%M:%SZ")\"" \
        "}" >/var/lib/setup.json
    chmod 400 /var/lib/setup.json

    update_setup_state "imgadm_setup"

    print_log \
        "If an unrecoverable error occurs, use sdc-rollback to return to 6.5"
}

post_tasks()
{
    # Need to wait for all svcs to be up before we can create additional zones
    # Give headnode.sh a second to emit all of its messages.
    sleep 1
    print_log "Upgrade: waiting for all svcs to be ready..."
    loops=0
    while [[ -n $(svcs -x) && $loops -lt ${ZONE_SETUP_TIMEOUT} ]]
{'fraction_non_alphanumeric': 0.14321497902185484, 'fraction_numerical': 0.010896111215479993, 'mean_word_length': 2.143082070458571, 'pattern_counts': {'":': 18, '<': 3, '<?xml version=': 0, '>': 38, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6232741', 'n_tokens_mistral': 5754, 'n_tokens_neox': 5442, 'n_words': 1572}