fix: AgentWizard URL拼接修正(origin/backend分离) + 复制兼容HTTP/移动端
This commit is contained in:
1 parent
2f4c0df0f2
commit
48b2d2281b
7 files changed
+60
-46
No files matched your search
@@ -0,0 +1,10 @@
|
|||||||
|
# AIOps Docker Compose 环境变量
|
||||||
|
# 复制为 .env 并修改密码
|
||||||
|
|
||||||
|
# MySQL 数据库密码(生产环境务必修改)
|
||||||
|
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD
|
||||||
|
MYSQL_PASSWORD=CHANGE_ME_USER_PASSWORD
|
||||||
|
|
||||||
|
# MySQL 数据库名和用户名(通常无需修改)
|
||||||
|
MYSQL_DATABASE=aiops
|
||||||
|
MYSQL_USER=aiops
|
||||||
@@ -21,5 +21,5 @@ DB_NAME=data/aiops.db
|
|||||||
# DB_NAME=aiops
|
# DB_NAME=aiops
|
||||||
|
|
||||||
# JWT 配置
|
# JWT 配置
|
||||||
JWT_SECRET=aiops-secret-key-change-in-production
|
JWT_SECRET=CHANGE_ME # 生产环境必须替换为随机生成的 32+ 字符密钥
|
||||||
JWT_EXPIRE_HOURS=24
|
JWT_EXPIRE_HOURS=24
|
||||||
+1
-1
@@ -225,7 +225,7 @@ func loadConfig() *config.Config {
|
|||||||
viper.SetDefault("redis.password", "")
|
viper.SetDefault("redis.password", "")
|
||||||
viper.SetDefault("redis.db", 0)
|
viper.SetDefault("redis.db", 0)
|
||||||
|
|
||||||
viper.SetDefault("jwt.secret", "aiops-jwt-secret-change-in-production")
|
viper.SetDefault("jwt.secret", "") // 生产环境必须通过配置或 JWT_SECRET 环境变量设置
|
||||||
viper.SetDefault("jwt.expire_hour", 24)
|
viper.SetDefault("jwt.expire_hour", 24)
|
||||||
|
|
||||||
viper.SetDefault("websocket.read_buffer_size", 1024)
|
viper.SetDefault("websocket.read_buffer_size", 1024)
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ services:
|
|||||||
container_name: ezops-mysql
|
container_name: ezops-mysql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: rootpassword
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-CHANGE_ME}
|
||||||
MYSQL_DATABASE: ezops
|
MYSQL_DATABASE: ezops
|
||||||
MYSQL_USER: ezops
|
MYSQL_USER: ezops
|
||||||
MYSQL_PASSWORD: ezops123
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-CHANGE_ME}
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -54,7 +54,7 @@ services:
|
|||||||
- DATABASE_MYSQL_HOST=mysql
|
- DATABASE_MYSQL_HOST=mysql
|
||||||
- DATABASE_MYSQL_PORT=3306
|
- DATABASE_MYSQL_PORT=3306
|
||||||
- DATABASE_MYSQL_USERNAME=ezops
|
- DATABASE_MYSQL_USERNAME=ezops
|
||||||
- DATABASE_MYSQL_PASSWORD=ezops123
|
- DATABASE_MYSQL_PASSWORD=${MYSQL_PASSWORD:-CHANGE_ME}
|
||||||
- DATABASE_MYSQL_DATABASE=ezops
|
- DATABASE_MYSQL_DATABASE=ezops
|
||||||
- REDIS_ENABLED=true
|
- REDIS_ENABLED=true
|
||||||
- REDIS_HOST=redis
|
- REDIS_HOST=redis
|
||||||
|
|||||||
+4
-4
@@ -7,10 +7,10 @@ services:
|
|||||||
container_name: aiops-mysql
|
container_name: aiops-mysql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: rootpassword
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-CHANGE_ME}
|
||||||
MYSQL_DATABASE: aiops
|
MYSQL_DATABASE: ${MYSQL_DATABASE:-aiops}
|
||||||
MYSQL_USER: aiops
|
MYSQL_USER: ${MYSQL_USER:-aiops}
|
||||||
MYSQL_PASSWORD: aiops123
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-CHANGE_ME}
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
|
|||||||
@@ -17,60 +17,64 @@ interface AgentWizardProps {
|
|||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 自动检测服务器地址:使用当前浏览器访问的主机名,端口固定 8080 */
|
/** 自动检测地址:origin(通过 Nginx 80 代理)用于安装脚本下载,backend 8080 用于 agent 直连 */
|
||||||
function detectServerAddress(): string {
|
function detectServerAddress() {
|
||||||
if (typeof window !== 'undefined' && window.location) {
|
if (typeof window !== 'undefined' && window.location) {
|
||||||
const host = window.location.hostname;
|
return {
|
||||||
return host ? `http://${host}:8080` : 'http://127.0.0.1:8080';
|
origin: window.location.origin, // http://10.10.10.75 → Nginx
|
||||||
|
backend: `${window.location.protocol}//${window.location.hostname}:8080`, // http://10.10.10.75:8080 → 后端直达
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return 'http://127.0.0.1:8080';
|
return { origin: 'http://127.0.0.1', backend: 'http://127.0.0.1:8080' };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
|
export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
|
||||||
const token = useUserStore((s) => s.token) || '<YOUR_TOKEN>';
|
const token = useUserStore((s) => s.token) || '<YOUR_TOKEN>';
|
||||||
const serverUrl = detectServerAddress();
|
const { origin, backend } = detectServerAddress();
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const [showManualInput, setShowManualInput] = useState(false);
|
const [showManualInput, setShowManualInput] = useState(false);
|
||||||
|
|
||||||
const installCommand = `curl -fsSL ${serverUrl.replace(/^http:/, 'http:')}/agent/install.sh | bash -s -- --server ${serverUrl} --token ${token}`;
|
// install.sh 通过 Nginx 代理下载(origin:80 → /agent/ → backend:8080)
|
||||||
|
const installCommand = `curl -fsSL ${origin}/agent/install.sh | bash -s -- --server ${backend} --token ${token}`;
|
||||||
|
|
||||||
// 剪贴板 fallback:execCommand('copy') 兼容 HTTP 环境 // Logan.Li
|
const handleCopy = () => {
|
||||||
const fallbackCopy = (text: string): boolean => {
|
|
||||||
const textArea = document.createElement('textarea');
|
const textArea = document.createElement('textarea');
|
||||||
textArea.value = text;
|
textArea.value = installCommand;
|
||||||
|
// 设置样式让其可见但不可交互,确保浏览器能选中
|
||||||
textArea.style.position = 'fixed';
|
textArea.style.position = 'fixed';
|
||||||
textArea.style.left = '-9999px';
|
textArea.style.top = '0';
|
||||||
textArea.style.top = '-9999px';
|
textArea.style.left = '0';
|
||||||
|
textArea.style.width = '2em';
|
||||||
|
textArea.style.height = '2em';
|
||||||
|
textArea.style.padding = '0';
|
||||||
|
textArea.style.border = 'none';
|
||||||
|
textArea.style.outline = 'none';
|
||||||
|
textArea.style.boxShadow = 'none';
|
||||||
|
textArea.style.background = 'transparent';
|
||||||
|
textArea.style.opacity = '0';
|
||||||
|
textArea.style.pointerEvents = 'none';
|
||||||
|
textArea.style.zIndex = '-1';
|
||||||
|
textArea.style.fontSize = '16px';
|
||||||
|
// iOS 需要 contentEditable + readOnly 兼容
|
||||||
|
textArea.contentEditable = 'true';
|
||||||
|
textArea.readOnly = true;
|
||||||
document.body.appendChild(textArea);
|
document.body.appendChild(textArea);
|
||||||
|
|
||||||
|
// 选中范围
|
||||||
textArea.focus();
|
textArea.focus();
|
||||||
textArea.select();
|
textArea.select();
|
||||||
|
// 兼容移动端
|
||||||
|
if (textArea.setSelectionRange) {
|
||||||
|
textArea.setSelectionRange(0, 999999);
|
||||||
|
}
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
try {
|
try {
|
||||||
success = document.execCommand('copy');
|
success = document.execCommand('copy');
|
||||||
} catch {
|
} catch {
|
||||||
// execCommand also failed
|
// execCommand failed
|
||||||
}
|
}
|
||||||
document.body.removeChild(textArea);
|
document.body.removeChild(textArea);
|
||||||
return success;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCopy = async () => {
|
|
||||||
let success = false;
|
|
||||||
|
|
||||||
// 方式1: Clipboard API(HTTPS / localhost 可用)
|
|
||||||
try {
|
|
||||||
if (navigator.clipboard && window.isSecureContext) {
|
|
||||||
await navigator.clipboard.writeText(installCommand);
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Clipboard API 不可用,尝试 fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方式2: execCommand fallback(HTTP 环境也可用)
|
|
||||||
if (!success) {
|
|
||||||
success = fallbackCopy(installCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
@@ -82,7 +86,7 @@ export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const binaryUrl = `${serverUrl}/agent/aiops-agent-linux-amd64`;
|
const binaryUrl = `${origin}/agent/aiops-agent-linux-amd64`;
|
||||||
|
|
||||||
const manualSteps = [
|
const manualSteps = [
|
||||||
{
|
{
|
||||||
@@ -108,7 +112,7 @@ export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
|
|||||||
``,
|
``,
|
||||||
`[Service]`,
|
`[Service]`,
|
||||||
`Type=simple`,
|
`Type=simple`,
|
||||||
`ExecStart=/usr/local/bin/aiops-agent --server ${serverUrl} --token ${token}`,
|
`ExecStart=/usr/local/bin/aiops-agent --server ${backend} --token ${token}`,
|
||||||
`Restart=always`,
|
`Restart=always`,
|
||||||
`RestartSec=5`,
|
`RestartSec=5`,
|
||||||
``,
|
``,
|
||||||
@@ -186,7 +190,7 @@ export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
|
|||||||
<div className="flex items-start gap-2 text-xs text-slate-500">
|
<div className="flex items-start gap-2 text-xs text-slate-500">
|
||||||
<Terminal className="h-3.5 w-3.5 mt-0.5 shrink-0" />
|
<Terminal className="h-3.5 w-3.5 mt-0.5 shrink-0" />
|
||||||
<span>
|
<span>
|
||||||
服务器地址已自动检测为当前访问地址({serverUrl})。Agent 安装成功后将自动连接并开始上报指标。
|
服务器地址已自动检测 — 安装脚本通过 Nginx 代理 ({origin}),Agent 直连后端 ({backend})。安装成功后将自动连接并开始上报指标。
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
Reference in new issue
Block a user