在Linux安装Cache的时候,有很多选择项需要用户输入。比如安装目录、用户密码、使用使用Unicode、所属用户、CSP密码等等。不利于实现一键部署检验web和数据库计划。之前的一键部署在安装Cache软件时候没有达到自动化。为此开发自动回复命令,通过他调用Cache安装命令,按指定文件一行行回复安装需要的选项。原理认为安装程序输入10秒没变化就认为他在等待输入,就回复一个信息给他的标准输入里。
C#代码
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Threading;
namespace autoreply
{
/// <summary>
/// [功能描述: 自动按步骤回复内容工具]<para/>
/// [创建者: zlz]<para/>
/// [创建时间: 20210801]<para/>
/// <说明>
/// 自动安装软件时候用
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
class Program
{
/// <summary>
/// 最后读取传
/// </summary>
private static string lastStr = "";
/// <summary>
/// 前一个传
/// </summary>
private static string preStr = "";
/// <summary>
/// 串相同判断次数
/// </summary>
private static int sameNum = 0;
/// <summary>
/// 进程
/// </summary>
private static Process proc = null;
/// <summary>
/// 回复队列
/// </summary>
private static Queue<string> replyQueue = new Queue<string>();
/// <summary>
/// 没变化秒数
/// </summary>
private static int second = 10;
/// <summary>
/// main
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//没参数提示
if (args == null || args.Length == 0)
{
Console.WriteLine("没有传入参数,尝试 autoreply --help");
return;
}
//第一个参数为要执行的命令
string cmd = "";
cmd = args[0];
if (cmd == "")
{
Console.WriteLine("没有传入调用命令!");
return;
}
else
{
Console.WriteLine("传入调用命令:"+ cmd);
}
//命令帮助
if (cmd == "--help")
{
string helpPath = AppContext.BaseDirectory + "help.txt";
if (File.Exists(helpPath))
{
Console.WriteLine(TxtUtil.ReadTxt(helpPath));
}
else
{
Console.WriteLine("autoreply /zlz/cache-2016.2.3.907.11.20446-lnxrhx64/cinstall /zlz/net5.0/cache.reply");
}
return;
}
//命令版本
else if (cmd == "--vertion")
{
Console.WriteLine("autoreply 0.0.1 20210801 zlz");
return;
}
//参数不足
if (args.Length < 2)
{
Console.WriteLine("没有传入回复文件路径!");
return;
}
//传入了秒数
if (args.Length>=3)
{
second = Convert.ToInt32(args[2]);
}
//自动按步骤回复的文件,第二个参数会按步骤回复文件
string replyFile = args[1];
//读取配置到队列
if (File.Exists(replyFile))
{
Console.WriteLine("读取" + replyFile + "回复信息,将依次回复以下信息(10秒内回复):");
StreamReader sr = new StreamReader(replyFile, Encoding.UTF8);
string line;
while ((line = sr.ReadLine()) != null)
{
replyQueue.Enqueue(line);
Console.WriteLine(line);
}
sr.Close();
sr.Dispose();
}
else
{
Console.WriteLine(replyFile + " 不存在!");
return;
}
//启动定时器
Timer myTimer = new Timer(Reply, "执行定时事件", 0, 1000);
//创建一个ProcessStartInfo对象 使用系统shell指定命令和参数 设置标准输出
string para = "";
string [] paraArr = cmd.Split(' ');
//提取命令和参数
if(paraArr.Length>1)
{
for(int i=1;i<paraArr.Length;i++)
{
if(para!="")
{
para += " " + paraArr[i];
}
else
{
para = paraArr[i];
}
}
}
cmd = cmd.Split(' ')[0];
var psi = new ProcessStartInfo(cmd, para)
{
RedirectStandardOutput = true,
RedirectStandardInput = true
};
Console.WriteLine("执行:"+cmd+"命令");
if(para!="")
{
Console.WriteLine("参数:" + para);
}
//启动进程
proc = Process.Start(psi);
if (proc == null)
{
Console.WriteLine("不能执行命令!");
return;
}
else
{
//开始读取
using (var sr = proc.StandardOutput)
{
while (!sr.EndOfStream)
{
string oneStr = sr.ReadLine();
//累积输出到读取的信息串
if (oneStr != "")
{
lastStr += oneStr;
}
Console.WriteLine(oneStr);
}
if (!proc.HasExited)
{
proc.Kill();
}
}
Console.WriteLine("执行结束");
}
/// <summary>
/// 监控回复信息
/// </summary>
static void Reply(object state)
{
//回复队列空了就不回复了
if (replyQueue.Count == 0)
{
return;
}
//输出串没变化就记录没输出监听次数
if (lastStr == preStr)
{
sameNum++;
}
else
{
sameNum = 0;
}
//检测秒数次没变化就认为在等待输入
if (sameNum > second)
{
sameNum = 0;
string oneReply = replyQueue.Dequeue();
Console.WriteLine(oneReply);
proc.StandardInput.WriteLine(oneReply);
}
preStr = lastStr;
}
}
}
}
文本工具
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace autoreply
{
///<summary NoteObject="Class">
/// [功能描述: Txt操作工具]<br></br>
/// [创建者: zlz]<br></br>
/// [创建时间: 20210711]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public static class TxtUtil
{
/// <summary>
/// 读取文件数据
/// </summary>
/// <param name="path">文件全路径</param>
/// <returns></returns>
public static string ReadTxt(string path)
{
//文件流
FileStream fs = null;
StreamReader sr = null;
try
{
//创建文件流
fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//创建字符串读取器
sr = new StreamReader(fs);
//读到尾
string str = sr.ReadToEnd();
return str;
}
finally
{
if (fs != null)
{
fs.Close();
}
if (sr != null)
{
sr.Close();
}
}
}
/// <summary>
/// 写入数据到指定文件
/// </summary>
/// <param name="path">文件全路径</param>
/// <param name="str">数据</param>
/// <param name="isReplace">是否提换,默认为替换,否则为添加</param>
/// <returns></returns>
public static bool WriteTxt(string path, string str, bool isReplace = true)
{
FileStream fs = null;
StreamWriter sw1 = null;
try
{
//如果是替换,先清除之前的内容
if (isReplace)
{
if (File.Exists(path))
{
File.Delete(path);
}
}
//创建文件流
fs = new FileStream(path, FileMode.Append,FileAccess.Write);
//创建字符串写入器
sw1 = new StreamWriter(fs);
//写入字符串
sw1.Write(str);
return true;
}
finally
{
if (sw1 != null)
{
sw1.Close();
}
if (fs != null)
{
fs.Close();
}
}
}
}
}
工具打包
工具安装命令
#!/bin/bash
#shell放在网站上供在线执行下载和初步部署数据库目录等
#20210801
#zlz
#----------------------------------------------------------
#清空老文件夹
if [ -d /usr/local/autoreply ];then
echo "已安装autoreply,删除/usr/local/autoreply文件夹"
rm -rf /usr/local/autoreply
else
echo "alias autoreply='dotnet /usr/local/autoreply/autoreply.dll'">>~/.bashrc
fi
if ! type dotnet >/dev/null 2>&1; then
sudo yum install dotnet-runtime-5.0
fi
apppath=$(cd "$(dirname "$0")";pwd)"/autoreply"
cp -r ${apppath} /usr/local/
source ~/.bashrc
echo "安装成功"
Cache第一次安装的回复文件
1
cache
/intersystem/cache
Yes
1
2
root
SYS
SYS
SYS
SYS
root
y
n
y
调用命令
[root@localhost net5.0]# dotnet autoreply.dll /zlz/cache-2016.2.3.907.11.20446-lnxrhx64/cinstall /zlz/net5.0/cache.reply
读取回复信息,将依次回复以下信息(10秒内回复):
1
cache
/intersystem/cache
Yes
1
2
root
SYS
SYS
SYS
SYS
root
y
n
y
1
Your system type is 'Red Hat Enterprise Linux (x64)'.
Enter instance name <CACHE>: cache
Enter a destination directory for the new instance.
Directory: /intersystem/cache
Directory '/intersystem/cache' does not exist.
Do you want to create it <Yes>? Yes
Select installation type.
1) Development - Install Cache server and all language bindings
2) Server only - Install Cache server
3) Custom
Setup type <1>? 1
Disk blocks required = 3492316
Disk blocks available = 46249336
How restrictive do you want the initial Security settings to be?
"Minimal" is the least restrictive, "Locked Down" is the most secure.
1) Minimal
2) Normal
3) Locked Down
Initial Security settings <1>? 2
What user should be the owner of this instance? root
A Cache account will also be created for user root.
Install will create the following Cache accounts for you:
_SYSTEM, Admin, SuperUser, root and CSPSystem.
Please enter the common password for _SYSTEM, Admin, SuperUser and root: stty: 标准输入: Inappropriate ioctl for device
SYS
stty: 标准输入: Inappropriate ioctl for device
Re-enter the password to confirm it: stty: 标准输入: Inappropriate ioctl for device
SYS
stty: 标准输入: Inappropriate ioctl for device
Please enter the password for CSPSystem: stty: 标准输入: Inappropriate ioctl for device
SYS
stty: 标准输入: Inappropriate ioctl for device
Re-enter the password to confirm it: stty: 标准输入: Inappropriate ioctl for device
SYS
stty: 标准输入: Inappropriate ioctl for device
What group should be allowed to start and stop
this instance? root
Do you want to install Cache Unicode support <No>? y
Do you want to enter a license key <No>? n
Please review the installation options:
------------------------------------------------------------------
Instance name: cache
Destination directory: /intersystem/cache
Cache version to install: 2016.2.3.907.11.20446
Installation type: Development
Unicode support: Y
Initial Security settings: Normal
User who owns instance: root
Group allowed to start and stop instance: root
Effective group for Cache processes: cacheusr
Effective user for Cache SuperServer: cacheusr
SuperServer port: 1972
WebServer port: 57772
JDBC Gateway port: 62972
CSP Gateway: using built-in web server
Client components: all
------------------------------------------------------------------
Do you want to proceed with the installation <Yes>? y
Starting installation...
Starting up Cache for loading...
../bin/cinstall -s . -B -c c -C /intersystem/cache/cache.cpf*cache -W 1 -g2
Starting Control Process
Allocated 94MB shared memory: 2MB global buffers, 35MB routine buffers
Cache startup successful.
System locale setting is 'zh_CN.UTF-8'
This copy of Cache has been licensed for use exclusively by:
License missing or unreadable.
Copyright (c) 1986-2020 by InterSystems Corporation
Any other use is a violation of your license agreement
^^/intersystem/cache/mgr/>
^^/intersystem/cache/mgr/>
Start of Cache initialization
Loading system routines
Updating Cachetemp and Cache database
Installing National Language support
Loading system classes
Updating Security database
Loading system source code
Building system indices
Updating Audit database
Updating Journal directory
Updating User database
Scheduling inventory scan
Cache initialization complete in 1 minute
See the cboot.log file for a record of the installation.
Starting up Cache...
Once this completes, users may access Cache
Starting CACHE
Using 'cache.cpf' configuration file
Starting Control Process
Automatically configuring buffers
Unable to allocate 312 MB shared memory...
Unable to allocate 285 MB shared memory...
Unable to allocate 257 MB shared memory...
Unable to allocate 230 MB shared memory...
Unable to allocate 202 MB shared memory...
Unable to allocate 175 MB shared memory...
Unable to allocate 147 MB shared memory...
Allocated 120MB shared memory: 26MB global buffers, 35MB routine buffers
This copy of Cache has been licensed for use exclusively by:
License missing or unreadable.
Copyright (c) 1986-2020 by InterSystems Corporation
Any other use is a violation of your license agreement
2 alert(s) during startup. See cconsole.log for details.
You can point your browser to http://localhost.localdomain:57772/csp/sys/UtilHome.csp
to access the management portal.
stty: 标准输入: Inappropriate ioctl for device
执行结束
[root@localhost net5.0]#
[root@localhost net5.0]#
[root@localhost net5.0]#
[root@localhost net5.0]#
[root@localhost net5.0]#
[root@localhost net5.0]# cache
Node: localhost.localdomain, Instance: CACHE
Username: _system
Password: ***
USER>h
测试bc命令回复
[root@localhost zlz]# autoreply --help
作为用dotnet对shell的补充工具,实现自动安装软件回复
#查看帮助
autoreply --help
#查看版本
autoreply --vertion
#执行指定命令,用指定文件路径的信息一行行回复
autoreply /zlz/cache-2016.2.3.907.11.20446-lnxrhx64/cinstall /zlz/net5.0/cache.reply
由zlz提供,后期陆续加入shell实现麻烦的功能进来
[root@localhost zlz]# echo "2*3" >> bc.rep
[root@localhost zlz]# echo "2*32" >> bc.rep
[root@localhost zlz]# echo "1024.4" >> bc.rep
[root@localhost zlz]# autoreply bc /zlz/bc.rep
读取/zlz/bc.rep回复信息,将依次回复以下信息(10秒内回复):
2*3
2*32
1024.4
执行:bc命令
2*3
6
2*32
64
1024.4
1024.4
^C执行结束
[root@localhost zlz]# autoreply bc /zlz/bc.rep 2
读取/zlz/bc.rep回复信息,将依次回复以下信息(10秒内回复):
2*3
2*32
1024.4
执行:bc命令
2*3
6
2*32
64
1024.4
1024.4