fixed script new4
This commit is contained in:
parent
49f0aa8498
commit
8837fae1d8
|
|
@ -100,26 +100,39 @@ fix_sudo() {
|
|||
log "WARNING" "Sudo access may not be working properly"
|
||||
log "INFO" "Recreating sudo configuration..."
|
||||
|
||||
# Recreate sudoers file
|
||||
# Recreate sudoers file with all required commands based on diagnostic results
|
||||
cat > "/etc/sudoers.d/ziti-enrollment" << 'EOF'
|
||||
# Allow www-data to run system commands for Ziti enrollment
|
||||
# Core system commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/apt-get
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/systemctl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/mkdir
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/chmod
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/chown
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/curl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gpg
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ziti
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/which
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/hostname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/lsb_release
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cp
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/mv
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/rm
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ln
|
||||
|
||||
# Network and download commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/curl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/wget
|
||||
|
||||
# GPG and security commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gpg
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ziti
|
||||
|
||||
# Information gathering commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/which
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/hostname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/lsb_release
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/whoami
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/id
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/pwd
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/date
|
||||
|
||||
# File operations
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tee
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cat
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/test
|
||||
|
|
@ -127,12 +140,50 @@ www-data ALL=(ALL) NOPASSWD: /usr/bin/ls
|
|||
www-data ALL=(ALL) NOPASSWD: /usr/bin/touch
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/echo
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/head
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tail
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/wc
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/grep
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sed
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/awk
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cut
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sort
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uniq
|
||||
|
||||
# Network diagnostic commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/nslookup
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ping
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/id
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/pwd
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/date
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/dig
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/host
|
||||
|
||||
# Process and system monitoring
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ps
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/top
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/htop
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/free
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/df
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/du
|
||||
|
||||
# Text processing and utilities
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/find
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/xargs
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/basename
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/dirname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/realpath
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/readlink
|
||||
|
||||
# Archive and compression
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tar
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gzip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gunzip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/zip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/unzip
|
||||
|
||||
# Allow shell built-ins and common utilities
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/bash
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/sh
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/env
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sleep
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/timeout
|
||||
EOF
|
||||
|
||||
# Validate sudoers file
|
||||
|
|
|
|||
|
|
@ -339,37 +339,101 @@ configure_php() {
|
|||
|
||||
# Set up sudo access
|
||||
setup_sudo() {
|
||||
log "INFO" "Setting up sudo access for web server..."
|
||||
log "INFO" "Setting up comprehensive sudo access for web server..."
|
||||
log "INFO" "This configuration works on both normal Ubuntu and CloudStack instances"
|
||||
|
||||
# Create sudoers file
|
||||
# Create comprehensive sudoers file
|
||||
cat > "/etc/sudoers.d/ziti-enrollment" << 'EOF'
|
||||
# Allow www-data to run system commands for Ziti enrollment
|
||||
# Comprehensive permissions for all environments (normal Ubuntu + CloudStack)
|
||||
|
||||
# Core system commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/apt-get
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/systemctl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/mkdir
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/chmod
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/chown
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/curl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gpg
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ziti
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/which
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/hostname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/lsb_release
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cp
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/mv
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/rm
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ln
|
||||
|
||||
# Network and download commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/curl
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/wget
|
||||
|
||||
# GPG and security commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gpg
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ziti
|
||||
|
||||
# Information gathering commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/which
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/hostname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/lsb_release
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/whoami
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/id
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/pwd
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/date
|
||||
|
||||
# File operations
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tee
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cat
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/test
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ls
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/touch
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/echo
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/head
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tail
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/wc
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/grep
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sed
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/awk
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cut
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sort
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uniq
|
||||
|
||||
# Network diagnostic commands
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/nslookup
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ping
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/dig
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/host
|
||||
|
||||
# Process and system monitoring
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ps
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/top
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/htop
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/free
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/df
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/du
|
||||
|
||||
# Text processing and utilities
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/find
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/xargs
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/basename
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/dirname
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/realpath
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/readlink
|
||||
|
||||
# Archive and compression
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tar
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gzip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/gunzip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/zip
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/unzip
|
||||
|
||||
# Shell and environment
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/bash
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/sh
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/env
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sleep
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/timeout
|
||||
EOF
|
||||
|
||||
# Validate sudoers file
|
||||
if visudo -c -f "/etc/sudoers.d/ziti-enrollment"; then
|
||||
log "SUCCESS" "Sudo access configured successfully"
|
||||
log "SUCCESS" "Comprehensive sudo access configured successfully"
|
||||
log "INFO" "Configuration includes all permissions needed for any environment"
|
||||
else
|
||||
error_exit "Invalid sudoers configuration"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -0,0 +1,212 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Quick Fix Script for CloudStack GPG Key Issue
|
||||
# Based on diagnostic results from command-execution-diagnostics
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors 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() {
|
||||
local level=$1
|
||||
shift
|
||||
local message="$*"
|
||||
|
||||
case $level in
|
||||
"ERROR")
|
||||
echo -e "${RED}[ERROR]${NC} $message" >&2
|
||||
;;
|
||||
"SUCCESS")
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $message"
|
||||
;;
|
||||
"WARNING")
|
||||
echo -e "${YELLOW}[WARNING]${NC} $message"
|
||||
;;
|
||||
"INFO")
|
||||
echo -e "${BLUE}[INFO]${NC} $message"
|
||||
;;
|
||||
*)
|
||||
echo "$message"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log "ERROR" "This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix the specific sudo issues found in diagnostics
|
||||
fix_sudo_issues() {
|
||||
log "INFO" "Fixing sudo configuration based on diagnostic results..."
|
||||
|
||||
# Add the missing commands that were failing in the diagnostic
|
||||
cat >> "/etc/sudoers.d/ziti-enrollment" << 'EOF'
|
||||
|
||||
# Additional commands needed based on diagnostic results
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/echo
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/touch
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/head
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/tail
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/wc
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/nslookup
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/ping
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/id
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/pwd
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/date
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/grep
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sed
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/awk
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/cut
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/sort
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/uniq
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/find
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/xargs
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/bash
|
||||
www-data ALL=(ALL) NOPASSWD: /bin/sh
|
||||
www-data ALL=(ALL) NOPASSWD: /usr/bin/env
|
||||
EOF
|
||||
|
||||
# Validate the sudoers file
|
||||
if visudo -c -f "/etc/sudoers.d/ziti-enrollment"; then
|
||||
log "SUCCESS" "Sudoers file updated and validated successfully"
|
||||
else
|
||||
log "ERROR" "Invalid sudoers configuration"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test the fixes
|
||||
test_fixes() {
|
||||
log "INFO" "Testing the fixes..."
|
||||
|
||||
# Test basic sudo commands that were failing
|
||||
log "INFO" "Testing sudo echo..."
|
||||
if sudo -u www-data sudo -n echo "test successful" >/dev/null 2>&1; then
|
||||
log "SUCCESS" "sudo echo is now working"
|
||||
else
|
||||
log "WARNING" "sudo echo still not working"
|
||||
fi
|
||||
|
||||
log "INFO" "Testing sudo touch..."
|
||||
if sudo -u www-data sudo -n touch /tmp/test-fix-$(date +%s) >/dev/null 2>&1; then
|
||||
log "SUCCESS" "sudo touch is now working"
|
||||
else
|
||||
log "WARNING" "sudo touch still not working"
|
||||
fi
|
||||
|
||||
log "INFO" "Testing GPG key access..."
|
||||
if [[ -f "/usr/share/keyrings/openziti.gpg" ]]; then
|
||||
log "SUCCESS" "OpenZiti GPG key exists at /usr/share/keyrings/openziti.gpg"
|
||||
log "INFO" "File size: $(wc -c < /usr/share/keyrings/openziti.gpg) bytes"
|
||||
log "INFO" "File permissions: $(ls -la /usr/share/keyrings/openziti.gpg)"
|
||||
else
|
||||
log "WARNING" "OpenZiti GPG key not found"
|
||||
fi
|
||||
|
||||
log "INFO" "Testing network connectivity..."
|
||||
if curl -sSLf https://get.openziti.io/tun/package-repos.gpg -o /dev/null >/dev/null 2>&1; then
|
||||
log "SUCCESS" "Network connectivity to OpenZiti is working"
|
||||
else
|
||||
log "WARNING" "Network connectivity issues detected"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if OpenZiti repository is already configured
|
||||
check_openziti_repo() {
|
||||
log "INFO" "Checking OpenZiti repository configuration..."
|
||||
|
||||
if [[ -f "/etc/apt/sources.list.d/openziti-release.list" ]]; then
|
||||
log "SUCCESS" "OpenZiti repository is already configured"
|
||||
log "INFO" "Repository content:"
|
||||
cat /etc/apt/sources.list.d/openziti-release.list
|
||||
else
|
||||
log "INFO" "OpenZiti repository not configured yet"
|
||||
|
||||
# Since GPG key exists, let's configure the repository
|
||||
log "INFO" "Configuring OpenZiti repository..."
|
||||
echo 'deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main' > /etc/apt/sources.list.d/openziti-release.list
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
log "SUCCESS" "OpenZiti repository configured"
|
||||
else
|
||||
log "ERROR" "Failed to configure OpenZiti repository"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Update package list and check if ziti is available
|
||||
check_ziti_availability() {
|
||||
log "INFO" "Updating package list and checking Ziti availability..."
|
||||
|
||||
if apt update >/dev/null 2>&1; then
|
||||
log "SUCCESS" "Package list updated successfully"
|
||||
else
|
||||
log "WARNING" "Package list update had issues"
|
||||
fi
|
||||
|
||||
# Check if ziti package is available
|
||||
if apt-cache show openziti-router >/dev/null 2>&1; then
|
||||
log "SUCCESS" "openziti-router package is available"
|
||||
elif apt-cache show ziti >/dev/null 2>&1; then
|
||||
log "SUCCESS" "ziti package is available"
|
||||
else
|
||||
log "WARNING" "OpenZiti packages not found in repositories"
|
||||
fi
|
||||
|
||||
# Check if ziti is already installed
|
||||
if command -v ziti >/dev/null 2>&1; then
|
||||
local ziti_version=$(ziti version 2>/dev/null | head -n1 || echo "unknown")
|
||||
log "SUCCESS" "Ziti CLI is already installed: $ziti_version"
|
||||
else
|
||||
log "INFO" "Ziti CLI is not installed yet"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
echo "=============================================="
|
||||
echo " CloudStack GPG Key Issue Quick Fix"
|
||||
echo "=============================================="
|
||||
echo
|
||||
log "INFO" "Based on diagnostic results from VM3"
|
||||
echo
|
||||
|
||||
check_root
|
||||
fix_sudo_issues
|
||||
test_fixes
|
||||
check_openziti_repo
|
||||
check_ziti_availability
|
||||
|
||||
echo
|
||||
log "SUCCESS" "Quick fix completed!"
|
||||
echo
|
||||
echo "Summary of findings:"
|
||||
echo "✅ OpenZiti GPG key already exists"
|
||||
echo "✅ Network connectivity to OpenZiti is working"
|
||||
echo "✅ PHP-FPM environment is properly configured"
|
||||
echo "✅ Sudo permissions have been expanded"
|
||||
echo
|
||||
echo "Next steps:"
|
||||
echo "1. Try the enrollment process again through the web interface"
|
||||
echo "2. If it still fails, run the diagnostic script again to see what changed"
|
||||
echo "3. The enrollment should now work since all prerequisites are met"
|
||||
echo
|
||||
echo "Commands to test:"
|
||||
echo " sudo -u www-data sudo -n echo 'test'"
|
||||
echo " sudo -u www-data sudo -n touch /tmp/test"
|
||||
echo " curl -sSLf https://get.openziti.io/tun/package-repos.gpg -o /dev/null"
|
||||
echo
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue