-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathubuntu-openstack-final.sh
More file actions
1620 lines (1309 loc) · 54.2 KB
/
ubuntu-openstack-final.sh
File metadata and controls
1620 lines (1309 loc) · 54.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
#############################################################
# Final OpenStack All-in-One Installation Script for Ubuntu 24.04 LTS
# OpenStack Release: 2024.2 (Dalmatian)
#
# This script incorporates all fixes and lessons learned
# Components: Keystone, Glance, Placement, Nova, Neutron,
# Horizon, Cinder
#
# Requirements:
# - Ubuntu 24.04 LTS (fresh installation)
# - Minimum 8GB RAM (16GB recommended)
# - Minimum 50GB disk space
# - 2 Network interfaces:
# - Management interface with static IP
# - Provider interface with NO IP configured
#
# Author: Carmine Bufano
# Date: November 2024
#############################################################
set -e
# Set non-interactive mode to avoid debconf warnings
export DEBIAN_FRONTEND=noninteractive
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
# Configuration variables
CONTROLLER_IP=""
PROVIDER_INTERFACE=""
ADMIN_PASS="Admin123!"
DEMO_PASS="Demo123!"
DB_PASS="DBPass123!"
RABBIT_PASS="Rabbit123!"
SERVICE_PASS="Service123!"
METADATA_SECRET=$(openssl rand -hex 10)
# State file to track installation progress
STATE_FILE="/root/.openstack_install_state"
CONFIG_FILE="/root/.openstack_config"
# Initialize state file if it doesn't exist
if [ ! -f "$STATE_FILE" ]; then
touch "$STATE_FILE"
fi
# Function to check if a step has been completed
is_completed() {
grep -q "^$1$" "$STATE_FILE" 2>/dev/null
}
# Function to mark a step as completed
mark_completed() {
if ! is_completed "$1"; then
echo "$1" >> "$STATE_FILE"
fi
}
# Pre-flight checks
pre_flight_checks() {
log "Running pre-flight checks..."
# Check Ubuntu version
if ! grep -q "Ubuntu 24.04" /etc/os-release; then
warning "This script is designed for Ubuntu 24.04 LTS"
read -p "Continue anyway? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# Check available memory
TOTAL_MEM=$(free -g | awk '/^Mem:/{print $2}')
if [ "$TOTAL_MEM" -lt 8 ]; then
warning "System has less than 8GB RAM. OpenStack may not run properly."
fi
# Check disk space
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
if [ "$AVAILABLE_SPACE" -lt 50 ]; then
warning "Less than 50GB disk space available. This might not be enough."
fi
info "Pre-flight checks completed"
}
# Function to get user input
get_config() {
if is_completed "config_saved"; then
log "Loading saved configuration..."
source "$CONFIG_FILE"
return
fi
echo "=== OpenStack All-in-One Configuration ==="
echo ""
info "Network Requirements:"
echo "1. Management interface: Should have a static IP configured"
echo "2. Provider interface: Should have NO IP address configured"
echo ""
# Show current network configuration
echo "Current network interfaces:"
ip -br addr show | grep -v lo
echo ""
# Get management IP
while true; do
read -p "Enter the management IP address (e.g., 10.0.0.11): " CONTROLLER_IP
if [[ $CONTROLLER_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
# Verify the IP exists on the system
if ip addr show | grep -q "$CONTROLLER_IP"; then
break
else
error "IP address $CONTROLLER_IP not found on any interface"
fi
else
error "Invalid IP address format"
fi
done
# Get provider interface
echo ""
echo "Available network interfaces:"
ip -o link show | awk -F': ' '{print $2}' | grep -v lo
echo ""
while true; do
read -p "Enter the provider network interface name (e.g., eth1, ens34): " PROVIDER_INTERFACE
if ip link show "$PROVIDER_INTERFACE" >/dev/null 2>&1; then
# Check if interface has an IP
if ip addr show "$PROVIDER_INTERFACE" | grep -q "inet "; then
warning "Interface $PROVIDER_INTERFACE has an IP address configured."
echo "The provider interface should NOT have an IP address."
read -p "Continue anyway? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
break
fi
else
break
fi
else
error "Interface $PROVIDER_INTERFACE not found"
fi
done
# Save configuration
cat > "$CONFIG_FILE" << EOF
CONTROLLER_IP="$CONTROLLER_IP"
PROVIDER_INTERFACE="$PROVIDER_INTERFACE"
ADMIN_PASS="$ADMIN_PASS"
DEMO_PASS="$DEMO_PASS"
DB_PASS="$DB_PASS"
RABBIT_PASS="$RABBIT_PASS"
SERVICE_PASS="$SERVICE_PASS"
METADATA_SECRET="$METADATA_SECRET"
EOF
chmod 600 "$CONFIG_FILE"
mark_completed "config_saved"
# Confirm settings
echo ""
echo "=== Configuration Summary ==="
echo "Management IP: $CONTROLLER_IP"
echo "Provider Interface: $PROVIDER_INTERFACE"
echo "Admin Password: $ADMIN_PASS"
echo "============================"
echo ""
read -p "Continue with these settings? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
rm -f "$CONFIG_FILE"
rm -f "$STATE_FILE"
exit 1
fi
}
# Update system
update_system() {
if is_completed "system_updated"; then
log "System already updated, skipping..."
return
fi
log "Updating system packages..."
apt update
apt upgrade -y
apt dist-upgrade -y
mark_completed "system_updated"
}
# Install basic utilities
install_utilities() {
if is_completed "utilities_installed"; then
log "Utilities already installed, skipping..."
return
fi
log "Installing basic utilities..."
apt install -y software-properties-common curl wget git vim htop net-tools lsof
apt install -y python3-pip python3-dev build-essential
apt install -y crudini jq
mark_completed "utilities_installed"
}
# MySQL command wrapper with error handling
mysql_cmd() {
if mysql -u root -p"$DB_PASS" -e "SELECT 1" >/dev/null 2>&1; then
mysql -u root -p"$DB_PASS" -e "$1" 2>/dev/null || true
else
mysql -e "$1" 2>/dev/null || true
fi
}
# Configure networking
configure_networking() {
if is_completed "networking_configured"; then
log "Networking already configured, skipping..."
return
fi
log "Configuring networking..."
# Set hostname
hostnamectl set-hostname controller
# Configure /etc/hosts
cat > /etc/hosts << EOF
127.0.0.1 localhost
$CONTROLLER_IP controller
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
# IMPORTANT: Do NOT modify network configuration here
# The provider interface should already be configured by the user
info "Using existing network configuration"
info "Management interface IP: $CONTROLLER_IP"
info "Provider interface: $PROVIDER_INTERFACE (should have no IP)"
mark_completed "networking_configured"
}
# Install and configure NTP
configure_ntp() {
if is_completed "ntp_configured"; then
log "NTP already configured, skipping..."
return
fi
log "Installing and configuring NTP (chrony)..."
apt install -y chrony
# Configure chrony
cp /etc/chrony/chrony.conf /etc/chrony/chrony.conf.backup
# Use Google's time servers
sed -i '/^pool/d' /etc/chrony/chrony.conf
sed -i '/^server/d' /etc/chrony/chrony.conf
cat >> /etc/chrony/chrony.conf << EOF
# Google Public NTP
server time.google.com iburst
server time2.google.com iburst
server time3.google.com iburst
server time4.google.com iburst
# Allow NTP client access from local network
allow 10.0.0.0/8
allow 192.168.0.0/16
allow 172.16.0.0/12
EOF
systemctl restart chrony
systemctl enable chrony
# Wait for time sync
sleep 5
chronyc sources
mark_completed "ntp_configured"
}
# Install and configure MariaDB
configure_mariadb() {
if is_completed "mariadb_configured"; then
log "MariaDB already configured, skipping..."
return
fi
log "Installing and configuring MariaDB..."
apt install -y mariadb-server python3-pymysql
# Create OpenStack database configuration
cat > /etc/mysql/mariadb.conf.d/99-openstack.cnf << EOF
[mysqld]
bind-address = $CONTROLLER_IP
default-storage-engine = innodb
innodb_file_per_table = on
max_connections = 4096
collation-server = utf8_general_ci
character-set-server = utf8
EOF
systemctl restart mysql
# Secure MariaDB installation
if ! mysql -u root -p"$DB_PASS" -e "SELECT 1" >/dev/null 2>&1; then
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$DB_PASS';"
fi
mysql_cmd "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
mysql_cmd "DELETE FROM mysql.user WHERE User='';"
mysql_cmd "DROP DATABASE IF EXISTS test;"
mysql_cmd "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
mysql_cmd "FLUSH PRIVILEGES;"
mark_completed "mariadb_configured"
}
# Install and configure RabbitMQ
configure_rabbitmq() {
if is_completed "rabbitmq_configured"; then
log "RabbitMQ already configured, skipping..."
return
fi
log "Installing and configuring RabbitMQ..."
apt install -y rabbitmq-server
systemctl enable rabbitmq-server
systemctl start rabbitmq-server
# Check if user already exists
if ! rabbitmqctl list_users | grep -q openstack; then
rabbitmqctl add_user openstack "$RABBIT_PASS"
rabbitmqctl set_permissions openstack ".*" ".*" ".*"
fi
mark_completed "rabbitmq_configured"
}
# Install and configure Memcached
configure_memcached() {
if is_completed "memcached_configured"; then
log "Memcached already configured, skipping..."
return
fi
log "Installing and configuring Memcached..."
apt install -y memcached python3-memcache
# Configure memcached to listen on controller IP
cp /etc/memcached.conf /etc/memcached.conf.backup
sed -i "s/^-l.*/-l 127.0.0.1,$CONTROLLER_IP/g" /etc/memcached.conf
systemctl restart memcached
systemctl enable memcached
mark_completed "memcached_configured"
}
# Install and configure Etcd
configure_etcd() {
if is_completed "etcd_configured"; then
log "Etcd already configured, skipping..."
return
fi
log "Installing and configuring Etcd..."
apt install -y etcd-server etcd-client
cat > /etc/default/etcd << EOF
ETCD_NAME="controller"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-01"
ETCD_INITIAL_CLUSTER="controller=http://$CONTROLLER_IP:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://$CONTROLLER_IP:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://$CONTROLLER_IP:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://$CONTROLLER_IP:2379,http://127.0.0.1:2379"
EOF
systemctl enable etcd
systemctl restart etcd
mark_completed "etcd_configured"
}
# Enable OpenStack repository
enable_openstack_repo() {
if is_completed "openstack_repo_enabled"; then
log "OpenStack repository already enabled, skipping..."
return
fi
log "Enabling OpenStack repository..."
add-apt-repository -y cloud-archive:dalmatian
apt update
mark_completed "openstack_repo_enabled"
}
# Install OpenStack client
install_openstack_client() {
if is_completed "openstack_client_installed"; then
log "OpenStack client already installed, skipping..."
return
fi
log "Installing OpenStack client..."
apt install -y python3-openstackclient
mark_completed "openstack_client_installed"
}
# Install and configure Keystone
configure_keystone() {
if is_completed "keystone_configured"; then
log "Keystone already configured, skipping..."
return
fi
log "Installing and configuring Keystone (Identity service)..."
# Create database
mysql_cmd "CREATE DATABASE IF NOT EXISTS keystone;"
mysql_cmd "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "FLUSH PRIVILEGES;"
# Install packages
apt install -y keystone apache2 libapache2-mod-wsgi-py3
# Configure Keystone
cp /etc/keystone/keystone.conf /etc/keystone/keystone.conf.backup
crudini --set /etc/keystone/keystone.conf database connection "mysql+pymysql://keystone:$SERVICE_PASS@controller/keystone"
crudini --set /etc/keystone/keystone.conf token provider fernet
# Populate database
su -s /bin/sh -c "keystone-manage db_sync" keystone
# Initialize Fernet key repositories
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
# Bootstrap the Identity service
keystone-manage bootstrap --bootstrap-password "$ADMIN_PASS" \
--bootstrap-admin-url "http://controller:5000/v3/" \
--bootstrap-internal-url "http://controller:5000/v3/" \
--bootstrap-public-url "http://controller:5000/v3/" \
--bootstrap-region-id RegionOne
# Configure Apache
if ! grep -q "ServerName controller" /etc/apache2/apache2.conf; then
echo "ServerName controller" >> /etc/apache2/apache2.conf
fi
systemctl restart apache2
systemctl enable apache2
mark_completed "keystone_configured"
}
# Create OpenStack environment scripts
create_env_scripts() {
if is_completed "env_scripts_created"; then
log "Environment scripts already created, skipping..."
return
fi
log "Creating environment scripts..."
# Admin credentials
cat > /root/admin-openrc << EOF
export OS_USERNAME=admin
export OS_PASSWORD=$ADMIN_PASS
export OS_PROJECT_NAME=admin
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
EOF
# Demo credentials
cat > /root/demo-openrc << EOF
export OS_USERNAME=demo
export OS_PASSWORD=$DEMO_PASS
export OS_PROJECT_NAME=myproject
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
EOF
chmod 600 /root/admin-openrc
chmod 600 /root/demo-openrc
mark_completed "env_scripts_created"
}
# Create initial projects and users
create_projects_users() {
if is_completed "projects_users_created"; then
log "Projects and users already created, skipping..."
return
fi
log "Creating initial projects and users..."
source /root/admin-openrc
# Create service project
if ! openstack project show service >/dev/null 2>&1; then
openstack project create --domain default --description "Service Project" service
fi
# Create demo project
if ! openstack project show myproject >/dev/null 2>&1; then
openstack project create --domain default --description "Demo Project" myproject
fi
# Create demo user
if ! openstack user show demo >/dev/null 2>&1; then
openstack user create --domain default --password "$DEMO_PASS" demo
fi
# Create user role
if ! openstack role show user >/dev/null 2>&1; then
openstack role create user
fi
# Add user role to demo user
openstack role add --project myproject --user demo user 2>/dev/null || true
mark_completed "projects_users_created"
}
# Install and configure Glance
configure_glance() {
if is_completed "glance_configured"; then
log "Glance already configured, skipping..."
return
fi
log "Installing and configuring Glance (Image service)..."
source /root/admin-openrc
# Create database
mysql_cmd "CREATE DATABASE IF NOT EXISTS glance;"
mysql_cmd "GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "FLUSH PRIVILEGES;"
# Create user and service
if ! openstack user show glance >/dev/null 2>&1; then
openstack user create --domain default --password "$SERVICE_PASS" glance
openstack role add --project service --user glance admin
fi
if ! openstack service show glance >/dev/null 2>&1; then
openstack service create --name glance --description "OpenStack Image" image
fi
# Create endpoints
if ! openstack endpoint list --service image | grep -q public; then
openstack endpoint create --region RegionOne image public http://controller:9292
openstack endpoint create --region RegionOne image internal http://controller:9292
openstack endpoint create --region RegionOne image admin http://controller:9292
fi
# Install packages
apt install -y glance
# Configure Glance
cp /etc/glance/glance-api.conf /etc/glance/glance-api.conf.backup
crudini --set /etc/glance/glance-api.conf database connection "mysql+pymysql://glance:$SERVICE_PASS@controller/glance"
crudini --set /etc/glance/glance-api.conf keystone_authtoken www_authenticate_uri http://controller:5000
crudini --set /etc/glance/glance-api.conf keystone_authtoken auth_url http://controller:5000
crudini --set /etc/glance/glance-api.conf keystone_authtoken memcached_servers controller:11211
crudini --set /etc/glance/glance-api.conf keystone_authtoken auth_type password
crudini --set /etc/glance/glance-api.conf keystone_authtoken project_domain_name Default
crudini --set /etc/glance/glance-api.conf keystone_authtoken user_domain_name Default
crudini --set /etc/glance/glance-api.conf keystone_authtoken project_name service
crudini --set /etc/glance/glance-api.conf keystone_authtoken username glance
crudini --set /etc/glance/glance-api.conf keystone_authtoken password "$SERVICE_PASS"
crudini --set /etc/glance/glance-api.conf paste_deploy flavor keystone
crudini --set /etc/glance/glance-api.conf glance_store stores file,http
crudini --set /etc/glance/glance-api.conf glance_store default_store file
crudini --set /etc/glance/glance-api.conf glance_store filesystem_store_datadir /var/lib/glance/images/
# Populate database
su -s /bin/sh -c "glance-manage db_sync" glance
# Start services
systemctl restart glance-api
systemctl enable glance-api
mark_completed "glance_configured"
}
# Install and configure Placement
configure_placement() {
if is_completed "placement_configured"; then
log "Placement already configured, skipping..."
return
fi
log "Installing and configuring Placement service..."
source /root/admin-openrc
# Create database
mysql_cmd "CREATE DATABASE IF NOT EXISTS placement;"
mysql_cmd "GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "FLUSH PRIVILEGES;"
# Create user and service
if ! openstack user show placement >/dev/null 2>&1; then
openstack user create --domain default --password "$SERVICE_PASS" placement
openstack role add --project service --user placement admin
fi
if ! openstack service show placement >/dev/null 2>&1; then
openstack service create --name placement --description "Placement API" placement
fi
# Create endpoints
if ! openstack endpoint list --service placement | grep -q public; then
openstack endpoint create --region RegionOne placement public http://controller:8778
openstack endpoint create --region RegionOne placement internal http://controller:8778
openstack endpoint create --region RegionOne placement admin http://controller:8778
fi
# Install packages
apt install -y placement-api
# Configure Placement
cp /etc/placement/placement.conf /etc/placement/placement.conf.backup
crudini --set /etc/placement/placement.conf placement_database connection "mysql+pymysql://placement:$SERVICE_PASS@controller/placement"
crudini --set /etc/placement/placement.conf api auth_strategy keystone
crudini --set /etc/placement/placement.conf keystone_authtoken auth_url http://controller:5000/v3
crudini --set /etc/placement/placement.conf keystone_authtoken memcached_servers controller:11211
crudini --set /etc/placement/placement.conf keystone_authtoken auth_type password
crudini --set /etc/placement/placement.conf keystone_authtoken project_domain_name Default
crudini --set /etc/placement/placement.conf keystone_authtoken user_domain_name Default
crudini --set /etc/placement/placement.conf keystone_authtoken project_name service
crudini --set /etc/placement/placement.conf keystone_authtoken username placement
crudini --set /etc/placement/placement.conf keystone_authtoken password "$SERVICE_PASS"
# Populate database
su -s /bin/sh -c "placement-manage db sync" placement
# Restart Apache
systemctl restart apache2
mark_completed "placement_configured"
}
# Install and configure Nova
configure_nova() {
if is_completed "nova_configured"; then
log "Nova already configured, skipping..."
return
fi
log "Installing and configuring Nova (Compute service)..."
source /root/admin-openrc
# Create databases
mysql_cmd "CREATE DATABASE IF NOT EXISTS nova_api;"
mysql_cmd "CREATE DATABASE IF NOT EXISTS nova;"
mysql_cmd "CREATE DATABASE IF NOT EXISTS nova_cell0;"
mysql_cmd "GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "FLUSH PRIVILEGES;"
# Create user and service
if ! openstack user show nova >/dev/null 2>&1; then
openstack user create --domain default --password "$SERVICE_PASS" nova
openstack role add --project service --user nova admin
fi
if ! openstack service show nova >/dev/null 2>&1; then
openstack service create --name nova --description "OpenStack Compute" compute
fi
# Create endpoints
if ! openstack endpoint list --service compute | grep -q public; then
openstack endpoint create --region RegionOne compute public http://controller:8774/v2.1
openstack endpoint create --region RegionOne compute internal http://controller:8774/v2.1
openstack endpoint create --region RegionOne compute admin http://controller:8774/v2.1
fi
# Install packages
apt install -y nova-api nova-conductor nova-novncproxy nova-scheduler nova-compute
# Configure Nova
cp /etc/nova/nova.conf /etc/nova/nova.conf.backup
crudini --set /etc/nova/nova.conf api_database connection "mysql+pymysql://nova:$SERVICE_PASS@controller/nova_api"
crudini --set /etc/nova/nova.conf database connection "mysql+pymysql://nova:$SERVICE_PASS@controller/nova"
crudini --set /etc/nova/nova.conf DEFAULT transport_url "rabbit://openstack:$RABBIT_PASS@controller:5672/"
crudini --set /etc/nova/nova.conf DEFAULT my_ip "$CONTROLLER_IP"
crudini --set /etc/nova/nova.conf api auth_strategy keystone
crudini --set /etc/nova/nova.conf keystone_authtoken www_authenticate_uri http://controller:5000/
crudini --set /etc/nova/nova.conf keystone_authtoken auth_url http://controller:5000/
crudini --set /etc/nova/nova.conf keystone_authtoken memcached_servers controller:11211
crudini --set /etc/nova/nova.conf keystone_authtoken auth_type password
crudini --set /etc/nova/nova.conf keystone_authtoken project_domain_name Default
crudini --set /etc/nova/nova.conf keystone_authtoken user_domain_name Default
crudini --set /etc/nova/nova.conf keystone_authtoken project_name service
crudini --set /etc/nova/nova.conf keystone_authtoken username nova
crudini --set /etc/nova/nova.conf keystone_authtoken password "$SERVICE_PASS"
crudini --set /etc/nova/nova.conf service_user send_service_user_token true
crudini --set /etc/nova/nova.conf service_user auth_url http://controller:5000/
crudini --set /etc/nova/nova.conf service_user auth_strategy keystone
crudini --set /etc/nova/nova.conf service_user auth_type password
crudini --set /etc/nova/nova.conf service_user project_domain_name Default
crudini --set /etc/nova/nova.conf service_user user_domain_name Default
crudini --set /etc/nova/nova.conf service_user project_name service
crudini --set /etc/nova/nova.conf service_user username nova
crudini --set /etc/nova/nova.conf service_user password "$SERVICE_PASS"
crudini --set /etc/nova/nova.conf vnc enabled true
crudini --set /etc/nova/nova.conf vnc server_listen '$my_ip'
crudini --set /etc/nova/nova.conf vnc server_proxyclient_address '$my_ip'
crudini --set /etc/nova/nova.conf glance api_servers http://controller:9292
crudini --set /etc/nova/nova.conf oslo_concurrency lock_path /var/lib/nova/tmp
crudini --set /etc/nova/nova.conf placement region_name RegionOne
crudini --set /etc/nova/nova.conf placement project_domain_name Default
crudini --set /etc/nova/nova.conf placement project_name service
crudini --set /etc/nova/nova.conf placement auth_type password
crudini --set /etc/nova/nova.conf placement user_domain_name Default
crudini --set /etc/nova/nova.conf placement auth_url http://controller:5000/v3
crudini --set /etc/nova/nova.conf placement username placement
crudini --set /etc/nova/nova.conf placement password "$SERVICE_PASS"
# Configure compute for QEMU/KVM
crudini --set /etc/nova/nova-compute.conf libvirt virt_type qemu
# Populate databases
su -s /bin/sh -c "nova-manage api_db sync" nova
su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova 2>/dev/null || true
su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova 2>/dev/null || true
su -s /bin/sh -c "nova-manage db sync" nova
# Verify cell registration
su -s /bin/sh -c "nova-manage cell_v2 list_cells" nova
# Start services
systemctl restart nova-api nova-scheduler nova-conductor nova-novncproxy nova-compute
systemctl enable nova-api nova-scheduler nova-conductor nova-novncproxy nova-compute
mark_completed "nova_configured"
}
# Install and configure Neutron
configure_neutron() {
if is_completed "neutron_configured"; then
log "Neutron already configured, skipping..."
return
fi
log "Installing and configuring Neutron (Networking service)..."
source /root/admin-openrc
# Create database
mysql_cmd "CREATE DATABASE IF NOT EXISTS neutron;"
mysql_cmd "GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'localhost' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' IDENTIFIED BY '$SERVICE_PASS';"
mysql_cmd "FLUSH PRIVILEGES;"
# Create user and service
if ! openstack user show neutron >/dev/null 2>&1; then
openstack user create --domain default --password "$SERVICE_PASS" neutron
openstack role add --project service --user neutron admin
fi
if ! openstack service show neutron >/dev/null 2>&1; then
openstack service create --name neutron --description "OpenStack Networking" network
fi
# Create endpoints
if ! openstack endpoint list --service network | grep -q public; then
openstack endpoint create --region RegionOne network public http://controller:9696
openstack endpoint create --region RegionOne network internal http://controller:9696
openstack endpoint create --region RegionOne network admin http://controller:9696
fi
# Install packages
apt install -y neutron-server neutron-plugin-ml2 \
neutron-openvswitch-agent neutron-l3-agent neutron-dhcp-agent \
neutron-metadata-agent
# Configure Neutron
cp /etc/neutron/neutron.conf /etc/neutron/neutron.conf.backup
crudini --set /etc/neutron/neutron.conf database connection "mysql+pymysql://neutron:$SERVICE_PASS@controller/neutron"
crudini --set /etc/neutron/neutron.conf DEFAULT core_plugin ml2
crudini --set /etc/neutron/neutron.conf DEFAULT service_plugins router
crudini --set /etc/neutron/neutron.conf DEFAULT transport_url "rabbit://openstack:$RABBIT_PASS@controller"
crudini --set /etc/neutron/neutron.conf DEFAULT auth_strategy keystone
crudini --set /etc/neutron/neutron.conf DEFAULT notify_nova_on_port_status_changes true
crudini --set /etc/neutron/neutron.conf DEFAULT notify_nova_on_port_data_changes true
crudini --set /etc/neutron/neutron.conf keystone_authtoken www_authenticate_uri http://controller:5000
crudini --set /etc/neutron/neutron.conf keystone_authtoken auth_url http://controller:5000
crudini --set /etc/neutron/neutron.conf keystone_authtoken memcached_servers controller:11211
crudini --set /etc/neutron/neutron.conf keystone_authtoken auth_type password
crudini --set /etc/neutron/neutron.conf keystone_authtoken project_domain_name Default
crudini --set /etc/neutron/neutron.conf keystone_authtoken user_domain_name Default
crudini --set /etc/neutron/neutron.conf keystone_authtoken project_name service
crudini --set /etc/neutron/neutron.conf keystone_authtoken username neutron
crudini --set /etc/neutron/neutron.conf keystone_authtoken password "$SERVICE_PASS"
crudini --set /etc/neutron/neutron.conf nova auth_url http://controller:5000
crudini --set /etc/neutron/neutron.conf nova auth_type password
crudini --set /etc/neutron/neutron.conf nova project_domain_name Default
crudini --set /etc/neutron/neutron.conf nova user_domain_name Default
crudini --set /etc/neutron/neutron.conf nova region_name RegionOne
crudini --set /etc/neutron/neutron.conf nova project_name service
crudini --set /etc/neutron/neutron.conf nova username nova
crudini --set /etc/neutron/neutron.conf nova password "$SERVICE_PASS"
crudini --set /etc/neutron/neutron.conf oslo_concurrency lock_path /var/lib/neutron/tmp
# Configure ML2 plugin
cp /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugins/ml2/ml2_conf.ini.backup
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 type_drivers flat,vlan,vxlan
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 tenant_network_types vxlan
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 mechanism_drivers openvswitch,l2population
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 extension_drivers port_security
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2_type_flat flat_networks provider
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2_type_vxlan vni_ranges 1:1000
crudini --set /etc/neutron/plugins/ml2/ml2_conf.ini securitygroup enable_ipset true
# Configure Open vSwitch agent
cp /etc/neutron/plugins/ml2/openvswitch_agent.ini /etc/neutron/plugins/ml2/openvswitch_agent.ini.backup
crudini --set /etc/neutron/plugins/ml2/openvswitch_agent.ini ovs bridge_mappings provider:br-provider
crudini --set /etc/neutron/plugins/ml2/openvswitch_agent.ini ovs local_ip "$CONTROLLER_IP"
crudini --set /etc/neutron/plugins/ml2/openvswitch_agent.ini agent tunnel_types vxlan
crudini --set /etc/neutron/plugins/ml2/openvswitch_agent.ini agent l2_population true
crudini --set /etc/neutron/plugins/ml2/openvswitch_agent.ini securitygroup firewall_driver openvswitch
# Configure L3 agent
cp /etc/neutron/l3_agent.ini /etc/neutron/l3_agent.ini.backup
crudini --set /etc/neutron/l3_agent.ini DEFAULT interface_driver openvswitch
# Configure DHCP agent
cp /etc/neutron/dhcp_agent.ini /etc/neutron/dhcp_agent.ini.backup
crudini --set /etc/neutron/dhcp_agent.ini DEFAULT interface_driver openvswitch
crudini --set /etc/neutron/dhcp_agent.ini DEFAULT dhcp_driver neutron.agent.linux.dhcp.Dnsmasq
crudini --set /etc/neutron/dhcp_agent.ini DEFAULT enable_isolated_metadata true
# Configure metadata agent
cp /etc/neutron/metadata_agent.ini /etc/neutron/metadata_agent.ini.backup
crudini --set /etc/neutron/metadata_agent.ini DEFAULT nova_metadata_host controller
crudini --set /etc/neutron/metadata_agent.ini DEFAULT metadata_proxy_shared_secret "$METADATA_SECRET"
# Configure Nova to use Neutron
crudini --set /etc/nova/nova.conf neutron auth_url http://controller:5000
crudini --set /etc/nova/nova.conf neutron auth_type password
crudini --set /etc/nova/nova.conf neutron project_domain_name Default
crudini --set /etc/nova/nova.conf neutron user_domain_name Default
crudini --set /etc/nova/nova.conf neutron region_name RegionOne
crudini --set /etc/nova/nova.conf neutron project_name service
crudini --set /etc/nova/nova.conf neutron username neutron
crudini --set /etc/nova/nova.conf neutron password "$SERVICE_PASS"
crudini --set /etc/nova/nova.conf neutron service_metadata_proxy true
crudini --set /etc/nova/nova.conf neutron metadata_proxy_shared_secret "$METADATA_SECRET"
# Create OVS bridge
systemctl start openvswitch-switch
systemctl enable openvswitch-switch
if ! ovs-vsctl br-exists br-provider; then
ovs-vsctl add-br br-provider
ovs-vsctl add-port br-provider "$PROVIDER_INTERFACE"
fi
# Create symbolic link
ln -sf /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini
# Populate database
su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neutron.conf \
--config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron
# Restart services
systemctl restart nova-api
systemctl restart neutron-server neutron-openvswitch-agent neutron-dhcp-agent \
neutron-metadata-agent neutron-l3-agent
systemctl enable neutron-server neutron-openvswitch-agent neutron-dhcp-agent \
neutron-metadata-agent neutron-l3-agent
mark_completed "neutron_configured"
}
# Install and configure Horizon
configure_horizon() {
if is_completed "horizon_configured"; then
log "Horizon already configured, skipping..."
return
fi
log "Installing and configuring Horizon (Dashboard)..."
# Install packages
apt install -y openstack-dashboard
# Fix the configuration file issue first
PROBLEM_FILE="/usr/share/openstack-dashboard/openstack_dashboard/local/local_settings.py"
if [ -f "$PROBLEM_FILE" ]; then
# Remove the problematic TEMPLATES line if it exists
sed -i '/TEMPLATES\[0\]/d' "$PROBLEM_FILE" 2>/dev/null || true
fi
# Create proper configuration
cat > /etc/openstack-dashboard/local_settings.py << EOF
# -*- coding: utf-8 -*-
import os
from django.utils.translation import gettext_lazy as _
DEBUG = False
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '$(openssl rand -hex 32)'