openSUSE to SLES Migration: Complete Guide

Tyler Maginnis | February 12, 2024

openSUSESLESmigrationenterprise Linuxsystem upgrade

Need Professional SUSE Enterprise Support?

Get expert assistance with your suse enterprise support implementation and management. Tyler on Tech Louisville provides priority support for Louisville businesses.

Same-day service available for Louisville area

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.