├── README └── nova-install /README: -------------------------------------------------------------------------------- 1 | If you'd like to contribute code or ideas for improving this script, planned 2 | changes are being documented here: 3 | 4 | http://etherpad.openstack.org/nova-install-script-todos 5 | 6 | ----- 7 | 8 | NAME 9 | nova-install -- configure a fully functioning OpenStack Nova component 10 | 11 | SYNOPSIS 12 | nova-install [-t type] [-V] [-h] 13 | 14 | DESCRIPTION 15 | The nova-install command will gather information, install dependencies, 16 | and then configure one of a number of different OpenStack component 17 | types as specified on the command line. 18 | 19 | A cloud controller will be configured to run all five Nova services 20 | (api, compute, network, objectstor, and scheduler), while a compute 21 | node will only run Nova's compute service. 22 | 23 | OPTIONS 24 | -t, --type 25 | Changes the type of component to install. Currently implemented 26 | types are 'cloud' (default) for installing a new cloud 27 | controller, and 'compute' for installing a compute node for an 28 | existing cloud. 29 | 30 | -V, --version 31 | Print the nova-install script's version information and exit. 32 | 33 | -h, --help 34 | View this help message about the available command-line options. 35 | -------------------------------------------------------------------------------- /nova-install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2011-2012 OpenStack, LLC. 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # nova-install - configure a fully functioning OpenStack Nova component 17 | 18 | # For detailed usage instructions, run: 19 | # nova-install --help 20 | 21 | # This script is intended to be ran on a fresh install on Ubuntu 10.04 64-bit. 22 | # Once ran with the appropiate variables, it will produce a fully functioning 23 | # Nova Cloud Contoller or Nova Compute Node. Eventually other Ubuntu releases, 24 | # as well as RPM-based distributions, will be supported. 25 | 26 | # Written by Wayne A. Walls (dubsquared) with the amazing help of Jordan Rinke 27 | # (JordanRinke), Vish Ishaya (vishy), Aaron Bull Schaefer (elasticdog), and 28 | # a lot of input from the fine folks in #openstack on irc.freenode.net! 29 | 30 | # Please contact script maintainers for questions, comments, or concerns: 31 | # Wayne -> wayne@openstack.org 32 | # Jordan -> jordan@openstack.org 33 | 34 | # You can also get assistance by stopping by irc.freenode.net - #openstack, 35 | # sending a message to the OpenStack mailing list - openstack@lists.launchpad.net, 36 | # or posting at https://answers.launchpad.net/openstack 37 | 38 | 39 | ##### Constants 40 | 41 | readonly VERSION=1.1 # release version of this script 42 | 43 | readonly BASENAME="${0##*/}" # name of this script for error output 44 | readonly CREDS_DIR='/root/creds' # directory to store nova credentials 45 | readonly LOG_FILE='/var/log/nova/install.log' # location of script log file 46 | readonly PARAMETERS="$*" # all of the specified input parameters 47 | readonly PPA='ppa:openstack-release/2011.3' # which ppa to install packages from 48 | readonly ROOT_UID=0 # users with $UID 0 have root privileges 49 | 50 | # Exit codes 51 | readonly EX_OK=0 # successful termination 52 | readonly EX_USAGE=64 # command line usage error 53 | readonly EX_OSFILE=72 # critical OS file missing 54 | readonly EX_NOPERM=77 # permission denied 55 | 56 | 57 | ##### Helper Functions 58 | 59 | # Print message to stderr and exit with the given status code, if one was supplied 60 | error_exit() { 61 | local message="$1" 62 | local status="$2" 63 | local max_status=255 # highest legal status code 64 | 65 | set -o xtrace 66 | echo "ERROR: $message" 1>&2 67 | set +o xtrace 68 | 69 | finalize_log 'installation process aborted due to error' 70 | 71 | if is_integer "$status" "$max_status"; then 72 | exit $status 73 | else 74 | exit 1 75 | fi 76 | } 77 | 78 | # Remove clutter from log and append a timestamp 79 | finalize_log() { 80 | local message="$1" 81 | 82 | sed -i'' -e '/^+ set +o xtrace$/d' $LOG_FILE 83 | echo "$(date) $BASENAME: $message ($PARAMETERS)" >>$LOG_FILE 84 | } 85 | 86 | # Prompt user for an IP address range, validate it, and then assign it to the given variable 87 | get_cidr_range() { 88 | local prompt="$1" 89 | local variable="$2" 90 | local max_prefix=32 # only 32 bits in an address 91 | 92 | while true; do 93 | read -e -p "${prompt}: " range 94 | local address=${range%/*} 95 | local prefix=${range##*/} 96 | 97 | if is_valid_ipv4 $address && is_integer "$prefix" "$max_prefix"; then 98 | # much safer than assigning with eval 99 | printf -v $variable %s "$range" 100 | break 101 | else 102 | echo -e "That IP address range is invalid...try again\n" 103 | fi 104 | done 105 | } 106 | 107 | # Prompt user for an IP address, validate it, and then assign it to the given 108 | # variable; a default is offered and required when calling this function 109 | get_host_ip() { 110 | local prompt="$1" 111 | local variable="$2" 112 | local default="$3" 113 | 114 | while true; do 115 | read -e -p "$prompt [$default]: " address 116 | 117 | # fall back to the default IP if none was input by user 118 | address=${address:-$default} 119 | 120 | if is_valid_ipv4 $address; then 121 | # much safer than assigning with eval 122 | printf -v $variable %s "$address" 123 | break 124 | else 125 | echo -e "That IP address is invalid...try again\n" 126 | fi 127 | done 128 | } 129 | 130 | # Prompt user for input, and do not accept an empty string 131 | get_input() { 132 | local prompt="$1" 133 | local variable="$2" 134 | 135 | while true; do 136 | read -e -p "$prompt: " 137 | 138 | if [[ -n $REPLY ]]; then 139 | # much safer than assigning with eval 140 | printf -v $variable %s "$REPLY" 141 | break 142 | fi 143 | done 144 | } 145 | 146 | # Prompt user for a number, validate that it is an integer, optionally checking 147 | # if it's less than or equal to the supplied maximum, and then assign it to the 148 | # given variable 149 | get_integer() { 150 | local prompt="$1" 151 | local variable="$2" 152 | # maximum might not be set 153 | set +o nounset 154 | local maximum="$3" 155 | set -o nounset 156 | 157 | while true; do 158 | read -e -p "$prompt: " number 159 | 160 | if is_integer "$number" "$maximum"; then 161 | # much safer than assigning with eval 162 | printf -v $variable %s "$number" 163 | break 164 | else 165 | if [[ -z $maximum ]]; then 166 | echo -e "The input must be an unsigned integer...try again\n" 167 | else 168 | echo -e "The input must be an unsigned integer and <= $maximum...try again\n" 169 | fi 170 | fi 171 | done 172 | } 173 | 174 | # Install each given package, checking first if it's already installed 175 | install_packages() { 176 | for package in "$@"; do 177 | echo -n "Installing package '$package' ... " 178 | 179 | set -o xtrace 180 | # skip if the package is already installed 181 | if is_installed $package; then 182 | set +o xtrace 183 | echo 'already installed' 184 | continue 185 | else 186 | apt-get install --quiet --assume-yes $package &>>$LOG_FILE 187 | set +o xtrace 188 | echo 'done' 189 | fi 190 | done 191 | } 192 | 193 | # Return whether or not the provided input is an integer, and optionally, less 194 | # than or equal to the given maximum 195 | is_integer() { 196 | local input="$1" 197 | # maximum might not be set 198 | set +o nounset 199 | local maximum="$2" 200 | set -o nounset 201 | 202 | case "$input" in 203 | # reject the following: 204 | # empty strings 205 | # anything other than digits 206 | ""|*[!0-9]*) return 1 ;; 207 | esac 208 | 209 | if [[ -n $maximum ]]; then 210 | (( $input <= $maximum )) 211 | fi 212 | } 213 | 214 | # Return whether or not the given package is already installed on the system 215 | is_installed() { 216 | set +o xtrace 217 | local package="$1" 218 | set -o xtrace 219 | dpkg -l $package 2>>$LOG_FILE | grep -q 'ii' 220 | } 221 | 222 | # Return whether or not the provided component is supported by the script 223 | is_supported_component() { 224 | local component="$1" 225 | case "$component" in 226 | cloud|compute) ;; 227 | *) return 1 ;; 228 | esac 229 | } 230 | 231 | # Return whether or not the provided input is a valid IPv4 address...assumes 232 | # only dotted quads are valid, rejecting addresses like 127.1 233 | is_valid_ipv4() { 234 | local input="$1" 235 | 236 | case "$input" in 237 | # reject the following: 238 | # empty strings 239 | # anything other than digits and dots 240 | # anything not ending in a digit 241 | ""|*[!0-9.]*|*[!0-9]) return 1 ;; 242 | esac 243 | 244 | # change IFS to a dot, only for this function 245 | local IFS=. 246 | 247 | # split the address into positional parameters 248 | set -- $* 249 | 250 | # there must be four parameters, each less than or equal to 255 251 | (( $# == 4 )) && 252 | (( $1 <= 255 )) && (( $2 <= 255 )) && (( $3 <= 255 )) && (( $4 <= 255 )) 253 | } 254 | 255 | # Display a section separator with the provided message 256 | section_banner() { 257 | local border='################################################################' 258 | echo -e "\n${border}" 259 | echo " $*" 260 | echo -e "${border}\n" 261 | } 262 | 263 | # Display the script's help message 264 | show_help() { 265 | cat <<-EOF 266 | 267 | NAME 268 | $BASENAME -- configure a fully functioning OpenStack Nova component 269 | 270 | SYNOPSIS 271 | $BASENAME [-t type] [-V] [-h] 272 | 273 | DESCRIPTION 274 | The $BASENAME command will gather information, install dependencies, 275 | and then configure one of a number of different OpenStack component 276 | types as specified on the command line. 277 | 278 | A cloud controller will be configured to run all five Nova services 279 | (api, compute, network, objectstor, and scheduler), while a compute 280 | node will only run Nova's compute service. 281 | 282 | OPTIONS 283 | -t, --type 284 | Changes the type of component to install. Currently implemented 285 | types are 'cloud' (default) for installing a new cloud 286 | controller, and 'compute' for installing a compute node for an 287 | existing cloud. 288 | 289 | -V, --version 290 | Print the $BASENAME script's version information and exit. 291 | 292 | -h, --help 293 | View this help message about the available command-line options. 294 | 295 | EOF 296 | } 297 | 298 | # Display a subsection separator with the provided message 299 | subsection_banner() { 300 | echo -e "\n$*" 301 | echo -e "${*//?/#}\n" 302 | } 303 | 304 | 305 | ##### Workflow Functions 306 | 307 | # Ensure user has root privileges and that we're on a supported linux box 308 | check_safety() { 309 | # root check 310 | if (( $UID != $ROOT_UID )); then 311 | error_exit 'Permission denied - you must have root privileges to run this script' $EX_NOPERM 312 | fi 313 | 314 | # linux check 315 | if [[ $OSTYPE != linux* ]]; then 316 | error_exit 'Not compatible - you must run this script on a Linux system' $EX_OSFILE 317 | fi 318 | 319 | # distribution check 320 | if [[ -f /etc/lsb-release ]]; then 321 | distro='ubuntu' 322 | else 323 | error_exit 'Not compatible - this script only supports Ubuntu at this time' $EX_OSFILE 324 | fi 325 | } 326 | 327 | # Initialize package dependencies based on OS and component type 328 | initialize_dependencies() { 329 | case "$component_type" in 330 | cloud) 331 | required_packages=" 332 | euca2ools 333 | mysql-server 334 | nova-api 335 | nova-compute 336 | nova-network 337 | nova-objectstore 338 | nova-scheduler 339 | unzip 340 | glance 341 | " 342 | ;; 343 | compute) 344 | required_packages=" 345 | nova-compute 346 | " 347 | ;; 348 | esac 349 | } 350 | 351 | # Initializes the local network interface variables using the first listed 352 | # interface; this could be improved later as it might not work as expected on 353 | # all systems 354 | initialize_network_variables() { 355 | local interface=$(/sbin/ifconfig -a | grep 'inet ' | grep -v '127.0.0.1' | head -n 1) 356 | 357 | local_address=$(echo "$interface" | cut -d: -f2 | awk '{ print $1 }') 358 | local_broadcast=$(echo "$interface" | cut -d: -f3 | awk '{ print $1 }') 359 | local_netmask=$(echo "$interface" | cut -d: -f4 | awk '{ print $1 }') 360 | local_gateway=$(/sbin/ip route | awk '/default/{ print $3 }') 361 | local_nameserver=$(awk '/nameserver/{ print $2 }' /etc/resolv.conf) 362 | } 363 | 364 | # Create the log file (if necessary) and append a timestamp 365 | start_log() { 366 | set -o xtrace 367 | mkdir -p "${LOG_FILE%/*}" 368 | set +o xtrace 369 | echo "$(date) $BASENAME: installation process initiated ($PARAMETERS)" >>$LOG_FILE 370 | } 371 | 372 | # Display installer introduction 373 | show_intro() { 374 | local wording 375 | if [[ $component_type == cloud ]]; then 376 | wording='Cloud Controller' 377 | elif [[ $component_type == compute ]]; then 378 | wording="Compute Node" 379 | fi 380 | 381 | cat <<-EOF 382 | 383 | Nova Installation Script v${VERSION} 384 | 385 | Setting up a Nova $wording is a multi-step process. After you seed 386 | information, the script will take over and finish off the installation for you. 387 | A complete log of commands will be availible at $LOG_FILE 388 | 389 | EOF 390 | read -s -n 1 -p 'Press any key to continue...' 391 | echo 392 | } 393 | 394 | # Prompt user for host IPs for various Nova services 395 | get_service_hosts() { 396 | section_banner 'Nova Services Configuration' 397 | 398 | cat <<-EOF 399 | This section includes setting the host IP addresses for the Nova Cloud 400 | Controller, S3, RabbitMQ, and MySQL services...these are typically hosted on 401 | the same machine. 402 | 403 | EOF 404 | get_host_ip 'Cloud Controller host IP address' cc_host_ip $local_address 405 | get_host_ip 'S3 host IP address' s3_host_ip $cc_host_ip 406 | get_host_ip 'RabbitMQ host IP address' rabbit_host_ip $cc_host_ip 407 | get_host_ip 'Glance host IP address' glance_host_ip $cc_host_ip 408 | get_host_ip 'MySQL host IP address' mysql_host_ip $cc_host_ip 409 | } 410 | 411 | # Prompt user for database root password...MySQL only for now, will update to 412 | # include others later 413 | get_database_creds() { 414 | local wording 415 | if [[ $component_type == cloud ]]; then 416 | wording='Desired' 417 | else 418 | wording="The Cloud Controller's" 419 | fi 420 | 421 | subsection_banner 'Database credentials' 422 | 423 | while true; do 424 | local mysql_pass2 425 | read -s -p "$wording MySQL root password: " mysql_pass 426 | echo 427 | read -s -p 'Verify MySQL root password: ' mysql_pass2 428 | echo 429 | 430 | if [[ $mysql_pass == $mysql_pass2 ]]; then 431 | if [[ -n $mysql_pass ]]; then 432 | break 433 | else 434 | echo -e "Password cannot be empty...try again\n" 435 | fi 436 | else 437 | echo -e "Passwords do not match...try again\n" 438 | fi 439 | done 440 | 441 | if [[ $component_type == cloud ]]; then 442 | set -o xtrace 443 | # preseed the password in preparation for package installation 444 | cat <<-MYSQL_PRESEED | debconf-set-selections 445 | mysql-server-5.1 mysql-server/root_password password $mysql_pass 446 | mysql-server-5.1 mysql-server/root_password_again password $mysql_pass 447 | mysql-server-5.1 mysql-server/start_on_boot boolean true 448 | MYSQL_PRESEED 449 | set +o xtrace 450 | fi 451 | } 452 | 453 | # Prompt user for the local machine's network interface settings 454 | get_bridge_info() { 455 | section_banner 'Local Network Settings' 456 | 457 | cat <<-EOF 458 | In order to set up the network bridge, we'll need some information on your 459 | local network interface configuration. The settings will default to the first 460 | known device as listed by 'ifconfig'. 461 | 462 | EOF 463 | 464 | get_host_ip "Enter this machine's IP address" bridge_address $local_address 465 | get_host_ip "Enter this machine's broadcast address" bridge_broadcast $local_broadcast 466 | get_host_ip "Enter this machine's netmask" bridge_netmask $local_netmask 467 | get_host_ip "Enter this machine's gateway" bridge_gateway $local_gateway 468 | get_host_ip "Enter this machine's DNS nameserver address" bridge_nameserver $local_nameserver 469 | } 470 | 471 | # Prompt user for desired project network configuration 472 | get_project_info() { 473 | section_banner 'Project Network Configuration' 474 | 475 | cat <<-EOF 476 | Here you will set the network range that ALL of your projects will reside in, 477 | and the number of IP addresses in that block that should be available for use. 478 | After that, you'll create a project administrator and a new project. 479 | 480 | EOF 481 | get_cidr_range 'Network range for ALL projects (normally x.x.x.x/12)' fixed_range 482 | get_integer 'Total amount of usable IPs for ALL projects' network_size 999999999 483 | 484 | subsection_banner 'New project creation' 485 | 486 | get_input 'User name for the project administrator' project_user 487 | get_input 'Name for the project' project_name 488 | echo 489 | get_cidr_range "Desired network range for the '$project_name' project (normally x.x.x.x/24)" project_cidr 490 | get_integer "How many networks for the '$project_name' project" project_network_count 999 491 | get_integer "How many available IPs per '$project_name' project network" project_ips_per_network 999999999 492 | } 493 | 494 | # We need the user to manually bypass the RabbitMQ installation splash screen 495 | bypass_rabbit_splash() { 496 | local package='rabbitmq-server' 497 | 498 | # skip if the package is already installed 499 | if ! is_installed $package; then 500 | cat <<-EOF 501 | 502 | ######## 503 | 504 | One last thing...there is currently no way to background/preeseed the 505 | RabbitMQ package's installation splash screen, so we'll need you to 506 | manually go through it. 507 | 508 | EOF 509 | read -s -n 1 -p 'Press any key to continue...' 510 | echo -e "\n" 511 | 512 | set -o xtrace 513 | apt-get install --quiet --assume-yes "$package" 514 | set +o xtrace 515 | fi 516 | } 517 | 518 | # Display auto-pilot notice 519 | show_auto_pilot() { 520 | section_banner 'ENTERING AUTO-PILOT MODE' 521 | 522 | cat <<-EOF 523 | At this point, you've entered all the information needed to finish the 524 | installation of this Nova component. Feel free to get some coffee, you have 525 | earned it! 526 | EOF 527 | sleep 4 528 | } 529 | 530 | # Install all required packages 531 | install_dependencies() { 532 | subsection_banner 'Installing packages' 533 | 534 | install_packages 'python-software-properties' 535 | echo -n "Adding '$PPA' repository ... " 536 | set -o xtrace 537 | add-apt-repository $PPA &>>$LOG_FILE 538 | apt-get update &>>$LOG_FILE 539 | set +o xtrace 540 | echo 'done' 541 | install_packages $required_packages 542 | } 543 | 544 | # Create nova.conf file, initialize the database, and generate user credentials 545 | setup_nova_config() { 546 | subsection_banner 'Setting up the Nova configuration file' 547 | 548 | echo -n 'Generating nova.conf ... ' 549 | if [[ $component_type == cloud ]]; then 550 | set -o xtrace 551 | cat >> /etc/nova/nova.conf <<-EOF 552 | --s3_host=$s3_host_ip 553 | --rabbit_host=$rabbit_host_ip 554 | --cc_host=$cc_host_ip 555 | --ec2_host=$s3_host_ip 556 | --osapi_host=$s3_host_ip 557 | --fixed_range=$fixed_range 558 | --network_size=$network_size 559 | --FAKE_subdomain=ec2 560 | --routing_source_ip=$cc_host_ip 561 | --verbose 562 | --sql_connection=mysql://root:$mysql_pass@$mysql_host_ip/nova 563 | --network_manager=nova.network.manager.FlatDHCPManager 564 | --glance_api_servers=$glance_host_ip:9292 565 | --image_service=nova.image.glance.GlanceImageService 566 | 567 | EOF 568 | sed -i 's/^\(ql_connection\s*=\s*\).*$/\1mysql:\/\/root:'$mysql_pass'@127\.0\.0\.1\/glance/' /etc/glance/glance-registry.conf 569 | sed -i 's/^\(ql_connection\s*=\s*\).*$/\1mysql:\/\/root:'$mysql_pass'@127\.0\.0\.1\/glance/' /etc/glance/glance-scrubber.conf 570 | set +o xtrace 571 | else 572 | set -o xtrace 573 | cat >> /etc/nova/nova.conf <<-EOF 574 | --s3_host=$s3_host_ip 575 | --rabbit_host=$rabbit_host_ip 576 | --cc_host=$cc_host_ip 577 | --ec2_host=$s3_host_ip 578 | --osapi_host=$s3_host_ip 579 | --sql_connection=mysql://root:$mysql_pass@$mysql_host_ip/nova 580 | --network_manager=nova.network.manager.FlatDHCPManager 581 | --glance_api_servers=$glance_host_ip:9292 582 | --image_service=nova.image.glance.GlanceImageService 583 | 584 | EOF 585 | set +o xtrace 586 | fi 587 | echo 'done' 588 | 589 | echo -n 'Setting proper permissions for nova.conf ... ' 590 | if ! grep -q '^nova' /etc/group; then 591 | set -o xtrace 592 | groupadd nova &>>$LOG_FILE 593 | set +o xtrace 594 | fi 595 | if ! groups nova | grep -q ' nova'; then 596 | set -o xtrace 597 | usermod -a -G nova nova &>>$LOG_FILE 598 | set +o xtrace 599 | fi 600 | set -o xtrace 601 | chown -R root:nova /etc/nova &>>$LOG_FILE 602 | chmod 640 /etc/nova/nova.conf &>>$LOG_FILE 603 | set +o xtrace 604 | echo 'done' 605 | } 606 | 607 | # Create a new database and initialize it with the project information 608 | finalize_database() { 609 | local mysql_config='/etc/mysql/my.cnf' 610 | 611 | subsection_banner 'Finalizing MySQL setup' 612 | 613 | echo -n 'Adjusting MySQL network configuration ... ' 614 | set -o xtrace 615 | # back up original my.cnf file 616 | [[ ! -f $mysql_config.bak ]] && cp $mysql_config{,.bak} 617 | sed -i 's/127.0.0.1/0.0.0.0/g' $mysql_config 618 | service mysql restart &>>$LOG_FILE 619 | set +o xtrace 620 | echo 'done' 621 | 622 | echo -n 'Creating database ... ' 623 | set -o xtrace 624 | mysql --user='root' --password="$mysql_pass" --execute "CREATE DATABASE nova;" 625 | mysql --user='root' --password="$mysql_pass" --execute "CREATE DATABASE glance;" 626 | mysql --user='root' --password="$mysql_pass" --execute "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;" 627 | mysql --user='root' --password="$mysql_pass" --execute "SET PASSWORD FOR 'root'@'%' = PASSWORD('$mysql_pass');" 628 | set +o xtrace 629 | echo 'done' 630 | 631 | echo -n 'Initializing database ... ' 632 | set -o xtrace 633 | nova-manage db sync &>>$LOG_FILE 634 | sleep 1 635 | /usr/bin/python /usr/bin/nova-manage user admin $project_user &>>$LOG_FILE 636 | /usr/bin/python /usr/bin/nova-manage project create $project_name $project_user &>>$LOG_FILE 637 | /usr/bin/python /usr/bin/nova-manage network create public $project_cidr $project_network_count $project_ips_per_network --bridge=br100 &>>$LOG_FILE 638 | set +o xtrace 639 | echo 'done' 640 | } 641 | 642 | # Generate user credentials and environment settings 643 | generate_credentials() { 644 | local novacreds="${CREDS_DIR}/novacreds.zip" 645 | local novarc="${CREDS_DIR}/novarc" 646 | 647 | subsection_banner 'Generate Nova user credentials' 648 | 649 | echo -n 'Generating and extracting novacreds.zip ... ' 650 | mkdir -p $CREDS_DIR 651 | set -o xtrace 652 | /usr/bin/python /usr/bin/nova-manage project zipfile $project_name $project_user $novacreds &>>$LOG_FILE 653 | sleep 3 654 | unzip -d $CREDS_DIR $novacreds &>>$LOG_FILE 655 | set +o xtrace 656 | echo 'done' 657 | 658 | echo -n 'Appending novarc environment settings to your ~/.bashrc ... ' 659 | set -o xtrace 660 | source $novarc 661 | echo -e '\n# OpenStack Nova Credentials' >> $HOME/.bashrc 662 | cat $novarc >> $HOME/.bashrc 663 | # back up original novarc file 664 | [[ ! -f $novarc.bak ]] && cp $novarc{,.bak} 665 | sed -i "s/127.0.0.1/$cc_host_ip/g" $novarc 666 | set +o xtrace 667 | echo 'done' 668 | } 669 | 670 | # Use a bridged network interface and adjust firewall if necessary 671 | configure_network() { 672 | subsection_banner 'Updating network interfaces' 673 | 674 | echo -n 'Adding bridge device ... ' 675 | set -o xtrace 676 | # back up original interfaces file 677 | [[ ! -f /etc/network/interaces.bak ]] && cp /etc/network/interfaces{,.bak} 678 | 679 | cat > /etc/network/interfaces << EOF 680 | # The loopback network interface 681 | auto lo 682 | iface lo inet loopback 683 | 684 | auto br100 685 | iface br100 inet static 686 | bridge_ports eth0 687 | bridge_stp off 688 | bridge_maxwait 0 689 | bridge_fd 0 690 | address $bridge_address 691 | netmask $bridge_netmask 692 | broadcast $bridge_broadcast 693 | gateway $bridge_gateway 694 | dns-nameservers $bridge_nameserver 695 | EOF 696 | set +o xtrace 697 | echo 'done' 698 | 699 | echo -n 'Restarting networking service ... ' 700 | set -o xtrace 701 | /etc/init.d/networking restart &>>$LOG_FILE 702 | set +o xtrace 703 | echo 'done' 704 | 705 | # any server that does /NOT/ have nova-api running on it will need this 706 | # firewall rule for UEC images to be able to fetch metadata info 707 | if [[ $component_type != cloud ]]; then 708 | echo -n 'Allowing image metadata traffic ... ' 709 | set -o xtrace 710 | iptables -t nat -A PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination $cc_host_ip:8773 711 | set +o xtrace 712 | echo 'done' 713 | fi 714 | } 715 | 716 | # Start bring services back up with the new configurations 717 | restart_services() { 718 | subsection_banner 'Bringing your Nova node online' 719 | 720 | echo -n 'Restarting Nova and Glance services ... ' 721 | if [[ $component_type == cloud ]]; then 722 | set -o xtrace 723 | source ${CREDS_DIR}/novarc 724 | restart libvirt-bin &>>$LOG_FILE 725 | restart nova-network &>>$LOG_FILE 726 | restart nova-compute &>>$LOG_FILE 727 | restart nova-api &>>$LOG_FILE 728 | restart nova-objectstore &>>$LOG_FILE 729 | restart nova-scheduler &>>$LOG_FILE 730 | restart glance-api &>>$LOG_FILE 731 | restart glance-registry &>>$LOG_FILE 732 | set +o xtrace 733 | else 734 | set -o xtrace 735 | restart libvirt-bin &>>$LOG_FILE 736 | restart nova-compute &>>$LOG_FILE 737 | set +o xtrace 738 | fi 739 | sleep 4 740 | echo 'done' 741 | 742 | if [[ $component_type == cloud ]]; then 743 | echo -e 'Ensure all five Nova services and Glance services are running:\n' 744 | else 745 | echo -e 'Ensure the Nova compute service is running:\n' 746 | fi 747 | 748 | set -o xtrace 749 | ps -ef c --sort=cmd | egrep 'PID|nova-[acnos]|glance-[ar]' 750 | set +o xtrace 751 | sleep 2 752 | } 753 | 754 | # Ensure proper initialization of KVM if it's available; 755 | # otherwise VMs run in the much slower QEMU mode 756 | fix_kvm_permissions() { 757 | if [[ -f /dev/kvm ]]; then 758 | set -o xtrace 759 | chgrp kvm /dev/kvm 760 | chmod g+rwx /dev/kvm 761 | set +o xtrace 762 | fi 763 | } 764 | 765 | # Authorize ICMP and SSH traffic between VMs by default 766 | allow_ping_and_ssh() { 767 | echo -n -e "\nAllowing ICMP and SSH access to all VMs ... " 768 | set -o xtrace 769 | euca-authorize -P icmp -t -1:-1 default &>>$LOG_FILE 770 | euca-authorize -P tcp -p 22 default &>>$LOG_FILE 771 | set +o xtrace 772 | echo 'done' 773 | } 774 | 775 | # Only one dnsmasq process starts, supposed to be two running at different 776 | # priorities. This fixes that...possible bug? 777 | fix_dnsmasq_bug() { 778 | set -o xtrace 779 | killall dnsmasq 780 | service nova-network restart &>>$LOG_FILE 781 | set +o xtrace 782 | } 783 | 784 | # Display closing message after a successful installation 785 | show_closing() { 786 | if [[ $component_type == cloud ]]; then 787 | cat <<-EOF 788 | 789 | 790 | ######################################################################## 791 | # You /MUST/ re-source your 'novarc' to use the API commands since the # 792 | # script cannot pass the source information out of its own process... # 793 | # the variables have been appended to your ~/.bashrc file for sourcing # 794 | ######################################################################## 795 | 796 | For reference, the generated credentials can be found in ${CREDS_DIR}/ 797 | 798 | 799 | The next thing you are going to want to do it get a VM to test with. 800 | You can find a test VM how-to and read about custom image creation here: 801 | 802 | http://nova.openstack.org/adminguide/multi.node.install.html 803 | http://wiki.openstack.org/GettingImages 804 | 805 | Enjoy your new private cloud! 806 | 807 | EOF 808 | else 809 | cat <<-EOF 810 | 811 | 812 | ######## 813 | 814 | That's it, your new Nova Compute Node is up and running! 815 | 816 | EOF 817 | fi 818 | } 819 | 820 | 821 | ##### Main 822 | 823 | # Default options 824 | component_type='cloud' # which nova component to install 825 | 826 | # Read command-line arguments 827 | while [[ $1 == -* ]]; do 828 | case "$1" in 829 | -t|--type) 830 | if (( $# > 1 )); then 831 | if is_supported_component "$2"; then 832 | component_type="$2" 833 | shift 2 834 | else 835 | echo "Unsupported component type: $2" 1>&2 836 | show_help 837 | exit $EX_USAGE 838 | fi 839 | else 840 | echo "The $1 option requires an argument: " 1>&2 841 | show_help 842 | exit $EX_USAGE 843 | fi 844 | ;; 845 | -h|--help|-\?) 846 | show_help 847 | exit $EX_OK 848 | ;; 849 | -V|--version) 850 | echo "$BASENAME $VERSION" 851 | exit $EX_OK 852 | ;; 853 | -*) 854 | echo "Invalid option: $1" 1>&2 855 | show_help 856 | exit $EX_USAGE 857 | ;; 858 | esac 859 | done 860 | 861 | # Saftey measures to fail early before problems snowball 862 | set -o errexit # exit if any command in this script has a non-zero status code 863 | set -o nounset # exit if an uninitialized variable is accidentally used 864 | 865 | check_safety 866 | initialize_dependencies 867 | initialize_network_variables 868 | start_log 869 | 870 | # Log xtrace to the log file when enabled 871 | exec 3>>$LOG_FILE 872 | BASH_XTRACEFD=3 873 | 874 | # User interaction required 875 | 876 | show_intro 877 | get_service_hosts 878 | get_database_creds 879 | get_bridge_info 880 | if [[ $component_type == cloud ]]; then 881 | get_project_info 882 | bypass_rabbit_splash 883 | fi 884 | 885 | # Automated steps 886 | 887 | show_auto_pilot 888 | install_dependencies 889 | setup_nova_config 890 | if [[ $component_type == cloud ]]; then 891 | finalize_database 892 | generate_credentials 893 | fi 894 | configure_network 895 | restart_services 896 | if [[ $component_type == cloud ]]; then 897 | allow_ping_and_ssh 898 | fix_dnsmasq_bug 899 | fi 900 | fix_kvm_permissions 901 | show_closing 902 | 903 | finalize_log 'installation process complete' 904 | 905 | exit $EX_OK 906 | --------------------------------------------------------------------------------