A service for managing and provisioning Bare Metal servers.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2911 lines
115KB

  1. #!/bin/bash
  2. #
  3. # lib/ironic
  4. # Functions to control the configuration and operation of the **Ironic** service
  5. # Dependencies:
  6. #
  7. # - ``functions`` file
  8. # - ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined
  9. # - ``SERVICE_{TENANT_NAME|PASSWORD}`` must be defined
  10. # - ``SERVICE_HOST``
  11. # - ``KEYSTONE_TOKEN_FORMAT`` must be defined
  12. # ``stack.sh`` calls the entry points in this order:
  13. #
  14. # - install_ironic
  15. # - install_ironicclient
  16. # - init_ironic
  17. # - start_ironic
  18. # - stop_ironic
  19. # - cleanup_ironic
  20. # ensure we don't re-source this in the same environment
  21. [[ -z "$_IRONIC_DEVSTACK_LIB" ]] || return 0
  22. declare -r -g _IRONIC_DEVSTACK_LIB=1
  23. # Save xtrace and pipefail settings
  24. _XTRACE_IRONIC=$(set +o | grep xtrace)
  25. _PIPEFAIL_IRONIC=$(set +o | grep pipefail)
  26. set -o xtrace
  27. set +o pipefail
  28. # Defaults
  29. # --------
  30. # Set up default directories
  31. GITDIR["python-ironicclient"]=$DEST/python-ironicclient
  32. GITDIR["ironic-lib"]=$DEST/ironic-lib
  33. GITREPO["pyghmi"]=${PYGHMI_REPO:-${GIT_BASE}/x/pyghmi}
  34. GITBRANCH["pyghmi"]=${PYGHMI_BRANCH:-master}
  35. GITDIR["pyghmi"]=$DEST/pyghmi
  36. GITREPO["virtualbmc"]=${VIRTUALBMC_REPO:-${GIT_BASE}/openstack/virtualbmc.git}
  37. GITBRANCH["virtualbmc"]=${VIRTUALBMC_BRANCH:-master}
  38. GITDIR["virtualbmc"]=$DEST/virtualbmc
  39. GITREPO["virtualpdu"]=${VIRTUALPDU_REPO:-${GIT_BASE}/openstack/virtualpdu.git}
  40. GITBRANCH["virtualpdu"]=${VIRTUALPDU_BRANCH:-master}
  41. GITDIR["virtualpdu"]=$DEST/virtualpdu
  42. GITREPO["sushy"]=${SUSHY_REPO:-${GIT_BASE}/openstack/sushy.git}
  43. GITBRANCH["sushy"]=${SUSHY_BRANCH:-master}
  44. GITDIR["sushy"]=$DEST/sushy
  45. GITREPO["sushy-tools"]=${SUSHY_TOOLS_REPO:-${GIT_BASE}/openstack/sushy-tools.git}
  46. GITBRANCH["sushy-tools"]=${SUSHY_TOOLS_BRANCH:-master}
  47. GITDIR["sushy-tools"]=$DEST/sushy-tools
  48. IRONIC_DIR=$DEST/ironic
  49. IRONIC_DEVSTACK_DIR=$IRONIC_DIR/devstack
  50. IRONIC_DEVSTACK_FILES_DIR=$IRONIC_DEVSTACK_DIR/files
  51. # TODO(dtantsur): delete these three when we migrate image building to
  52. # ironic-python-agent-builder completely
  53. IRONIC_PYTHON_AGENT_REPO=${IRONIC_PYTHON_AGENT_REPO:-${GIT_BASE}/openstack/ironic-python-agent.git}
  54. IRONIC_PYTHON_AGENT_BRANCH=${IRONIC_PYTHON_AGENT_BRANCH:-$TARGET_BRANCH}
  55. IRONIC_PYTHON_AGENT_DIR=$DEST/ironic-python-agent
  56. IRONIC_PYTHON_AGENT_BUILDER_REPO=${IRONIC_PYTHON_AGENT_BUILDER_REPO:-${GIT_BASE}/openstack/ironic-python-agent-builder.git}
  57. IRONIC_PYTHON_AGENT_BUILDER_BRANCH=${IRONIC_PYTHON_AGENT_BUILDER_BRANCH:-$TARGET_BRANCH}
  58. IRONIC_PYTHON_AGENT_BUILDER_DIR=$DEST/ironic-python-agent-builder
  59. IRONIC_DIB_BINDEP_FILE=https://opendev.org/openstack/diskimage-builder/raw/branch/master/bindep.txt
  60. IRONIC_DATA_DIR=$DATA_DIR/ironic
  61. IRONIC_STATE_PATH=/var/lib/ironic
  62. IRONIC_AUTH_CACHE_DIR=${IRONIC_AUTH_CACHE_DIR:-/var/cache/ironic}
  63. IRONIC_CONF_DIR=${IRONIC_CONF_DIR:-/etc/ironic}
  64. IRONIC_CONF_FILE=$IRONIC_CONF_DIR/ironic.conf
  65. IRONIC_ROOTWRAP_CONF=$IRONIC_CONF_DIR/rootwrap.conf
  66. # Deploy Ironic API under uwsgi (NOT mod_wsgi) server.
  67. # Devstack aims to remove mod_wsgi support, so ironic shouldn't use it too.
  68. # If set to False that will fall back to use the eventlet server that
  69. # can happen on grenade runs.
  70. # The (confusing) name IRONIC_USE_MOD_WSGI is left for backward compatibility,
  71. # for example during grenade runs
  72. # TODO(pas-ha) remove IRONIC_USE_MOD_WSGI var after oldest supported
  73. # stable branch is stable/rocky
  74. IRONIC_USE_MOD_WSGI=$(trueorfalse $ENABLE_HTTPD_MOD_WSGI_SERVICES IRONIC_USE_MOD_WSGI)
  75. # If True, will deploy Ironic API under WSGI server, currently supported one
  76. # is uwsgi.
  77. # Defaults to the (now confusingly named) IRONIC_USE_MOD_WSGI for backward compat
  78. IRONIC_USE_WSGI=$(trueorfalse $IRONIC_USE_MOD_WSGI IRONIC_USE_WSGI)
  79. # Whether DevStack will be setup for bare metal or VMs
  80. IRONIC_IS_HARDWARE=$(trueorfalse False IRONIC_IS_HARDWARE)
  81. # Deploy callback timeout can be changed from its default (1800), if required.
  82. IRONIC_CALLBACK_TIMEOUT=${IRONIC_CALLBACK_TIMEOUT:-}
  83. # Timeout before retrying PXE boot. Set low to help the CI.
  84. if [[ "$IRONIC_IS_HARDWARE" == False ]]; then
  85. IRONIC_PXE_BOOT_RETRY_TIMEOUT=${IRONIC_PXE_BOOT_RETRY_TIMEOUT:-600}
  86. else
  87. IRONIC_PXE_BOOT_RETRY_TIMEOUT=${IRONIC_PXE_BOOT_RETRY_TIMEOUT:-}
  88. fi
  89. # Ping timeout after the node becomes active
  90. IRONIC_PING_TIMEOUT=${IRONIC_PING_TIMEOUT:-}
  91. # Deploy to hardware platform
  92. IRONIC_HW_NODE_CPU=${IRONIC_HW_NODE_CPU:-1}
  93. IRONIC_HW_NODE_RAM=${IRONIC_HW_NODE_RAM:-512}
  94. IRONIC_HW_NODE_DISK=${IRONIC_HW_NODE_DISK:-10}
  95. IRONIC_HW_EPHEMERAL_DISK=${IRONIC_HW_EPHEMERAL_DISK:-0}
  96. IRONIC_HW_ARCH=${IRONIC_HW_ARCH:-x86_64}
  97. # The file is composed of multiple lines, each line includes fields
  98. # separated by white space, in the format:
  99. #
  100. # <BMC address> <MAC address> <BMC username> <BMC password> [<driver specific fields>]
  101. #
  102. # For example:
  103. #
  104. # 192.168.110.107 00:1e:67:57:50:4c root otc123
  105. #
  106. # Supported IRONIC_DEPLOY_DRIVERs:
  107. # ipmi:
  108. # <BMC address> <MAC address> <BMC username> <BMC password>
  109. #
  110. # idrac:
  111. # <BMC address> <MAC address> <BMC username> <BMC password>
  112. #
  113. # irmc:
  114. # <BMC address> <MAC address> <BMC username> <BMC password>
  115. #
  116. IRONIC_HWINFO_FILE=${IRONIC_HWINFO_FILE:-$IRONIC_DATA_DIR/hardware_info}
  117. # Set up defaults for functional / integration testing
  118. IRONIC_NODE_UUID=${IRONIC_NODE_UUID:-`uuidgen`}
  119. IRONIC_SCRIPTS_DIR=${IRONIC_SCRIPTS_DIR:-$IRONIC_DEVSTACK_DIR/tools/ironic/scripts}
  120. IRONIC_TEMPLATES_DIR=${IRONIC_TEMPLATES_DIR:-$IRONIC_DEVSTACK_DIR/tools/ironic/templates}
  121. IRONIC_BAREMETAL_BASIC_OPS=$(trueorfalse False IRONIC_BAREMETAL_BASIC_OPS)
  122. IRONIC_TFTPBOOT_DIR=${IRONIC_TFTPBOOT_DIR:-$IRONIC_DATA_DIR/tftpboot}
  123. IRONIC_TFTPSERVER_IP=${IRONIC_TFTPSERVER_IP:-$HOST_IP}
  124. IRONIC_TFTP_BLOCKSIZE=${IRONIC_TFTP_BLOCKSIZE:-$((PUBLIC_BRIDGE_MTU-50))}
  125. IRONIC_VM_COUNT=${IRONIC_VM_COUNT:-1}
  126. IRONIC_VM_SPECS_CPU=${IRONIC_VM_SPECS_CPU:-1}
  127. IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-1280}
  128. IRONIC_VM_SPECS_CPU_ARCH=${IRONIC_VM_SPECS_CPU_ARCH:-'x86_64'}
  129. IRONIC_VM_SPECS_DISK=${IRONIC_VM_SPECS_DISK:-10}
  130. IRONIC_VM_SPECS_DISK_FORMAT=${IRONIC_VM_SPECS_DISK_FORMAT:-qcow2}
  131. IRONIC_VM_EPHEMERAL_DISK=${IRONIC_VM_EPHEMERAL_DISK:-0}
  132. IRONIC_VM_EMULATOR=${IRONIC_VM_EMULATOR:-'/usr/bin/qemu-system-x86_64'}
  133. IRONIC_VM_ENGINE=${IRONIC_VM_ENGINE:-qemu}
  134. IRONIC_VM_NETWORK_BRIDGE=${IRONIC_VM_NETWORK_BRIDGE:-brbm}
  135. IRONIC_VM_INTERFACE_COUNT=${IRONIC_VM_INTERFACE_COUNT:-2}
  136. IRONIC_VM_VOLUME_COUNT=${IRONIC_VM_VOLUME_COUNT:-1}
  137. IRONIC_VM_MACS_CSV_FILE=${IRONIC_VM_MACS_CSV_FILE:-$IRONIC_DATA_DIR/ironic_macs.csv}
  138. IRONIC_CLEAN_NET_NAME=${IRONIC_CLEAN_NET_NAME:-${IRONIC_PROVISION_NETWORK_NAME:-${PRIVATE_NETWORK_NAME}}}
  139. IRONIC_RESCUE_NET_NAME=${IRONIC_RESCUE_NET_NAME:-${IRONIC_CLEAN_NET_NAME}}
  140. IRONIC_EXTRA_PXE_PARAMS=${IRONIC_EXTRA_PXE_PARAMS:-}
  141. IRONIC_TTY_DEV=${IRONIC_TTY_DEV:-ttyS0,115200}
  142. IRONIC_TEMPEST_BUILD_TIMEOUT=${IRONIC_TEMPEST_BUILD_TIMEOUT:-${BUILD_TIMEOUT:-}}
  143. if [[ -n "$BUILD_TIMEOUT" ]]; then
  144. echo "WARNING: BUILD_TIMEOUT variable is renamed to IRONIC_TEMPEST_BUILD_TIMEOUT and will be deprecated in Pike."
  145. fi
  146. IRONIC_DEFAULT_API_VERSION=${IRONIC_DEFAULT_API_VERSION:-}
  147. IRONIC_CMD="openstack baremetal"
  148. if [[ -n "$IRONIC_DEFAULT_API_VERSION" ]]; then
  149. IRONIC_CMD="$IRONIC_CMD --os-baremetal-api-version $IRONIC_DEFAULT_API_VERSION"
  150. fi
  151. IRONIC_ENABLED_HARDWARE_TYPES=${IRONIC_ENABLED_HARDWARE_TYPES:-"ipmi,fake-hardware"}
  152. # list of all available driver interfaces types
  153. IRONIC_DRIVER_INTERFACE_TYPES="bios boot power management deploy console inspect raid rescue storage network vendor"
  154. IRONIC_ENABLED_BIOS_INTERFACES=${IRONIC_ENABLED_BIOS_INTERFACES:-"fake,no-bios"}
  155. IRONIC_ENABLED_BOOT_INTERFACES=${IRONIC_ENABLED_BOOT_INTERFACES:-"fake,ipxe"}
  156. IRONIC_ENABLED_CONSOLE_INTERFACES=${IRONIC_ENABLED_CONSOLE_INTERFACES:-"fake,no-console"}
  157. IRONIC_ENABLED_DEPLOY_INTERFACES=${IRONIC_ENABLED_DEPLOY_INTERFACES:-"fake,iscsi,direct"}
  158. IRONIC_ENABLED_INSPECT_INTERFACES=${IRONIC_ENABLED_INSPECT_INTERFACES:-"fake,no-inspect"}
  159. IRONIC_ENABLED_MANAGEMENT_INTERFACES=${IRONIC_ENABLED_MANAGEMENT_INTERFACES:-"fake,ipmitool,noop"}
  160. IRONIC_ENABLED_NETWORK_INTERFACES=${IRONIC_ENABLED_NETWORK_INTERFACES:-"flat,noop"}
  161. IRONIC_ENABLED_POWER_INTERFACES=${IRONIC_ENABLED_POWER_INTERFACES:-"fake,ipmitool"}
  162. IRONIC_ENABLED_RAID_INTERFACES=${IRONIC_ENABLED_RAID_INTERFACES:-"fake,agent,no-raid"}
  163. IRONIC_ENABLED_RESCUE_INTERFACES=${IRONIC_ENABLED_RESCUE_INTERFACES:-"fake,no-rescue"}
  164. IRONIC_ENABLED_STORAGE_INTERFACES=${IRONIC_ENABLED_STORAGE_INTERFACES:-"fake,cinder,noop"}
  165. IRONIC_ENABLED_VENDOR_INTERFACES=${IRONIC_ENABLED_VENDOR_INTERFACES:-"fake,ipmitool,no-vendor"}
  166. # for usage with hardware types
  167. IRONIC_DEFAULT_BIOS_INTERFACE=${IRONIC_DEFAULT_BIOS_INTERFACE:-}
  168. IRONIC_DEFAULT_BOOT_INTERFACE=${IRONIC_DEFAULT_BOOT_INTERFACE:-}
  169. IRONIC_DEFAULT_CONSOLE_INTERFACE=${IRONIC_DEFAULT_CONSOLE_INTERFACE:-}
  170. IRONIC_DEFAULT_DEPLOY_INTERFACE=${IRONIC_DEFAULT_DEPLOY_INTERFACE:-}
  171. IRONIC_DEFAULT_INSPECT_INTERFACE=${IRONIC_DEFAULT_INSPECT_INTERFACE:-}
  172. IRONIC_DEFAULT_MANAGEMENT_INTERFACE=${IRONIC_DEFAULT_MANAGEMENT_INTERFACE:-}
  173. IRONIC_DEFAULT_NETWORK_INTERFACE=${IRONIC_DEFAULT_NETWORK_INTERFACE:-}
  174. IRONIC_DEFAULT_POWER_INTERFACE=${IRONIC_DEFAULT_POWER_INTERFACE:-}
  175. IRONIC_DEFAULT_RAID_INTERFACE=${IRONIC_DEFAULT_RAID_INTERFACE:-}
  176. IRONIC_DEFAULT_RESCUE_INTERFACE=${IRONIC_DEFAULT_RESCUE_INTERFACE:-}
  177. IRONIC_DEFAULT_STORAGE_INTERFACE=${IRONIC_DEFAULT_STORAGE_INTERFACE:-}
  178. IRONIC_DEFAULT_VENDOR_INTERFACE=${IRONIC_DEFAULT_VENDOR_INTERFACE:-}
  179. # If IRONIC_VM_ENGINE is explicitly set to "auto" or "kvm",
  180. # devstack will attempt to use hardware virtualization
  181. # (aka nested kvm). We do not enable it in the infra gates
  182. # because it is not consistently supported/working across
  183. # all gate infrastructure providers.
  184. if [[ "$IRONIC_VM_ENGINE" == "auto" ]]; then
  185. sudo modprobe kvm || true
  186. if [ ! -e /dev/kvm ]; then
  187. echo "WARNING: Switching to QEMU"
  188. IRONIC_VM_ENGINE=qemu
  189. if [[ -z "$IRONIC_VM_EMULATOR" ]]; then
  190. IRONIC_VM_EMULATOR='/usr/bin/qemu-system-x86_64'
  191. fi
  192. else
  193. IRONIC_VM_ENGINE=kvm
  194. fi
  195. fi
  196. if [[ "$IRONIC_VM_ENGINE" == "kvm" ]]; then
  197. # Set this to empty, so configure-vm.py can autodetect location
  198. # of KVM binary
  199. IRONIC_VM_EMULATOR=""
  200. fi
  201. # By default, baremetal VMs will console output to file.
  202. IRONIC_VM_LOG_CONSOLE=$(trueorfalse True IRONIC_VM_LOG_CONSOLE)
  203. IRONIC_VM_LOG_DIR=${IRONIC_VM_LOG_DIR:-$IRONIC_DATA_DIR/logs/}
  204. IRONIC_VM_LOG_ROTATE=$(trueorfalse True IRONIC_VM_LOG_ROTATE)
  205. # Set resource_classes for nodes to use Nova's placement engine
  206. IRONIC_DEFAULT_RESOURCE_CLASS=${IRONIC_DEFAULT_RESOURCE_CLASS:-baremetal}
  207. # Set traits for nodes. Traits should be separated by whitespace.
  208. IRONIC_DEFAULT_TRAITS=${IRONIC_DEFAULT_TRAITS-CUSTOM_GOLD}
  209. # Whether to build the ramdisk or download a prebuilt one.
  210. IRONIC_BUILD_DEPLOY_RAMDISK=$(trueorfalse True IRONIC_BUILD_DEPLOY_RAMDISK)
  211. # Ironic IPA ramdisk type, supported types are:
  212. IRONIC_SUPPORTED_RAMDISK_TYPES_RE="^(tinyipa|dib)$"
  213. IRONIC_RAMDISK_TYPE=${IRONIC_RAMDISK_TYPE:-tinyipa}
  214. # Confirm we have a supported ramdisk type or fail early.
  215. if [[ ! "$IRONIC_RAMDISK_TYPE" =~ $IRONIC_SUPPORTED_RAMDISK_TYPES_RE ]]; then
  216. die $LINENO "Unrecognized IRONIC_RAMDISK_TYPE: $IRONIC_RAMDISK_TYPE. Expected 'tinyipa' or 'dib'"
  217. fi
  218. # If present, these files are used as deploy ramdisk/kernel.
  219. # (The value must be an absolute path)
  220. IRONIC_DEPLOY_RAMDISK=${IRONIC_DEPLOY_RAMDISK:-$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.initramfs}
  221. IRONIC_DEPLOY_KERNEL=${IRONIC_DEPLOY_KERNEL:-$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.kernel}
  222. IRONIC_DEPLOY_ISO=${IRONIC_DEPLOY_ISO:-$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.iso}
  223. # If present, this file is used to deploy/boot nodes over virtual media
  224. # (The value must be an absolute path)
  225. IRONIC_EFIBOOT=${IRONIC_EFIBOOT:-$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.efiboot}
  226. # NOTE(jroll) this needs to be updated when stable branches are cut
  227. IPA_DOWNLOAD_BRANCH=${IPA_DOWNLOAD_BRANCH:-master}
  228. IPA_DOWNLOAD_BRANCH=$(echo $IPA_DOWNLOAD_BRANCH | tr / -)
  229. # OS for using with DIB images
  230. IRONIC_DIB_RAMDISK_OS=${IRONIC_DIB_RAMDISK_OS:-centos8}
  231. IRONIC_DIB_RAMDISK_RELEASE=${IRONIC_DIB_RAMDISK_RELEASE:-}
  232. # Configure URLs required to download ramdisk if we're not building it, and
  233. # IRONIC_DEPLOY_RAMDISK/KERNEL or the RAMDISK/KERNEL_URLs have not been
  234. # preconfigured.
  235. if [[ "$IRONIC_BUILD_DEPLOY_RAMDISK" == "False" && \
  236. ! (-e "$IRONIC_DEPLOY_RAMDISK" && -e "$IRONIC_DEPLOY_KERNEL") && \
  237. (-z "$IRONIC_AGENT_KERNEL_URL" || -z "$IRONIC_AGENT_RAMDISK_URL") ]]; then
  238. case $IRONIC_RAMDISK_TYPE in
  239. tinyipa)
  240. IRONIC_AGENT_KERNEL_FILE=tinyipa-${IPA_DOWNLOAD_BRANCH}.vmlinuz
  241. IRONIC_AGENT_RAMDISK_FILE=tinyipa-${IPA_DOWNLOAD_BRANCH}.gz
  242. ;;
  243. dib)
  244. IRONIC_AGENT_KERNEL_FILE=ipa-${IRONIC_DIB_RAMDISK_OS}-${IPA_DOWNLOAD_BRANCH}.kernel
  245. IRONIC_AGENT_RAMDISK_FILE=ipa-${IRONIC_DIB_RAMDISK_OS}-${IPA_DOWNLOAD_BRANCH}.initramfs
  246. ;;
  247. esac
  248. IRONIC_AGENT_KERNEL_URL=https://tarballs.openstack.org/ironic-python-agent/${IRONIC_RAMDISK_TYPE}/files/${IRONIC_AGENT_KERNEL_FILE}
  249. IRONIC_AGENT_RAMDISK_URL=https://tarballs.openstack.org/ironic-python-agent/${IRONIC_RAMDISK_TYPE}/files/${IRONIC_AGENT_RAMDISK_FILE}
  250. fi
  251. # This refers the options for disk-image-create and the platform on which
  252. # to build the dib based ironic-python-agent ramdisk.
  253. IRONIC_DIB_RAMDISK_OPTIONS=${IRONIC_DIB_RAMDISK_OPTIONS:-}
  254. if [[ -z "$IRONIC_DIB_RAMDISK_OPTIONS" ]]; then
  255. if [[ "$IRONIC_DIB_RAMDISK_OS" == "centos8" ]]; then
  256. # Adapt for DIB naming change
  257. IRONIC_DIB_RAMDISK_OS=centos-minimal
  258. IRONIC_DIB_RAMDISK_RELEASE=8
  259. fi
  260. IRONIC_DIB_RAMDISK_OPTIONS="$IRONIC_DIB_RAMDISK_OS"
  261. fi
  262. # DHCP timeout for the dhcp-all-interfaces element.
  263. IRONIC_DIB_DHCP_TIMEOUT=${IRONIC_DIB_DHCP_TIMEOUT:-60}
  264. # Some drivers in Ironic require deploy ramdisk in bootable ISO format.
  265. # Set this variable to "true" to build an ISO for deploy ramdisk and
  266. # upload to Glance.
  267. IRONIC_DEPLOY_ISO_REQUIRED=$(trueorfalse False IRONIC_DEPLOY_ISO_REQUIRED)
  268. if [[ "$IRONIC_DEPLOY_ISO_REQUIRED" = "True" \
  269. && "$IRONIC_BUILD_DEPLOY_RAMDISK" = "False" \
  270. && ! -e "$IRONIC_DEPLOY_ISO" ]]; then
  271. die "Prebuilt ISOs are not available, provide an ISO via IRONIC_DEPLOY_ISO \
  272. or set IRONIC_BUILD_DEPLOY_RAMDISK=True to use ISOs"
  273. fi
  274. # Which deploy driver to use - valid choices right now
  275. # are ``ipmi``, ``snmp`` and ``redfish``.
  276. #
  277. # Additional valid choices if IRONIC_IS_HARDWARE == true are:
  278. # ``idrac`` and ``irmc``.
  279. IRONIC_DEPLOY_DRIVER=${IRONIC_DEPLOY_DRIVER:-ipmi}
  280. # If the requested driver is not yet enable, enable it, if it is not it will fail anyway
  281. if [[ -z "$(echo ${IRONIC_ENABLED_HARDWARE_TYPES} | grep -w ${IRONIC_DEPLOY_DRIVER})" ]]; then
  282. die "The deploy driver $IRONIC_DEPLOY_DRIVER is not in the list of enabled \
  283. hardware types $IRONIC_ENABLED_HARDWARE_TYPES"
  284. fi
  285. # Support entry points installation of console scripts
  286. IRONIC_BIN_DIR=$(get_python_exec_prefix)
  287. IRONIC_UWSGI_CONF=$IRONIC_CONF_DIR/ironic-uwsgi.ini
  288. IRONIC_UWSGI=$IRONIC_BIN_DIR/ironic-api-wsgi
  289. # Ironic connection info. Note the port must be specified.
  290. if is_service_enabled tls-proxy; then
  291. IRONIC_SERVICE_PROTOCOL=https
  292. fi
  293. IRONIC_SERVICE_PROTOCOL=${IRONIC_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
  294. IRONIC_SERVICE_PORT=${IRONIC_SERVICE_PORT:-6385}
  295. IRONIC_SERVICE_PORT_INT=${IRONIC_SERVICE_PORT_INT:-16385}
  296. # If ironic api running under apache or UWSGI we use the path rather than port
  297. if [[ "$IRONIC_USE_WSGI" == "True" ]]; then
  298. IRONIC_HOSTPORT=${IRONIC_HOSTPORT:-$SERVICE_HOST/baremetal}
  299. else
  300. IRONIC_HOSTPORT=${IRONIC_HOSTPORT:-$SERVICE_HOST:$IRONIC_SERVICE_PORT}
  301. fi
  302. # Enable iPXE
  303. IRONIC_IPXE_ENABLED=$(trueorfalse True IRONIC_IPXE_ENABLED)
  304. # Options below are only applied when IRONIC_IPXE_ENABLED is True
  305. IRONIC_IPXE_USE_SWIFT=$(trueorfalse False IRONIC_IPXE_USE_SWIFT)
  306. IRONIC_HTTP_DIR=${IRONIC_HTTP_DIR:-$IRONIC_DATA_DIR/httpboot}
  307. IRONIC_HTTP_PORT=${IRONIC_HTTP_PORT:-3928}
  308. # Allow using JSON RPC instead of oslo.messaging
  309. IRONIC_RPC_TRANSPORT=${IRONIC_RPC_TRANSPORT:-oslo}
  310. IRONIC_JSON_RPC_PORT=${IRONIC_JSON_RPC_PORT:-8089}
  311. # The first port in the range to bind the Virtual BMCs. The number of
  312. # ports that will be used depends on $IRONIC_VM_COUNT variable, e.g if
  313. # $IRONIC_VM_COUNT=3 the ports 6230, 6231 and 6232 will be used for the
  314. # Virtual BMCs, one for each VM.
  315. IRONIC_VBMC_PORT_RANGE_START=${IRONIC_VBMC_PORT_RANGE_START:-6230}
  316. IRONIC_VBMC_CONFIG_FILE=${IRONIC_VBMC_CONFIG_FILE:-$IRONIC_CONF_DIR/virtualbmc/virtualbmc.conf}
  317. IRONIC_VBMC_LOGFILE=${IRONIC_VBMC_LOGFILE:-$IRONIC_VM_LOG_DIR/virtualbmc.log}
  318. IRONIC_VBMC_SYSTEMD_SERVICE=devstack@virtualbmc.service
  319. # Virtual PDU configs
  320. IRONIC_VPDU_CONFIG_FILE=${IRONIC_VPDU_CONFIG_FILE:-$IRONIC_CONF_DIR/virtualpdu/virtualpdu.conf}
  321. IRONIC_VPDU_PORT_RANGE_START=${IRONIC_VPDU_PORT_RANGE_START:-1}
  322. IRONIC_VPDU_LISTEN_PORT=${IRONIC_VPDU_LISTEN_PORT:-1161}
  323. IRONIC_VPDU_COMMUNITY=${IRONIC_VPDU_COMMUNITY:-private}
  324. IRONIC_VPDU_SNMPDRIVER=${IRONIC_VPDU_SNMPDRIVER:-apc_rackpdu}
  325. IRONIC_VPDU_SYSTEMD_SERVICE=devstack@virtualpdu.service
  326. # Redfish configs
  327. IRONIC_REDFISH_EMULATOR_PORT=${IRONIC_REDFISH_EMULATOR_PORT:-9132}
  328. IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE="devstack@redfish-emulator.service"
  329. IRONIC_REDFISH_EMULATOR_CONFIG=${IRONIC_REDFISH_EMULATOR_CONFIG:-$IRONIC_CONF_DIR/redfish/emulator.conf}
  330. # To explicitly enable configuration of Glance with Swift
  331. # (which is required by some vendor drivers), set this
  332. # variable to true.
  333. IRONIC_CONFIGURE_GLANCE_WITH_SWIFT=$(trueorfalse False IRONIC_CONFIGURE_GLANCE_WITH_SWIFT)
  334. # The path to the libvirt hooks directory, used if IRONIC_VM_LOG_ROTATE is True
  335. IRONIC_LIBVIRT_HOOKS_PATH=${IRONIC_LIBVIRT_HOOKS_PATH:-/etc/libvirt/hooks/}
  336. LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"}
  337. LIBVIRT_STORAGE_POOL_PATH=${LIBVIRT_STORAGE_POOL_PATH:-/var/lib/libvirt/images}
  338. # The authentication strategy used by ironic-api. Valid values are:
  339. # keystone and noauth.
  340. IRONIC_AUTH_STRATEGY=${IRONIC_AUTH_STRATEGY:-keystone}
  341. # By default, terminal SSL certificate is disabled.
  342. IRONIC_TERMINAL_SSL=$(trueorfalse False IRONIC_TERMINAL_SSL)
  343. IRONIC_TERMINAL_CERT_DIR=${IRONIC_TERMINAL_CERT_DIR:-$IRONIC_DATA_DIR/terminal_cert/}
  344. # This flag is used to allow adding Link-Local-Connection info
  345. # to ironic port-create command. LLC info is obtained from
  346. # IRONIC_{VM,HW}_NODES_FILE
  347. IRONIC_USE_LINK_LOCAL=$(trueorfalse False IRONIC_USE_LINK_LOCAL)
  348. # Allow selecting dhcp provider
  349. IRONIC_DHCP_PROVIDER=${IRONIC_DHCP_PROVIDER:-neutron}
  350. # This is the network interface to use for a node
  351. IRONIC_NETWORK_INTERFACE=${IRONIC_NETWORK_INTERFACE:-}
  352. # Ironic provision network name, if this value is set it means we are using
  353. # multi-tenant networking. If not set, then we are not using multi-tenant
  354. # networking and are therefore using a 'flat' network.
  355. IRONIC_PROVISION_NETWORK_NAME=${IRONIC_PROVISION_NETWORK_NAME:-}
  356. # Provision network provider type. Can be flat or vlan.
  357. # This is only used if IRONIC_PROVISION_NETWORK_NAME has been set.
  358. IRONIC_PROVISION_PROVIDER_NETWORK_TYPE=${IRONIC_PROVISION_PROVIDER_NETWORK_TYPE:-'vlan'}
  359. # If IRONIC_PROVISION_PROVIDER_NETWORK_TYPE is vlan. VLAN_ID may be specified. If it is not set,
  360. # vlan will be allocated dynamically.
  361. # This is only used if IRONIC_PROVISION_NETWORK_NAME has been set.
  362. IRONIC_PROVISION_SEGMENTATION_ID=${IRONIC_PROVISION_SEGMENTATION_ID:-}
  363. # Allocation network pool for provision network
  364. # Example: IRONIC_PROVISION_ALLOCATION_POOL=start=10.0.5.10,end=10.0.5.100
  365. # This is only used if IRONIC_PROVISION_NETWORK_NAME has been set.
  366. IRONIC_PROVISION_ALLOCATION_POOL=${IRONIC_PROVISION_ALLOCATION_POOL:-'start=10.0.5.10,end=10.0.5.100'}
  367. # Ironic provision subnet name.
  368. # This is only used if IRONIC_PROVISION_NETWORK_NAME has been set.
  369. IRONIC_PROVISION_PROVIDER_SUBNET_NAME=${IRONIC_PROVISION_PROVIDER_SUBNET_NAME:-${IRONIC_PROVISION_NETWORK_NAME}-subnet}
  370. # When enabled this will set the physical_network attribute for ironic ports
  371. # and subnet-to-segment association on provisioning network will be configured.
  372. # NOTE: The neutron segments service_plugin must be loaded for this.
  373. IRONIC_USE_NEUTRON_SEGMENTS=$(trueorfalse False IRONIC_USE_NEUTRON_SEGMENTS)
  374. # This is the storage interface to use for a node
  375. # Only 'cinder' can be set for testing boot from volume
  376. IRONIC_STORAGE_INTERFACE=${IRONIC_STORAGE_INTERFACE:-}
  377. # With multinode case all ironic-conductors should have IP from provisioning network.
  378. # IRONIC_PROVISION_SUBNET_GATEWAY - is configured on primary node.
  379. # Ironic provision subnet gateway.
  380. IRONIC_PROVISION_SUBNET_GATEWAY=${IRONIC_PROVISION_SUBNET_GATEWAY:-'10.0.5.1'}
  381. IRONIC_PROVISION_SUBNET_SUBNODE_IP=${IRONIC_PROVISION_SUBNET_SUBNODE_IP:-'10.0.5.2'}
  382. # Ironic provision subnet prefix
  383. # Example: IRONIC_PROVISION_SUBNET_PREFIX=10.0.5.0/24
  384. IRONIC_PROVISION_SUBNET_PREFIX=${IRONIC_PROVISION_SUBNET_PREFIX:-'10.0.5.0/24'}
  385. if [[ "$HOST_TOPOLOGY_ROLE" == "primary" ]]; then
  386. IRONIC_TFTPSERVER_IP=$IRONIC_PROVISION_SUBNET_GATEWAY
  387. IRONIC_HTTP_SERVER=$IRONIC_PROVISION_SUBNET_GATEWAY
  388. fi
  389. if [[ "$HOST_TOPOLOGY_ROLE" == "subnode" ]]; then
  390. IRONIC_TFTPSERVER_IP=$IRONIC_PROVISION_SUBNET_SUBNODE_IP
  391. IRONIC_HTTP_SERVER=$IRONIC_PROVISION_SUBNET_SUBNODE_IP
  392. fi
  393. IRONIC_HTTP_SERVER=${IRONIC_HTTP_SERVER:-$IRONIC_TFTPSERVER_IP}
  394. # Port that must be permitted for iSCSI connections to be
  395. # established from the tenant network.
  396. ISCSI_SERVICE_PORT=${ISCSI_SERVICE_PORT:-3260}
  397. # Retrieving logs from the deploy ramdisk
  398. #
  399. # IRONIC_DEPLOY_LOGS_COLLECT possible values are:
  400. # * always: Collect the ramdisk logs from the deployment on success or
  401. # failure (Default in DevStack for debugging purpose).
  402. # * on_failure: Collect the ramdisk logs upon a deployment failure
  403. # (Default in Ironic).
  404. # * never: Never collect the ramdisk logs.
  405. IRONIC_DEPLOY_LOGS_COLLECT=${IRONIC_DEPLOY_LOGS_COLLECT:-always}
  406. # IRONIC_DEPLOY_LOGS_STORAGE_BACKEND possible values are:
  407. # * local: To store the logs in the local filesystem (Default in Ironic and DevStack).
  408. # * swift: To store the logs in Swift.
  409. IRONIC_DEPLOY_LOGS_STORAGE_BACKEND=${IRONIC_DEPLOY_LOGS_STORAGE_BACKEND:-local}
  410. # The path to the directory where Ironic should put the logs when IRONIC_DEPLOY_LOGS_STORAGE_BACKEND is set to "local"
  411. IRONIC_DEPLOY_LOGS_LOCAL_PATH=${IRONIC_DEPLOY_LOGS_LOCAL_PATH:-$IRONIC_VM_LOG_DIR/deploy_logs}
  412. # Fast track option
  413. IRONIC_DEPLOY_FAST_TRACK=${IRONIC_DEPLOY_FAST_TRACK:-False}
  414. # Define baremetal min_microversion in tempest config. Default value None is picked from tempest.
  415. TEMPEST_BAREMETAL_MIN_MICROVERSION=${TEMPEST_BAREMETAL_MIN_MICROVERSION:-}
  416. # Define baremetal max_microversion in tempest config. No default value means that it is picked from tempest.
  417. TEMPEST_BAREMETAL_MAX_MICROVERSION=${TEMPEST_BAREMETAL_MAX_MICROVERSION:-}
  418. # get_pxe_boot_file() - Get the PXE/iPXE boot file path
  419. function get_pxe_boot_file {
  420. local pxe_boot_file
  421. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
  422. if is_ubuntu; then
  423. pxe_boot_file=/usr/lib/ipxe/undionly.kpxe
  424. elif is_fedora || is_suse; then
  425. pxe_boot_file=/usr/share/ipxe/undionly.kpxe
  426. fi
  427. else
  428. # Standard PXE
  429. if is_ubuntu; then
  430. # Ubuntu Xenial (16.04) places the file under /usr/lib/PXELINUX
  431. pxe_paths="/usr/lib/syslinux/pxelinux.0 /usr/lib/PXELINUX/pxelinux.0"
  432. for p in $pxe_paths; do
  433. if [[ -f $p ]]; then
  434. pxe_boot_file=$p
  435. fi
  436. done
  437. elif is_fedora || is_suse; then
  438. pxe_boot_file=/usr/share/syslinux/pxelinux.0
  439. fi
  440. fi
  441. echo $pxe_boot_file
  442. }
  443. # PXE boot image
  444. IRONIC_PXE_BOOT_IMAGE=${IRONIC_PXE_BOOT_IMAGE:-$(get_pxe_boot_file)}
  445. IRONIC_AUTOMATED_CLEAN_ENABLED=$(trueorfalse True IRONIC_AUTOMATED_CLEAN_ENABLED)
  446. IRONIC_SECURE_BOOT=${IRONIC_SECURE_BOOT:-False}
  447. IRONIC_UEFI_BOOT_LOADER=${IRONIC_UEFI_BOOT_LOADER:-grub2}
  448. IRONIC_GRUB2_SHIM_FILE=${IRONIC_GRUB2_SHIM_FILE:-}
  449. IRONIC_GRUB2_FILE=${IRONIC_GRUB2_FILE:-}
  450. IRONIC_UEFI_FILES_DIR=${IRONIC_UEFI_FILES_DIR:-/var/lib/libvirt/images}
  451. UEFI_LOADER_PATH=$IRONIC_UEFI_FILES_DIR/OVMF_CODE.fd
  452. UEFI_NVRAM_PATH=$IRONIC_UEFI_FILES_DIR/OVMF_VARS.fd
  453. # Handle architecture specific package installs
  454. if [[ $IRONIC_HW_ARCH == "x86_64" ]]; then
  455. install_package shim
  456. if is_ubuntu; then
  457. install_package grub-efi-amd64-signed
  458. elif is_fedora; then
  459. install_package grub2-efi
  460. fi
  461. fi
  462. # Sanity checks
  463. if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  464. if [[ "$IRONIC_IPXE_ENABLED" == "False" ]] && [[ "$IRONIC_UEFI_BOOT_LOADER" != "grub2" ]]; then
  465. die $LINENO "Boot mode UEFI is only supported with iPXE and grub2 bootloaders."
  466. fi
  467. if ! is_fedora && ! is_ubuntu; then
  468. die $LINENO "Boot mode UEFI only works in Ubuntu or Fedora for now."
  469. fi
  470. if is_arch "x86_64"; then
  471. if is_ubuntu; then
  472. install_package grub-efi
  473. elif is_fedora; then
  474. install_package grub2 grub2-efi
  475. fi
  476. fi
  477. if is_ubuntu && [[ -z $IRONIC_GRUB2_FILE ]]; then
  478. IRONIC_GRUB2_SHIM_FILE=/usr/lib/shim/shimx64.efi
  479. IRONIC_GRUB2_FILE=/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed
  480. fi
  481. if [[ "$IRONIC_IPXE_ENABLED" == "False" ]]; then
  482. # NOTE(TheJulia): While we no longer directly copy the
  483. # IRONIC_GRUB2_FILE, we still check the existence as
  484. # without the bootloader package we would be unable to build
  485. # the netboot core image.
  486. if [[ -z $IRONIC_GRUB2_SHIM_FILE ]] || [[ -z $IRONIC_GRUB2_FILE ]] || [[ ! -f $IRONIC_GRUB2_SHIM_FILE ]] || [[ ! -f $IRONIC_GRUB2_FILE ]]; then
  487. die $LINENO "Grub2 Bootloader and Shim file missing."
  488. fi
  489. fi
  490. fi
  491. # TODO(dtantsur): change this when we change the default value.
  492. IRONIC_DEFAULT_BOOT_OPTION=${IRONIC_DEFAULT_BOOT_OPTION:-netboot}
  493. if [ $IRONIC_DEFAULT_BOOT_OPTION != "netboot" ] && [ $IRONIC_DEFAULT_BOOT_OPTION != "local" ]; then
  494. die $LINENO "Supported values for IRONIC_DEFAULT_BOOT_OPTION are 'netboot' and 'local' only."
  495. fi
  496. # TODO(pas-ha) find a way to (cross-)sign the custom CA bundle used by tls-proxy
  497. # with default iPXE cert - for reference see http://ipxe.org/crypto
  498. if is_service_enabled tls-proxy && [[ "$IRONIC_IPXE_USE_SWIFT" == "True" ]]; then
  499. die $LINENO "Ironic in DevStack does not yet support booting iPXE from HTTPS URLs"
  500. fi
  501. # Timeout for "manage" action. 2 minutes is more than enough.
  502. IRONIC_MANAGE_TIMEOUT=${IRONIC_MANAGE_TIMEOUT:-120}
  503. # Timeout for "provide" action. This involves cleaning. Generally, 15 minutes
  504. # should be enough, but real hardware may need more.
  505. IRONIC_CLEANING_TIMEOUT=${IRONIC_CLEANING_TIMEOUT:-1200}
  506. IRONIC_CLEANING_DELAY=10
  507. IRONIC_CLEANING_ATTEMPTS=$(( $IRONIC_CLEANING_TIMEOUT / $IRONIC_CLEANING_DELAY ))
  508. # Timeout for ironic-neutron-agent to report state before providing nodes.
  509. # The agent reports every 60 seconds, 2 minutes should do.
  510. IRONIC_NEUTRON_AGENT_REPORT_STATE_DELAY=10
  511. IRONIC_NEUTRON_AGENT_REPORT_STATE_TIMEOUT=${IRONIC_NEUTRON_AGENT_REPORT_STATE_TIMEOUT:-120}
  512. IRONIC_NEUTRON_AGENT_REPORT_STATE_ATTEMPTS=$(( $IRONIC_NEUTRON_AGENT_REPORT_STATE_TIMEOUT / IRONIC_NEUTRON_AGENT_REPORT_STATE_DELAY ))
  513. # Username to use by Ansible to access ramdisk,
  514. # to be set as '[ansible]/default_username' option.
  515. # If not set here (default), will be set to 'tc' for TinyIPA ramdisk,
  516. # for other ramdisks it must be either provided here,
  517. # or set manually per-node via ironic API
  518. IRONIC_ANSIBLE_SSH_USER=${IRONIC_ANSIBLE_SSH_USER:-}
  519. # Path to the private SSH key to use by ansible deploy interface
  520. # that will be set as '[ansible]/default_key_file' option in config.
  521. # The public key path is assumed to be ${IRONIC_ANSIBLE_SSH_KEY}.pub
  522. # and will be used when rebuilding the image to include this public key
  523. # in ~/.ssh/authorized_keys of a $IRONIC_ANSIBLE_SSH_USER in the ramdisk.
  524. # Only the TinyIPA ramdisks are currently supported for such rebuild.
  525. # For TinyIPA ramdisks, if the specified file doesn't exist, it will
  526. # be created and will contain a new RSA passwordless key. We assume
  527. # that the directories in the path to this file exist and are
  528. # writable.
  529. # For other ramdisk types, make sure the corresponding public key is baked into
  530. # the ramdisk to be used by DevStack and provide the path to the private key here,
  531. # or set it manually per node via ironic API.
  532. # FIXME(pas-ha) auto-generated keys currently won't work for multi-node
  533. # DevStack deployment, as we do not distribute this generated key to subnodes yet.
  534. IRONIC_ANSIBLE_SSH_KEY=${IRONIC_ANSIBLE_SSH_KEY:-$IRONIC_DATA_DIR/ansible_ssh_key}
  535. IRONIC_AGENT_IMAGE_DOWNLOAD_SOURCE=${IRONIC_AGENT_IMAGE_DOWNLOAD_SOURCE:-swift}
  536. # Functions
  537. # ---------
  538. # UEFI related functions
  539. function get_uefi_ipxe_boot_file {
  540. if is_ubuntu; then
  541. echo /usr/lib/ipxe/ipxe.efi
  542. elif is_fedora; then
  543. echo /usr/share/ipxe/ipxe-x86_64.efi
  544. fi
  545. }
  546. function get_uefi_loader {
  547. if is_ubuntu; then
  548. echo /usr/share/OVMF/OVMF_CODE.fd
  549. elif is_fedora; then
  550. echo /usr/share/edk2/ovmf/OVMF_CODE.fd
  551. fi
  552. }
  553. function get_uefi_nvram {
  554. if is_ubuntu; then
  555. echo /usr/share/OVMF/OVMF_VARS.fd
  556. elif is_fedora; then
  557. echo /usr/share/edk2/ovmf/OVMF_VARS.fd
  558. fi
  559. }
  560. # Misc
  561. function restart_libvirt {
  562. local libvirt_service_name="libvirtd"
  563. if is_ubuntu && ! type libvirtd; then
  564. libvirt_service_name="libvirt-bin"
  565. fi
  566. restart_service $libvirt_service_name
  567. }
  568. # Test if any Ironic services are enabled
  569. # is_ironic_enabled
  570. function is_ironic_enabled {
  571. [[ ,${ENABLED_SERVICES} =~ ,"ir-" ]] && return 0
  572. return 1
  573. }
  574. function is_deployed_by_agent {
  575. [[ -z "${IRONIC_DEPLOY_DRIVER%%agent*}" || "$IRONIC_DEFAULT_DEPLOY_INTERFACE" == "direct" ]] && return 0
  576. return 1
  577. }
  578. function is_deployed_by_ipmi {
  579. [[ "$IRONIC_DEPLOY_DRIVER" == ipmi ]] && return 0
  580. return 1
  581. }
  582. function is_deployed_by_ilo {
  583. [[ "${IRONIC_DEPLOY_DRIVER}" == ilo ]] && return 0
  584. return 1
  585. }
  586. function is_deployed_by_drac {
  587. [[ "${IRONIC_DEPLOY_DRIVER}" == idrac ]] && return 0
  588. return 1
  589. }
  590. function is_deployed_by_snmp {
  591. [[ "${IRONIC_DEPLOY_DRIVER}" == snmp ]] && return 0
  592. return 1
  593. }
  594. function is_deployed_by_redfish {
  595. [[ "$IRONIC_DEPLOY_DRIVER" == redfish ]] && return 0
  596. return 1
  597. }
  598. function is_deployed_by_irmc {
  599. [[ "$IRONIC_DEPLOY_DRIVER" == irmc ]] && return 0
  600. return 1
  601. }
  602. function is_deployed_by_xclarity {
  603. [[ "$IRONIC_DEPLOY_DRIVER" == xclarity ]] && return 0
  604. return 1
  605. }
  606. function is_drac_enabled {
  607. [[ -z "${IRONIC_ENABLED_HARDWARE_TYPES%%*idrac*}" ]] && return 0
  608. return 1
  609. }
  610. function is_ansible_deploy_enabled {
  611. [[ -z "${IRONIC_ENABLED_DEPLOY_INTERFACES%%*ansible*}" ]] && return 0
  612. return 1
  613. }
  614. function is_redfish_enabled {
  615. [[ -z "${IRONIC_ENABLED_HARDWARE_TYPES%%*redfish*}" ]] && return 0
  616. return 1
  617. }
  618. function is_ansible_with_tinyipa {
  619. # NOTE(pas-ha) we support rebuilding the ramdisk to include (generated) SSH keys
  620. # as needed for ansible deploy interface only for TinyIPA ramdisks for now
  621. is_ansible_deploy_enabled && [[ "$IRONIC_RAMDISK_TYPE" == "tinyipa" ]] && return 0
  622. return 1
  623. }
  624. function is_glance_configuration_required {
  625. is_deployed_by_agent || is_ansible_deploy_enabled || [[ "$IRONIC_CONFIGURE_GLANCE_WITH_SWIFT" == "True" ]] && return 0
  626. return 1
  627. }
  628. function is_deploy_iso_required {
  629. [[ "$IRONIC_IS_HARDWARE" == "True" && "$IRONIC_DEPLOY_ISO_REQUIRED" == "True" ]] && return 0
  630. return 1
  631. }
  632. # Assert that the redfish hardware type is enabled in case we are using
  633. # the redfish driver
  634. if is_deployed_by_redfish && [[ "$IRONIC_ENABLED_HARDWARE_TYPES" != *"redfish"* ]]; then
  635. die $LINENO "Please make sure that the redfish hardware" \
  636. "type is enabled. Take a look at the " \
  637. "IRONIC_ENABLED_HARDWARE_TYPES configuration option" \
  638. "for DevStack"
  639. fi
  640. # Assert that for non-TynyIPA ramdisks and Ansible, the private SSH key file to use exists.
  641. if is_ansible_deploy_enabled && [[ "$IRONIC_RAMDISK_TYPE" != "tinyipa" ]]; then
  642. if [[ ! -f $IRONIC_ANSIBLE_SSH_KEY ]]; then
  643. die $LINENO "Using non-TinyIPA ramdisks with ansible deploy interface" \
  644. "requires setting IRONIC_ANSIBLE_SSH_KEY to existing"\
  645. "private SSH key file to be used by Ansible."
  646. fi
  647. fi
  648. # Syslinux >= 5.00 pxelinux.0 binary is not "stand-alone" anymore,
  649. # it depends on some c32 modules to work correctly.
  650. # More info: http://www.syslinux.org/wiki/index.php/Library_modules
  651. function setup_syslinux_modules {
  652. # Ignore it for iPXE, it doesn't repend on syslinux modules
  653. [[ "$IRONIC_IPXE_ENABLED" == "True" ]] && return 0
  654. # Ubuntu Xenial keeps doesn't ship pxelinux.0 as part of syslinux anymore
  655. if is_ubuntu && [[ -d /usr/lib/PXELINUX/ ]]; then
  656. # TODO(lucasagomes): Figure out whether its UEFI or BIOS once
  657. # we have UEFI support in DevStack
  658. cp -aR /usr/lib/syslinux/modules/bios/*.c32 $IRONIC_TFTPBOOT_DIR
  659. else
  660. cp -aR $(dirname $IRONIC_PXE_BOOT_IMAGE)/*.c32 $IRONIC_TFTPBOOT_DIR
  661. fi
  662. }
  663. function start_virtualbmc {
  664. start_service $IRONIC_VBMC_SYSTEMD_SERVICE
  665. }
  666. function stop_virtualbmc {
  667. stop_service $IRONIC_VBMC_SYSTEMD_SERVICE
  668. }
  669. function cleanup_virtualbmc {
  670. stop_virtualbmc
  671. disable_service $IRONIC_VBMC_SYSTEMD_SERVICE
  672. local unitfile="$SYSTEMD_DIR/$IRONIC_VBMC_SYSTEMD_SERVICE"
  673. sudo rm -f $unitfile
  674. $SYSTEMCTL daemon-reload
  675. }
  676. function install_virtualbmc {
  677. # Install pyghmi from source, if requested, otherwise it will be
  678. # downloaded as part of the virtualbmc installation
  679. if use_library_from_git "pyghmi"; then
  680. git_clone_by_name "pyghmi"
  681. setup_dev_lib "pyghmi"
  682. fi
  683. if use_library_from_git "virtualbmc"; then
  684. git_clone_by_name "virtualbmc"
  685. setup_dev_lib "virtualbmc"
  686. else
  687. pip_install_gr "virtualbmc"
  688. fi
  689. local cmd
  690. cmd=$(which vbmcd)
  691. cmd+=" --foreground"
  692. write_user_unit_file $IRONIC_VBMC_SYSTEMD_SERVICE "$cmd" "" "$STACK_USER"
  693. local unitfile="$SYSTEMD_DIR/$IRONIC_VBMC_SYSTEMD_SERVICE"
  694. iniset -sudo $unitfile "Service" "Environment" "VIRTUALBMC_CONFIG=$IRONIC_VBMC_CONFIG_FILE"
  695. enable_service $IRONIC_VBMC_SYSTEMD_SERVICE
  696. }
  697. function configure_virtualbmc {
  698. if [[ ! -d $(dirname $IRONIC_VBMC_CONFIG_FILE) ]]; then
  699. mkdir -p $(dirname $IRONIC_VBMC_CONFIG_FILE)
  700. fi
  701. iniset -sudo $IRONIC_VBMC_CONFIG_FILE log debug True
  702. }
  703. function start_virtualpdu {
  704. start_service $IRONIC_VPDU_SYSTEMD_SERVICE
  705. }
  706. function stop_virtualpdu {
  707. stop_service $IRONIC_VPDU_SYSTEMD_SERVICE
  708. }
  709. function cleanup_virtualpdu {
  710. stop_virtualpdu
  711. disable_service $IRONIC_VPDU_SYSTEMD_SERVICE
  712. local unitfile="$SYSTEMD_DIR/$IRONIC_VPDU_SYSTEMD_SERVICE"
  713. sudo rm -f $unitfile
  714. $SYSTEMCTL daemon-reload
  715. }
  716. function install_virtualpdu {
  717. if use_library_from_git "virtualpdu"; then
  718. git_clone_by_name "virtualpdu"
  719. setup_dev_lib "virtualpdu"
  720. else
  721. pip_install "virtualpdu"
  722. fi
  723. local cmd
  724. cmd=$(which virtualpdu)
  725. cmd+=" $IRONIC_VPDU_CONFIG_FILE"
  726. write_user_unit_file $IRONIC_VPDU_SYSTEMD_SERVICE "$cmd" "" "$STACK_USER"
  727. enable_service $IRONIC_VPDU_SYSTEMD_SERVICE
  728. }
  729. function configure_virtualpdu {
  730. mkdir -p $(dirname $IRONIC_VPDU_CONFIG_FILE)
  731. iniset -sudo $IRONIC_VPDU_CONFIG_FILE global debug True
  732. iniset -sudo $IRONIC_VPDU_CONFIG_FILE global libvirt_uri "qemu:///system"
  733. iniset -sudo $IRONIC_VPDU_CONFIG_FILE PDU listen_address ${HOST_IP}
  734. iniset -sudo $IRONIC_VPDU_CONFIG_FILE PDU listen_port ${IRONIC_VPDU_LISTEN_PORT}
  735. iniset -sudo $IRONIC_VPDU_CONFIG_FILE PDU community ${IRONIC_VPDU_COMMUNITY}
  736. iniset -sudo $IRONIC_VPDU_CONFIG_FILE PDU ports $(_generate_pdu_ports)
  737. iniset -sudo $IRONIC_VPDU_CONFIG_FILE PDU outlet_default_state "OFF"
  738. }
  739. # _generate_pdu_ports() - Generates list of port:node_name.
  740. function _generate_pdu_ports {
  741. pdu_port_number=${IRONIC_VPDU_PORT_RANGE_START}
  742. port_config=()
  743. for vm_name in $(_ironic_bm_vm_names); do
  744. port_config+=("${pdu_port_number}:${vm_name}")
  745. pdu_port_number=$(( pdu_port_number + 1 ))
  746. done
  747. echo ${port_config[*]} | tr ' ' ','
  748. }
  749. function start_redfish {
  750. start_service $IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE
  751. }
  752. function stop_redfish {
  753. stop_service $IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE
  754. }
  755. function cleanup_redfish {
  756. stop_redfish
  757. rm -f $IRONIC_REDFISH_EMULATOR_CONFIG
  758. disable_service $IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE
  759. local unitfile="$SYSTEMD_DIR/$IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE"
  760. sudo rm -f $unitfile
  761. $SYSTEMCTL daemon-reload
  762. }
  763. function install_redfish {
  764. # TODO(lucasagomes): Use Apache WSGI instead of gunicorn
  765. gunicorn=gunicorn
  766. if python3_enabled; then
  767. gunicorn=${gunicorn}3
  768. fi
  769. if is_ubuntu; then
  770. install_package $gunicorn
  771. else
  772. pip_install_gr "gunicorn"
  773. fi
  774. if use_library_from_git "sushy-tools"; then
  775. git_clone_by_name "sushy-tools"
  776. setup_dev_lib "sushy-tools"
  777. else
  778. pip_install "sushy-tools"
  779. fi
  780. local cmd
  781. cmd=$(which $gunicorn)
  782. cmd+=" sushy_tools.emulator.main:app"
  783. cmd+=" --bind ${HOST_IP}:${IRONIC_REDFISH_EMULATOR_PORT}"
  784. cmd+=" --env FLASK_DEBUG=1"
  785. cmd+=" --env SUSHY_EMULATOR_CONFIG=${IRONIC_REDFISH_EMULATOR_CONFIG}"
  786. write_user_unit_file $IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE "$cmd" "" "$STACK_USER"
  787. enable_service $IRONIC_REDFISH_EMULATOR_SYSTEMD_SERVICE
  788. }
  789. function configure_redfish {
  790. if [[ ! -d $(dirname $IRONIC_REDFISH_EMULATOR_CONFIG) ]]; then
  791. mkdir -p $(dirname $IRONIC_REDFISH_EMULATOR_CONFIG)
  792. fi
  793. cat - <<EOF > $IRONIC_REDFISH_EMULATOR_CONFIG
  794. SUSHY_EMULATOR_BOOT_LOADER_MAP = {
  795. 'UEFI': {
  796. 'x86_64': '$UEFI_LOADER_PATH'
  797. },
  798. 'Legacy': {
  799. 'x86_64': None
  800. }
  801. }
  802. EOF
  803. }
  804. function setup_sushy {
  805. if use_library_from_git "sushy"; then
  806. git_clone_by_name "sushy"
  807. setup_dev_lib "sushy"
  808. else
  809. pip_install_gr "sushy"
  810. fi
  811. }
  812. # install_ironic() - Install the things!
  813. function install_ironic {
  814. # NOTE(vsaienko) do not check required_services on subnode
  815. if [[ "$HOST_TOPOLOGY_ROLE" != "subnode" ]]; then
  816. # make sure all needed service were enabled
  817. local req_services="key"
  818. if is_service_enabled nova && [[ "$VIRT_DRIVER" == "ironic" ]]; then
  819. req_services+=" nova glance neutron"
  820. fi
  821. for srv in $req_services; do
  822. if ! is_service_enabled "$srv"; then
  823. die $LINENO "$srv should be enabled for Ironic."
  824. fi
  825. done
  826. fi
  827. if use_library_from_git "ironic-lib"; then
  828. git_clone_by_name "ironic-lib"
  829. setup_dev_lib "ironic-lib"
  830. fi
  831. setup_develop $IRONIC_DIR
  832. if [[ "$IRONIC_USE_WSGI" == "True" || "$IRONIC_IPXE_ENABLED" == "True" ]]; then
  833. install_apache_wsgi
  834. fi
  835. if [[ "$IRONIC_BOOT_MODE" == "uefi" && "$IRONIC_IS_HARDWARE" == "False" ]]; then
  836. # Append the nvram configuration to libvirt if it's not present already
  837. if ! sudo grep -q "^nvram" /etc/libvirt/qemu.conf; then
  838. echo "nvram=[\"$UEFI_LOADER_PATH:$UEFI_NVRAM_PATH\"]" | sudo tee -a /etc/libvirt/qemu.conf
  839. fi
  840. # Replace the default virtio PXE ROM in QEMU with an EFI capable
  841. # one. The EFI ROM should work on with both boot modes, Legacy
  842. # BIOS and UEFI.
  843. if is_ubuntu; then
  844. # (rpittau) in bionic the UEFI in the ovmf 0~20180205.c0d9813c-2
  845. # package is broken: EFI v2.70 by EDK II
  846. # As a workaround, here we download and install the old working
  847. # version from the multiverse repository: EFI v2.60 by EDK II
  848. # Bug reference:
  849. # https://bugs.launchpad.net/ubuntu/+source/edk2/+bug/1821729
  850. local temp_deb
  851. temp_deb="$(mktemp)"
  852. wget http://archive.ubuntu.com/ubuntu/pool/multiverse/e/edk2/ovmf_0~20160408.ffea0a2c-2_all.deb -O "$temp_deb"
  853. sudo dpkg -i "$temp_deb"
  854. rm -f "$temp_deb"
  855. # NOTE(TheJulia): This no longer seems required as the ovmf images
  856. # DO correctly network boot. The effect of this is making the
  857. # default boot loader iPXE, which is not always desired nor
  858. # realistic for hardware in the field.
  859. # If it is after Train, we should likely just delete the lines
  860. # below and consider the same for Fedora.
  861. # sudo rm /usr/share/qemu/pxe-virtio.rom
  862. # sudo ln -s /usr/lib/ipxe/qemu/efi-virtio.rom /usr/share/qemu/pxe-virtio.rom
  863. elif is_fedora; then
  864. sudo rm /usr/share/qemu/pxe-virtio.rom
  865. sudo ln -s /usr/share/ipxe.efi/1af41000.rom /usr/share/qemu/pxe-virtio.rom
  866. fi
  867. # Restart libvirt to the changes to take effect
  868. restart_libvirt
  869. fi
  870. if is_redfish_enabled || is_deployed_by_redfish; then
  871. setup_sushy
  872. fi
  873. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  874. if is_deployed_by_ipmi; then
  875. install_virtualbmc
  876. fi
  877. if is_deployed_by_snmp; then
  878. install_virtualpdu
  879. fi
  880. if is_deployed_by_redfish; then
  881. install_redfish
  882. fi
  883. fi
  884. if is_drac_enabled; then
  885. pip_install python-dracclient
  886. fi
  887. if is_ansible_deploy_enabled; then
  888. pip_install "$(grep '^ansible' $IRONIC_DIR/driver-requirements.txt | awk '{print $1}')"
  889. fi
  890. }
  891. # install_ironicclient() - Collect sources and prepare
  892. function install_ironicclient {
  893. if use_library_from_git "python-ironicclient"; then
  894. git_clone_by_name "python-ironicclient"
  895. setup_dev_lib "python-ironicclient"
  896. else
  897. # nothing actually "requires" ironicclient, so force instally from pypi
  898. pip_install_gr python-ironicclient
  899. fi
  900. }
  901. # _cleanup_ironic_apache_additions() - Remove uwsgi files, disable and remove apache vhost file
  902. function _cleanup_ironic_apache_additions {
  903. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]]; then
  904. sudo rm -rf $IRONIC_HTTP_DIR
  905. disable_apache_site ipxe-ironic
  906. sudo rm -f $(apache_site_config_for ipxe-ironic)
  907. fi
  908. if [[ "$IRONIC_USE_WSGI" == "True" ]]; then
  909. remove_uwsgi_config "$IRONIC_UWSGI_CONF" "$IRONIC_UWSGI"
  910. fi
  911. restart_apache_server
  912. }
  913. # _config_ironic_apache_ipxe() - Configure ironic IPXE site
  914. function _config_ironic_apache_ipxe {
  915. local ipxe_apache_conf
  916. ipxe_apache_conf=$(apache_site_config_for ipxe-ironic)
  917. sudo cp $IRONIC_DEVSTACK_FILES_DIR/apache-ipxe-ironic.template $ipxe_apache_conf
  918. sudo sed -e "
  919. s|%PUBLICPORT%|$IRONIC_HTTP_PORT|g;
  920. s|%HTTPROOT%|$IRONIC_HTTP_DIR|g;
  921. s|%APACHELOGDIR%|$APACHE_LOG_DIR|g;
  922. " -i $ipxe_apache_conf
  923. enable_apache_site ipxe-ironic
  924. }
  925. # cleanup_ironic_config_files() - Remove residual cache/config/log files,
  926. # left over from previous runs that would need to clean up.
  927. function cleanup_ironic_config_files {
  928. sudo rm -rf $IRONIC_AUTH_CACHE_DIR $IRONIC_CONF_DIR
  929. sudo rm -rf $IRONIC_VM_LOG_DIR/*
  930. }
  931. # cleanup_ironic() - Clean everything left from Ironic
  932. function cleanup_ironic {
  933. cleanup_ironic_config_files
  934. # Cleanup additions made to Apache
  935. if [[ "$IRONIC_USE_WSGI" == "True" || "$IRONIC_IPXE_ENABLED" == "True" ]]; then
  936. _cleanup_ironic_apache_additions
  937. fi
  938. cleanup_virtualbmc
  939. cleanup_virtualpdu
  940. cleanup_redfish
  941. # Remove the hook to disable log rotate
  942. sudo rm -rf $IRONIC_LIBVIRT_HOOKS_PATH/qemu
  943. }
  944. # configure_ironic_dirs() - Create all directories required by Ironic and
  945. # associated services.
  946. function configure_ironic_dirs {
  947. sudo install -d -o $STACK_USER $IRONIC_CONF_DIR $STACK_USER $IRONIC_DATA_DIR \
  948. $IRONIC_STATE_PATH $IRONIC_TFTPBOOT_DIR $IRONIC_TFTPBOOT_DIR/pxelinux.cfg
  949. sudo chown -R $STACK_USER:$STACK_USER $IRONIC_TFTPBOOT_DIR
  950. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]]; then
  951. sudo install -d -o $STACK_USER -g $STACK_USER $IRONIC_HTTP_DIR
  952. fi
  953. if [ ! -f "$IRONIC_PXE_BOOT_IMAGE" ]; then
  954. die $LINENO "PXE boot file $IRONIC_PXE_BOOT_IMAGE not found."
  955. fi
  956. # Copy PXE binary
  957. # NOTE(mjturek): The PXE binary is x86_64 specific. So it should only be copied when
  958. # deploying to an x86_64 node.
  959. if [[ $IRONIC_HW_ARCH == "x86_64" ]]; then
  960. cp $IRONIC_PXE_BOOT_IMAGE $IRONIC_TFTPBOOT_DIR
  961. setup_syslinux_modules
  962. fi
  963. if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  964. local uefi_boot_file
  965. uefi_boot_file=$(get_uefi_ipxe_boot_file)
  966. if [ ! -f $uefi_boot_file ]; then
  967. die $LINENO "UEFI boot file $uefi_boot_file not found."
  968. fi
  969. cp $uefi_boot_file $IRONIC_TFTPBOOT_DIR
  970. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  971. local uefi_loader
  972. local uefi_nvram
  973. # Copy the OVMF images to libvirt's path
  974. uefi_loader=$(get_uefi_loader)
  975. uefi_nvram=$(get_uefi_nvram)
  976. sudo cp $uefi_loader $UEFI_LOADER_PATH
  977. sudo cp $uefi_nvram $UEFI_NVRAM_PATH
  978. fi
  979. fi
  980. # Create the logs directory when saving the deploy logs to the filesystem
  981. if [[ "$IRONIC_DEPLOY_LOGS_STORAGE_BACKEND" == "local" && "$IRONIC_DEPLOY_LOGS_COLLECT" != "never" ]]; then
  982. install -d -o $STACK_USER $IRONIC_DEPLOY_LOGS_LOCAL_PATH
  983. fi
  984. }
  985. function configure_ironic_networks {
  986. if [[ -n "${IRONIC_PROVISION_NETWORK_NAME}" ]]; then
  987. echo_summary "Configuring Ironic provisioning network"
  988. configure_ironic_provision_network
  989. fi
  990. echo_summary "Configuring Ironic cleaning network"
  991. configure_ironic_cleaning_network
  992. echo_summary "Configuring Ironic rescue network"
  993. configure_ironic_rescue_network
  994. }
  995. function configure_ironic_cleaning_network {
  996. iniset $IRONIC_CONF_FILE neutron cleaning_network $IRONIC_CLEAN_NET_NAME
  997. }
  998. function configure_ironic_rescue_network {
  999. iniset $IRONIC_CONF_FILE neutron rescuing_network $IRONIC_RESCUE_NET_NAME
  1000. }
  1001. function configure_ironic_provision_network {
  1002. # This is only called if IRONIC_PROVISION_NETWORK_NAME has been set and
  1003. # means we are using multi-tenant networking.
  1004. local net_id
  1005. local ironic_provision_network_ip
  1006. # NOTE(vsaienko) For multinode case there is no need to create a new provisioning
  1007. # network on subnode, as it was created on primary node. Just get an existed network UUID.
  1008. if [[ "$HOST_TOPOLOGY_ROLE" != "subnode" ]]; then
  1009. die_if_not_set $LINENO IRONIC_PROVISION_SUBNET_PREFIX "You must specify the IRONIC_PROVISION_SUBNET_PREFIX"
  1010. die_if_not_set $LINENO PHYSICAL_NETWORK "You must specify the PHYSICAL_NETWORK"
  1011. die_if_not_set $LINENO IRONIC_PROVISION_SUBNET_GATEWAY "You must specify the IRONIC_PROVISION_SUBNET_GATEWAY"
  1012. net_id=$(openstack network create --provider-network-type $IRONIC_PROVISION_PROVIDER_NETWORK_TYPE \
  1013. --provider-physical-network "$PHYSICAL_NETWORK" \
  1014. ${IRONIC_PROVISION_SEGMENTATION_ID:+--provider-segment $IRONIC_PROVISION_SEGMENTATION_ID} \
  1015. ${IRONIC_PROVISION_NETWORK_NAME} -f value -c id)
  1016. die_if_not_set $LINENO net_id "Failure creating net_id for $IRONIC_PROVISION_NETWORK_NAME"
  1017. if [[ "${IRONIC_USE_NEUTRON_SEGMENTS}" == "True" ]]; then
  1018. local net_segment_id
  1019. net_segment_id=$(openstack network segment list --network $net_id -f value -c ID)
  1020. die_if_not_set $LINENO net_segment_id "Failure getting net_segment_id for $IRONIC_PROVISION_NETWORK_NAME"
  1021. fi
  1022. local subnet_id
  1023. subnet_id="$(openstack subnet create --ip-version 4 \
  1024. ${IRONIC_PROVISION_ALLOCATION_POOL:+--allocation-pool $IRONIC_PROVISION_ALLOCATION_POOL} \
  1025. ${net_segment_id:+--network-segment $net_segment_id} \
  1026. $IRONIC_PROVISION_PROVIDER_SUBNET_NAME \
  1027. --gateway $IRONIC_PROVISION_SUBNET_GATEWAY --network $net_id \
  1028. --subnet-range $IRONIC_PROVISION_SUBNET_PREFIX -f value -c id)"
  1029. die_if_not_set $LINENO subnet_id "Failure creating SUBNET_ID for $IRONIC_PROVISION_NETWORK_NAME"
  1030. ironic_provision_network_ip=$IRONIC_PROVISION_SUBNET_GATEWAY
  1031. else
  1032. net_id=$(openstack network show $IRONIC_PROVISION_NETWORK_NAME -f value -c id)
  1033. ironic_provision_network_ip=$IRONIC_PROVISION_SUBNET_SUBNODE_IP
  1034. fi
  1035. IRONIC_PROVISION_SEGMENTATION_ID=${IRONIC_PROVISION_SEGMENTATION_ID:-`openstack network show ${net_id} -f value -c provider:segmentation_id`}
  1036. provision_net_prefix=${IRONIC_PROVISION_SUBNET_PREFIX##*/}
  1037. # Set provision network GW on physical interface
  1038. # Add vlan on br interface in case of IRONIC_PROVISION_PROVIDER_NETWORK_TYPE==vlan
  1039. # othervise assign ip to br interface directly.
  1040. if [[ "$IRONIC_PROVISION_PROVIDER_NETWORK_TYPE" == "vlan" ]]; then
  1041. sudo ip link add link $OVS_PHYSICAL_BRIDGE name $OVS_PHYSICAL_BRIDGE.$IRONIC_PROVISION_SEGMENTATION_ID type vlan id $IRONIC_PROVISION_SEGMENTATION_ID
  1042. sudo ip link set dev $OVS_PHYSICAL_BRIDGE up
  1043. sudo ip link set dev $OVS_PHYSICAL_BRIDGE.$IRONIC_PROVISION_SEGMENTATION_ID up
  1044. sudo ip addr add dev $OVS_PHYSICAL_BRIDGE.$IRONIC_PROVISION_SEGMENTATION_ID $ironic_provision_network_ip/$provision_net_prefix
  1045. else
  1046. sudo ip link set dev $OVS_PHYSICAL_BRIDGE up
  1047. sudo ip addr add dev $OVS_PHYSICAL_BRIDGE $ironic_provision_network_ip/$provision_net_prefix
  1048. fi
  1049. iniset $IRONIC_CONF_FILE neutron provisioning_network $IRONIC_PROVISION_NETWORK_NAME
  1050. }
  1051. function cleanup_ironic_provision_network {
  1052. # Cleanup OVS_PHYSICAL_BRIDGE subinterfaces
  1053. local bridge_subint
  1054. bridge_subint=$(cat /proc/net/dev | sed -n "s/^\(${OVS_PHYSICAL_BRIDGE}\.[0-9]*\).*/\1/p")
  1055. for sub_int in $bridge_subint; do
  1056. sudo ip link set dev $sub_int down
  1057. sudo ip link del dev $sub_int
  1058. done
  1059. }
  1060. # configure_ironic() - Set config files, create data dirs, etc
  1061. function configure_ironic {
  1062. configure_ironic_dirs
  1063. # (re)create ironic configuration file and configure common parameters.
  1064. rm -f $IRONIC_CONF_FILE
  1065. iniset $IRONIC_CONF_FILE DEFAULT debug True
  1066. inicomment $IRONIC_CONF_FILE DEFAULT log_file
  1067. iniset $IRONIC_CONF_FILE database connection `database_connection_url ironic`
  1068. iniset $IRONIC_CONF_FILE DEFAULT state_path $IRONIC_STATE_PATH
  1069. iniset $IRONIC_CONF_FILE DEFAULT use_syslog $SYSLOG
  1070. # NOTE(vsaienko) with multinode each conductor should have its own host.
  1071. iniset $IRONIC_CONF_FILE DEFAULT host $LOCAL_HOSTNAME
  1072. # Retrieve deployment logs
  1073. iniset $IRONIC_CONF_FILE agent deploy_logs_collect $IRONIC_DEPLOY_LOGS_COLLECT
  1074. iniset $IRONIC_CONF_FILE agent deploy_logs_storage_backend $IRONIC_DEPLOY_LOGS_STORAGE_BACKEND
  1075. iniset $IRONIC_CONF_FILE agent deploy_logs_local_path $IRONIC_DEPLOY_LOGS_LOCAL_PATH
  1076. # Set image_download_source for direct interface
  1077. iniset $IRONIC_CONF_FILE agent image_download_source $IRONIC_AGENT_IMAGE_DOWNLOAD_SOURCE
  1078. # Configure JSON RPC backend
  1079. iniset $IRONIC_CONF_FILE DEFAULT rpc_transport $IRONIC_RPC_TRANSPORT
  1080. iniset $IRONIC_CONF_FILE json_rpc port $IRONIC_JSON_RPC_PORT
  1081. # Set fast track options
  1082. iniset $IRONIC_CONF_FILE deploy fast_track $IRONIC_DEPLOY_FAST_TRACK
  1083. # No need to check if RabbitMQ is enabled, this call does it in a smart way
  1084. if [[ "$IRONIC_RPC_TRANSPORT" == "oslo" ]]; then
  1085. iniset_rpc_backend ironic $IRONIC_CONF_FILE
  1086. fi
  1087. # Configure Ironic conductor, if it was enabled.
  1088. if is_service_enabled ir-cond; then
  1089. configure_ironic_conductor
  1090. fi
  1091. # Configure Ironic API, if it was enabled.
  1092. if is_service_enabled ir-api; then
  1093. configure_ironic_api
  1094. fi
  1095. # Format logging
  1096. setup_logging $IRONIC_CONF_FILE
  1097. # Adds ironic site for IPXE
  1098. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]]; then
  1099. _config_ironic_apache_ipxe
  1100. fi
  1101. # Adds uWSGI for Ironic API
  1102. if [[ "$IRONIC_USE_WSGI" == "True" ]]; then
  1103. write_uwsgi_config "$IRONIC_UWSGI_CONF" "$IRONIC_UWSGI" "/baremetal"
  1104. fi
  1105. if [[ "$os_VENDOR" =~ (Debian|Ubuntu) ]]; then
  1106. # The groups change with newer libvirt. Older Ubuntu used
  1107. # 'libvirtd', but now uses libvirt like Debian. Do a quick check
  1108. # to see if libvirtd group already exists to handle grenade's case.
  1109. LIBVIRT_GROUP=$(cut -d ':' -f 1 /etc/group | grep 'libvirtd$' || true)
  1110. LIBVIRT_GROUP=${LIBVIRT_GROUP:-libvirt}
  1111. else
  1112. LIBVIRT_GROUP=libvirtd
  1113. fi
  1114. if ! getent group $LIBVIRT_GROUP >/dev/null; then
  1115. sudo groupadd $LIBVIRT_GROUP
  1116. fi
  1117. # NOTE(vsaienko) Add stack to libvirt group when installing without nova.
  1118. if ! is_service_enabled nova; then
  1119. # Disable power state change callbacks to nova.
  1120. iniset $IRONIC_CONF_FILE nova send_power_notifications false
  1121. add_user_to_group $STACK_USER $LIBVIRT_GROUP
  1122. # This is the basic set of devices allowed / required by all virtual machines.
  1123. # Add /dev/net/tun to cgroup_device_acl, needed for type=ethernet interfaces
  1124. if ! sudo grep -q '^cgroup_device_acl' /etc/libvirt/qemu.conf; then
  1125. cat <<EOF | sudo tee -a /etc/libvirt/qemu.conf
  1126. cgroup_device_acl = [
  1127. "/dev/null", "/dev/full", "/dev/zero",
  1128. "/dev/random", "/dev/urandom",
  1129. "/dev/ptmx", "/dev/kvm", "/dev/kqemu",
  1130. "/dev/rtc", "/dev/hpet","/dev/net/tun",
  1131. "/dev/vfio/vfio",
  1132. ]
  1133. EOF
  1134. restart_libvirt
  1135. fi
  1136. fi
  1137. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  1138. if is_deployed_by_ipmi; then
  1139. configure_virtualbmc
  1140. start_virtualbmc
  1141. fi
  1142. if is_deployed_by_snmp; then
  1143. configure_virtualpdu
  1144. start_virtualpdu
  1145. fi
  1146. if is_deployed_by_redfish; then
  1147. configure_redfish
  1148. start_redfish
  1149. fi
  1150. fi
  1151. }
  1152. # configure_ironic_api() - Is used by configure_ironic(). Performs
  1153. # API specific configuration.
  1154. function configure_ironic_api {
  1155. iniset $IRONIC_CONF_FILE DEFAULT auth_strategy $IRONIC_AUTH_STRATEGY
  1156. configure_auth_token_middleware $IRONIC_CONF_FILE ironic $IRONIC_AUTH_CACHE_DIR/api
  1157. if [[ "$IRONIC_USE_WSGI" == "True" ]]; then
  1158. iniset $IRONIC_CONF_FILE oslo_middleware enable_proxy_headers_parsing True
  1159. elif is_service_enabled tls-proxy; then
  1160. iniset $IRONIC_CONF_FILE oslo_middleware enable_proxy_headers_parsing True
  1161. iniset $IRONIC_CONF_FILE api port $IRONIC_SERVICE_PORT_INT
  1162. else
  1163. iniset $IRONIC_CONF_FILE api port $IRONIC_SERVICE_PORT
  1164. fi
  1165. }
  1166. # configure_client_for() - is used by configure_ironic_conductor.
  1167. # Sets options to instantiate clients for other services
  1168. # single argument - config section to fill
  1169. function configure_client_for {
  1170. local service_config_section
  1171. service_config_section=$1
  1172. # keystoneauth auth plugin options
  1173. iniset $IRONIC_CONF_FILE $service_config_section auth_type password
  1174. iniset $IRONIC_CONF_FILE $service_config_section auth_url $KEYSTONE_SERVICE_URI
  1175. iniset $IRONIC_CONF_FILE $service_config_section username ironic
  1176. iniset $IRONIC_CONF_FILE $service_config_section password $SERVICE_PASSWORD
  1177. iniset $IRONIC_CONF_FILE $service_config_section project_name $SERVICE_PROJECT_NAME
  1178. iniset $IRONIC_CONF_FILE $service_config_section user_domain_id default
  1179. iniset $IRONIC_CONF_FILE $service_config_section project_domain_id default
  1180. # keystoneauth session options
  1181. iniset $IRONIC_CONF_FILE $service_config_section cafile $SSL_BUNDLE_FILE
  1182. # keystoneauth adapter options
  1183. # NOTE(pas-ha) relying on defaults for valid_interfaces being "internal,public" in ironic
  1184. iniset $IRONIC_CONF_FILE $service_config_section region_name $REGION_NAME
  1185. }
  1186. # configure_ironic_conductor() - Is used by configure_ironic().
  1187. # Sets conductor specific settings.
  1188. function configure_ironic_conductor {
  1189. # NOTE(pas-ha) service_catalog section is used to discover
  1190. # ironic API endpoint from keystone catalog
  1191. local client_sections="neutron swift glance inspector cinder service_catalog json_rpc nova"
  1192. for conf_section in $client_sections; do
  1193. configure_client_for $conf_section
  1194. done
  1195. configure_rootwrap ironic
  1196. # set up drivers / hardware types
  1197. iniset $IRONIC_CONF_FILE DEFAULT enabled_hardware_types $IRONIC_ENABLED_HARDWARE_TYPES
  1198. iniset $IRONIC_CONF_FILE conductor automated_clean $IRONIC_AUTOMATED_CLEAN_ENABLED
  1199. # configure enabled and default interfaces
  1200. local iface
  1201. local iface_var
  1202. local iface_uppercase
  1203. local default_iface_var
  1204. for iface in ${IRONIC_DRIVER_INTERFACE_TYPES}; do
  1205. iface_uppercase="${iface^^}"
  1206. iface_var="IRONIC_ENABLED_${iface_uppercase}_INTERFACES"
  1207. iniset $IRONIC_CONF_FILE DEFAULT enabled_${iface}_interfaces ${!iface_var}
  1208. default_iface_var="IRONIC_DEFAULT_${iface_uppercase}_INTERFACE"
  1209. if [[ -n "${!default_iface_var}" ]]; then
  1210. if [[ ! "${!iface_var}" =~ ${!default_iface_var} ]]; then
  1211. die $LINENO "Default interface set for ${iface} interface is not enabled."
  1212. fi
  1213. iniset $IRONIC_CONF_FILE DEFAULT default_${iface}_interface ${!default_iface_var}
  1214. fi
  1215. done
  1216. if is_deployed_by_redfish; then
  1217. # TODO(lucasagomes): We need to make it easier to configure
  1218. # specific driver interfaces in DevStack
  1219. iniset $IRONIC_CONF_FILE DEFAULT enabled_power_interfaces "redfish"
  1220. iniset $IRONIC_CONF_FILE DEFAULT enabled_management_interfaces "redfish"
  1221. fi
  1222. if is_deployed_by_snmp; then
  1223. # TODO(lucasagomes): We need to make it easier to configure
  1224. # specific driver interfaces in DevStack
  1225. iniset $IRONIC_CONF_FILE DEFAULT enabled_power_interfaces "snmp"
  1226. iniset $IRONIC_CONF_FILE DEFAULT enabled_management_interfaces "noop"
  1227. fi
  1228. if is_ansible_deploy_enabled; then
  1229. if is_ansible_with_tinyipa; then
  1230. if [[ ! -f $IRONIC_ANSIBLE_SSH_KEY ]]; then
  1231. # generate ssh key if absent as we will rebuild the ramdisk
  1232. # TODO(pas-ha) make it work for multi-node DevStack:
  1233. # - generate outside of this script
  1234. # - pass path in as $IRONIC_ANSIBLE_SSH_KEY
  1235. # - distribute private key to subnodes under the same path
  1236. # Similar to what we do for n-g-s, may be even re-use its key.
  1237. ssh-keygen -t rsa -N '' -f $IRONIC_ANSIBLE_SSH_KEY
  1238. chmod 600 $IRONIC_ANSIBLE_SSH_KEY
  1239. fi
  1240. if [[ -z $IRONIC_ANSIBLE_SSH_USER ]]; then
  1241. # we definitely know the default username to use for TinyIPA image
  1242. IRONIC_ANSIBLE_SSH_USER='tc'
  1243. fi
  1244. # (rpittau) most recent tinyipa uses python3 natively so we need to change
  1245. # the default ansible python interpreter.
  1246. iniset $IRONIC_CONF_FILE ansible default_python_interpreter /usr/bin/python3
  1247. fi
  1248. iniset $IRONIC_CONF_FILE ansible default_key_file $IRONIC_ANSIBLE_SSH_KEY
  1249. if [[ -n $IRONIC_ANSIBLE_SSH_USER ]]; then
  1250. iniset $IRONIC_CONF_FILE ansible default_username $IRONIC_ANSIBLE_SSH_USER
  1251. fi
  1252. # TODO(pas-ha) find a way to include the CA bundle into the image during rebuild,
  1253. # at least for the tinyipa ramdisk
  1254. iniset $IRONIC_CONF_FILE ansible image_store_insecure "True"
  1255. fi
  1256. iniset $IRONIC_CONF_FILE DEFAULT rootwrap_config $IRONIC_ROOTWRAP_CONF
  1257. iniset $IRONIC_CONF_FILE conductor api_url $IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT
  1258. if [[ -n "$IRONIC_CALLBACK_TIMEOUT" ]]; then
  1259. iniset $IRONIC_CONF_FILE conductor deploy_callback_timeout $IRONIC_CALLBACK_TIMEOUT
  1260. fi
  1261. iniset $IRONIC_CONF_FILE pxe tftp_server $IRONIC_TFTPSERVER_IP
  1262. iniset $IRONIC_CONF_FILE pxe tftp_root $IRONIC_TFTPBOOT_DIR
  1263. iniset $IRONIC_CONF_FILE pxe tftp_master_path $IRONIC_TFTPBOOT_DIR/master_images
  1264. if [[ -n "$IRONIC_PXE_BOOT_RETRY_TIMEOUT" ]]; then
  1265. iniset $IRONIC_CONF_FILE pxe boot_retry_timeout $IRONIC_PXE_BOOT_RETRY_TIMEOUT
  1266. fi
  1267. if [[ "$IRONIC_TERMINAL_SSL" == "True" ]]; then
  1268. # Make sure the cert directory exist
  1269. sudo mkdir -p $IRONIC_TERMINAL_CERT_DIR
  1270. sudo chown $STACK_USER $IRONIC_TERMINAL_CERT_DIR
  1271. iniset $IRONIC_CONF_FILE console terminal_cert_dir $IRONIC_TERMINAL_CERT_DIR
  1272. # Generate the SSL certificate
  1273. openssl req \
  1274. -x509 \
  1275. -days 365 \
  1276. -newkey rsa:1024 \
  1277. -nodes \
  1278. -keyout $IRONIC_TERMINAL_CERT_DIR/certificate.pem.key \
  1279. -out $IRONIC_TERMINAL_CERT_DIR/certificate.pem \
  1280. -subj '/O=OpenStack/OU=DevStack Servers'
  1281. fi
  1282. local pxe_params="nofb nomodeset console=${IRONIC_TTY_DEV}"
  1283. pxe_params+=" systemd.journald.forward_to_console=yes"
  1284. if is_service_enabled tls-proxy; then
  1285. pxe_params+=" ipa-insecure=1"
  1286. fi
  1287. pxe_params+=" $IRONIC_EXTRA_PXE_PARAMS"
  1288. if [[ -n "$pxe_params" ]]; then
  1289. iniset $IRONIC_CONF_FILE pxe pxe_append_params "$pxe_params"
  1290. fi
  1291. local kernel_append_params="nofb nomodeset console=${IRONIC_TTY_DEV}"
  1292. kernel_append_params+=" systemd.journald.forward_to_console=yes"
  1293. if is_service_enabled tls-proxy; then
  1294. kernel_append_params+=" ipa-insecure=1"
  1295. fi
  1296. if [[ -n "kernel_append_params" ]]; then
  1297. iniset $IRONIC_CONF_FILE redfish kernel_append_params "$kernel_append_params"
  1298. fi
  1299. # Set these options for scenarios in which the agent fetches the image
  1300. # directly from glance, and don't set them where the image is pushed
  1301. # over iSCSI.
  1302. if is_glance_configuration_required; then
  1303. if [[ "$SWIFT_ENABLE_TEMPURLS" == "False" ]] ; then
  1304. die $LINENO "SWIFT_ENABLE_TEMPURLS must be True. This is " \
  1305. "required either because IRONIC_DEPLOY_DRIVER was " \
  1306. "set to some agent_* driver OR configuration of " \
  1307. "Glance with Swift was explicitly requested with " \
  1308. "IRONIC_CONFIGURE_GLANCE_WITH_SWIFT=True"
  1309. fi
  1310. iniset $IRONIC_CONF_FILE glance swift_temp_url_duration 3600
  1311. fi
  1312. if is_deployed_by_agent; then
  1313. iniset $IRONIC_CONF_FILE api ramdisk_heartbeat_timeout 30
  1314. fi
  1315. # FIXME: this really needs to be tested in the gate. For now, any
  1316. # test using the agent ramdisk should skip the erase_devices clean
  1317. # step because it is too slow to run in the gate.
  1318. iniset $IRONIC_CONF_FILE deploy erase_devices_priority 0
  1319. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
  1320. local pxebin
  1321. pxebin=`basename $IRONIC_PXE_BOOT_IMAGE`
  1322. uefipxebin=`basename $(get_uefi_ipxe_boot_file)`
  1323. iniset $IRONIC_CONF_FILE pxe ipxe_enabled True
  1324. iniset $IRONIC_CONF_FILE pxe pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
  1325. iniset $IRONIC_CONF_FILE pxe pxe_bootfile_name $pxebin
  1326. iniset $IRONIC_CONF_FILE pxe uefi_pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
  1327. iniset $IRONIC_CONF_FILE pxe uefi_pxe_bootfile_name $uefipxebin
  1328. iniset $IRONIC_CONF_FILE deploy http_root $IRONIC_HTTP_DIR
  1329. iniset $IRONIC_CONF_FILE deploy http_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT"
  1330. if [[ "$IRONIC_IPXE_USE_SWIFT" == "True" ]]; then
  1331. iniset $IRONIC_CONF_FILE pxe ipxe_use_swift True
  1332. fi
  1333. fi
  1334. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  1335. iniset $IRONIC_CONF_FILE neutron port_setup_delay 15
  1336. fi
  1337. iniset $IRONIC_CONF_FILE dhcp dhcp_provider $IRONIC_DHCP_PROVIDER
  1338. iniset $IRONIC_CONF_FILE deploy default_boot_option $IRONIC_DEFAULT_BOOT_OPTION
  1339. isolinux=$(find -L /usr /opt /etc -type f -name "isolinux.bin" | head -1)
  1340. if [[ -n "$isolinux" ]]; then
  1341. iniset $IRONIC_CONF_FILE DEFAULT isolinux_bin "$isolinux"
  1342. fi
  1343. }
  1344. # create_ironic_cache_dir() - Part of the init_ironic() process
  1345. function create_ironic_cache_dir {
  1346. # Create cache dir
  1347. sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/api
  1348. sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/api
  1349. rm -f $IRONIC_AUTH_CACHE_DIR/api/*
  1350. sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/registry
  1351. sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/registry
  1352. rm -f $IRONIC_AUTH_CACHE_DIR/registry/*
  1353. }
  1354. # create_ironic_accounts() - Set up common required ironic accounts
  1355. # Project User Roles
  1356. # ------------------------------------------------------------------
  1357. # service ironic admin
  1358. # service nova baremetal_admin
  1359. # demo demo baremetal_observer
  1360. function create_ironic_accounts {
  1361. if [[ "$ENABLED_SERVICES" =~ "ir-api" && "$ENABLED_SERVICES" =~ "key" ]]; then
  1362. # Define service and endpoints in Keystone
  1363. get_or_create_service "ironic" "baremetal" "Ironic baremetal provisioning service"
  1364. get_or_create_endpoint "baremetal" \
  1365. "$REGION_NAME" \
  1366. "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT"
  1367. # Create ironic service user
  1368. # TODO(deva): make this work with the 'service' role
  1369. # https://bugs.launchpad.net/ironic/+bug/1605398
  1370. create_service_user "ironic" "admin"
  1371. # Create additional bare metal tenant and roles
  1372. get_or_create_role baremetal_admin
  1373. get_or_create_role baremetal_observer
  1374. if is_service_enabled nova; then
  1375. get_or_add_user_project_role baremetal_admin nova $SERVICE_PROJECT_NAME
  1376. fi
  1377. get_or_add_user_project_role baremetal_observer demo demo
  1378. fi
  1379. }
  1380. # init_ironic() - Initialize databases, etc.
  1381. function init_ironic {
  1382. if [[ "$HOST_TOPOLOGY_ROLE" != "subnode" ]]; then
  1383. # (Re)create ironic database
  1384. recreate_database ironic
  1385. # Migrate ironic database
  1386. $IRONIC_BIN_DIR/ironic-dbsync --config-file=$IRONIC_CONF_FILE
  1387. fi
  1388. create_ironic_cache_dir
  1389. # NOTE(rloo): We're not upgrading but want to make sure this command works,
  1390. # even though we're not parsing the output of this command.
  1391. $IRONIC_BIN_DIR/ironic-status upgrade check
  1392. }
  1393. # _ironic_bm_vm_names() - Generates list of names for baremetal VMs.
  1394. function _ironic_bm_vm_names {
  1395. local idx
  1396. local num_vms
  1397. num_vms=$(($IRONIC_VM_COUNT - 1))
  1398. for idx in $(seq 0 $num_vms); do
  1399. echo "$(get_ironic_node_prefix)-${idx}"
  1400. done
  1401. }
  1402. # start_ironic() - Start running processes, including screen
  1403. function start_ironic {
  1404. # Start Ironic API server, if enabled.
  1405. if is_service_enabled ir-api; then
  1406. start_ironic_api
  1407. fi
  1408. # Start Ironic conductor, if enabled.
  1409. if is_service_enabled ir-cond; then
  1410. start_ironic_conductor
  1411. fi
  1412. # Start Apache if iPXE is enabled
  1413. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
  1414. restart_apache_server
  1415. fi
  1416. }
  1417. # start_ironic_api() - Used by start_ironic().
  1418. # Starts Ironic API server.
  1419. function start_ironic_api {
  1420. local service_port=$IRONIC_SERVICE_PORT
  1421. local service_protocol=$IRONIC_SERVICE_PROTOCOL
  1422. local ironic_url
  1423. # Get right service port for testing
  1424. if is_service_enabled tls-proxy; then
  1425. service_port=$IRONIC_SERVICE_PORT_INT
  1426. service_protocol="http"
  1427. fi
  1428. if [[ "$IRONIC_USE_WSGI" == "True" ]]; then
  1429. run_process "ir-api" "$IRONIC_BIN_DIR/uwsgi --procname-prefix ironic-api --ini $IRONIC_UWSGI_CONF"
  1430. ironic_url=$service_protocol://$SERVICE_HOST/baremetal
  1431. else
  1432. run_process ir-api "$IRONIC_BIN_DIR/ironic-api --config-file=$IRONIC_CONF_FILE"
  1433. ironic_url=$service_protocol://$SERVICE_HOST:$service_port
  1434. fi
  1435. echo "Waiting for ir-api ($ironic_url) to start..."
  1436. if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget --no-proxy -q -O- $ironic_url; do sleep 1; done"; then
  1437. die $LINENO "ir-api did not start"
  1438. fi
  1439. if is_service_enabled tls-proxy; then
  1440. start_tls_proxy ironic '*' $IRONIC_SERVICE_PORT $SERVICE_HOST $IRONIC_SERVICE_PORT_INT
  1441. fi
  1442. }
  1443. # start_ironic_conductor() - Used by start_ironic().
  1444. # Starts Ironic conductor.
  1445. function start_ironic_conductor {
  1446. run_process ir-cond "$IRONIC_BIN_DIR/ironic-conductor --config-file=$IRONIC_CONF_FILE"
  1447. # Wait up to 30 seconds for ironic-conductor to start and register itself
  1448. local attempt
  1449. local max_attempts=7
  1450. for attempt in $(seq 1 $max_attempts); do
  1451. if openstack baremetal driver list | grep -q $IRONIC_DEPLOY_DRIVER; then
  1452. break
  1453. fi
  1454. if [ $attempt -eq $max_attempts ]; then
  1455. die $LINENO "Driver $IRONIC_DEPLOY_DRIVER did not appear in the driver list"
  1456. fi
  1457. echo "Still waiting for ironic-conductor to start, current state:"
  1458. openstack baremetal driver list
  1459. sleep 5
  1460. done
  1461. }
  1462. # stop_ironic() - Stop running processes
  1463. function stop_ironic {
  1464. stop_process ir-api
  1465. stop_process ir-cond
  1466. }
  1467. # create_ovs_taps is also called by the devstack/upgrade/resources.sh script
  1468. #
  1469. # create_ovs_taps ironic_network_id
  1470. # NOTE(vsaienko) Ironic supports only Flat Neutron network.
  1471. # create_ovs_taps are needed in order to provide connectivity from ironic-conductor
  1472. # to VM. With Neutron Flat network it will be not needed.
  1473. function create_ovs_taps {
  1474. local ironic_net_id
  1475. ironic_net_id=$1
  1476. die_if_not_set $LINENO ironic_net_id "Failed to get ironic network id"
  1477. # Work around: No netns exists on host until a Neutron port is created. We
  1478. # need to create one in Neutron to know what netns to tap into prior to the
  1479. # first node booting.
  1480. local port_id
  1481. port_id=$(openstack port create --network ${ironic_net_id} temp_port -c id -f value)
  1482. die_if_not_set $LINENO port_id "Failed to create neutron port"
  1483. # intentional sleep to make sure the tag has been set to port
  1484. sleep 10
  1485. local tapdev
  1486. tapdev=$(sudo ip netns exec qdhcp-${ironic_net_id} ip link list | grep " tap" | cut -d':' -f2 | cut -d'@' -f1 | cut -b2-)
  1487. die_if_not_set $LINENO tapdev "Failed to get tap device id"
  1488. local tag_id
  1489. tag_id=$(sudo ovs-vsctl get port ${tapdev} tag)
  1490. die_if_not_set $LINENO tag_id "Failed to get tag id"
  1491. local ovs_tap=ovs-tap
  1492. local brbm_tap=brbm-tap
  1493. # make sure veth pair is not existing, otherwise delete its links
  1494. sudo ip link show $ovs_tap && sudo ip link delete $ovs_tap
  1495. sudo ip link show $brbm_tap && sudo ip link delete $brbm_tap
  1496. # create veth pair for future interconnection between br-int and brbm
  1497. sudo ip link add $brbm_tap type veth peer name $ovs_tap
  1498. sudo ip link set dev $brbm_tap up
  1499. sudo ip link set dev $ovs_tap up
  1500. sudo ovs-vsctl -- --if-exists del-port $ovs_tap -- add-port br-int $ovs_tap tag=$tag_id
  1501. sudo ovs-vsctl -- --if-exists del-port $brbm_tap -- add-port $IRONIC_VM_NETWORK_BRIDGE $brbm_tap
  1502. # Remove the port needed only for workaround.
  1503. openstack port delete $port_id
  1504. # Finally, share the fixed tenant network across all tenants. This allows the host
  1505. # to serve TFTP to a single network namespace via the tap device created above.
  1506. openstack network set $ironic_net_id --share
  1507. }
  1508. function setup_qemu_log_hook {
  1509. # Make sure the libvirt hooks directory exist
  1510. sudo mkdir -p $IRONIC_LIBVIRT_HOOKS_PATH
  1511. # Copy the qemu hook to the right directory
  1512. sudo cp $IRONIC_DEVSTACK_FILES_DIR/hooks/qemu.py $IRONIC_LIBVIRT_HOOKS_PATH/qemu
  1513. sudo chmod -v +x $IRONIC_LIBVIRT_HOOKS_PATH/qemu
  1514. sudo sed -e "
  1515. s|%LOG_DIR%|$IRONIC_VM_LOG_DIR|g;
  1516. " -i $IRONIC_LIBVIRT_HOOKS_PATH/qemu
  1517. restart_libvirt
  1518. mkdir -p $IRONIC_VM_LOG_DIR
  1519. cat >${IRONIC_VM_LOG_DIR}/README << EOF
  1520. This directory contains the serial console log files from the virtual Ironic
  1521. bare-metal nodes. The *_console_* log files are the original log files and
  1522. include ANSI control codes which can make the output difficult to read. The
  1523. *_no_ansi_* log files have had ANSI control codes removed from the file and are
  1524. easier to read.
  1525. On some occasions there won't be a corresponding *_no_ansi_* log file, for
  1526. example if the job failed due to a time-out. You may see a log file without a
  1527. date/time in the file name. In that case you can display the logfile in your
  1528. console by doing:
  1529. $ curl URL_TO_LOGFILE
  1530. This will have your terminal process the ANSI escape codes.
  1531. Another option, if you have the 'pv' executable installed, is to simulate a
  1532. low-speed connection. In this example simulate a 300 Bytes/second connection.
  1533. $ curl URL_TO_LOGFILE | pv -q -L 300
  1534. This can allow you to see some of the content before the screen is cleared by
  1535. an ANSI escape sequence.
  1536. EOF
  1537. }
  1538. function initialize_libvirt_storage_pool {
  1539. [ -d $LIBVIRT_STORAGE_POOL_PATH ] || sudo mkdir -p $LIBVIRT_STORAGE_POOL_PATH
  1540. if ! sudo virsh pool-list --all | grep -q $LIBVIRT_STORAGE_POOL; then
  1541. sudo virsh pool-define-as --name $LIBVIRT_STORAGE_POOL dir \
  1542. --target $LIBVIRT_STORAGE_POOL_PATH >&2
  1543. sudo virsh pool-autostart $LIBVIRT_STORAGE_POOL >&2
  1544. sudo virsh pool-start $LIBVIRT_STORAGE_POOL >&2
  1545. fi
  1546. pool_state=$(sudo virsh pool-info $LIBVIRT_STORAGE_POOL | grep State | awk '{ print $2 }')
  1547. if [ "$pool_state" != "running" ] ; then
  1548. sudo virsh pool-start $LIBVIRT_STORAGE_POOL >&2
  1549. fi
  1550. }
  1551. function create_bridge_and_vms {
  1552. # Call libvirt setup scripts in a new shell to ensure any new group membership
  1553. sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/setup-network.sh $IRONIC_VM_NETWORK_BRIDGE $PUBLIC_BRIDGE_MTU"
  1554. if [[ "$IRONIC_VM_LOG_CONSOLE" == "True" ]] ; then
  1555. local log_arg="-l $IRONIC_VM_LOG_DIR"
  1556. if [[ "$IRONIC_VM_LOG_ROTATE" == "True" ]] ; then
  1557. setup_qemu_log_hook
  1558. fi
  1559. else
  1560. local log_arg=""
  1561. fi
  1562. local vbmc_port=$IRONIC_VBMC_PORT_RANGE_START
  1563. local pdu_outlet=$IRONIC_VPDU_PORT_RANGE_START
  1564. local vm_name
  1565. local vm_opts=""
  1566. if [[ -n "$IRONIC_VM_EMULATOR" ]]; then
  1567. vm_opts+=" -e $IRONIC_VM_EMULATOR"
  1568. fi
  1569. vm_opts+=" -E $IRONIC_VM_ENGINE"
  1570. if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  1571. vm_opts+=" -L $UEFI_LOADER_PATH -N $UEFI_NVRAM_PATH"
  1572. fi
  1573. if [[ -n "$LIBVIRT_NIC_DRIVER" ]]; then
  1574. vm_opts+=" -D $LIBVIRT_NIC_DRIVER"
  1575. elif [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  1576. # Note(derekh) UEFI for the moment doesn't work with the e1000 net driver
  1577. vm_opts+=" -D virtio"
  1578. fi
  1579. initialize_libvirt_storage_pool
  1580. local bridge_mac
  1581. bridge_mac=$(ip link show dev $IRONIC_VM_NETWORK_BRIDGE | grep -Eo "ether [A-Za-z0-9:]+"|sed "s/ether\ //")
  1582. for vm_name in $(_ironic_bm_vm_names); do
  1583. # pick up the $LIBVIRT_GROUP we have possibly joint
  1584. newgrp $LIBVIRT_GROUP <<SUBSHELL
  1585. $IRONIC_SCRIPTS_DIR/create-node.sh -n $vm_name \
  1586. -c $IRONIC_VM_SPECS_CPU -m $IRONIC_VM_SPECS_RAM -d $IRONIC_VM_SPECS_DISK \
  1587. -a $IRONIC_VM_SPECS_CPU_ARCH -b $IRONIC_VM_NETWORK_BRIDGE $vm_opts -p $vbmc_port -o $pdu_outlet \
  1588. -i $IRONIC_VM_INTERFACE_COUNT -f $IRONIC_VM_SPECS_DISK_FORMAT -M $PUBLIC_BRIDGE_MTU $log_arg \
  1589. -v $IRONIC_VM_VOLUME_COUNT -P $LIBVIRT_STORAGE_POOL >> $IRONIC_VM_MACS_CSV_FILE
  1590. SUBSHELL
  1591. if is_deployed_by_ipmi; then
  1592. vbmc --no-daemon add $vm_name --port $vbmc_port
  1593. vbmc --no-daemon start $vm_name
  1594. fi
  1595. echo " ${bridge_mac} $IRONIC_VM_NETWORK_BRIDGE" >> $IRONIC_VM_MACS_CSV_FILE
  1596. vbmc_port=$((vbmc_port+1))
  1597. pdu_outlet=$((pdu_outlet+1))
  1598. # It is sometimes useful to dump out the VM configuration to validate it.
  1599. sudo virsh dumpxml $vm_name
  1600. done
  1601. if [[ -z "${IRONIC_PROVISION_NETWORK_NAME}" ]]; then
  1602. local ironic_net_id
  1603. ironic_net_id=$(openstack network show "$PRIVATE_NETWORK_NAME" -c id -f value)
  1604. create_ovs_taps $ironic_net_id
  1605. # NOTE(vsaienko) Neutron no longer setup routing to private network.
  1606. # https://github.com/openstack-dev/devstack/commit/1493bdeba24674f6634160d51b8081c571df4017
  1607. # Add route here to have connection to VMs during provisioning.
  1608. local pub_router_id
  1609. local r_net_gateway
  1610. pub_router_id=$(openstack router show $Q_ROUTER_NAME -f value -c id)
  1611. r_net_gateway=$(sudo ip netns exec qrouter-$pub_router_id ip -4 route get 8.8.8.8 |grep dev | awk '{print $7}')
  1612. local replace_range=${SUBNETPOOL_PREFIX_V4}
  1613. if [[ -z "${SUBNETPOOL_V4_ID}" ]]; then
  1614. replace_range=${FIXED_RANGE}
  1615. fi
  1616. sudo ip route replace $replace_range via $r_net_gateway
  1617. fi
  1618. # Here is a good place to restart tcpdump to begin capturing packets.
  1619. # See: https://docs.openstack.org/devstack/latest/debugging.html
  1620. # stop_tcpdump
  1621. # start_tcpdump
  1622. }
  1623. function wait_for_nova_resources {
  1624. # After nodes have been enrolled, we need to wait for both ironic and
  1625. # nova's periodic tasks to populate the resource tracker with available
  1626. # nodes and resources. Wait up to 2 minutes for a given resource before
  1627. # timing out.
  1628. local expected_count=$1
  1629. local resource_class=${IRONIC_DEFAULT_RESOURCE_CLASS^^}
  1630. # TODO(dtantsur): switch to Placement OSC plugin, once it exists
  1631. local token
  1632. token=$(openstack token issue -f value -c id)
  1633. local endpoint
  1634. endpoint=$(openstack endpoint list --service placement --interface public -f value -c URL)
  1635. die_if_not_set $LINENO endpoint "Cannot find Placement API endpoint"
  1636. local i
  1637. local count
  1638. echo_summary "Waiting up to 3 minutes for placement to pick up $expected_count nodes"
  1639. for i in $(seq 1 12); do
  1640. # Fetch provider UUIDs from Placement
  1641. local providers
  1642. providers=$(curl -sH "X-Auth-Token: $token" $endpoint/resource_providers \
  1643. | jq -r '.resource_providers[].uuid')
  1644. local p
  1645. # Total count of the resource class, has to be equal to nodes count
  1646. count=0
  1647. for p in $providers; do
  1648. local amount
  1649. # A resource class inventory record looks something like
  1650. # {"max_unit": 1, "min_unit": 1, "step_size": 1, "reserved": 0, "total": 1, "allocation_ratio": 1}
  1651. # Subtrack reserved from total (defaulting both to 0)
  1652. amount=$(curl -sH "X-Auth-Token: $token" $endpoint/resource_providers/$p/inventories \
  1653. | jq ".inventories.CUSTOM_$resource_class as \$cls
  1654. | (\$cls.total // 0) - (\$cls.reserved // 0)")
  1655. # Check whether the resource provider has all expected traits
  1656. # registered against it.
  1657. rp_traits=$(curl -sH "X-Auth-Token: $token" \
  1658. -H "OpenStack-API-Version: placement 1.6" \
  1659. $endpoint/resource_providers/$p/traits)
  1660. for trait in $IRONIC_DEFAULT_TRAITS; do
  1661. if [[ $(echo "$rp_traits" | jq ".traits | contains([\"$trait\"])") == false ]]; then
  1662. amount=0
  1663. fi
  1664. done
  1665. if [ $amount -gt 0 ]; then
  1666. count=$(( count + $amount ))
  1667. fi
  1668. done
  1669. if [ $count -ge $expected_count ]; then
  1670. return 0
  1671. fi
  1672. if is_service_enabled n-api; then
  1673. $TOP_DIR/tools/discover_hosts.sh
  1674. fi
  1675. sleep 15
  1676. done
  1677. die $LINENO "Timed out waiting for Nova to track $expected_count nodes"
  1678. }
  1679. function _clean_ncpu_failure {
  1680. SCREEN_NAME=${SCREEN_NAME:-stack}
  1681. SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
  1682. n_cpu_failure="$SERVICE_DIR/$SCREEN_NAME/n-cpu.failure"
  1683. if [ -f ${n_cpu_failure} ]; then
  1684. mv ${n_cpu_failure} "${n_cpu_failure}.before-restart-by-ironic"
  1685. fi
  1686. }
  1687. function provide_nodes {
  1688. local nodes=$@
  1689. for node_id in $nodes; do
  1690. $IRONIC_CMD node provide $node_id
  1691. done
  1692. local attempt
  1693. for attempt in $(seq 1 $IRONIC_CLEANING_ATTEMPTS); do
  1694. local available
  1695. available=$(openstack baremetal node list --provision-state available -f value -c UUID)
  1696. local nodes_not_finished=
  1697. for node_id in $nodes; do
  1698. if ! echo $available | grep -q $node_id; then
  1699. nodes_not_finished+=" $node_id"
  1700. fi
  1701. done
  1702. nodes=$nodes_not_finished
  1703. if [[ "$nodes" == "" ]]; then
  1704. break
  1705. fi
  1706. echo "Waiting for nodes to become available: $nodes"
  1707. echo "Currently available: $available"
  1708. sleep $IRONIC_CLEANING_DELAY
  1709. done
  1710. if [[ "$nodes" != "" ]]; then
  1711. die $LINENO "Some nodes did not finish cleaning: $nodes"
  1712. fi
  1713. }
  1714. function wait_for_ironic_neutron_agent_report_state_for_all_nodes {
  1715. local nodes=$@
  1716. echo "Waiting for ironic-neutron-agent to report state for nodes: $nodes"
  1717. local attempt
  1718. for attempt in $(seq 1 $IRONIC_NEUTRON_AGENT_REPORT_STATE_ATTEMPTS); do
  1719. local reported
  1720. reported=$(openstack network agent list -f value -c Host -c Binary | grep ironic-neutron-agent | cut -d ' ' -f 1 | paste -s -d ' ')
  1721. echo "Currently reported nodes: $reported"
  1722. local can_break
  1723. for node_id in $nodes; do
  1724. if echo $reported | grep -q $node_id; then
  1725. can_break="True"
  1726. else
  1727. can_break="False"
  1728. break
  1729. fi
  1730. done
  1731. if [[ $can_break == "True" ]]; then
  1732. break
  1733. fi
  1734. sleep $IRONIC_NEUTRON_AGENT_REPORT_STATE_DELAY
  1735. done
  1736. if [[ "$can_break" == "False" ]]; then
  1737. die $LINENO "ironic-neutron-agent did not report some nodes."
  1738. fi
  1739. }
  1740. function enroll_nodes {
  1741. local chassis_id
  1742. chassis_id=$($IRONIC_CMD chassis create --description "ironic test chassis" -f value -c uuid)
  1743. die_if_not_set $LINENO chassis_id "Failed to create chassis"
  1744. local node_prefix
  1745. node_prefix=$(get_ironic_node_prefix)
  1746. local interface_info
  1747. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  1748. local ironic_node_cpu=$IRONIC_VM_SPECS_CPU
  1749. local ironic_node_ram=$IRONIC_VM_SPECS_RAM
  1750. local ironic_node_disk=$IRONIC_VM_SPECS_DISK
  1751. local ironic_ephemeral_disk=$IRONIC_VM_EPHEMERAL_DISK
  1752. local ironic_node_arch=x86_64
  1753. local ironic_hwinfo_file=$IRONIC_VM_MACS_CSV_FILE
  1754. if is_deployed_by_ipmi; then
  1755. local node_options="\
  1756. --driver-info ipmi_address=${HOST_IP} \
  1757. --driver-info ipmi_username=admin \
  1758. --driver-info ipmi_password=password"
  1759. elif is_deployed_by_snmp; then
  1760. local node_options="\
  1761. --driver-info snmp_driver=${IRONIC_VPDU_SNMPDRIVER} \
  1762. --driver-info snmp_address=${HOST_IP} \
  1763. --driver-info snmp_port=${IRONIC_VPDU_LISTEN_PORT} \
  1764. --driver-info snmp_protocol=2c \
  1765. --driver-info snmp_community=${IRONIC_VPDU_COMMUNITY}"
  1766. elif is_deployed_by_redfish; then
  1767. local node_options="\
  1768. --driver-info redfish_address=http://${HOST_IP}:${IRONIC_REDFISH_EMULATOR_PORT} \
  1769. --driver-info redfish_username=admin \
  1770. --driver-info redfish_password=password"
  1771. fi
  1772. else
  1773. local ironic_node_cpu=$IRONIC_HW_NODE_CPU
  1774. local ironic_node_ram=$IRONIC_HW_NODE_RAM
  1775. local ironic_node_disk=$IRONIC_HW_NODE_DISK
  1776. local ironic_ephemeral_disk=$IRONIC_HW_EPHEMERAL_DISK
  1777. local ironic_node_arch=$IRONIC_HW_ARCH
  1778. local ironic_hwinfo_file=$IRONIC_HWINFO_FILE
  1779. fi
  1780. local total_nodes=0
  1781. local total_cpus=0
  1782. local node_uuids=
  1783. local node_id
  1784. while read hardware_info; do
  1785. local node_name
  1786. node_name=$node_prefix-$total_nodes
  1787. local node_capabilities=""
  1788. if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  1789. node_capabilities+=" --property capabilities=boot_mode:uefi"
  1790. fi
  1791. if [[ "$IRONIC_SECURE_BOOT" == "True" ]]; then
  1792. if [[ -n "$node_capabilities" ]]; then
  1793. node_capabilities+=",secure_boot:true"
  1794. else
  1795. node_capabilities+=" --property capabilities=secure_boot:true"
  1796. fi
  1797. fi
  1798. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  1799. interface_info=$(echo $hardware_info | awk '{print $1}')
  1800. if is_deployed_by_ipmi; then
  1801. local vbmc_port
  1802. vbmc_port=$(echo $hardware_info | awk '{print $2}')
  1803. node_options+=" --driver-info ipmi_port=$vbmc_port"
  1804. elif is_deployed_by_snmp; then
  1805. local pdu_outlet
  1806. pdu_outlet=$(echo $hardware_info | awk '{print $3}')
  1807. node_options+=" --driver-info snmp_outlet=$pdu_outlet"
  1808. elif is_deployed_by_redfish; then
  1809. node_options+=" --driver-info redfish_system_id=/redfish/v1/Systems/$node_name"
  1810. fi
  1811. # Local-link-connection options
  1812. local llc_opts=""
  1813. if [[ "${IRONIC_USE_LINK_LOCAL}" == "True" ]]; then
  1814. local switch_info
  1815. local switch_id
  1816. switch_id=$(echo $hardware_info |awk '{print $4}')
  1817. switch_info=$(echo $hardware_info |awk '{print $5}')
  1818. # NOTE(vsaienko) we will add port_id later in the code.
  1819. llc_opts="--local-link-connection switch_id=${switch_id} \
  1820. --local-link-connection switch_info=${switch_info} "
  1821. fi
  1822. if [[ "${IRONIC_STORAGE_INTERFACE}" == "cinder" ]]; then
  1823. local connector_iqn="iqn.2017-05.org.openstack.$node_prefix-$total_nodes"
  1824. if [[ -n "$node_capabilities" ]]; then
  1825. node_capabilities+=",iscsi_boot:True"
  1826. else
  1827. node_capabilities+=" --property capabilities=iscsi_boot:True"
  1828. fi
  1829. fi
  1830. else
  1831. # Currently we require all hardware platform have same CPU/RAM/DISK info
  1832. # in future, this can be enhanced to support different type, and then
  1833. # we create the bare metal flavor with minimum value
  1834. local bmc_address
  1835. bmc_address=$(echo $hardware_info |awk '{print $1}')
  1836. local mac_address
  1837. mac_address=$(echo $hardware_info |awk '{print $2}')
  1838. local bmc_username
  1839. bmc_username=$(echo $hardware_info |awk '{print $3}')
  1840. local bmc_passwd
  1841. bmc_passwd=$(echo $hardware_info |awk '{print $4}')
  1842. local node_options=""
  1843. if is_deployed_by_ipmi; then
  1844. node_options+=" --driver-info ipmi_address=$bmc_address \
  1845. --driver-info ipmi_password=$bmc_passwd \
  1846. --driver-info ipmi_username=$bmc_username"
  1847. elif is_deployed_by_ilo; then
  1848. node_options+=" --driver-info ilo_address=$bmc_address \
  1849. --driver-info ilo_password=$bmc_passwd \
  1850. --driver-info ilo_username=$bmc_username"
  1851. if [[ $IRONIC_ENABLED_BOOT_INTERFACES == *"ilo-virtual-media"* ]]; then
  1852. node_options+=" --driver-info ilo_deploy_iso=$IRONIC_DEPLOY_ISO_ID"
  1853. fi
  1854. elif is_deployed_by_drac; then
  1855. node_options+=" --driver-info drac_address=$bmc_address \
  1856. --driver-info drac_password=$bmc_passwd \
  1857. --driver-info drac_username=$bmc_username"
  1858. elif is_deployed_by_redfish; then
  1859. local bmc_redfish_system_id
  1860. bmc_redfish_system_id=$(echo $hardware_info |awk '{print $5}')
  1861. node_options+=" --driver-info redfish_address=https://$bmc_address \
  1862. --driver-info redfish_system_id=$bmc_redfish_system_id \
  1863. --driver-info redfish_password=$bmc_passwd \
  1864. --driver-info redfish_username=$bmc_username \
  1865. --driver-info redfish_verify_ca=False"
  1866. elif is_deployed_by_irmc; then
  1867. node_options+=" --driver-info irmc_address=$bmc_address \
  1868. --driver-info irmc_password=$bmc_passwd \
  1869. --driver-info irmc_username=$bmc_username"
  1870. if [[ -n "$IRONIC_DEPLOY_ISO_ID" ]]; then
  1871. node_options+=" --driver-info irmc_deploy_iso=$IRONIC_DEPLOY_ISO_ID"
  1872. fi
  1873. elif is_deployed_by_xclarity; then
  1874. local xclarity_hardware_id
  1875. xclarity_hardware_id=$(echo $hardware_info |awk '{print $5}')
  1876. node_options+=" --driver-info xclarity_manager_ip=$bmc_address \
  1877. --driver-info xclarity_password=$bmc_passwd \
  1878. --driver-info xclarity_username=$bmc_username \
  1879. --driver-info xclarity_hardware_id=$xclarity_hardware_id"
  1880. fi
  1881. interface_info="${mac_address}"
  1882. fi
  1883. # First node created will be used for testing in ironic w/o glance
  1884. # scenario, so we need to know its UUID.
  1885. local standalone_node_uuid=""
  1886. if [ $total_nodes -eq 0 ]; then
  1887. standalone_node_uuid="--uuid $IRONIC_NODE_UUID"
  1888. fi
  1889. # TODO(dtantsur): it would be cool to test with different resource
  1890. # classes, but for now just use the same.
  1891. node_id=$($IRONIC_CMD node create $standalone_node_uuid \
  1892. --chassis $chassis_id \
  1893. --driver $IRONIC_DEPLOY_DRIVER \
  1894. --name $node_name \
  1895. --resource-class $IRONIC_DEFAULT_RESOURCE_CLASS \
  1896. --property cpu_arch=$ironic_node_arch \
  1897. $node_capabilities \
  1898. $node_options \
  1899. -f value -c uuid)
  1900. die_if_not_set $LINENO node_id "Failed to create node"
  1901. node_uuids+=" $node_id"
  1902. if [[ -n $IRONIC_DEFAULT_TRAITS ]]; then
  1903. $IRONIC_CMD node add trait $node_id $IRONIC_DEFAULT_TRAITS
  1904. fi
  1905. $IRONIC_CMD node manage $node_id --wait $IRONIC_MANAGE_TIMEOUT || \
  1906. die $LINENO "Node did not reach manageable state in $IRONIC_MANAGE_TIMEOUT seconds"
  1907. # NOTE(vsaienko) IPA didn't automatically recognize root devices less than 4Gb.
  1908. # Setting root hint allows to install OS on such devices.
  1909. # 0x1af4 is VirtIO vendor device ID.
  1910. if [[ "$ironic_node_disk" -lt "4" && is_deployed_by_agent ]]; then
  1911. $IRONIC_CMD node set $node_id --property \
  1912. root_device='{"vendor": "0x1af4"}'
  1913. fi
  1914. # In case we using portgroups, we should API version that support them.
  1915. # Othervise API will return 406 ERROR
  1916. # NOTE(vsaienko) interface_info is in the following format here:
  1917. # mac1,tap-node0i1;mac2,tap-node0i2;...;macN,tap-node0iN
  1918. for info in ${interface_info//;/ }; do
  1919. local mac_address=""
  1920. local port_id=""
  1921. local llc_port_opt=""
  1922. local physical_network=""
  1923. mac_address=$(echo $info| awk -F ',' '{print $1}')
  1924. port_id=$(echo $info| awk -F ',' '{print $2}')
  1925. if [[ "${IRONIC_USE_LINK_LOCAL}" == "True" ]]; then
  1926. llc_port_opt+=" --local-link-connection port_id=${port_id} "
  1927. fi
  1928. if [[ "${IRONIC_USE_NEUTRON_SEGMENTS}" == "True" ]]; then
  1929. physical_network=" --physical-network ${PHYSICAL_NETWORK} "
  1930. fi
  1931. $IRONIC_CMD port create --node $node_id $llc_opts $llc_port_opt $mac_address $physical_network
  1932. done
  1933. # NOTE(vsaienko) use node-update instead of specifying network_interface
  1934. # during node creation. If node is added with latest version of API it
  1935. # will NOT go to available state automatically.
  1936. if [[ -n "${IRONIC_NETWORK_INTERFACE}" ]]; then
  1937. $IRONIC_CMD node set $node_id --network-interface $IRONIC_NETWORK_INTERFACE || \
  1938. die $LINENO "Failed to update network interface for node"
  1939. fi
  1940. if [[ -n "${IRONIC_STORAGE_INTERFACE}" ]]; then
  1941. $IRONIC_CMD node set $node_id --storage-interface $IRONIC_STORAGE_INTERFACE || \
  1942. die $LINENO "Failed to update storage interface for node $node_id"
  1943. if [[ -n "${connector_iqn}" ]]; then
  1944. $IRONIC_CMD volume connector create --node $node_id --type iqn \
  1945. --connector-id $connector_iqn || \
  1946. die $LINENO "Failed to create volume connector for node $node_id"
  1947. fi
  1948. fi
  1949. total_nodes=$((total_nodes+1))
  1950. done < $ironic_hwinfo_file
  1951. # NOTE(hjensas): ensure ironic-neutron-agent has done report_state for all
  1952. # nodes we attempt cleaning.
  1953. if [[ "${IRONIC_USE_NEUTRON_SEGMENTS}" == "True" ]]; then
  1954. wait_for_ironic_neutron_agent_report_state_for_all_nodes $node_uuids
  1955. fi
  1956. # NOTE(dtantsur): doing it outside of the loop, because of cleaning
  1957. provide_nodes $node_uuids
  1958. if is_service_enabled nova && [[ "$VIRT_DRIVER" == "ironic" ]]; then
  1959. if [[ "$HOST_TOPOLOGY_ROLE" != "subnode" ]]; then
  1960. local adjusted_disk
  1961. adjusted_disk=$(($ironic_node_disk - $ironic_ephemeral_disk))
  1962. openstack flavor create --ephemeral $ironic_ephemeral_disk --ram $ironic_node_ram --disk $adjusted_disk --vcpus $ironic_node_cpu baremetal
  1963. local resource_class=${IRONIC_DEFAULT_RESOURCE_CLASS^^}
  1964. openstack flavor set baremetal --property "resources:CUSTOM_$resource_class"="1"
  1965. openstack flavor set baremetal --property "resources:DISK_GB"="0"
  1966. openstack flavor set baremetal --property "resources:MEMORY_MB"="0"
  1967. openstack flavor set baremetal --property "resources:VCPU"="0"
  1968. openstack flavor set baremetal --property "cpu_arch"="$ironic_node_arch"
  1969. if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
  1970. openstack flavor set baremetal --property "capabilities:boot_mode"="uefi"
  1971. fi
  1972. for trait in $IRONIC_DEFAULT_TRAITS; do
  1973. openstack flavor set baremetal --property "trait:$trait"="required"
  1974. done
  1975. if [[ "$IRONIC_SECURE_BOOT" == "True" ]]; then
  1976. openstack flavor set baremetal --property "capabilities:secure_boot"="true"
  1977. fi
  1978. # NOTE(dtantsur): sometimes nova compute fails to start with ironic due
  1979. # to keystone restarting and not being able to authenticate us.
  1980. # Restart it just to be sure (and avoid gate problems like bug 1537076)
  1981. stop_nova_compute || /bin/true
  1982. # NOTE(pas-ha) if nova compute failed before restart, .failure file
  1983. # that was created will fail the service_check in the end of the deployment
  1984. _clean_ncpu_failure
  1985. start_nova_compute
  1986. else
  1987. # NOTE(vsaienko) we enrolling IRONIC_VM_COUNT on each node. So on subnode
  1988. # we expect to have 2 x total_cpus
  1989. total_nodes=$(( total_nodes * 2 ))
  1990. fi
  1991. wait_for_nova_resources $total_nodes
  1992. fi
  1993. }
  1994. function die_if_module_not_loaded {
  1995. if ! grep -q $1 /proc/modules; then
  1996. die $LINENO "$1 kernel module is not loaded"
  1997. fi
  1998. }
  1999. function configure_iptables {
  2000. # enable tftp natting for allowing connections to HOST_IP's tftp server
  2001. if ! running_in_container; then
  2002. sudo modprobe nf_conntrack_tftp
  2003. sudo modprobe nf_nat_tftp
  2004. else
  2005. die_if_module_not_loaded nf_conntrack_tftp
  2006. die_if_module_not_loaded nf_nat_tftp
  2007. fi
  2008. # explicitly allow DHCP - packets are occasionally being dropped here
  2009. sudo iptables -I INPUT -p udp --dport 67:68 --sport 67:68 -j ACCEPT || true
  2010. # nodes boot from TFTP and callback to the API server listening on $HOST_IP
  2011. sudo iptables -I INPUT -d $IRONIC_TFTPSERVER_IP -p udp --dport 69 -j ACCEPT || true
  2012. # To use named /baremetal endpoint we should open default apache port
  2013. if [[ "$IRONIC_USE_WSGI" == "False" ]]; then
  2014. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
  2015. # open ironic API on baremetal network
  2016. sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
  2017. # allow IPA to connect to ironic API on subnode
  2018. sudo iptables -I FORWARD -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
  2019. else
  2020. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport 80 -j ACCEPT || true
  2021. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport 443 -j ACCEPT || true
  2022. # open ironic API on baremetal network
  2023. sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport 80 -j ACCEPT || true
  2024. sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport 443 -j ACCEPT || true
  2025. fi
  2026. if is_deployed_by_agent; then
  2027. # agent ramdisk gets instance image from swift
  2028. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true
  2029. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $GLANCE_SERVICE_PORT -j ACCEPT || true
  2030. fi
  2031. if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
  2032. sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport $IRONIC_HTTP_PORT -j ACCEPT || true
  2033. fi
  2034. if [[ "${IRONIC_STORAGE_INTERFACE}" == "cinder" ]]; then
  2035. sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $ISCSI_SERVICE_PORT -s $FLOATING_RANGE -j ACCEPT || true
  2036. fi
  2037. # (rpittau) workaround to allow TFTP traffic on ubuntu bionic with conntrack helper disabled
  2038. local qrouter
  2039. qrouter=$(sudo ip netns list | grep qrouter | awk '{print $1;}')
  2040. if [[ ! -z "$qrouter" ]]; then
  2041. sudo ip netns exec $qrouter /sbin/iptables -A PREROUTING -t raw -p udp --dport 69 -j CT --helper tftp
  2042. fi
  2043. }
  2044. function configure_tftpd {
  2045. # stop tftpd and setup serving via xinetd
  2046. stop_service tftpd-hpa || true
  2047. [ -f /etc/init/tftpd-hpa.conf ] && echo "manual" | sudo tee /etc/init/tftpd-hpa.override
  2048. sudo cp $IRONIC_TEMPLATES_DIR/tftpd-xinetd.template /etc/xinetd.d/tftp
  2049. sudo sed -e "s|%TFTPBOOT_DIR%|$IRONIC_TFTPBOOT_DIR|g" -i /etc/xinetd.d/tftp
  2050. sudo sed -e "s|%MAX_BLOCKSIZE%|$IRONIC_TFTP_BLOCKSIZE|g" -i /etc/xinetd.d/tftp
  2051. # setup tftp file mapping to satisfy requests at the root (booting) and
  2052. # /tftpboot/ sub-dir (as per deploy-ironic elements)
  2053. # this section is only for ubuntu and fedora
  2054. if [[ "$IRONIC_IPXE_ENABLED" == "False" && \
  2055. ( "$IRONIC_BOOT_MODE" == "uefi" || "$IRONIC_SECURE_BOOT" == "True" ) && \
  2056. "$IRONIC_UEFI_BOOT_LOADER" == "grub2" ]]; then
  2057. local grub_dir
  2058. echo "re ^($IRONIC_TFTPBOOT_DIR/) $IRONIC_TFTPBOOT_DIR/\2" >$IRONIC_TFTPBOOT_DIR/map-file
  2059. echo "re ^$IRONIC_TFTPBOOT_DIR/ $IRONIC_TFTPBOOT_DIR/" >>$IRONIC_TFTPBOOT_DIR/map-file
  2060. echo "re ^(^/) $IRONIC_TFTPBOOT_DIR/\1" >>$IRONIC_TFTPBOOT_DIR/map-file
  2061. echo "re ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >>$IRONIC_TFTPBOOT_DIR/map-file
  2062. sudo cp $IRONIC_GRUB2_SHIM_FILE $IRONIC_TFTPBOOT_DIR/bootx64.efi
  2063. if is_fedora; then
  2064. grub_subdir="EFI/fedora"
  2065. elif is_ubuntu; then
  2066. grub_subdir="boot/grub"
  2067. fi
  2068. grub_dir=$IRONIC_TFTPBOOT_DIR/$grub_subdir
  2069. mkdir -p $grub_dir
  2070. # Grub looks for numerous files when the grubnetx.efi binary is used :\
  2071. # specifically .lst files which define module lists which we can't seem
  2072. # to find on disk. That being said, the grub-mknetdir utility generates
  2073. # these files for us.
  2074. grub-mknetdir --net-directory="$IRONIC_TFTPBOOT_DIR" --subdir="$grub_subdir"
  2075. sudo cp $grub_dir/x86_64-efi/core.efi $IRONIC_TFTPBOOT_DIR/grubx64.efi
  2076. cat << EOF > $grub_dir/grub.cfg
  2077. set default=master
  2078. set timeout=1
  2079. set hidden_timeout_quiet=false
  2080. menuentry "master" {
  2081. configfile $IRONIC_TFTPBOOT_DIR/\$net_default_mac.conf
  2082. }
  2083. EOF
  2084. chmod 644 $grub_dir/grub.cfg
  2085. iniset $IRONIC_CONF_FILE pxe uefi_pxe_config_template '$pybasedir/drivers/modules/pxe_grub_config.template'
  2086. iniset $IRONIC_CONF_FILE pxe uefi_pxe_bootfile_name "bootx64.efi"
  2087. else
  2088. echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file
  2089. echo "r ^(/tftpboot/) $IRONIC_TFTPBOOT_DIR/\2" >>$IRONIC_TFTPBOOT_DIR/map-file
  2090. fi
  2091. sudo chmod -R 0755 $IRONIC_TFTPBOOT_DIR
  2092. restart_service xinetd
  2093. }
  2094. function build_ipa_ramdisk {
  2095. local kernel_path=$1
  2096. local ramdisk_path=$2
  2097. local iso_path=$3
  2098. case $IRONIC_RAMDISK_TYPE in
  2099. 'tinyipa')
  2100. build_tinyipa_ramdisk $kernel_path $ramdisk_path $iso_path
  2101. ;;
  2102. 'dib')
  2103. build_ipa_dib_ramdisk $kernel_path $ramdisk_path $iso_path
  2104. ;;
  2105. *)
  2106. die $LINENO "Unrecognised IRONIC_RAMDISK_TYPE: $IRONIC_RAMDISK_TYPE. Expected either of 'dib' or 'tinyipa'."
  2107. ;;
  2108. esac
  2109. }
  2110. function setup_ipa_builder {
  2111. git_clone $IRONIC_PYTHON_AGENT_BUILDER_REPO $IRONIC_PYTHON_AGENT_BUILDER_DIR $IRONIC_PYTHON_AGENT_BUILDER_BRANCH
  2112. }
  2113. function build_tinyipa_ramdisk {
  2114. echo "Building ironic-python-agent deploy ramdisk"
  2115. local kernel_path=$1
  2116. local ramdisk_path=$2
  2117. local iso_path=$3
  2118. cd $IRONIC_PYTHON_AGENT_BUILDER_DIR/tinyipa
  2119. export BUILD_AND_INSTALL_TINYIPA=true
  2120. if is_ansible_deploy_enabled; then
  2121. export AUTHORIZE_SSH=true
  2122. export SSH_PUBLIC_KEY=$IRONIC_ANSIBLE_SSH_KEY.pub
  2123. fi
  2124. make
  2125. cp tinyipa.gz $ramdisk_path
  2126. cp tinyipa.vmlinuz $kernel_path
  2127. if is_deploy_iso_required; then
  2128. make iso
  2129. cp tinyipa.iso $iso_path
  2130. fi
  2131. make clean
  2132. cd -
  2133. }
  2134. function rebuild_tinyipa_for_ansible {
  2135. local ansible_tinyipa_ramdisk_name
  2136. pushd $IRONIC_PYTHON_AGENT_BUILDER_DIR/tinyipa
  2137. export TINYIPA_RAMDISK_FILE=$IRONIC_DEPLOY_RAMDISK
  2138. export SSH_PUBLIC_KEY=$IRONIC_ANSIBLE_SSH_KEY.pub
  2139. make addssh
  2140. ansible_tinyipa_ramdisk_name="ansible-$(basename $IRONIC_DEPLOY_RAMDISK)"
  2141. mv $ansible_tinyipa_ramdisk_name $TOP_DIR/files
  2142. make clean
  2143. popd
  2144. IRONIC_DEPLOY_RAMDISK=$TOP_DIR/files/$ansible_tinyipa_ramdisk_name
  2145. }
  2146. # install_diskimage_builder() - Collect source and prepare or install from pip
  2147. function install_diskimage_builder {
  2148. if use_library_from_git "diskimage-builder"; then
  2149. git_clone_by_name "diskimage-builder"
  2150. setup_dev_lib -bindep "diskimage-builder"
  2151. else
  2152. local bindep_file
  2153. bindep_file=$(mktemp)
  2154. curl -o "$bindep_file" "$IRONIC_DIB_BINDEP_FILE"
  2155. install_bindep "$bindep_file"
  2156. pip_install_gr "diskimage-builder"
  2157. fi
  2158. }
  2159. function build_ipa_dib_ramdisk {
  2160. local kernel_path=$1
  2161. local ramdisk_path=$2
  2162. local iso_path=$3
  2163. local tempdir
  2164. tempdir=$(mktemp -d --tmpdir=${DEST})
  2165. # install diskimage-builder if not present
  2166. if ! $(type -P disk-image-create > /dev/null); then
  2167. install_diskimage_builder
  2168. fi
  2169. echo "Building IPA ramdisk with DIB options: $IRONIC_DIB_RAMDISK_OPTIONS"
  2170. if is_deploy_iso_required; then
  2171. IRONIC_DIB_RAMDISK_OPTIONS+=" iso"
  2172. fi
  2173. git_clone $IRONIC_PYTHON_AGENT_BUILDER_REPO $IRONIC_PYTHON_AGENT_BUILDER_DIR $IRONIC_PYTHON_AGENT_BUILDER_BRANCH
  2174. ELEMENTS_PATH="$IRONIC_PYTHON_AGENT_BUILDER_DIR/dib" \
  2175. DIB_DHCP_TIMEOUT=$IRONIC_DIB_DHCP_TIMEOUT \
  2176. DIB_RELEASE=$IRONIC_DIB_RAMDISK_RELEASE \
  2177. DIB_REPOLOCATION_ironic_python_agent="$IRONIC_PYTHON_AGENT_DIR" \
  2178. DIB_REPOLOCATION_requirements="$DEST/requirements" \
  2179. disk-image-create "$IRONIC_DIB_RAMDISK_OPTIONS" \
  2180. -x -o "$tempdir/ironic-agent" \
  2181. ironic-python-agent-ramdisk
  2182. chmod -R +r $tempdir
  2183. mv "$tempdir/ironic-agent.kernel" "$kernel_path"
  2184. mv "$tempdir/ironic-agent.initramfs" "$ramdisk_path"
  2185. if is_deploy_iso_required; then
  2186. mv "$tempdir/ironic-agent.iso" "$iso_path"
  2187. fi
  2188. rm -rf $tempdir
  2189. }
  2190. # download EFI boot loader image and upload it to glance
  2191. # this function sets ``IRONIC_EFIBOOT_ID``
  2192. function upload_baremetal_ironic_efiboot {
  2193. declare -g IRONIC_EFIBOOT_ID
  2194. local efiboot_name
  2195. efiboot_name=$(basename $IRONIC_EFIBOOT)
  2196. echo_summary "Building and uploading EFI boot image for ironic"
  2197. if [ ! -e "$IRONIC_EFIBOOT" ]; then
  2198. local efiboot_path
  2199. efiboot_path=$(mktemp -d --tmpdir=${DEST})/$efiboot_name
  2200. local efiboot_mount
  2201. efiboot_mount=$(mktemp -d --tmpdir=${DEST})
  2202. dd if=/dev/zero \
  2203. of=$efiboot_path \
  2204. bs=4096 count=1024
  2205. mkfs.fat -s 4 -r 512 -S 4096 $efiboot_path
  2206. sudo mount $efiboot_path $efiboot_mount
  2207. sudo mkdir -p $efiboot_mount/efi/boot
  2208. sudo grub-mkimage \
  2209. -C xz \
  2210. -O x86_64-efi \
  2211. -p /boot/grub \
  2212. -o $efiboot_mount/efi/boot/bootx64.efi \
  2213. boot linux linuxefi search normal configfile \
  2214. part_gpt btrfs ext2 fat iso9660 loopback \
  2215. test keystatus gfxmenu regexp probe \
  2216. efi_gop efi_uga all_video gfxterm font \
  2217. echo read ls cat png jpeg halt reboot
  2218. sudo umount $efiboot_mount
  2219. mv $efiboot_path $IRONIC_EFIBOOT
  2220. fi
  2221. # load efiboot into glance
  2222. IRONIC_EFIBOOT_ID=$(openstack \
  2223. image create \
  2224. $efiboot_name \
  2225. --public --disk-format=raw \
  2226. --container-format=bare \
  2227. -f value -c id \
  2228. < $IRONIC_EFIBOOT)
  2229. die_if_not_set $LINENO IRONIC_EFIBOOT_ID "Failed to load EFI bootloader image into glance"
  2230. iniset $IRONIC_CONF_FILE conductor bootloader $IRONIC_EFIBOOT_ID
  2231. }
  2232. # build deploy kernel+ramdisk, then upload them to glance
  2233. # this function sets ``IRONIC_DEPLOY_KERNEL_ID``, ``IRONIC_DEPLOY_RAMDISK_ID``
  2234. function upload_baremetal_ironic_deploy {
  2235. declare -g IRONIC_DEPLOY_KERNEL_ID IRONIC_DEPLOY_RAMDISK_ID
  2236. local ironic_deploy_kernel_name
  2237. local ironic_deploy_ramdisk_name
  2238. ironic_deploy_kernel_name=$(basename $IRONIC_DEPLOY_KERNEL)
  2239. ironic_deploy_ramdisk_name=$(basename $IRONIC_DEPLOY_RAMDISK)
  2240. if [[ "$HOST_TOPOLOGY_ROLE" != "subnode" ]]; then
  2241. echo_summary "Creating and uploading baremetal images for ironic"
  2242. if [ ! -e "$IRONIC_DEPLOY_RAMDISK" ] || \
  2243. [ ! -e "$IRONIC_DEPLOY_KERNEL" ] || \
  2244. ( is_deploy_iso_required && [ ! -e "$IRONIC_DEPLOY_ISO" ] ); then
  2245. # setup IRONIC_PYTHON_AGENT_BUILDER_DIR
  2246. setup_ipa_builder
  2247. # files don't exist, need to build them
  2248. if [ "$IRONIC_BUILD_DEPLOY_RAMDISK" = "True" ]; then
  2249. # we can build them only if we're not offline
  2250. if [ "$OFFLINE" != "True" ]; then
  2251. build_ipa_ramdisk $IRONIC_DEPLOY_KERNEL $IRONIC_DEPLOY_RAMDISK $IRONIC_DEPLOY_ISO
  2252. else
  2253. die $LINENO "Deploy kernel+ramdisk or iso files don't exist and cannot be built in OFFLINE mode"
  2254. fi
  2255. else
  2256. # Grab the agent image tarball, either from a local file or remote URL
  2257. if [[ "$IRONIC_AGENT_KERNEL_URL" =~ "file://" ]]; then
  2258. cp ${IRONIC_AGENT_KERNEL_URL:7} $IRONIC_DEPLOY_KERNEL
  2259. else
  2260. wget "$IRONIC_AGENT_KERNEL_URL" -O $IRONIC_DEPLOY_KERNEL
  2261. fi
  2262. if [[ "$IRONIC_AGENT_RAMDISK_URL" =~ "file://" ]]; then
  2263. cp ${IRONIC_AGENT_RAMDISK_URL:7} $IRONIC_DEPLOY_RAMDISK
  2264. else
  2265. wget "$IRONIC_AGENT_RAMDISK_URL" -O $IRONIC_DEPLOY_RAMDISK
  2266. fi
  2267. if is_ansible_with_tinyipa; then
  2268. # NOTE(pas-ha) if using ansible-deploy and tinyipa,
  2269. # this will rebuild ramdisk and override $IRONIC_DEPLOY_RAMDISK
  2270. rebuild_tinyipa_for_ansible
  2271. fi
  2272. fi
  2273. fi
  2274. # load them into glance
  2275. if ! is_deploy_iso_required; then
  2276. IRONIC_DEPLOY_KERNEL_ID=$(openstack \
  2277. image create \
  2278. $ironic_deploy_kernel_name \
  2279. --public --disk-format=aki \
  2280. --container-format=aki \
  2281. < $IRONIC_DEPLOY_KERNEL | grep ' id ' | get_field 2)
  2282. die_if_not_set $LINENO IRONIC_DEPLOY_KERNEL_ID "Failed to load kernel image into glance"
  2283. IRONIC_DEPLOY_RAMDISK_ID=$(openstack \
  2284. image create \
  2285. $ironic_deploy_ramdisk_name \
  2286. --public --disk-format=ari \
  2287. --container-format=ari \
  2288. < $IRONIC_DEPLOY_RAMDISK | grep ' id ' | get_field 2)
  2289. die_if_not_set $LINENO IRONIC_DEPLOY_RAMDISK_ID "Failed to load ramdisk image into glance"
  2290. else
  2291. IRONIC_DEPLOY_ISO_ID=$(openstack \
  2292. image create \
  2293. $(basename $IRONIC_DEPLOY_ISO) \
  2294. --public --disk-format=iso \
  2295. --container-format=bare \
  2296. < $IRONIC_DEPLOY_ISO -f value -c id)
  2297. die_if_not_set $LINENO IRONIC_DEPLOY_ISO_ID "Failed to load deploy iso into glance"
  2298. fi
  2299. else
  2300. if is_ansible_with_tinyipa; then
  2301. ironic_deploy_ramdisk_name="ansible-$ironic_deploy_ramdisk_name"
  2302. fi
  2303. IRONIC_DEPLOY_KERNEL_ID=$(openstack image show $ironic_deploy_kernel_name -f value -c id)
  2304. IRONIC_DEPLOY_RAMDISK_ID=$(openstack image show $ironic_deploy_ramdisk_name -f value -c id)
  2305. fi
  2306. iniset $IRONIC_CONF_FILE conductor deploy_kernel $IRONIC_DEPLOY_KERNEL_ID
  2307. iniset $IRONIC_CONF_FILE conductor deploy_ramdisk $IRONIC_DEPLOY_RAMDISK_ID
  2308. iniset $IRONIC_CONF_FILE conductor rescue_kernel $IRONIC_DEPLOY_KERNEL_ID
  2309. iniset $IRONIC_CONF_FILE conductor rescue_ramdisk $IRONIC_DEPLOY_RAMDISK_ID
  2310. }
  2311. function prepare_baremetal_basic_ops {
  2312. if [[ "$IRONIC_BAREMETAL_BASIC_OPS" != "True" ]]; then
  2313. return 0
  2314. fi
  2315. if ! is_service_enabled nova && [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
  2316. local image_file_path
  2317. if [[ ${IRONIC_WHOLEDISK_IMAGE_NAME} =~ \.img$ ]]; then
  2318. image_file_path=$FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}
  2319. else
  2320. image_file_path=$FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}.img
  2321. fi
  2322. sudo install -g $LIBVIRT_GROUP -o $STACK_USER -m 644 $image_file_path $IRONIC_HTTP_DIR
  2323. fi
  2324. upload_baremetal_ironic_deploy
  2325. if [[ "$IRONIC_BOOT_MODE" == "uefi" && is_deployed_by_redfish ]]; then
  2326. upload_baremetal_ironic_efiboot
  2327. fi
  2328. configure_tftpd
  2329. configure_iptables
  2330. }
  2331. function cleanup_baremetal_basic_ops {
  2332. if [[ "$IRONIC_BAREMETAL_BASIC_OPS" != "True" ]]; then
  2333. return 0
  2334. fi
  2335. rm -f $IRONIC_VM_MACS_CSV_FILE
  2336. sudo rm -rf $IRONIC_DATA_DIR $IRONIC_STATE_PATH
  2337. local vm_name
  2338. for vm_name in $(_ironic_bm_vm_names); do
  2339. # Delete the Virtual BMCs
  2340. if is_deployed_by_ipmi; then
  2341. vbmc --no-daemon list | grep -a $vm_name && vbmc --no-daemon delete $vm_name || /bin/true
  2342. fi
  2343. # pick up the $LIBVIRT_GROUP we have possibly joint
  2344. newgrp $LIBVIRT_GROUP <<SUBSHELL
  2345. $IRONIC_SCRIPTS_DIR/cleanup-node.sh $vm_name
  2346. SUBSHELL
  2347. # Cleanup node bridge/interfaces
  2348. for i in $(seq 1 $IRONIC_VM_INTERFACE_COUNT); do
  2349. sudo ip link del dev tap-${vm_name}i${i}
  2350. done
  2351. done
  2352. sudo ovs-vsctl --if-exists del-br $IRONIC_VM_NETWORK_BRIDGE
  2353. sudo rm -rf /etc/xinetd.d/tftp /etc/init/tftpd-hpa.override
  2354. restart_service xinetd
  2355. sudo iptables -D INPUT -d $HOST_IP -p udp --dport 69 -j ACCEPT || true
  2356. sudo iptables -D INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
  2357. sudo iptables -D INPUT -d $HOST_IP -p tcp --dport 80 -j ACCEPT || true
  2358. sudo iptables -D INPUT -d $HOST_IP -p tcp --dport 443 -j ACCEPT || true
  2359. if is_deployed_by_agent; then
  2360. # agent ramdisk gets instance image from swift
  2361. sudo iptables -D INPUT -d $HOST_IP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true
  2362. fi
  2363. sudo rmmod nf_conntrack_tftp || true
  2364. sudo rmmod nf_nat_tftp || true
  2365. }
  2366. function ironic_configure_tempest {
  2367. iniset $TEMPEST_CONFIG service_available ironic True
  2368. if [[ -n "$TEMPEST_BAREMETAL_MIN_MICROVERSION" ]]; then
  2369. iniset $TEMPEST_CONFIG baremetal min_microversion $TEMPEST_BAREMETAL_MIN_MICROVERSION
  2370. fi
  2371. if [[ -n "$TEMPEST_BAREMETAL_MAX_MICROVERSION" ]]; then
  2372. iniset $TEMPEST_CONFIG baremetal max_microversion $TEMPEST_BAREMETAL_MAX_MICROVERSION
  2373. fi
  2374. if [[ -n "$IRONIC_VM_COUNT" ]]; then
  2375. iniset $TEMPEST_CONFIG baremetal available_nodes $IRONIC_VM_COUNT
  2376. fi
  2377. if [[ -n "$IRONIC_PING_TIMEOUT" ]]; then
  2378. iniset $TEMPEST_CONFIG validation ping_timeout $IRONIC_PING_TIMEOUT
  2379. fi
  2380. if is_service_enabled nova; then
  2381. local bm_flavor_id
  2382. bm_flavor_id=$(openstack flavor show baremetal -f value -c id)
  2383. die_if_not_set $LINENO bm_flavor_id "Failed to get id of baremetal flavor"
  2384. iniset $TEMPEST_CONFIG compute flavor_ref $bm_flavor_id
  2385. iniset $TEMPEST_CONFIG compute flavor_ref_alt $bm_flavor_id
  2386. iniset $TEMPEST_CONFIG compute-feature-enabled disk_config False
  2387. if [[ "$IRONIC_NETWORK_INTERFACE" == "neutron" && $IRONIC_VM_INTERFACE_COUNT -gt 1 ]]; then
  2388. iniset $TEMPEST_CONFIG compute-feature-enabled interface_attach True
  2389. else
  2390. iniset $TEMPEST_CONFIG compute-feature-enabled interface_attach False
  2391. fi
  2392. fi
  2393. # NOTE(jlvillal): If IRONIC_PROVISION_NETWORK_NAME is set it means that
  2394. # nodes are using the neutron network driver / multi-tenant networking.
  2395. # Otherwise we are using a flat-network.
  2396. if [[ -n "${IRONIC_PROVISION_NETWORK_NAME}" ]]; then
  2397. # multi-tenant networking
  2398. iniset $TEMPEST_CONFIG baremetal use_provision_network True
  2399. else
  2400. # flat-network
  2401. iniset $TEMPEST_CONFIG compute fixed_network_name $PRIVATE_NETWORK_NAME
  2402. # NOTE(jroll) this disables multitenant network tests from tempest's
  2403. # tree, but not from our tree. This is a bit inconsistent, we should
  2404. # fix it.
  2405. iniset $TEMPEST_CONFIG auth create_isolated_networks False
  2406. iniset $TEMPEST_CONFIG network shared_physical_network True
  2407. fi
  2408. if is_service_enabled glance; then
  2409. local image_uuid
  2410. image_uuid=$(openstack image show $IRONIC_IMAGE_NAME -f value -c id)
  2411. iniset $TEMPEST_CONFIG compute image_ref $image_uuid
  2412. iniset $TEMPEST_CONFIG compute image_ref_alt $image_uuid
  2413. image_uuid=$(openstack image show $IRONIC_WHOLEDISK_IMAGE_NAME -f value -c id)
  2414. iniset $TEMPEST_CONFIG baremetal whole_disk_image_ref $image_uuid
  2415. image_uuid=$(openstack image show $IRONIC_PARTITIONED_IMAGE_NAME -f value -c id)
  2416. iniset $TEMPEST_CONFIG baremetal partition_image_ref $image_uuid
  2417. fi
  2418. iniset $TEMPEST_CONFIG baremetal whole_disk_image_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT/${IRONIC_WHOLEDISK_IMAGE_NAME}.img"
  2419. iniset $TEMPEST_CONFIG baremetal whole_disk_image_checksum $(md5sum $FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}.img)
  2420. # NOTE(dtantsur): keep this option here until the defaults change in
  2421. # ironic-tempest-plugin to disable classic drivers testing.
  2422. iniset $TEMPEST_CONFIG baremetal enabled_drivers ""
  2423. iniset $TEMPEST_CONFIG baremetal enabled_hardware_types $IRONIC_ENABLED_HARDWARE_TYPES
  2424. iniset $TEMPEST_CONFIG baremetal enabled_bios_interfaces $IRONIC_ENABLED_BIOS_INTERFACES
  2425. iniset $TEMPEST_CONFIG baremetal enabled_deploy_interfaces $IRONIC_ENABLED_DEPLOY_INTERFACES
  2426. iniset $TEMPEST_CONFIG baremetal enabled_boot_interfaces $IRONIC_ENABLED_BOOT_INTERFACES
  2427. iniset $TEMPEST_CONFIG baremetal enabled_rescue_interfaces $IRONIC_ENABLED_RESCUE_INTERFACES
  2428. iniset $TEMPEST_CONFIG baremetal default_rescue_interface $IRONIC_DEFAULT_RESCUE_INTERFACE
  2429. # Driver for API tests
  2430. iniset $TEMPEST_CONFIG baremetal driver fake-hardware
  2431. local adjusted_root_disk_size_gb
  2432. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  2433. adjusted_root_disk_size_gb=$(( ${IRONIC_VM_SPECS_DISK} - ${IRONIC_VM_EPHEMERAL_DISK} ))
  2434. else
  2435. adjusted_root_disk_size_gb=$(( ${IRONIC_HW_NODE_DISK} - ${IRONIC_HW_EPHEMERAL_DISK} ))
  2436. fi
  2437. iniset $TEMPEST_CONFIG baremetal adjusted_root_disk_size_gb $adjusted_root_disk_size_gb
  2438. if [[ -n "${IRONIC_TEMPEST_BUILD_TIMEOUT}" ]]; then
  2439. iniset $TEMPEST_CONFIG baremetal unprovision_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2440. iniset $TEMPEST_CONFIG baremetal active_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2441. iniset $TEMPEST_CONFIG baremetal deploywait_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2442. iniset $TEMPEST_CONFIG baremetal power_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2443. iniset $TEMPEST_CONFIG baremetal rescue_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2444. iniset $TEMPEST_CONFIG baremetal unrescue_timeout $IRONIC_TEMPEST_BUILD_TIMEOUT
  2445. fi
  2446. if [[ $IRONIC_VM_VOLUME_COUNT -gt 1 ]]; then
  2447. iniset $TEMPEST_CONFIG baremetal_feature_enabled software_raid True
  2448. fi
  2449. # Enabled features
  2450. iniset $TEMPEST_CONFIG baremetal_feature_enabled ipxe_enabled $IRONIC_IPXE_ENABLED
  2451. iniset $TEMPEST_CONFIG baremetal_feature_enabled fast_track_discovery $IRONIC_DEPLOY_FAST_TRACK
  2452. if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
  2453. # Adoption requires reading or guessing the BMC credentials, so let's
  2454. # not enable it for real hardware, at least for now.
  2455. iniset $TEMPEST_CONFIG baremetal_feature_enabled adoption True
  2456. fi
  2457. }
  2458. function get_ironic_node_prefix {
  2459. local node_prefix="node"
  2460. if [[ "$HOST_TOPOLOGY_ROLE" == "subnode" ]]; then
  2461. node_prefix="$HOST_TOPOLOGY_ROLE"
  2462. fi
  2463. echo $node_prefix
  2464. }
  2465. function setup_vxlan_network {
  2466. sudo ovs-vsctl add-port $IRONIC_VM_NETWORK_BRIDGE phy-brbm-infra
  2467. sudo ovs-vsctl add-port $PUBLIC_BRIDGE phy-infra-brbm
  2468. sudo ovs-vsctl set interface phy-brbm-infra type=patch
  2469. sudo ovs-vsctl set interface phy-infra-brbm type=patch
  2470. sudo ovs-vsctl set interface phy-infra-brbm options:peer=phy-brbm-infra
  2471. sudo ovs-vsctl set interface phy-brbm-infra options:peer=phy-infra-brbm
  2472. }
  2473. # Restore xtrace + pipefail
  2474. $_XTRACE_IRONIC
  2475. $_PIPEFAIL_IRONIC
  2476. # Tell emacs to use shell-script-mode
  2477. ## Local variables:
  2478. ## mode: shell-script
  2479. ## End: