openSUSE to SLES Migration: Complete Guide
Migrating from openSUSE to SUSE Linux Enterprise Server (SLES) provides enterprise support, stability, and long-term maintenance. This guide covers the complete migration process, from planning to post-migration optimization.
Introduction to Migration
Key differences between openSUSE and SLES: - Support Model: Community vs. Enterprise support - Release Cycle: Rolling/Regular vs. Service Pack model - Package Selection: Cutting-edge vs. Enterprise-tested - Maintenance: Community-driven vs. Professional support - Certification: Hardware and software certifications - SLA: No SLA vs. Enterprise SLA
Pre-Migration Planning
System Assessment
# Current system information
cat /etc/os-release
uname -a
df -h
free -h
# Installed packages inventory
rpm -qa > opensuse-packages.txt
zypper packages --installed-only > installed-packages-detailed.txt
# Repository list
zypper repos -u > repositories.txt
# Service status
systemctl list-units --type=service --state=running > running-services.txt
# Network configuration
ip addr show > network-config.txt
ip route show > routing-table.txt
cat /etc/resolv.conf > dns-config.txt
# Hardware inventory
sudo hwinfo --short > hardware-inventory.txt
lspci > pci-devices.txt
lsusb > usb-devices.txt
# Kernel modules
lsmod > kernel-modules.txt
# Configuration backup
tar -czf /backup/opensuse-configs.tar.gz \
/etc/fstab \
/etc/hosts \
/etc/hostname \
/etc/sysconfig/ \
/etc/systemd/system/ \
/etc/ssh/sshd_config
Compatibility Check
# Check for non-standard packages
cat > check-compatibility.sh << 'EOF'
#!/bin/bash
# Check package compatibility with SLES
echo "Checking package compatibility..."
# Get list of installed packages
rpm -qa --qf "%{NAME}\n" | sort > installed.txt
# Common packages that need attention
PROBLEM_PACKAGES=(
"packman"
"vlc"
"chromium"
"steam"
"wine"
)
echo "Packages that may need alternatives in SLES:"
for pkg in "${PROBLEM_PACKAGES[@]}"; do
if grep -q "^$pkg" installed.txt; then
echo "- $pkg"
fi
done
# Check for OBS packages
echo -e "\nPackages from OBS repositories:"
rpm -qa --qf "%{NAME}|%{VENDOR}\n" | grep -i "obs://" | cut -d'|' -f1
# Check for custom repositories
echo -e "\nNon-standard repositories:"
zypper repos | grep -v "openSUSE\|Update"
EOF
chmod +x check-compatibility.sh
./check-compatibility.sh
Application Inventory
# Document critical applications
cat > application-inventory.sh << 'EOF'
#!/bin/bash
# Create application inventory
OUTPUT="application-inventory.md"
echo "# Application Inventory" > $OUTPUT
echo "Generated: $(date)" >> $OUTPUT
echo "" >> $OUTPUT
# Web servers
echo "## Web Servers" >> $OUTPUT
for srv in apache2 nginx lighttpd; do
if systemctl is-enabled $srv &>/dev/null; then
echo "- $srv: $(rpm -q $srv)" >> $OUTPUT
fi
done
# Database servers
echo -e "\n## Database Servers" >> $OUTPUT
for db in mysql mariadb postgresql mongodb redis; do
if systemctl is-enabled $db &>/dev/null; then
echo "- $db: $(rpm -q $db)" >> $OUTPUT
fi
done
# Programming languages
echo -e "\n## Programming Languages" >> $OUTPUT
for lang in python3 php ruby perl nodejs java-1_8_0-openjdk; do
if rpm -q $lang &>/dev/null; then
echo "- $lang: $(rpm -q $lang)" >> $OUTPUT
fi
done
# Custom applications
echo -e "\n## Custom Applications" >> $OUTPUT
echo "List custom applications installed in:" >> $OUTPUT
echo "- /opt/*" >> $OUTPUT
echo "- /usr/local/*" >> $OUTPUT
ls -la /opt/ >> $OUTPUT 2>/dev/null
ls -la /usr/local/bin/ >> $OUTPUT 2>/dev/null
EOF
chmod +x application-inventory.sh
./application-inventory.sh
Migration Methods
Method 1: Fresh Installation with Data Migration
# Backup critical data
cat > backup-data.sh << 'EOF'
#!/bin/bash
# Comprehensive backup script
BACKUP_DIR="/backup/opensuse-migration"
mkdir -p $BACKUP_DIR
# System configurations
tar -czf $BACKUP_DIR/etc-configs.tar.gz /etc/
# User data
tar -czf $BACKUP_DIR/home-dirs.tar.gz /home/
# Application data
for dir in /var/www /var/lib/mysql /var/lib/pgsql /opt; do
if [ -d "$dir" ]; then
tar -czf $BACKUP_DIR/$(basename $dir)-data.tar.gz $dir
fi
done
# Package list for reference
rpm -qa > $BACKUP_DIR/package-list.txt
zypper packages --installed-only > $BACKUP_DIR/packages-detailed.txt
# Service configurations
systemctl list-unit-files > $BACKUP_DIR/systemd-units.txt
# Crontabs
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u $user -l > $BACKUP_DIR/crontab-$user.txt 2>/dev/null
done
# Firewall rules
if command -v firewall-cmd &>/dev/null; then
firewall-cmd --list-all-zones > $BACKUP_DIR/firewall-rules.txt
fi
echo "Backup completed to $BACKUP_DIR"
EOF
chmod +x backup-data.sh
sudo ./backup-data.sh
Method 2: In-Place Conversion (Advanced)
# WARNING: This method is complex and risky
# Always test in a non-production environment first
# Step 1: Repository preparation
cat > prepare-sles-migration.sh << 'EOF'
#!/bin/bash
# Prepare system for SLES migration
# Backup current repositories
zypper repos -e backup-repos.repo
# Remove openSUSE repositories
zypper repos | grep -i opensuse | awk '{print $3}' | \
while read repo; do
zypper removerepo "$repo"
done
# Add SLES repositories (requires registration code)
echo "SLES repositories will be added after registration"
# Clean package cache
zypper clean -a
# Update repository metadata
zypper refresh
EOF
chmod +x prepare-sles-migration.sh
Method 3: Parallel Installation
# Install SLES on separate partition
# Then migrate data and configurations
# Mount SLES partition
mount /dev/sdb1 /mnt/sles
# Sync user data
rsync -avzP /home/ /mnt/sles/home/
# Sync application data
rsync -avzP /var/www/ /mnt/sles/var/www/
rsync -avzP /opt/ /mnt/sles/opt/
# Export/Import databases
# MySQL/MariaDB
mysqldump --all-databases > all-databases.sql
# On SLES: mysql < all-databases.sql
# PostgreSQL
sudo -u postgres pg_dumpall > postgresql-all.sql
# On SLES: sudo -u postgres psql < postgresql-all.sql
SLES Installation and Registration
Installing SLES
# After SLES installation, register the system
sudo SUSEConnect -r YOUR-REGISTRATION-CODE
# Add necessary modules
sudo SUSEConnect -p sle-module-basesystem/15.5/x86_64
sudo SUSEConnect -p sle-module-server-applications/15.5/x86_64
sudo SUSEConnect -p sle-module-web-scripting/15.5/x86_64
sudo SUSEConnect -p sle-module-development-tools/15.5/x86_64
# Update system
sudo zypper ref
sudo zypper up
# Install compatibility packages
sudo zypper install \
yast2-migration \
yast2-migration-sle \
supportutils \
suse-migration-services
Package Mapping
# Create package mapping script
cat > map-packages.sh << 'EOF'
#!/bin/bash
# Map openSUSE packages to SLES equivalents
declare -A PACKAGE_MAP=(
["chromium"]="firefox-esr"
["packman-essentials"]="" # No equivalent, skip
["vlc"]="" # Use alternative media player
["patterns-openSUSE-games"]="" # Not available in SLES
["wine"]="" # Available through SLES SDK
)
# Read openSUSE package list
while IFS= read -r pkg; do
if [[ -n "${PACKAGE_MAP[$pkg]}" ]]; then
echo "Replace $pkg with ${PACKAGE_MAP[$pkg]}"
elif [[ "${PACKAGE_MAP[$pkg]}" == "" ]]; then
echo "Skip $pkg (no SLES equivalent)"
else
# Check if package exists in SLES
if zypper search -x "$pkg" &>/dev/null; then
echo "Install $pkg"
else
echo "Manual review needed: $pkg"
fi
fi
done < opensuse-packages.txt
EOF
chmod +x map-packages.sh
Data Migration
User and Group Migration
# Export users and groups
cat > migrate-users.sh << 'EOF'
#!/bin/bash
# Migrate users and groups
# Backup current SLES users
cp /etc/passwd /etc/passwd.sles-backup
cp /etc/shadow /etc/shadow.sles-backup
cp /etc/group /etc/group.sles-backup
cp /etc/gshadow /etc/gshadow.sles-backup
# Extract non-system users from openSUSE backup
awk -F: '$3 >= 1000 && $3 < 65534 {print}' /backup/opensuse/etc/passwd > users-to-migrate.txt
awk -F: '$3 >= 1000 && $3 < 65534 {print}' /backup/opensuse/etc/group > groups-to-migrate.txt
# Create groups first
while IFS=: read -r group x gid members; do
if ! getent group "$group" >/dev/null; then
groupadd -g "$gid" "$group"
echo "Created group: $group"
fi
done < groups-to-migrate.txt
# Create users
while IFS=: read -r user x uid gid gecos home shell; do
if ! getent passwd "$user" >/dev/null; then
useradd -u "$uid" -g "$gid" -c "$gecos" -d "$home" -s "$shell" "$user"
echo "Created user: $user"
fi
done < users-to-migrate.txt
# Restore user passwords from shadow file
# Manual process - requires careful handling
echo "Manually update /etc/shadow with password hashes from backup"
EOF
chmod +x migrate-users.sh
Application Data Migration
# Web server migration
cat > migrate-webserver.sh << 'EOF'
#!/bin/bash
# Migrate web server configuration and data
# Apache configuration
if [ -d /backup/opensuse/etc/apache2 ]; then
# Backup SLES Apache config
cp -r /etc/apache2 /etc/apache2.sles-backup
# Copy site configurations
cp /backup/opensuse/etc/apache2/vhosts.d/*.conf /etc/apache2/vhosts.d/
# Copy custom modules configuration
cp /backup/opensuse/etc/apache2/conf.d/*.conf /etc/apache2/conf.d/
# Restore web content
rsync -avz /backup/opensuse/srv/www/ /srv/www/
# Set permissions
chown -R wwwrun:www /srv/www/htdocs
# Test configuration
apache2ctl configtest
fi
# PHP configuration
if [ -f /backup/opensuse/etc/php7/apache2/php.ini ]; then
# Compare and merge PHP settings
diff /backup/opensuse/etc/php7/apache2/php.ini /etc/php7/apache2/php.ini > php-config-diff.txt
echo "Review php-config-diff.txt and apply necessary changes"
fi
# Enable and start services
systemctl enable apache2
systemctl start apache2
EOF
chmod +x migrate-webserver.sh
Database Migration
# MySQL/MariaDB migration
cat > migrate-mysql.sh << 'EOF'
#!/bin/bash
# Migrate MySQL/MariaDB databases
# Install MariaDB if not present
zypper install mariadb mariadb-client
# Start service
systemctl start mariadb
systemctl enable mariadb
# Secure installation
mysql_secure_installation
# Restore databases
mysql -u root -p < /backup/opensuse/all-databases.sql
# Restore user privileges
mysql -u root -p < /backup/opensuse/mysql-users.sql
# Update configuration
cp /backup/opensuse/etc/my.cnf.d/*.cnf /etc/my.cnf.d/
# Restart service
systemctl restart mariadb
EOF
chmod +x migrate-mysql.sh
# PostgreSQL migration
cat > migrate-postgresql.sh << 'EOF'
#!/bin/bash
# Migrate PostgreSQL databases
# Install PostgreSQL
zypper install postgresql postgresql-server
# Initialize database
systemctl start postgresql
systemctl enable postgresql
# Restore all databases
sudo -u postgres psql < /backup/opensuse/postgresql-all.sql
# Copy configuration files
cp /backup/opensuse/var/lib/pgsql/data/postgresql.conf /var/lib/pgsql/data/
cp /backup/opensuse/var/lib/pgsql/data/pg_hba.conf /var/lib/pgsql/data/
# Restart PostgreSQL
systemctl restart postgresql
EOF
chmod +x migrate-postgresql.sh
Service Configuration
Systemd Service Migration
# Migrate custom systemd services
cat > migrate-services.sh << 'EOF'
#!/bin/bash
# Migrate systemd services
# Copy custom service files
for service in /backup/opensuse/etc/systemd/system/*.service; do
if [ -f "$service" ]; then
service_name=$(basename "$service")
# Skip if it's a system service
if [[ ! "$service_name" =~ ^(sshd|network|systemd-) ]]; then
cp "$service" /etc/systemd/system/
echo "Migrated service: $service_name"
fi
fi
done
# Reload systemd
systemctl daemon-reload
# List migrated services
echo "Migrated services:"
ls -la /etc/systemd/system/*.service | grep -v '@'
# Enable services based on openSUSE configuration
while IFS= read -r line; do
service=$(echo "$line" | awk '{print $1}')
if [ -f "/etc/systemd/system/$service" ]; then
systemctl enable "$service"
echo "Enabled: $service"
fi
done < /backup/opensuse/enabled-services.txt
EOF
chmod +x migrate-services.sh
Network Configuration
# Network configuration migration
cat > migrate-network.sh << 'EOF'
#!/bin/bash
# Migrate network configuration
# YaST network configuration
if [ -d /backup/opensuse/etc/sysconfig/network ]; then
# Backup SLES network config
cp -r /etc/sysconfig/network /etc/sysconfig/network.sles-backup
# Copy interface configurations
for iface in /backup/opensuse/etc/sysconfig/network/ifcfg-*; do
if [[ ! "$iface" =~ ifcfg-lo ]]; then
cp "$iface" /etc/sysconfig/network/
fi
done
# Copy routing configuration
cp /backup/opensuse/etc/sysconfig/network/routes /etc/sysconfig/network/
# Copy DNS configuration
cp /backup/opensuse/etc/sysconfig/network/config /etc/sysconfig/network/
fi
# NetworkManager configurations (if used)
if [ -d /backup/opensuse/etc/NetworkManager/system-connections ]; then
cp /backup/opensuse/etc/NetworkManager/system-connections/* \
/etc/NetworkManager/system-connections/
chmod 600 /etc/NetworkManager/system-connections/*
fi
# Restart network service
systemctl restart network
# or
systemctl restart NetworkManager
EOF
chmod +x migrate-network.sh
Application-Specific Migrations
Development Environment
# Migrate development tools
cat > migrate-dev-env.sh << 'EOF'
#!/bin/bash
# Migrate development environment
# Programming languages
LANGUAGES=(python3 ruby perl nodejs gcc make)
for lang in "${LANGUAGES[@]}"; do
zypper install "$lang"
done
# Python packages
if [ -f /backup/opensuse/python-packages.txt ]; then
pip3 install -r /backup/opensuse/python-packages.txt
fi
# Ruby gems
if [ -f /backup/opensuse/gem-list.txt ]; then
while IFS= read -r gem; do
gem install "$gem"
done < /backup/opensuse/gem-list.txt
fi
# Node.js packages
if [ -f /backup/opensuse/npm-global.txt ]; then
while IFS= read -r package; do
npm install -g "$package"
done < /backup/opensuse/npm-global.txt
fi
# Development tools
zypper install \
git \
subversion \
docker \
docker-compose \
vagrant \
ansible
EOF
chmod +x migrate-dev-env.sh
Container Workloads
# Migrate Docker containers
cat > migrate-docker.sh << 'EOF'
#!/bin/bash
# Migrate Docker containers and images
# Install Docker
zypper install docker docker-compose
# Start Docker
systemctl enable docker
systemctl start docker
# Load Docker images from backup
if [ -d /backup/opensuse/docker-images ]; then
for image in /backup/opensuse/docker-images/*.tar; do
docker load -i "$image"
echo "Loaded: $image"
done
fi
# Restore Docker volumes
if [ -d /backup/opensuse/var/lib/docker/volumes ]; then
systemctl stop docker
rsync -avz /backup/opensuse/var/lib/docker/volumes/ /var/lib/docker/volumes/
systemctl start docker
fi
# Restore docker-compose projects
if [ -d /backup/opensuse/docker-compose-projects ]; then
cp -r /backup/opensuse/docker-compose-projects /opt/
fi
# Import Docker registry credentials
if [ -f /backup/opensuse/.docker/config.json ]; then
mkdir -p ~/.docker
cp /backup/opensuse/.docker/config.json ~/.docker/
fi
EOF
chmod +x migrate-docker.sh
Post-Migration Tasks
System Optimization
# SLES-specific optimizations
cat > optimize-sles.sh << 'EOF'
#!/bin/bash
# Optimize SLES after migration
# Update system
zypper ref
zypper up
# Install recommended patterns
zypper install -t pattern base enhanced_base
# Configure automatic updates
cat > /etc/sysconfig/automatic_online_update << EOL
AOU_ENABLE_CRONJOB="true"
AOU_SKIP_INTERACTIVE_PATCHES="true"
AOU_PATCH_CATEGORIES="security"
EOL
# Enable SUSEConnect timer
systemctl enable --now suse-connect.timer
# Configure tuned for performance
zypper install tuned
systemctl enable --now tuned
tuned-adm profile throughput-performance
# Clean up unnecessary packages
zypper remove --clean-deps $(zypper packages --orphaned | tail -n +5 | awk '{print $5}')
# Update bootloader
grub2-mkconfig -o /boot/grub2/grub.cfg
EOF
chmod +x optimize-sles.sh
Security Hardening
# Apply SLES security settings
cat > secure-sles.sh << 'EOF'
#!/bin/bash
# Security hardening for SLES
# Install security tools
zypper install \
aide \
audit \
apparmor-utils \
firewalld
# Enable security services
systemctl enable --now auditd
systemctl enable --now apparmor
systemctl enable --now firewalld
# Configure firewall
firewall-cmd --set-default-zone=public
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
# SSH hardening
sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
# System audit
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Enable USBGuard
zypper install usbguard
systemctl enable --now usbguard
EOF
chmod +x secure-sles.sh
Validation and Testing
System Validation
# Validation script
cat > validate-migration.sh << 'EOF'
#!/bin/bash
# Validate SLES migration
echo "=== SLES Migration Validation ==="
echo
# System information
echo "System Information:"
cat /etc/os-release | grep -E "^(NAME|VERSION)="
uname -a
echo
# Registration status
echo "Registration Status:"
SUSEConnect -s
echo
# Service status
echo "Critical Services:"
for service in sshd firewalld apache2 mariadb postgresql; do
if systemctl is-enabled "$service" &>/dev/null; then
status=$(systemctl is-active "$service")
echo "$service: $status"
fi
done
echo
# Network connectivity
echo "Network Connectivity:"
ip addr show | grep -E "^[0-9]+:|inet "
echo
# Disk usage
echo "Disk Usage:"
df -h
echo
# Repository status
echo "Enabled Repositories:"
zypper repos --enabled
echo
# Failed services
echo "Failed Services:"
systemctl --failed
echo
# System logs
echo "Recent System Errors:"
journalctl -p err -n 10
EOF
chmod +x validate-migration.sh
./validate-migration.sh > migration-validation.log
Application Testing
# Test migrated applications
cat > test-applications.sh << 'EOF'
#!/bin/bash
# Test migrated applications
# Web server test
if systemctl is-active apache2 &>/dev/null; then
echo "Testing Apache..."
curl -s -o /dev/null -w "%{http_code}" http://localhost
echo
fi
# Database tests
if systemctl is-active mariadb &>/dev/null; then
echo "Testing MariaDB..."
mysql -e "SHOW DATABASES;" && echo "MariaDB: OK"
fi
if systemctl is-active postgresql &>/dev/null; then
echo "Testing PostgreSQL..."
sudo -u postgres psql -c "\l" && echo "PostgreSQL: OK"
fi
# Custom application tests
echo "Add custom application tests here"
EOF
chmod +x test-applications.sh
Rollback Plan
Creating Rollback Points
# Create system snapshot before major changes
snapper create -d "Before openSUSE migration"
snapper list
# Backup critical data
cat > create-rollback-point.sh << 'EOF'
#!/bin/bash
# Create rollback point
ROLLBACK_DIR="/backup/sles-rollback-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$ROLLBACK_DIR"
# System state
rpm -qa > "$ROLLBACK_DIR/packages.txt"
cp -r /etc "$ROLLBACK_DIR/"
tar -czf "$ROLLBACK_DIR/var-lib.tar.gz" /var/lib/
# Database dumps
mysqldump --all-databases > "$ROLLBACK_DIR/mysql-all.sql" 2>/dev/null
sudo -u postgres pg_dumpall > "$ROLLBACK_DIR/postgresql-all.sql" 2>/dev/null
echo "Rollback point created: $ROLLBACK_DIR"
EOF
chmod +x create-rollback-point.sh
Troubleshooting Common Issues
Package Conflicts
# Resolve package conflicts
zypper install --force-resolution package-name
# Find file conflicts
rpm -Va | grep -E "^..5"
# Rebuild RPM database
rpm --rebuilddb
Service Migration Issues
# Debug service failures
systemctl status service-name
journalctl -xe -u service-name
# Check for missing dependencies
ldd /path/to/binary | grep "not found"
# SELinux/AppArmor issues
aa-status
aa-complain /etc/apparmor.d/profile-name
Best Practices
Documentation
# Document the migration
cat > migration-documentation.md << 'EOF'
# SLES Migration Documentation
## Migration Date: [DATE]
## Pre-Migration State
- openSUSE Version:
- Kernel Version:
- Key Applications:
## Migration Method Used
- [ ] Fresh Installation
- [ ] In-Place Conversion
- [ ] Parallel Installation
## Issues Encountered
1.
2.
## Resolutions Applied
1.
2.
## Post-Migration Configuration
- SLES Version:
- Registration Status:
- Enabled Modules:
## Testing Results
- [ ] System boots successfully
- [ ] All services running
- [ ] Applications functional
- [ ] Data integrity verified
## Follow-up Tasks
1.
2.
EOF
Conclusion
Migrating from openSUSE to SLES requires careful planning and execution. Always test the migration process in a non-production environment first. Document all changes and maintain backups throughout the process. With proper preparation, the migration can be completed successfully while maintaining service availability and data integrity.