前言
越来越多的需求无法单纯的用shell来实现了,或者用shell不如用Python来实现。因为Python中的列表和字典真的是非常非常的常用以及好用。而我这里有一个需求,先从yaml或者json中获取我要的值,然后通过Python二开kubernetes(其实就是调用一些库来拿到k8s集群上我想要的东西定制化一下),获取k8s集群上我需要的数据,然后这部分数据要在GitLab CICD中配合前面从yaml或者json取到的数据做判断(当然逻辑不是这么简单,相对复杂)。那么我从yaml或者json中获取到的数据最好是用一个env的形式传进Python脚本,循环、判断结束后,然后在Linux系统上设置一个env,让GitLab CI的pipeline中获取到这个env,然后判断是否要继续pipeline还是中断这个pipeline。
方法一、通过export key=value方式设置环境变量
提示: 该方法没有用,并不会生效
|
|
方法二、通过向宿主机/etc/profile文件添加
提示: 该方法没有用,并不会生效
|
|
可以看到文件是追加进去了,但是却没有生效,也许是我的方式不对,不应该就os.popen?然后手动执行就生效了。
方法三、通过os.environ[‘key’] = ‘value’的方式设置环境变量
提示: Python脚本中可以获取到变量值,但是Python脚本结束后在命令行终端就无法获取到了
|
|
可以看到执行脚本后直接echo输出变量时拿不到变量值的
原因分析
对于环境变量的设置来说,Python直接执行export NAMESPACE=paas
是无法设置成功的,设置方法可以通过os.environ['NAMESPACE'] = 'paas'
来设置,但是由于Python运行是启动新的进程,设置的环境变量只在该进程内有效,所以set_env.py
执行完毕后也无法再获取到设置的环境变量。
解决方法
当我们直接在命令行或者shell中执行export NAMESPACE=paas
是可以成功设置的,也就是说在标准输出中执行该命令是可以设置为session级别的环境变量(其实也是进程级别,在shell中在启动进程就属于该shell的子进程是可以继承父进程的环境变量),所以可以通过echo $NAMESPACE
命令再次查到结果。
比如:
|
|
所以,如果我们要通过Python脚本来设置Linux上的环境变量,并且可以让通过Python脚本设置的环境变量在Linux系统上能被shell命令拿到,那么我们就可以将export的命令重定向到标准输出即可,在Python中最简单的重定向到标准输出就是print了。
方法四、更改脚本,实现Python设置Linux上的环境变量
提示: 这个方法能够做到,但是当你Python脚本中逻辑复杂,有很多变量、注释、调用了操作系统上的命令以及有很多print等,那么则可能会出现误判。因此那种复杂场景不是很建议用这种方式。
先简单说一下eval命令:
格式:
eval command-line
command-line就是在终端上输入的一条命令。但是在这条命令的前面加了一个eval命令时,他的结果就是shell在执行命令之前扫描它两次。
例子1:
|
|
解释:这里第一次进行扫描时,会替换出pipe的值,也就是管道符"|",然后eval再次扫描命令行,这时候shell就把 | 作为了管道符进行命令执行。
也就是说:如果变量中包含任何需要shell直接在命令行中看到的字符(不是替换的结果),就可以使用eval。命令行结束符(;| &),I/o重定向符(< >)和引号就属于对shell具有特殊意义的符号,必须直接出现在命令行中。
例子2:
|
|
可以看到,第一遍扫描后,shell把反斜杠去掉了。当shell再次扫描该行时,它替换了$3的值,并执行echo命令,输出了18
再来说我们的原先的话题,如下:
|
|
可以看到,在方法四种,我们的需求就实现了。
那么针对我的需求,我就可以用这种方式在Linux系统上设置一个环境变量,然后执行脚本结束后,捕获到我需要的变量,然后判断变量就可以知道是否需要去强制中断我的pipeline还是让pipeline继续运行了。
但是这里会有一个问题,就是用了eval命令。eval命令会两次解析脚本,如果脚本中有过多且过于复杂的变量,那么很有可能误操作,因此这种需求下还是要慎用这个方式。
方法五、用shell获得Python的print的值(类似方法四)
和方法四有点类似,也是想要通过shell来获取Python的print的值。如果打印1,表示我要退出pipeline,如果打印为0,则表示正常执行pipeline,但是这个也会有一定的问题。如下:
|
|
这种情况下是没有问题的,但是你要考虑另一种问题,因为可能存在很多次循环,如果第一次循环打印1,第二次循环打印了0,然后循环结束了,最终打印了1又打印了0。那这个怎么算?算最后一次的0那就不会中断pipeline了,那算第一次的1?这种明显是有逻辑问题。正常来说我们获取到Python中打印的1就是要告诉pipeline退出流水线的。
如下:这是我实战的脚本,但是里面就是因为存在多次循环,都拿到了1,所以这里赋值给变量的时候出现了两个1,此时shell判断就产生了误判,变成了nothing to do!
,而实际上他是1,应该退出pipeline的。
|
|
因此这个方式不是很好,适用于只有一个返回值的情况,才不会误判。
方法六、终极大招,用退出码 sys.exit()
前面的5种方法都不行,那难道没办法了吗?这个需求做不了了?其实可以换一种思路,我们使用退出码来作为信号标识。
执行sys.exit()
语句会直接退出程序,这也是经常使用的方法,也不需要考虑平台等因素的影响,一般是退出Python程序的首选方法。该方法中包含一个参数status,默认为0,表示正常退出,也可以为1,表示异常退出。
注意: 要先在Python脚本中import sys
导入模块才能使用sys.exit()
哦!
例子如下:
|
|
以上方法六可知,通过echo $?
这样就拿到了它的退出状态码。当退出码为1时,表示我要让整个pipeline退出了。为0,则什么都不做,继续执行pipeline。
此时通过方法六,我们的需求就达到了!这也是目前来说一个比较好的方式!
退出GitLab CICD的pipeline的方式:在stage中使用 exit 1
即可,如下:
|
|
----- 本页内容已结束,喜欢请分享并注明原文链接 -----