summaryrefslogtreecommitdiff
path: root/devstack/lib/heat
blob: 8e953ca2610c8b65b041bd58a93a82b30599a5cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#!/bin/bash
#
# lib/heat
# Install and start **Heat** service

# To enable, add the following to localrc
#
#   ENABLED_SERVICES+=,heat,h-api,h-api-cfn,h-eng

# Dependencies:
# (none)

# stack.sh
# ---------
# - install_heatclient
# - install_heat
# - configure_heatclient
# - configure_heat
# - init_heat
# - start_heat
# - stop_heat
# - cleanup_heat

# Save trace setting
_XTRACE_HEAT=$(set +o | grep xtrace)
set +o xtrace

# Defaults
# --------

# set up default directories
GITDIR["python-heatclient"]=$DEST/python-heatclient

# python heat client library
GITREPO["python-heatclient"]=${HEATCLIENT_REPO:-${GIT_BASE}/openstack/python-heatclient.git}
GITBRANCH["python-heatclient"]=${HEATCLIENT_BRANCH:-master}

# Use HEAT_USE_MOD_WSGI for backward compatibility
HEAT_USE_APACHE=${HEAT_USE_APACHE:-${HEAT_USE_MOD_WSGI:-True}}

HEAT_DIR=$DEST/heat
HEAT_FILES_DIR=$HEAT_DIR/heat/httpd/files

HEAT_STANDALONE=$(trueorfalse False HEAT_STANDALONE)
HEAT_ENABLE_ADOPT_ABANDON=$(trueorfalse False HEAT_ENABLE_ADOPT_ABANDON)
HEAT_CONF_DIR=/etc/heat
HEAT_CONF=$HEAT_CONF_DIR/heat.conf
HEAT_ENV_DIR=$HEAT_CONF_DIR/environment.d
HEAT_TEMPLATES_DIR=$HEAT_CONF_DIR/templates
HEAT_API_HOST=${HEAT_API_HOST:-$SERVICE_HOST}
HEAT_API_PORT=${HEAT_API_PORT:-8004}
HEAT_SERVICE_USER=${HEAT_SERVICE_USER:-heat}
HEAT_TRUSTEE_USER=${HEAT_TRUSTEE_USER:-$HEAT_SERVICE_USER}
HEAT_TRUSTEE_PASSWORD=${HEAT_TRUSTEE_PASSWORD:-$SERVICE_PASSWORD}
HEAT_TRUSTEE_DOMAIN=${HEAT_TRUSTEE_DOMAIN:-default}

# Support entry points installation of console scripts
HEAT_BIN_DIR=$(get_python_exec_prefix)
HEAT_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-uwsgi.ini
HEAT_CFN_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-cfn-uwsgi.ini
HEAT_API_UWSGI=$HEAT_BIN_DIR/heat-wsgi-api
HEAT_CFN_API_UWSGI=$HEAT_BIN_DIR/heat-wsgi-api-cfn

# other default options
if [[ "$HEAT_STANDALONE" == "True" ]]; then
    # for standalone, use defaults which require no service user
    HEAT_STACK_DOMAIN=$(trueorfalse False HEAT_STACK_DOMAIN)
    HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-password}
    if [[ ${HEAT_DEFERRED_AUTH} != "password" ]]; then
        # Heat does not support keystone trusts when deployed in
        # standalone mode
        die $LINENO \
            'HEAT_DEFERRED_AUTH can only be set to "password" when HEAT_STANDALONE is True.'
    fi
else
    HEAT_STACK_DOMAIN=$(trueorfalse True HEAT_STACK_DOMAIN)
    HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-}
fi
HEAT_PLUGIN_DIR=${HEAT_PLUGIN_DIR:-$DATA_DIR/heat/plugins}
ENABLE_HEAT_PLUGINS=${ENABLE_HEAT_PLUGINS:-}
HEAT_ENGINE_WORKERS=${HEAT_ENGINE_WORKERS:=$(( ($(nproc)/4)<2 ? 2 : ($(nproc)/4) ))}

# Functions
# ---------

# Test if any Heat services are enabled
# is_heat_enabled
function is_heat_enabled {
    [[ ,${ENABLED_SERVICES} =~ ,"h-" ]] && return 0
    return 1
}

# cleanup_heat() - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_heat {
    if [[ "$HEAT_USE_APACHE" == "True" ]]; then
        _cleanup_heat_apache_wsgi
    fi
    sudo rm -rf $HEAT_ENV_DIR
    sudo rm -rf $HEAT_TEMPLATES_DIR
    sudo rm -rf $HEAT_CONF_DIR
}

# configure_heat() - Set config files, create data dirs, etc
function configure_heat {

    sudo install -d -o $STACK_USER $HEAT_CONF_DIR
    # remove old config files
    rm -f $HEAT_CONF_DIR/heat-*.conf

    HEAT_API_CFN_HOST=${HEAT_API_CFN_HOST:-$SERVICE_HOST}
    HEAT_API_CFN_PORT=${HEAT_API_CFN_PORT:-8000}
    HEAT_ENGINE_HOST=${HEAT_ENGINE_HOST:-$SERVICE_HOST}
    HEAT_ENGINE_PORT=${HEAT_ENGINE_PORT:-8001}
    HEAT_API_PASTE_FILE=$HEAT_CONF_DIR/api-paste.ini

    cp $HEAT_DIR/etc/heat/api-paste.ini $HEAT_API_PASTE_FILE

    # common options
    iniset_rpc_backend heat $HEAT_CONF
    if [[ "$HEAT_USE_APACHE" == "True" && "$WSGI_MODE" == "uwsgi" ]]; then
        iniset $HEAT_CONF DEFAULT heat_metadata_server_url http://$HEAT_API_CFN_HOST/heat-api-cfn
        iniset $HEAT_CONF DEFAULT heat_waitcondition_server_url http://$HEAT_API_CFN_HOST/heat-api-cfn/v1/waitcondition
    else
        iniset $HEAT_CONF DEFAULT heat_metadata_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT
        iniset $HEAT_CONF DEFAULT heat_waitcondition_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1/waitcondition
    fi

    iniset $HEAT_CONF database connection `database_connection_url heat`
    # we are using a hardcoded auth_encryption_key as it has to be the same for
    # multinode deployment.
    iniset $HEAT_CONF DEFAULT auth_encryption_key "767c3ed056cbaa3b9dfedb8c6f825bf0"

    iniset $HEAT_CONF DEFAULT region_name_for_services "$REGION_NAME"

    # logging
    iniset $HEAT_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL

    # reduce Heat engine workers
    iniset $HEAT_CONF DEFAULT num_engine_workers "$HEAT_ENGINE_WORKERS"

    local no_format="False"
    if [[ "$HEAT_USE_APACHE" == "True" && "$WSGI_MODE" != "uwsgi" ]]; then
         no_format="True"
    fi

    # Format logging
    setup_logging $HEAT_CONF $no_format

    if [[ ! -z "$HEAT_DEFERRED_AUTH" ]]; then
        iniset $HEAT_CONF DEFAULT deferred_auth_method $HEAT_DEFERRED_AUTH
    fi

    if [[ "$HEAT_USE_APACHE" == "True" ]]; then
        if [[ $WSGI_MODE == "uwsgi" ]]; then
            write_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI" "/heat-api"
            # configure threads for h-api to avoid IO wait and messaging timeout. We use
            # 'nproc/4' to calculate API workers, hence, 4 would be probably correct
            # approximation.
            iniset "$HEAT_API_UWSGI_CONF" uwsgi threads 4
            write_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI" "/heat-api-cfn"
        else
            _config_heat_apache_wsgi
        fi
    fi

    if [[ "$HEAT_STANDALONE" = "True" ]]; then
        iniset $HEAT_CONF paste_deploy flavor standalone
        iniset $HEAT_CONF clients_heat url "http://$HEAT_API_HOST:$HEAT_API_PORT/v1/%(tenant_id)s"
    else
        configure_auth_token_middleware $HEAT_CONF heat
    fi

    # If HEAT_DEFERRED_AUTH is unset or explicitly set to trusts, configure
    # the section for the client plugin associated with the trustee
    if [ -z "$HEAT_DEFERRED_AUTH" -o "trusts" == "$HEAT_DEFERRED_AUTH" ]; then
        iniset $HEAT_CONF trustee auth_type password
        iniset $HEAT_CONF trustee auth_url $KEYSTONE_AUTH_URI
        iniset $HEAT_CONF trustee username $HEAT_TRUSTEE_USER
        iniset $HEAT_CONF trustee password $HEAT_TRUSTEE_PASSWORD
        iniset $HEAT_CONF trustee user_domain_id $HEAT_TRUSTEE_DOMAIN
    fi

    # clients_keystone
    iniset $HEAT_CONF clients_keystone auth_uri $KEYSTONE_AUTH_URI

    # OpenStack API
    iniset $HEAT_CONF heat_api bind_port $HEAT_API_PORT
    iniset $HEAT_CONF heat_api workers "$API_WORKERS"

    # Cloudformation API
    iniset $HEAT_CONF heat_api_cfn bind_port $HEAT_API_CFN_PORT

    if is_ssl_enabled_service "key" || is_service_enabled tls-proxy; then
        iniset $HEAT_CONF clients_keystone ca_file $SSL_BUNDLE_FILE
    fi

    if is_ssl_enabled_service "nova" || is_service_enabled tls-proxy; then
        iniset $HEAT_CONF clients_nova ca_file $SSL_BUNDLE_FILE
    fi

    if is_ssl_enabled_service "cinder" || is_service_enabled tls-proxy; then
        iniset $HEAT_CONF clients_cinder ca_file $SSL_BUNDLE_FILE
    fi

    if [[ "$HEAT_ENABLE_ADOPT_ABANDON" = "True" ]]; then
        iniset $HEAT_CONF DEFAULT enable_stack_adopt true
        iniset $HEAT_CONF DEFAULT enable_stack_abandon true
    fi

    iniset $HEAT_CONF cache enabled "True"
    iniset $HEAT_CONF cache backend "dogpile.cache.memory"

    if ! is_service_enabled c-bak; then
        iniset $HEAT_CONF volumes backups_enabled false
    fi

    sudo install -d -o $STACK_USER $HEAT_ENV_DIR $HEAT_TEMPLATES_DIR

    # copy the default environment
    cp $HEAT_DIR/etc/heat/environment.d/* $HEAT_ENV_DIR/

    # copy the default templates
    cp $HEAT_DIR/etc/heat/templates/* $HEAT_TEMPLATES_DIR/

    # Enable heat plugins.
    # NOTE(nic): The symlink nonsense is necessary because when
    # plugins are installed in "developer mode", the final component
    # of their target directory is always "resources", which confuses
    # Heat's plugin loader into believing that all plugins are named
    # "resources", and therefore are all the same plugin; so it
    # will only load one of them.  Linking them all to a common
    # location with unique names avoids that type of collision,
    # while still allowing the plugins to be edited in-tree.
    local err_count=0

    if [[ -n "$ENABLE_HEAT_PLUGINS" ]]; then
        mkdir -p $HEAT_PLUGIN_DIR
        # Clean up cruft from any previous runs
        rm -f $HEAT_PLUGIN_DIR/*
        iniset $HEAT_CONF DEFAULT plugin_dirs $HEAT_PLUGIN_DIR
    fi

    for heat_plugin in $ENABLE_HEAT_PLUGINS; do
        if [[ -d $HEAT_DIR/contrib/$heat_plugin ]]; then
            setup_package $HEAT_DIR/contrib/$heat_plugin -e
            ln -s $HEAT_DIR/contrib/$heat_plugin/$heat_plugin/resources $HEAT_PLUGIN_DIR/$heat_plugin
        else
            : # clear retval on the test so that we can roll up errors
            err $LINENO "Requested Heat plugin(${heat_plugin}) not found."
            err_count=$(($err_count + 1))
        fi
    done
    [ $err_count -eq 0 ] || die $LINENO "$err_count of the requested Heat plugins could not be installed."
}

# init_heat() - Initialize database
function init_heat {
    # recreate db only if one of the db services is enabled
    if is_service_enabled $DATABASE_BACKENDS; then
        # (re)create heat database
        recreate_database heat
        $HEAT_BIN_DIR/heat-manage db_sync
    fi
}


# install_heatclient() - Collect source and prepare
function install_heatclient {
    if use_library_from_git "python-heatclient"; then
        git_clone_by_name "python-heatclient"
        setup_dev_lib "python-heatclient"
        sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-heatclient"]}/tools/,/etc/bash_completion.d/}heat.bash_completion
    fi
}

# install_heat() - Collect source and prepare
function install_heat {
    setup_develop $HEAT_DIR
    if [[ "$HEAT_USE_APACHE" == "True" ]]; then
       if [ "$WSGI_MODE" == "uwsgi" ]; then
           pip_install uwsgi
       else
           install_apache_wsgi
       fi
    fi
}

# start_heat() - Start running processes, including screen
function start_heat {
    run_process h-eng "$HEAT_BIN_DIR/heat-engine --config-file=$HEAT_CONF"

    # If the site is not enabled then we are in a grenade scenario
    local enabled_site_file
    enabled_site_file=$(apache_site_config_for heat-api)
    if [[ "$HEAT_USE_APACHE" == "True" ]]; then
        if [[ -f ${enabled_site_file} && "$WSGI_MODE" != "uwsgi" ]]; then
            enable_apache_site heat-api
            enable_apache_site heat-api-cfn
            restart_apache_server
        else
            run_process h-api "$HEAT_BIN_DIR/uwsgi --ini $HEAT_API_UWSGI_CONF" ""
            run_process h-api-cfn "$HEAT_BIN_DIR/uwsgi --ini $HEAT_CFN_API_UWSGI_CONF" ""
        fi
    else
        run_process h-api "$HEAT_BIN_DIR/heat-api --config-file=$HEAT_CONF"
        run_process h-api-cfn "$HEAT_BIN_DIR/heat-api-cfn --config-file=$HEAT_CONF"
    fi
}

function _stop_processes {
    local serv
    for serv in h-api h-api-cfn; do
        stop_process $serv
    done
}

# stop_heat() - Stop running processes
function stop_heat {
    # Kill the screen windows
    stop_process h-eng

    if [[ "$HEAT_USE_APACHE" == "True" ]]; then
        if [[ "$WSGI_MODE" == "uwsgi" ]]; then
            _stop_processes
        else
            disable_apache_site heat-api
            disable_apache_site heat-api-cfn
            restart_apache_server
        fi
    else
       _stop_processes
    fi
}

# _cleanup_heat_apache_wsgi() - Remove wsgi files, disable and remove apache vhost file
function _cleanup_heat_apache_wsgi {
    if [[ "$WSGI_MODE" == "uwsgi" ]]; then
        remove_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI"
        remove_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI"
    fi
    sudo rm -f $(apache_site_config_for heat-api)
    sudo rm -f $(apache_site_config_for heat-api-cfn)
}

# _config_heat_apache_wsgi() - Set WSGI config files of Heat
function _config_heat_apache_wsgi {

    local heat_apache_conf
    heat_apache_conf=$(apache_site_config_for heat-api)
    local heat_cfn_apache_conf
    heat_cfn_apache_conf=$(apache_site_config_for heat-api-cfn)
    local heat_ssl=""
    local heat_certfile=""
    local heat_keyfile=""
    local heat_api_port=$HEAT_API_PORT
    local heat_cfn_api_port=$HEAT_API_CFN_PORT
    local venv_path=""

    sudo cp $HEAT_FILES_DIR/heat-api.conf $heat_apache_conf
    sudo sed -e "
        s|%PUBLICPORT%|$heat_api_port|g;
        s|%APACHE_NAME%|$APACHE_NAME|g;
        s|%HEAT_BIN_DIR%|$HEAT_BIN_DIR|g;
        s|%API_WORKERS%|$API_WORKERS|g;
        s|%SSLENGINE%|$heat_ssl|g;
        s|%SSLCERTFILE%|$heat_certfile|g;
        s|%SSLKEYFILE%|$heat_keyfile|g;
        s|%USER%|$STACK_USER|g;
        s|%VIRTUALENV%|$venv_path|g
    " -i $heat_apache_conf

    sudo cp $HEAT_FILES_DIR/heat-api-cfn.conf $heat_cfn_apache_conf
    sudo sed -e "
        s|%PUBLICPORT%|$heat_cfn_api_port|g;
        s|%APACHE_NAME%|$APACHE_NAME|g;
        s|%HEAT_BIN_DIR%|$HEAT_BIN_DIR|g;
        s|%API_WORKERS%|$API_WORKERS|g;
        s|%SSLENGINE%|$heat_ssl|g;
        s|%SSLCERTFILE%|$heat_certfile|g;
        s|%SSLKEYFILE%|$heat_keyfile|g;
        s|%USER%|$STACK_USER|g;
        s|%VIRTUALENV%|$venv_path|g
    " -i $heat_cfn_apache_conf

}


# create_heat_accounts() - Set up common required heat accounts
function create_heat_accounts {
    if [[ "$HEAT_STANDALONE" != "True" ]]; then

        local heat_api_service_url
        local heat_cfn_api_service_url

        if [[ "$HEAT_USE_APACHE" == "True" && "$WSGI_MODE" == "uwsgi" ]]; then
            heat_api_service_url="$SERVICE_PROTOCOL://$HEAT_API_HOST/heat-api/v1/\$(project_id)s"
            heat_cfn_api_service_url="$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST/heat-api-cfn/v1"
        else
            heat_api_service_url="$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(project_id)s"
            heat_cfn_api_service_url="$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1"
        fi

        create_service_user "heat" "admin"
        get_or_create_service "heat" "orchestration" "Heat Orchestration Service"
        get_or_create_endpoint \
            "orchestration" \
            "$REGION_NAME" \
            "$heat_api_service_url"

        get_or_create_service "heat-cfn" "cloudformation" "Heat CloudFormation Service"
        get_or_create_endpoint \
            "cloudformation"  \
            "$REGION_NAME" \
            "$heat_cfn_api_service_url"

        # heat_stack_user role is for users created by Heat
        get_or_create_role "heat_stack_user"
    fi

    if [[ "$HEAT_STACK_DOMAIN" == "True" ]]; then
        # domain -> heat and user -> heat_domain_admin
        domain_id=$(get_or_create_domain heat 'Owns users and projects created by heat')
        iniset $HEAT_CONF DEFAULT stack_user_domain_id ${domain_id}
        get_or_create_user heat_domain_admin $SERVICE_PASSWORD heat
        get_or_add_user_domain_role admin heat_domain_admin heat
        iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
        iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
    fi
}

# configure_tempest_for_heat()
# NOTE (gmann): Configure all the Tempest setting for Heat service in
# this function.
function configure_tempest_for_heat {
    # Skip SoftwareConfigIntegrationTest because it requires a custom image
    # Skip AutoscalingLoadBalancerTest and AutoscalingLoadBalancerv2Test as deprecated neutron-lbaas service is not enabled
    # Skip CfnInitIntegrationTest as latest fedora images don't have heat-cfntools
    iniset $TEMPEST_CONFIG heat_plugin skip_scenario_test_list 'AutoscalingLoadBalancerTest, AutoscalingLoadBalancerv2Test, \
	    SoftwareConfigIntegrationTest, AodhAlarmTest, CfnInitIntegrationTest'
    # Skip LoadBalancerv2Test as deprecated neutron-lbaas service is not enabled.
    # Also Skip a few tests failing because of a known libvirt issue in Jammy
    # https://bugs.launchpad.net/nova/+bug/1998274
    iniset $TEMPEST_CONFIG heat_plugin skip_functional_test_list 'LoadBalancerv2Test, NotificationTest, \
        UpdateStackTest.test_stack_update_with_replacing_userdata, \
        CancelUpdateTest.test_cancel_update_server_with_port'

    openstack flavor show m1.heat_int || openstack flavor create m1.heat_int --ram 512 --disk 10
    openstack flavor show m1.heat_micro || openstack flavor create m1.heat_micro --ram 128 --disk 1

    export OS_CLOUD=devstack
    openstack network show heat-net || openstack network create heat-net
    openstack subnet show heat-subnet || openstack subnet create heat-subnet --network heat-net --subnet-range 10.0.5.0/24
    openstack router add subnet router1 heat-subnet

    # NOTE(ianw) OpenDev infra only keeps the latest two Fedora's
    # around; prefer the mirror but allow fallback
    if [[ -e /etc/ci/mirror_info.sh ]]; then
        source /etc/ci/mirror_info.sh
    fi
    HEAT_TEST_FEDORA_IMAGE_UPSTREAM=https://download.fedoraproject.org/pub/fedora/linux
    HEAT_TEST_FEDORA_IMAGE_PATH=releases/36/Cloud/x86_64/images/Fedora-Cloud-Base-36-1.5.x86_64.qcow2
    if curl --output /dev/null --silent --head --fail "${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}"; then
        export HEAT_TEST_FEDORA_IMAGE="${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}"
    else
        export HEAT_TEST_FEDORA_IMAGE="${HEAT_TEST_FEDORA_IMAGE_UPSTREAM}/${HEAT_TEST_FEDORA_IMAGE_PATH}"
    fi
    TOKEN=$(openstack token issue -c id -f value)
    local image_exists=$( openstack image list | grep "Fedora-Cloud-Base-36-1.5.x86_64" )
    if [[ -z $image_exists ]]; then
        if is_service_enabled g-api; then
            upload_image $HEAT_TEST_FEDORA_IMAGE $TOKEN
        fi
    fi

    if is_service_enabled tls-proxy; then
        iniset $TEMPEST_CONFIG heat_plugin ca_file $SSL_BUNDLE_FILE
    fi
    # add application credential and secret to support test multi-cloud
    app_cred_id=$(openstack application credential show  heat_multicloud || openstack application credential create heat_multicloud \
        --secret secret --unrestricted -c id -f value)
    export OS_CREDENTIAL_SECRET_ID=$(openstack secret store -n heat-multi-cloud-test-cred --payload \
        '{"auth_type": "v3applicationcredential", "auth": {"auth_url": $OS_AUTH_URL, "application_credential_id": $app_cred_id, "application_credential_secret": "secret"}}'\
        -c "Secret href" -f value)
    source $TOP_DIR/openrc demo demo
    iniset $TEMPEST_CONFIG heat_plugin username $OS_USERNAME
    iniset $TEMPEST_CONFIG heat_plugin password $OS_PASSWORD
    iniset $TEMPEST_CONFIG heat_plugin project_name $OS_PROJECT_NAME
    iniset $TEMPEST_CONFIG heat_plugin auth_url $OS_AUTH_URL
    iniset $TEMPEST_CONFIG heat_plugin user_domain_id $OS_USER_DOMAIN_ID
    iniset $TEMPEST_CONFIG heat_plugin project_domain_id $OS_PROJECT_DOMAIN_ID
    iniset $TEMPEST_CONFIG heat_plugin user_domain_name $OS_USER_DOMAIN_NAME
    iniset $TEMPEST_CONFIG heat_plugin project_domain_name $OS_PROJECT_DOMAIN_NAME
    iniset $TEMPEST_CONFIG heat_plugin region $OS_REGION_NAME
    iniset $TEMPEST_CONFIG heat_plugin auth_version $OS_IDENTITY_API_VERSION

    source $TOP_DIR/openrc admin admin
    iniset $TEMPEST_CONFIG heat_plugin admin_username $OS_USERNAME
    iniset $TEMPEST_CONFIG heat_plugin admin_password $OS_PASSWORD
    export OS_CLOUD=devstack-admin
}

# Restore xtrace
$_XTRACE_HEAT