剖析组件应用市场的安装

java运维管理平台怎么支持组件的安装呢?怎么能够达到和应用市场一样的效果呢?效果图如下:
应用商店支持的组件列表:
在这里插入图片描述
应用商店组件的安装:
在这里插入图片描述
在这里插入图片描述

1.组件包的制作

1.1 组件包结构

package:用于存放实际组件包安装包,必须有xxx-版本号.tar.gz安装包
scripts:用于存放安装脚本,脚本必须包含install.sh,可以包含初始化脚本init.sh
xxx.svg:应用组件的svg图,如:jdk.svg
xxx.yaml:应用组件基本配置项
xxx.yaml参数说名:

kind(必填): 类型定义,发布基础组件时 ,指定类型为 component (类型:string)
name(必填): 组件在平台显示的名称,请与组件目录名称保持一致,建议字符:英文、数字、_ (类型:string)
version(必填): 上传后显示的组件版本,建议字符: 数字、字母、_ 、. (类型:string)
description: 组件描述信息,建议长度256字符之内,请针对组件书写贴切的描述文字 (类型:string)
labels(必填): 组件所属标签,请针对组件功能设置准确标签,平台会针对该标签对组件进行分类,(类型:list[string,string...]),目前只支持【数据库 中间件 环境组件 服务协调】
auto_launch: 指定该服务安装后是否需要启动 (类型:boolean)
base_env: 指定组件是否为基础环境组件,如 jdk, 该类组件以基础环境方式安装 (类型:boolean)
ports: 定义组件所需端口号,如不启用端口,可留空 (类型:list[map,map...])
monitor: 组件监控相关配置,定义该组件在安装后如何监控 ,如果不需要监控可留空 (类型: map)
install(必填): 定义安装组件时所需参数,该参数会传入到 安装脚本中 (类型:list[map,map...]name: 传入参数中文描述名称,该名称会在用户安装组件时显示到表单中 (类型: string)key: 传入参数key值,会将该key与值 传入到安装脚本中 (类型:string)default: 上面key默认值 (类型: stirng)

1.2 package下xx-版本号.tar.gz结构

conf:存放组件包自定义的配置
lib:存放组件包jar包
app.sh(必须存在):用于启动、停止、重启服务命令
在这里插入图片描述

1.3 组件包制作示例

1.3.1 package改造

安装包需要打包成tar.gz安装包,安装包必须包含app.sh和lib目录里。
lib是组件的jar包
conf是组件所需的配置信息
app.sh是启动组件的执行脚本;(此脚本示例只适用于java -jar的启动,其他非springboot项目不适用,如果有自己自动脚本的可以参考这个进行改造app.sh的内容)

#!/bin/sh
PRG="$0"while [ -h "$PRG" ] ; dols=`ls -ld "$PRG"`link=`expr "$ls" : '.*-> \(.*\)$'`if expr "$link" : '/.*' > /dev/null; thenPRG="$link"elsePRG=`dirname "$PRG"`/"$link"fi
donePRGDIR=`dirname "$PRG"`SERVICE_HOME=`cd "$PRGDIR" >/dev/null; pwd`
SERVICE_PID=$SERVICE_HOME/pid
JAVA_OPTS="-Xms128m -Xmx128m"start() {echo "Waiting for service start ...."nohup java $JAVA_OPTS -jar $JAVA_OPTS $SERVICE_HOME/lib/agent-*.jar --spring.config.location=$SERVICE_HOME/config/application.properties > /dev/null 2>&1 &pid=$!echo $pid > $SERVICE_HOME/pidsleep 5checkPidAliveif [[ (( $? -eq 0 )) ]]; thenecho "Service started(pid=$pid)!"exit 0elseecho "Service failed to start!"exit 1fi
}stop() {echo "Waiting for service stop ...."  for i in `ls -t $SERVICE_PID 2>/dev/null`doread pid < $i# 判断进程号是否存在if ps -p $pid > /dev/null 2>&1; thenkill  "$pid"sleep 5checkPidAliveif [[ (( $? -eq 0 )) ]]; thenecho "Service failed to stop!"exit 0elseecho "" > $iecho "Service stoped(pid=$pid)!"exit 1fielseecho "" > $iecho "Service has bean stoped!"return 0fidone
}status() {checkPidAliveif [[ (( $? -eq 0 )) ]]; thenecho '{"status":"UP"}'exit 0elseecho '{"status":"DOWN"}'exit 1fi
}checkPidAlive() {for i in `ls -t $SERVICE_PID 2>/dev/null`doread pid < $i# 判断进程号是否存在if ps -p $pid > /dev/null 2>&1; thenreturn 0elsereturn 1fidonereturn 1
}# See how we were called.
case "$1" instart)start;;stop)stop;;restart)stopstart;;status)status;;*)echo $"Usage: $0 {start|stop|restart|status}"exit 1
esac
1.3.2 scripts改造

存放install.sh主要是解压package中的安装包到对应目录

#!/bin/bashcd "$(dirname $0)"arg="$1"
if test $# -lt 1; thenecho -e "缺少参数"exit 1
fi# 获取解压后文件名
Get_untar_name() {local src_tar_path=$1local untar_raw_install_package_nameif [ ! -f "$src_tar_path" ]; thenecho -e "压缩文件${src_tar_path}不存在"exit 1fiuntar_raw_install_package_name=$(timeout 2 tar tf "$src_tar_path"  | tail -n 1 | tr '/' ' '| awk '{print $1}')if [ "$untar_raw_install_package_name" = "" ]; thenecho "解压${src_tar_path}错误"fiecho "$untar_raw_install_package_name"
}IFS="," read -r -a all_param <<< "$arg"
for param in "${all_param[@]}"; do param=$(echo "$param" | sed 's/^[ \t]*//g' | sed 's/[ \t]*$//g')if [ "$param" = "" ]; thencontinuefivalue=$(echo "${param}" | sed -n "s/^[ |        ]*base_dir[ | ]*=[ |   ]*\(.*\)[ |     ]*/\1/p")    if [ "$value" != "" ]; then base_dir="${value}";breakfi
donemkdir -p "${base_dir}"
tar_file="../package/agent.tar.gz"
untar_name=$(Get_untar_name $tar_file)
install_dir="${base_dir}/${untar_name}"
tar xf $tar_file -C "$base_dir" 
echo "install_dir=$install_dir"
1.3.3 xxx.yaml改造
# 类型定义,发布基础组件时 ,指定类型为 component (类型:string)
kind: component
# 组件在平台显示的名称,请与组件目录名称保持一致,建议字符:英文、数字、_ (类型:string)
name: adfs-server
# 上传后显示的组件版本,建议字符: 数字、字母、_ 、. (类型:string)
version: "2.6.1"
# 组件描述信息,建议长度256字符之内,请针对组件书写贴切的描述文字 (类型:string)
description: "文件网关组件,主要用于文件节点间的传输功能"
# 组件所属标签,请针对组件功能设置准确标签,平台会针对该标签对组件进行分类,(类型:list[string,string...])
labels:- "环境组件"
# 指定该服务安装后是否需要启动 (类型:boolean)
auto_launch: false
# 指定组件是否为基础环境组件,如 jdk, 该类组件以基础环境方式安装 (类型:boolean)
base_env: 
# 定义组件所需端口号,如不启用端口,可留空 (类型:list[map,map...])
ports:
# 组件监控相关配置,定义该组件在安装后如何监控 ,如果不需要监控可留空 (类型: map)
monitor:
# 定义安装组件时所需参数,该参数会传入到 安装脚本中 (类型:list[map,map...])
install:# 传入参数中文描述名称,该名称会在用户安装组件时显示到表单中 (类型: string)- name: "安装目录"# 传入参数key值,会将该key与值 传入到安装脚本中 (类型:string)key: base_dir# 上面key默认值 (类型: stirng)default: "{data_path}/adfs"  # 注: {data_path} 为主机数据目录占位符,请勿使用其他代替
# 定义该组件安装所需依赖组件名称与版本,如不需其他组件依赖,可留空 (类型: list[map,map..])
dependencies:- name: javaversion: 1.8.0_201
# 该组件所需最小资源需求 (类型:map)
# 定义安装组件时所需参数,该参数会传入到 安装脚本中 (类型:list[map,map...])
install:# 传入参数中文描述名称,该名称会在用户安装组件时显示到表单中 (类型: string)- name: "安装目录"# 传入参数key值,会将该key与值 传入到安装脚本中 (类型:string)key: base_dir# 上面key默认值 (类型: string)default: "{data_path}/app/adfs"  # 注: {data_path} 为主机数据目录占位符,请勿使用其他代替- name: "日志目录"key: log_dirdefault: "{data_path}/logs/adfs"- name: "数据目录"key: data_dirdefault: "{data_path}/appData/adfs"

1.4 打包成组件包

将制作的包用cmd命令在组件包外层执行tar 打成tar.gz包,上传到应用市场即可

tar -zcvf xxx.tar.gz xxx

1.5 组件包安装核心代码

	boolean executeInstallShell(ComponentConfigRecordPO record, ComponentInstallPO install, ComponentPO componentPO) {//TODO 这里主机密码需要从主机表中获取并解密FileInfoPO fileInfoPO = fileInfoService.getBaseMapper().selectById(componentPO.getFileId());if (fileInfoPO == null) {throw new BusinessException(AppComponentResponseCode.FILE_NOT_FOUND, componentPO.getFileId());}File temp = fileInfoService.loadFileToTemp(fileInfoPO.getFileId(), fileInfoPO.getName());record.setDataChangeCreatedTime(LocalDateTimeUtil.now());String remoteFilePath = JschUtils.formatUserPath(record.getInstallUser()) + record.getInstallPath() + StrUtil.C_SLASH + componentPO.getInstallPackageName();Session session = JschUtil.openSession(record.getIp(), 22, record.getInstallUser(), record.getInstallPassword());log.info("成功连接到主机{}", record.getIp());String result = JschUtil.exec(session, "mkdir -p " + JschUtils.formatMkdirPath(record.getInstallPath()), Charset.defaultCharset());log.info("开始发送组件包到主机{}", record.getIp());try {JschUtils.uploadFile(record.getIp(), record.getInstallUser(), record.getInstallPassword(), 22, temp.getAbsolutePath(), remoteFilePath);} catch (Exception e) {log.info("开始发送组件包到主机{}发生异常,安装失败", record.getIp());record.setDataChangeLastModifiedTime(LocalDateTimeUtil.now());          configRecordMapper.updateById(record);return false;}log.info("接收组件安装包到主机{}成功", record.getIp());result = JschUtil.exec(session, "tar -zxvf " + JschUtils.formatUserPath(record.getInstallUser()) + record.getInstallPath() + StrUtil.C_SLASH + componentPO.getInstallPackageName(), Charset.defaultCharset());log.info("开始解压组件安装包{}成功", componentPO.getInstallPackageName());log.info("开始执行组件安装脚本");result = JschUtil.exec(session, "sh " + JschUtils.formatUserPath(record.getInstallUser()) + StrUtil.C_SLASH + componentPO.getComponentName() + StrUtil.C_SLASH + Const.APP_COMPONENT_INSTALL + " base_dir=" + JschUtils.formatUserPath(record.getInstallUser()) + record.getInstallPath(), Charset.defaultCharset());log.info("执行组件安装脚本成功");String cmd = "source /etc/profile && sh cmd start;sh " + JschUtils.formatUserPath(record.getInstallUser()) + record.getInstallPath() + StrUtil.C_SLASH + componentPO.getComponentName() + StrUtil.C_SLASH + Const.APP_INSTACE_RESTART_SHELL;log.info("开始执行组件启动脚本:{}", cmd);result = JschUtil.exec(session, cmd, Charset.defaultCharset());log.info("执行组件启动脚本成功");log.info("主机{}安装组件【{}】结束", record.getIp(), install.getComponentName());JschUtil.close(session);record.setDataChangeLastModifiedTime(LocalDateTimeUtil.now());//安装完成之后更新安装状态record.setStatus(ComponentInstallStatusEnum.INSTALL_SUCCESS.getValue());configRecordMapper.updateById(record);//4 安装实例表入库  【注意】安装成功才有实例,失败没有实例createServiceInstance(record, install, componentPO);return true;}

完整代码需要后续整理之后会上传码云,到时候也会同步更新到文章中,尽请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/640200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL进阶】SQL优化

文章目录 SQL 优化主键优化数据组织方式页分裂页合并主键设计原则 insert优化order by优化group by优化limit优化count优化 SQL 优化 主键优化 数据组织方式 在InnoDB存储引擎中&#xff0c;表数据都是根据主键顺序组织存放的&#xff0c;这种存储方式的表称为索引组织表 在In…

数据结构Java版(4)——链表

一、概述 链表是一种常见的数据结构&#xff0c;用于存储一系列具有相同类型的数据元素。它由多个节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。 链表与数组不同&#xff0c;它的节点在内存中不是连续存储的&#xff0c;而是通过每个节点中的指针…

测试C#调用OpenCvSharp和ViewFaceCore从摄像头中识别人脸

学习了基于OpenCvSharp获取摄像头数据&#xff0c;同时学习了基于ViewFaceCore的人脸识别用法&#xff0c;将这两者结合即是从摄像头中识别人脸。本文测试测试C#调用OpenCvSharp和ViewFaceCore从摄像头中识别人脸&#xff0c;并进行人脸红框标记。   新建Winform项目&#xf…

OpenSource - 文件在线预览模块(多格式转 PDF 文件)

文章目录 文件在线预览模块&#xff08;多格式转PDF文件&#xff09;现已支持格式如下界面展示运行方式接口介绍文件上传文件转 PDF文件转图片文件转SVG 参数配置其他说明项目关联关键词文档转换预览技术说明同步转换异步转换 主要技术乱码问题处理帮助文档 前端预览弹出层用法…

整除的特征及解释

整除的特征及解释 整除的含义 简单地说&#xff0c;当一个非零整数除另一个整数得到整数商而没有余数时&#xff0c;叫做整除。如62&#xff1d;3&#xff0c;就说2整除6或6能被2整除。 用数学语言描述&#xff1a;若整数b除以非零整数a&#xff0c;商为整数&#xff0c;且余…

zookeeper弱密码漏洞修复

1.连接zookeeper 进入zookeeper安装目录 bin目录下 ./zkCli.sh -server IP:21812.查看节点 ls /3.查看节点权限 getAcl /zookeeper4.设置IP权限 setAcl / ip:127.0.0.1:cdrwa,ip:10.86.30.11:cdrwazookeeper的权限不具备继承性,父子节点的权限相互独立,因此需要为每个子…

11- OpenCV:自定义线性滤波(卷积,卷积边缘)

目录 一、卷积 1、卷积概念 2、卷积如何工作 3、常见算子&#xff08;卷积核 Kenel&#xff09; 4、自定义卷积模糊 5、代码演示 二、卷积边缘 1、卷积边缘问题 2、处理边缘 3、相关的API说明 4、代码演示 一、卷积 1、卷积概念 &#xff08;1&#xff09;在OpenC…

生成当天递增唯一的流水号的几种方式

说明&#xff1a;当开发中&#xff0c;如交易、文件传输过程中的文件名&#xff0c;可能需要我们使用一串唯一的数字来锁定这一条“交互记录”&#xff0c;即流水号。 本文介绍几种生成6位递增唯一&#xff0c;且每日重置的流水号的方式。 方式一&#xff1a;使用Redis 我们…

SpringSecurity(11)——核心组件和认证流程

获取用户信息 // 获取安全上下文对象&#xff0c;就是那个保存在 ThreadLocal 里面的安全上下文对象 // 总是不为null(如果不存在&#xff0c;则创建一个authentication属性为null的empty安全上下文对象) SecurityContext securityContext SecurityContextHolder.getContext(…

微信轰炸-python实现方法

新手&#xff0c;一般都需要执行以下命令&#xff0c;用来导入对应模块 pip install -i Simple Index pynput 键盘winr进入输入cmd 执行该命令即可&#xff1a;pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pynput 打开pycharm,输入代码如下 from pynput.keybo…

AI视频智能识别技术在智慧农业大棚升级改造管理场景中的应用方案

一、需求分析 随着科技的进步和农业现代化的推进&#xff0c;智能化技术逐渐成为现代农业发展的重要支撑。农业大棚作为现代农业的重要组成部分&#xff0c;其智能化改造对于提高农业生产效率、降低成本、增加收益具有重要意义。利用先进的信息化手段来对农业大棚进行管理&…

NOC总线(2)

1. NoC的路由 在NoC交换信息时&#xff0c;需要确定从源节点到目标节点所经过的路径&#xff0c;这时就需要路由算法来确定该路径。路由算法分为静态路由算法和动态路由算法两种。 静态路由算法对于两节点之间的路径是固定的&#xff0c;结构简单&#xff0c;便于硬件实…

【算法分析与设计】二叉树的层序遍历

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xf…

idea插件开发

1&#xff0c; file-new project 如图&#xff0c;选择了安装路径&#xff0c;报错【select home directory for intellij platform plugin sdk】。&#xff08;注意是安装路径最外层的文件夹&#xff0c;不是里面的lib&#xff0c;jbr这一层级&#xff09; 2&#xff0c;点击了…

HTML前端CSS实现只显示1行或者2行、3行剩余显示省略号

想要做的效果: 文本只一行显示 /**实现思路&#xff1a;1.设置inline-block属相2.强制不换行3.固定高度4.隐藏超出部分5.显示“……”*/ {display: inline-block;white-space: nowrap; width: 100%; overflow: hidden;text-overflow:ellipsis; }文本只多行显示 /** 实现思路&…

【Java发送邮箱】spring boot 发送邮箱

导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency> 2.在properties配置邮箱 # 发件人QQ号 spring.mail.username2508575653qq.com # QQ邮箱授权码 sp…

xshell配置隧道转移规则

钢铁知识库&#xff0c;一个学习python爬虫、数据分析的知识库。人生苦短&#xff0c;快用python。 xshell是什么 通俗点说就是一款强大ssh远程软件&#xff0c;可以方便运维人员对服务器进行管理操作&#xff0c;功能很多朋友们自行探索&#xff0c;今天只聊其中一个功能点那…

HNU-数据挖掘-实验2-数据降维与可视化

数据挖掘课程实验实验2 数据降维与可视化 计科210X 甘晴void 202108010XXX 文章目录 数据挖掘课程实验<br>实验2 数据降维与可视化实验背景实验目标实验数据集说明实验参考步骤实验过程1.对数据进行初步降维2.使用无监督数据降维方法&#xff0c;比如PCA&#xff0c;I…

既是API调试平台也是自动化测试工具?Apipost

Apipost提供可视化的API自动化测试功能&#xff0c;使用Apipost研发人员可以设计、调试接口&#xff0c;测试人员可以基于同一数据源进行测试&#xff0c;Apipost 接口自动化功能在上次更新中进行了逻辑调整&#xff0c;带来更好的交互操作、更多的控制器选择&#xff0c;同时新…

SpringMvc中拦截器的配置及应用

拦截器原理 在 Spring MVC 中&#xff0c;拦截器&#xff08;Interceptor&#xff09;是一种机制&#xff0c;用于拦截请求并在处理程序&#xff08;Controller&#xff09;执行之前或之后执行一些操作。拦截器允许您在请求的不同阶段&#xff08;如处理程序执行前、处理程序执…