#!/usr/bin/bash

. /usr/libexec/vstorage-ui-backend/libexec/keystone-functions.sh

PSQL="sudo -iu postgres psql --no-align --tuples-only --quiet"

OS_PASSWORD=$(get_keystone_pswd) || return 1

MAGNUM_DOMAIN_ID=$($PSQL keystone -c "select id from project where is_domain='t' and name='magnum'")
if [ -z "$MAGNUM_DOMAIN_ID" ]; then
    >&2 echo Unable to find project_admin role ID
    exit 1
fi

PROJECT_ADMIN_ROLE_ID=$($PSQL keystone -c "select id from role where name='project_admin'")
if [ -z "$PROJECT_ADMIN_ROLE_ID" ]; then
    >&2 echo Unable to find project_admin role ID
    exit 1
fi

CLUSTER_UUID=$1
REQ_NEW_USER_ID=$2
DRY_RUN=""

if [ -z "$CLUSTER_UUID" ]; then
    # no parameters passed - dry run
    DRY_RUN="true"
fi

if [ -z "$CLUSTER_UUID" ] || [ "$CLUSTER_UUID" = "all" ]; then
    TRUSTS=$($PSQL magnum -c "select trust_id from cluster")
else
    TRUSTS=$($PSQL magnum -v "cluster=$CLUSTER_UUID" <<< "select trust_id from cluster where uuid=:'cluster'")
fi

if [ ! -z "$REQ_NEW_USER_ID" ]; then
    FOUND_USER_ID=$($PSQL keystone -v "user_id=$REQ_NEW_USER_ID" <<< "select user_id from local_user where user_id=:'user_id'")
    if [ -z "$FOUND_USER_ID" ]; then
         >&2 echo Unable to find user with id '"'"$REQ_NEW_USER_ID"'"'
         exit 1
    fi
fi

if [ "$DRY_RUN" = "true" ]; then
    >&2 echo Running in dry run mode
fi

for TRUST in $TRUSTS; do
    CLUSTER_UUID=$($PSQL magnum -c "select uuid from cluster where trust_id='$TRUST'")
    TRUSTOR_DOMAIN_ID=$($PSQL keystone -c "select domain_id from trust join local_user on local_user.user_id=trust.trustor_user_id where trust.id='"$TRUST"'")
    if [[ "$MAGNUM_DOMAIN_ID" == "$TRUSTOR_DOMAIN_ID" ]] && [ -z "$REQ_NEW_USER_ID" ]; then
        >&2 echo Skipping $CLUSTER_UUID with trust $TRUST because it is already owned by a service user
        continue
    fi

    # collect some facts
    TRUSTEE_NAME=$($PSQL magnum  -c "select trustee_username from cluster where trust_id='$TRUST'")
    TRUSTEE_USER_ID=$($PSQL magnum -c "select trustee_user_id from cluster where trust_id='$TRUST'")
    TRUSTEE_PASSWORD=$($PSQL magnum -c "select trustee_password from cluster where trust_id='$TRUST'")
    CLUSTER_PROJECT_ID=$($PSQL magnum -c "select project_id from cluster where trust_id='$TRUST'")
    CLUSTER_STACK_ID=$($PSQL magnum -c "select stack_id from cluster where trust_id='$TRUST'")
    STACK_USER_CREDS_ID=$($PSQL heat -c "select user_creds_id from stack where id='$CLUSTER_STACK_ID'")
    STACK_ENCODED_TRUST_ID=$($PSQL heat -c "select trust_id from user_creds where id='$STACK_USER_CREDS_ID'")

    # "notgood but just long ..." is default heat encryption key
    STACK_TRUST_ID=$(python -c "from oslo_utils import encodeutils;from cryptography import fernet; import base64; print(fernet.Fernet(base64.b64encode(('notgood but just long enough i t' * 2)[:32].encode('utf-8'))).decrypt(encodeutils.safe_encode('$STACK_ENCODED_TRUST_ID')))")

    NEW_USER_ID=$REQ_NEW_USER_ID
    if [ -z "$REQ_NEW_USER_ID" ]; then
        TEMPFILE=$(mktemp /tmp/reassign-coe-cluster-XXXXX)
        if [ $? -ne 0 ]; then
              >&2 echo Unable to create a temporary file for cluster $CLUSTER_UUID
              continue
        fi

        # get user's public key used for the cluster
        KEY_PAIR=$($PSQL magnum -c "select keypair from cluster where trust_id='$TRUST'")
        OS_AUTH_URL=$OS_AUTH_URL OS_USER_ID=$TRUSTEE_USER_ID OS_PASSWORD=$TRUSTEE_PASSWORD OS_TRUST_ID=$TRUST OS_AUTH_URL=https://127.0.0.1:35357/v3 OS_PROJECT_ID="" OS_PROJECT_NAME="" \
            openstack --insecure keypair show $KEY_PAIR --public-key > "$TEMPFILE"

        if [ ! -s "$TEMPFILE" ]; then
             # skip if public key is not available
             >&2 echo Skipping cluster $CLUSTER_UUID because public key $KEY_PAIR is not available from current trustee user
             rm -f "$TEMPFILE"
             continue
        fi

        if [ "$DRY_RUN" = "true" ]; then
            >&2 echo Cluster $CLUSTER_UUID is ready for trust reconfiguration
            continue
        fi

        >&2 echo Reassigning cluster $CLUSTER_UUID

        # get or create a service user
        NEW_USER_ID=$(OS_PASSWORD=$OS_PASSWORD openstack $OPENSTACK_CLIENT_ARGS user show --domain magnum "$TRUSTEE_NAME"_"$TRUSTEE_USER_ID" -c id -f value || \
                      OS_PASSWORD=$OS_PASSWORD openstack $OPENSTACK_CLIENT_ARGS user create --domain magnum "$TRUSTEE_NAME"_"$TRUSTEE_USER_ID" -c id -f value)

        if [ -z "$NEW_USER_ID" ]; then
             >&2 echo Unable to create a new service user for cluster $CLUSTER_UUID
             rm -f "$TEMPFILE"
             continue
        fi
        >&2 echo New service user ID for cluster $CLUSTER_UUID is $NEW_USER_ID

        # assign service user's password
        OS_PASSWORD=$OS_PASSWORD openstack $OPENSTACK_CLIENT_ARGS user set $NEW_USER_ID --password $TRUSTEE_PASSWORD  # stupid openstack set --password-prompt works only in TTY
        if [ $? -ne 0 ]; then
             >&2 echo Skipping cluster $CLUSTER_UUID because unable to set password for new service user $NEW_USER_ID
             continue
        fi

        # assign role for the service user in the project
        OS_PASSWORD=$OS_PASSWORD openstack $OPENSTACK_CLIENT_ARGS role add --user $NEW_USER_ID --project $CLUSTER_PROJECT_ID $PROJECT_ADMIN_ROLE_ID || exit 1
        if [ $? -ne 0 ]; then
             >&2 echo Skipping cluster $CLUSTER_UUID because unable to add role for new service user $NEW_USER_ID
             rm -f "$TEMPFILE"
             continue
        fi

        # upload user's public key for the service user
        OS_PASSWORD=$TRUSTEE_PASSWORD OS_AUTH_URL=$OS_AUTH_URL OS_USER_ID=$NEW_USER_ID OS_PROJECT_ID=$CLUSTER_PROJECT_ID openstack --insecure keypair show $KEY_PAIR --public-key > "$TEMPFILE-1" || \
            OS_PASSWORD=$TRUSTEE_PASSWORD OS_AUTH_URL=$OS_AUTH_URL OS_USER_ID=$NEW_USER_ID OS_PROJECT_ID=$CLUSTER_PROJECT_ID openstack --insecure keypair create $KEY_PAIR --public-key "$TEMPFILE"
        rm -f "$TEMPFILE" "$TEMPFILE-1"
        if [ $? -ne 0 ]; then
             >&2 echo Skipping cluster $CLUSTER_UUID because unable to create a key pair $KEY_PAIR for new service user $NEW_USER_ID
             continue
        fi
    fi

    # since 5.3 we use only project_admin role in coe cluster trust, these two commands fixes trust state in Keystone DB, we don't need to fix heat trust as it always used Member role
    $PSQL keystone -c "insert into trust_role (trust_id, role_id) values ('$TRUST', '$PROJECT_ADMIN_ROLE_ID')" 2>/dev/null
    $PSQL keystone -c "delete from trust_role where trust_id='$TRUST' and role_id!='$PROJECT_ADMIN_ROLE_ID'"

    # reassign all trusts and records in Keystone, Magnum and Heat DBs to new service user
    $PSQL keystone -c "update trust set trustor_user_id='$NEW_USER_ID', extra=(extra::jsonb||'"'{"roles":[{"id": "'$PROJECT_ADMIN_ROLE_ID'"}]}'"')::text where id='$TRUST'"
    $PSQL keystone -c "update trust set trustor_user_id='$NEW_USER_ID' where id='$STACK_TRUST_ID'"
    $PSQL heat -c "update user_creds set trustor_user_id='$NEW_USER_ID' where id='$STACK_USER_CREDS_ID';"
    $PSQL magnum -c "update cluster set user_id='$NEW_USER_ID' where trust_id='$TRUST';"

    >&2 echo Cluster $CLUSTER_UUID trust $TRUST and stack trust $STACK_TRUST_ID have been reconfigured

    # each extra nodegroup has own stack and such stack has own trust we need to patch
    NODEGROUP_STACK_IDS=$($PSQL magnum -c "select stack_id from nodegroup where cluster_id='$CLUSTER_UUID' and name not in ('default-master', 'default-worker')")
    for CLUSTER_STACK_ID in $NODEGROUP_STACK_IDS; do
        STACK_USER_CREDS_ID=$($PSQL heat -c "select user_creds_id from stack where id='$CLUSTER_STACK_ID'")
        STACK_ENCODED_TRUST_ID=$($PSQL heat -c "select trust_id from user_creds where id='$STACK_USER_CREDS_ID'")
        STACK_TRUST_ID=$(python -c "from oslo_utils import encodeutils;from cryptography import fernet; import base64; print(fernet.Fernet(base64.b64encode(('notgood but just long enough i t' * 2)[:32].encode('utf-8'))).decrypt(encodeutils.safe_encode('$STACK_ENCODED_TRUST_ID')))")
        $PSQL keystone -c "update trust set trustor_user_id='$NEW_USER_ID' where id='$STACK_TRUST_ID'"
        $PSQL heat -c "update user_creds set trustor_user_id='$NEW_USER_ID' where id='$STACK_USER_CREDS_ID';"
        >&2 echo Cluster $CLUSTER_UUID nodegroup stack trust $STACK_TRUST_ID have been reconfigured
    done

done
