Linux可执行文件制作

Linux可执行文件制作

背景

测试过程中,需要针对不同的Linux系统、核心服务版本进行验证,各种环境依赖的python版本以及已安装的库存在较大差异,考虑到实际测试需求以及出差现场使用的要求,需要将测试脚本打包为可执行文件,可以最大程度上减少依赖,保障测试程序的可用性和易用性。本文介绍一种利用python的pyinstaller库,将程序打包为可执行文件的方式,脱离自动化工程或复杂的环境配置。后半部分针对一些固有化的实现进行介绍,希望对大家有所帮助。

环境配置

当前使用的编程语言为python3,建议在测试服务器上安装python3,将能够更好地进行兼容。

Python3环境安装问题

  可参考https://wiki.hikvision.com.cn/pages/viewpage.action?pageId=49800240

Pyinstaller安装及使用

安装

(1)方式一:直接用pip安装

pip install pyinstaller

(2)方式二:源码安装

下载pyinstaller安装包后执行以下命令手动安装:

tar -zxvf PyInstaller-3.6.tar.gz

cd PyInstaller-3.6/

python3 setup.py build

python3 setup.py install

如果输入 pyinstaller 命令可以直接使用,那就可以了。

  • 问题1:输入pyinstaller命令提示 command not found

解决方式:复制pyinstaller到/usr/bin/下

cd /usr/local/python3/bin/

cp pyinstaller /usr/bin/.

  • 问题2:python setup.py build报错

  • 解决:需要升级setuotool的版本

wget https://pypi.python.org/packages/41/80/268fda78a53c2629128f8174d2952c7f902c93ebaa2062b64f27aa101b07/setuptools-38.2.3.zip#md5=0ae64455d276ff864b40aca9c06ea7c1

unzip setuptools-38.2.3.zip

cd setuptools-38.2.3

python setup.py install

 

  • 问题3:包依赖关系处理

在linux下安装rpm包的时候发现,安装一个服务需要安装很多rpm包,比如安装apache,最少需要安装3-4个包,当然主包只有一个,其中还有好多依赖关系,甚至会出现循环依赖的“死锁”。为了避免包之间的依赖关系问题,可以采取同时安装所有有关rpm包的方式:

rpm -ivh xx1.rpm xx2.rpm xx3.rpm

 

使用

  Pyinstaller使用方法:

rpm -ivh xx1.rpm xx2.rpm xx3.rpm

 

  • 打包成功后有缺失包

安装时,wheel库通过python setup.py build & python setup.py install 安装失败。需要先将wheel文件下载到本地,然后pip install ...wheel。
资源链接:各种python wheel文件

 

  • 包缺失

问题:python用pyinstaller打包时,打包的py文件中有import paramiko,打好包后的文件执行时提示,No module named paramiko。

解决:添加一个-p的参数。如:

pyinstaller -F xx.py -p paramiko

 

  • Hidden-import

常用关键字及代码

(1)日志输出

当前可执行文件执行,会在控制台输出必要的结果,但对于问题的排查或记录来说还是比较麻烦,为生成便于问题定位及结果记录的日志文件,使用python中的logging模块。

logging模块主要提供了一些函数和类来支持灵活地输出日志,实现日志系统相应的功能,可以使用到应用程序和库里。主要提供了类Logger、Handler、Filter和Formatter。

 

日志总共定义的级别:

 

CRITICAL   50

ERROR     40

WARNING  30

INFO       20

DEBUG     10

NOTSET     0

 

 

使用举例:

# INFO级别输出一条日志。

logging.info(msg, *args, **kwargs)

 

#level级别输出一条日志。

logging.log(level, msg, *args, **kwargs)

 

# 设置那一级别的日志不再输出。

logging.disable(lvl)

(2)解密

def _decode_password(self, encode_password):
   
"""
   
对加密的密码进行处理, jar包实现
   
:return: str
    """
   
java_path = 'jdk1.8.0_161/bin/java'
   
subprocess.getoutput('chmod 777 %s' % java_path)
    cmd = java_path +
' -jar decode.jar'
   
decode_result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
    decode_result.stdin.write(encode_password.encode(
'gbk') + b'\r\n')
    out
, err = decode_result.communicate()
   
try:
        file_context = out + err
        file_context = file_context.decode(
'utf8')
        decode_password =
str(file_context.split("密码:")[1])
        decode_password = decode_password.rstrip(
'\r\n')
        decode_password = decode_password.rstrip(
'\n')
        logging.info(
"the password decoded%s" % decode_password)
        result = decode_password
   
except Exception as e:
        logging.info(
"the password decoded failed")
        logging.debug(e)
        result =
False
    return
result

(3)配置获取(以redis配置获取为例)

def get_conf_redis(self):
   
"""获取redis配置信息"""
   
conf_content = subprocess.getoutput("cat %s/../components/redislinux64.1/conf/config.properties\n" % self.path)
    redis_conf = {}
   
for conf in conf_content.splitlines():
       
# centerdb数据库
       
if conf.find('cache.1.@ip=') >= 0:
            redis_conf[
'redis_ip'] = conf.split('ip=')[-1]
       
elif conf.find('cache.1.port=') >= 0:
            redis_conf[
'redis_port'] = conf.split('port=')[-1]
       
elif conf.find('cache.1.password=') >= 0:
            cas_password = conf.split(
'password=')[-1]
            redis_conf[
'redis_password'] = self._decode_password(cas_password)
   
return redis_conf

(4)在linux上远程其他服务器(以读取文件为例)

def ssh_machine_file_path(self, machine):
   
"""ssh连接,获取文件路径"""
   
# 实例化SSHClient
   
ssh = paramiko.SSHClient()
   
# 自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接
   
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

   
# 连接SSH服务端,以用户名和密码进行认证
   
ssh.connect(hostname=machine[0], port=machine[1], username=machine[2], password=machine[3])
   
# 执行
   
stdin, stdout, stderr = ssh.exec_command('find %s/components/*/conf -type f -name "config.properties"' % self.path)
   
# 打印执行结果
   
result = stdout.read().decode('utf-8')
    result = result.split(
'\n')

   
for i in result[::-1]:
       
if 'fail' in i or i == '':
           
print(i)
            result.remove(i)

    result.append(
'%s/opsMgrAgent/conf/config.properties' % self.path)

   
print(result)
    ssh.close()
   
return result

(5)配置文件处理

def set_section_variables(self, section, dict_value, ini_name='use_dict_ip'):

    """

    写入section的值

    :param section: str

    :param dict_value: dict

    :param ini_name:

    """

    if ini_name == 'use_dict_ip':

        try:

            ini_name = dict_value['bic_ip']

        except KeyError as e:

            raise Exception('dic_has_no_key:%s' % e)

    #config_path = os.path.join(self.service_path, 'variables.ini')

    config = configparser.ConfigParser()

    config.read(self.config_path, encoding='utf-8')

    if not config.has_section(section):

        config.add_section(section)

    for key, value in dict_value.items():

        config.set(section, key, value)

    config.write(open(self.config_path, "w", encoding='utf-8'))



def del_section_variables(self, section):

    config = configparser.ConfigParser()

    config.read(self.config_path, encoding='utf-8')

    if config.has_section(section):

        config.remove_section(section)

    config.write(open(self.config_path, "w", encoding='utf-8'))

环境分享

pyinstaller –F xx.py

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值