You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Tiobon.Web.Core/Tiobon.Core.OPS.Tool/View/Frm_MultiEnvironment.cs

621 lines
28 KiB

using Tiobon.Core.OPS.Tool.OPS.Tool.Helper;
using Tiobon.Core.OPS.Tool.OPS.Tool.Model;
using Tiobon.Core.OPS.Tool.OPS.Tool.src;
using Renci.SshNet;
using Renci.SshNet.Sftp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Tiobon.Core.OPS.Tool.OPS.Tool.View
{
public partial class Frm_MultiEnvironment : Form
{
bool isLinux = Const.config.system == "Linux";
#region 初始化
public Frm_MultiEnvironment()
{
InitializeComponent();
this.Text = $"多环境管理 - {Const.config.name} {Const.config.ip}";
RefreshView();
}
private void RefreshView(bool invoke = false)
{
if (invoke)
{
try
{
BeginInvoke(new EventHandler(delegate
{
listView_MultiEnv.Items.Clear();
Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(o =>
{
ListViewItem item = new ListViewItem();
item.SubItems[0].Text = o.Name;
item.SubItems.Add(o.FileName);
item.SubItems.Add(o.DefaultPort);
item.SubItems.Add(o.DefaultMask);
listView_MultiEnv.Items.Add(item);
});
}));
}
catch { }
}
else
{
listView_MultiEnv.Items.Clear();
Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(o =>
{
ListViewItem item = new ListViewItem();
item.SubItems[0].Text = o.Name;
item.SubItems.Add(o.FileName);
item.SubItems.Add(o.DefaultPort);
item.SubItems.Add(o.DefaultMask);
listView_MultiEnv.Items.Add(item);
});
}
}
#endregion
#region 新增、编辑、删除
private void tsmi_Create_Click(object sender, EventArgs e)
{
using (Frm_MultiItem f = new Frm_MultiItem())
{
f.ShowDialog();
}
RefreshView();
}
private void tsmi_Edit_Click(object sender, EventArgs e)
{
Edit();
}
private void listView_MultiEnv_MouseDoubleClick(object sender, MouseEventArgs e)
{
Edit();
}
private void Edit()
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
using (Frm_MultiItem f = new Frm_MultiItem($"{this.listView_MultiEnv.SelectedItems[0].Text}"))
{
f.ShowDialog();
}
RefreshView();
}
private void tsmi_Delete_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
if (MessageBox.Show("是否确认删除?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
if (!(item is null))
{
Const.MultiEnvs.Remove(item);
Const.SaveMultiEnv();
RefreshView();
}
}
#endregion
#region 重启
private void tsmi_Restart_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
var name = this.listView_MultiEnv.SelectedItems[0].Text;
if (MessageBox.Show($"是否确认重启[{name}]?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
if (!exist)
{
MessageBox.Show($"环境[{name}]未部署,不执行此操作", "提示");
return;
}
try
{
LoadingHelper.ShowLoading("正在重启服务,请稍等...", this, (obj) =>
{
var b_suc = ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart;", out string result);
Thread.Sleep(2000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart rtm", out _);
Thread.Sleep(5000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart job", out _);
Thread.Sleep(2000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart hfs", out _);
Thread.Sleep(2000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart iot", out _);
Thread.Sleep(2000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart ts", out _);
Thread.Sleep(2000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart webapi", out _);
Thread.Sleep(10000);
ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart nginx", out _);
if (b_suc)
{
MessageBox.Show($"环境[{name}]重启成功!", "提示");
}
else
{
MessageBox.Show($"环境[{name}]重启失败:\r\n{result}", "提示");
}
});
}
catch { }
}
#endregion
#region 停止
private void tsmi_Stop_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
var name = this.listView_MultiEnv.SelectedItems[0].Text;
if (MessageBox.Show($"是否确认停止[{name}]?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
if (!exist)
{
MessageBox.Show($"环境[{name}]未部署,不执行此操作", "提示");
return;
}
try
{
LoadingHelper.ShowLoading("正在停止服务,请稍等...", this, (obj) =>
{
var b_suc = ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose stop;", out string result);
if (b_suc)
{
MessageBox.Show($"环境[{name}]停止成功!", "提示");
}
else
{
MessageBox.Show($"环境[{name}]停止失败:\r\n{result}", "提示");
}
});
}
catch { }
}
#endregion
#region 前端
private void tsmi_Web_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
try
{
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
if (!exist)
{
MessageBox.Show($"环境[{item.Name}]未部署,不执行此操作", "提示");
return;
}
System.Diagnostics.Process.Start($"http://{item.Ip}:{item.DefaultPort}00");
}
catch { }
}
#endregion
#region 数据库
private void tsmi_Database_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
try
{
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
if (!exist)
{
MessageBox.Show($"环境[{item.Name}]未部署,不执行此操作", "提示");
return;
}
string heidisql = @"C:\Program Files\HeidiSQL\heidisql.exe";
if (!File.Exists(heidisql))
{
MessageBox.Show($"未能检测到 [HeidiSQL],请先安装!\r\n默认检测路径为:{heidisql}", "提示");
}
else
{
System.Diagnostics.Process.Start(heidisql, $" -d {item.Ip}({item.FileName}) -n {0} -h {item.Ip} -u root -p jlmed#123 -P {item.DefaultPort}90");
}
}
catch { }
}
#endregion
#region 数据库初始化
private void tsmi_DBInit_Click(object sender, EventArgs e)
{
if (this.listView_MultiEnv.SelectedItems.Count <= 0)
return;
var name = this.listView_MultiEnv.SelectedItems[0].Text;
if (MessageBox.Show($"此操作存在极高风险\r\n1、会重置数据密码为jlmed#123\r\n2、现有数据将丢失,数据库重置为初始状态\r\n是否确认初始化数据库[{name}]?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
if (!exist)
{
MessageBox.Show($"环境[{name}]未部署,不执行此操作", "提示");
return;
}
if (MessageBox.Show($"是否已经联系过研发,确认必须执行此操作?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
try
{
LoadingHelper.ShowLoading("正在初始化数据库,请稍等...", this, (obj) =>
{
var script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost mysql --default-character-set=utf8 < conf/mysql/hdis_db.sql;";
Const.write_log($"初始化数据库:{script}");
var b_suc = ExecSsh(script, out string result);
if (!b_suc)
{
Const.write_log($"初始化数据库:{result}");
MessageBox.Show($"初始化数据库:{result}", "提示");
return;
}
Const.write_log($"初始化数据库成功");
System.Threading.Thread.Sleep(10000);
script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost hdis --default-character-set=utf8 < conf/mysql/hdis_table.sql;";
Const.write_log($"初始化数据库表:{script}");
b_suc = ExecSsh(script, out result);
if (!b_suc)
{
Const.write_log($"初始化数据库表失败:{result}");
MessageBox.Show($"初始化数据库表失败:\r\n{result}", "提示");
return;
}
Const.write_log($"初始化数据库表成功");
System.Threading.Thread.Sleep(10000);
script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost mysql --default-character-set=utf8 < conf/mysql/hdis_user.sql;";
Const.write_log($"初始化用户信息:{script}");
b_suc = ExecSsh(script, out result);
if (!b_suc)
{
Const.write_log($"初始化用户信息失败:{result}");
MessageBox.Show($"初始化用户信息失败:\r\n{result}", "提示");
return;
}
Const.write_log($"初始化用户信息成功");
System.Threading.Thread.Sleep(10000);
script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -e \"ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'jlmed#123'; flush privileges; \";";
Const.write_log($"初始化用户密码:{script}");
b_suc = ExecSsh(script, out result);
if (!b_suc)
{
Const.write_log($"初始化用户密码失败:{result}");
MessageBox.Show($"初始化用户密码失败:\r\n{result}", "提示");
return;
}
Const.write_log($"初始化用户密码成功");
System.Threading.Thread.Sleep(10000);
script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart;";
Const.write_log($"重启服务:{script}");
b_suc = ExecSsh(script, out result);
if (!b_suc)
{
Const.write_log($"重启服务失败:{result}");
MessageBox.Show($"重启服务失败:\r\n{result}", "提示");
return;
}
Const.write_log($"重启服务成功");
});
}
catch { }
}
#endregion
#region 同步
private void ll_Sync_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
try
{
LoadingHelper.ShowLoading("正在同步数据,请稍等...", this, (obj) =>
{
if (isLinux)
{
var hospitals = ListDirectory($"/home/{Const.config.ssh_user}/ihdis").Select(o => o.Name).ToList();
hospitals.ForEach(hospitalName =>
{
//服务器端数据
if (!Exists($"/home/{Const.config.ssh_user}/ihdis/{hospitalName}/.env"))
{
Const.write_log($"发现 文件夹 {hospitalName} 不存在 .env 文件,跳过同步");
return;
}
var fname = GetTempFileName(".env");
bool b_suc = DownloadFile($"/home/{Const.config.ssh_user}/ihdis/{hospitalName}/.env", fname);
var content = File.ReadAllText(fname);
var datas = content.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
var hospital = new MultiEnvInfo
{
Name = hospitalName,
FileName = hospitalName,
Ip = Const.config.ip,
DefaultPort = datas.Where(d => d.StartsWith("IHDIS_PORT=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
DefaultMask = datas.Where(d => d.StartsWith("mask=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
};
//是否存在
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.FileName == hospitalName).FirstOrDefault();
if (item == null)
{
if (b_suc)
{
Const.MultiEnvs.Add(hospital);
Const.write_log($"发现新环境 {hospitalName} 端口 {hospital.DefaultPort} 掩码 {hospital.DefaultMask}");
}
}
else
{
if (item.DefaultPort != hospital.DefaultPort || item.DefaultMask != hospital.DefaultMask)
{
Const.write_log($"更新环境 {hospitalName} 端口号 {item.DefaultPort} 掩码 {hospital.DefaultMask}");
item.DefaultPort = hospital.DefaultPort;
}
else
{
Const.write_log($"医院 {hospitalName} 端口号一致 {hospital.DefaultPort} 掩码一致 {DefaultMask}");
}
}
});
//本地数据
var notExsit = new List<MultiEnvInfo>();
Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(hospital =>
{
if (!hospitals.Contains(hospital.FileName))
{
notExsit.Add(hospital);
}
});
notExsit.ForEach(hospital =>
{
Const.MultiEnvs.Remove(hospital);
//环境不存在
Const.write_log($"环境已经不存在 {hospital.FileName}");
});
Const.SaveMultiEnv();
RefreshView(true);
}
else
{
var hospitals = new List<string>();
DirectoryInfo directory = new DirectoryInfo(Const.config.install_dir);
FileSystemInfo[] filesArray = directory.GetFileSystemInfos();
//foreach (var filesItem in filesArray)
filesArray.ForEach(filesItem =>
{
//是否是一个文件夹
if (filesItem.Attributes == FileAttributes.Directory)
{
var hospitalName = filesItem.Name;
//服务器端数据
if (!File.Exists($"{filesItem.FullName}/.env"))
{
Const.write_log($"发现 文件夹 {hospitalName} 不存在 .env 文件,跳过同步");
return;
}
hospitals.Add(hospitalName);
var content = File.ReadAllText($"{filesItem.FullName}/.env");
var datas = content.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
var hospital = new MultiEnvInfo
{
Name = hospitalName,
FileName = hospitalName,
Ip = Const.config.ip,
DefaultPort = datas.Where(d => d.StartsWith("IHDIS_PORT=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
DefaultMask = datas.Where(d => d.StartsWith("mask=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
};
//是否存在
var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.FileName == hospitalName).FirstOrDefault();
if (item == null)
{
Const.MultiEnvs.Add(hospital);
Const.write_log($"发现新环境 {hospitalName} 端口 {hospital.DefaultPort} 掩码 {hospital.DefaultMask}");
}
else
{
if (item.DefaultPort != hospital.DefaultPort || item.DefaultMask != hospital.DefaultMask)
{
Const.write_log($"更新环境 {hospitalName} 端口号 {item.DefaultPort} 掩码 {hospital.DefaultMask}");
item.DefaultPort = hospital.DefaultPort;
}
else
{
Const.write_log($"医院 {hospitalName} 端口号一致 {hospital.DefaultPort} 掩码一致 {DefaultMask}");
}
}
}
});
//本地数据
var notExsit = new List<MultiEnvInfo>();
Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(hospital =>
{
if (!hospitals.Contains(hospital.FileName))
notExsit.Add(hospital);
});
notExsit.ForEach(hospital =>
{
Const.MultiEnvs.Remove(hospital);
//环境不存在
Const.write_log($"环境已经不存在 {hospital.FileName}");
});
Const.SaveMultiEnv();
RefreshView(true);
}
});
}
catch { }
}
#endregion
#region 辅助方法
private bool ExecSsh(string command, out string result)
{
bool b_suc = false;
result = string.Empty;
try
{
using (SshClient ssh = new SshClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
{
ssh.Connect();
var cmd = ssh.RunCommand(command);
if (cmd.ExitStatus != 0)
{
result = cmd.Error;
}
else
{
b_suc = true;
result = $"{cmd.Result}{cmd.Error}";
}
}
}
catch (Exception ex)
{
result = ex.Message;
}
Const.write_log(result);
return b_suc;
}
private bool Exists(string path)
{
bool b_suc = false;
try
{
using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
{
sftp.Connect();
b_suc = sftp.Exists(path);
}
}
catch (Exception ex)
{
Const.write_log(ex.ToString());
}
return b_suc;
}
/// <summary>
/// 获取当前目录的文件夹列表
/// </summary>
/// <param name="server"></param>
/// <param name="remotePath"></param>
/// <returns></returns>
private List<SftpFile> ListDirectory(string remotePath)
{
List<SftpFile> list = new List<SftpFile>();
try
{
using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
{
sftp.Connect();
list = sftp.ListDirectory(remotePath).Where(f => f.IsDirectory && f.Name != "." && f.Name != "..").ToList();
}
}
catch (Exception ex)
{
Const.write_log($"获取文件夹失败:{remotePath} {ex.Message}");
}
return list;
}
/// <summary>
/// 下载单个文件
/// </summary>
/// <param name="remotePath"></param>
/// <param name="localFile"></param>
/// <returns></returns>
public static bool DownloadFile(string remoteFile, string localFile)
{
bool b_suc = false;
try
{
using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
{
sftp.Connect();
if (sftp.Exists(remoteFile))
{
Const.write_log($"下载文件 {remoteFile}");
if (File.Exists(localFile))
{
File.Delete(localFile);
System.Threading.Thread.Sleep(50);
}
var sftFile = sftp.ListDirectory(remoteFile.Substring(0, remoteFile.LastIndexOf('/'))).Where(o => o.FullName == remoteFile).FirstOrDefault();
using (var file = File.OpenWrite(localFile))
{
sftp.DownloadFile(remoteFile, file);
Const.write_log($"成功 {remoteFile} =>> {localFile} len {file.Length} byte");
b_suc = true;
}
}
else
{
Const.write_log($"文件不存在 {remoteFile}");
}
}
}
catch (Exception ex)
{
Const.write_log($"下载文件失败:{remoteFile} {ex.Message}");
}
return b_suc;
}
/// <summary>
/// 获取临时文件名
/// </summary>
/// <param name="fname"></param>
/// <param name="random"></param>
/// <returns></returns>
private string GetTempFileName(string fname, bool random = true)
{
return $"{System.Environment.GetEnvironmentVariable("TEMP")}\\{fname}" + (random ? $"_{DateTime.Now.Ticks}" : "");
}
#endregion
}
}