OS X下让supervisor开机启动,以及权限、环境变量、codesign问题

项目使用到一套自己搭建的web操作平台。该平台用python+flask+redis+git+svn进行自动化操作。其启动脚本采用的是supervisor来管理。

今天想让开机自动运行supervisor,于是进行了一番尝试。
¶我们的目标

当然,不是“没有蛀牙”。

下文模拟的目标是

系统启动时 无需 登陆,用supervisord启动某supervisord.conf。
看似很简单,其实踩了不少坑。

添加plist脚本

sudo vim /Library/LaunchDaemons/com.agendaless.supervisord.plist

复制以下内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
    </dict>
    <key>Label</key>
    <string>com.agendaless.supervisord</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/supervisord</string>
        <string>-n</string>
        <string>-c</string>
        <string>/etc/supervisord.d/supervisord.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

接着注册plist

sudo launchctl load /Library/LaunchDaemons/com.agendaless.supervisord.plist

重启之后就发现可以自动运行了。
But, 事情哪有那么简单
首先解答下为何放在这个目录,以及agent和daemon的区别
根据apple文档,plist文件可以存在于如下几个地方:

类型 位置 执行条件
用户的agent ~/Library/LaunchAgents 当前登录的用户
全局agent /Library/LaunchAgents 当前登录的用户
全局Daemons /Library/LaunchDaemons root 或者用User制定的用户
系统agent /System/Library/LaunchAgents 当前登录的用户
系统daemon /System/Library/LaunchDaemons root 或者用User制定的用户

Agent和Daemon最大的区别在于,Agent是需要用户登录才能触发,Daemon是不需要用户登录。
这样,排除system用的目录,只剩下全局Daemons(Global agent),也就是/Library/LaunchDaemons了。
But, 事情哪有那么简单
这样启动supervisor之后,是默认用的root用户启动。所以,当你的脚本中有用到类似于Python中os.path.expanduser('~')的命令时,其实你拿到的是/Users/root。
这一定不是你想要的结果。
根据supervisor的文档,你可以指定user

[program:test]
user=yourname

But, 事情哪有那么简单
查看supervisor的源代码,这个命令只是把进程移交给了这个user。
os.path.expanduser('~')这种命令,是获取的环境变量$HOME。而user=yourname并不会影响任何环境变量。没错,现在os.path.expanduser('~')的结果应该还是/Users/root,但是如果你执行print os.system("whoami") 那就会是yourname。

so? byebye supervisor。 我转而查找launchd的方法。
launchd这个玩意是mac用来替代cron的。我想,一定不会太挫吧。于是在开发文档中又看到:

UserName <string>
This optional key specifies the user to run the job as. This key is only applicable when launchd is running as root.

哦,只在root触发时才有用。没问题。另外也发现了UserGroup这个key,大同小异。那我们加上:
在/Library/LaunchDaemons/com.agendaless.supervisord.plist中最外层dict里面添加:

<key>UserName</key>
<string>yourname</string>
<key>GroupName</key>
<string>staff</string>

然后直接暴力sudo reboot(其实也可以先用launchctl unload com.agendaless.supervisord.plist再launchctl load com.agendaless.supervisord.plist)
ok,程序进来了,一切ok。os.path.expanduser('~')也对了。
But, 事情哪有那么简单
可能到这儿对大多数人都没问题了。但是我的程序是要用这套东西build ios和android的游戏。
命令中有一句,xcodebuild,是在一个Makefile中,这个Makefile的执行,是靠os.system执行。
当程序跑到这里时,会报出错误:

[BEROR]Code Sign error: Provisioning profile does not match bundle identifier: The provisioning profile specified in your build settings (“farm_dev”) has an AppID of “com.wemomo.game.farm” which does not match your bundle identifier “com.ejoy.test.farm”.

[BEROR]CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 8.4'
根据网上内容,可能由于钥匙串没有解锁。所以我们用

os.system('security unlock -p "pwd" ~/Library/Keychains/login.keychain')
os.system('security set-keychain-settings -t 3600 -l ~/Library/Keychains/login.keychain')
来解锁。

可是错误依旧存在
搜了搜,可以强制导入某程序可用的key,用security import后加参数-T

os.system('security import login.keychain -P "pwd" -T /usr/bin/codesign')

依然不行。我差点就放弃了。可是我看到了这篇回复。

回复中说:

我通过添加SessionCreate这个key到org.jenkins-ci.plist中去解决了这个问题。
抱着试一试的心态,我也添加了。终于,成功了。
最后,我的plist是这样的

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>EnvironmentVariables</key>
    <dict>
        <key>ANDROID_NDK_DIR</key>
 <string>/Users/farmbuilder/android/android-ndk-r9d</string>
        <key>ANDROID_TOOLS_DIR</key>
 <string>/Users/farmbuilder/android/android-sdks/tools</string>
    </dict>
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
    </dict>
    <key>Label</key>
    <string>com.agendaless.supervisord</string>
    <key>ProgramArguments</key>
    <array>
 <string>/usr/local/bin/supervisord</string>
        <string>-n</string>
        <string>-c</string>
        <string>/Users/farmbuilder/Projects/packer/supervisord.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>farmbuilder</string>
    <key>GroupName</key>
    <string>staff</string>
    <key>SessionCreate</key>
    <true />
</dict>
</plist>

可以看到,我使用了EnvironmentVariables来添加环境变量。这个效果,可以等同于在supervisord.conf文件中的[supervisord]段添加environment=ANDROID_NDK_DIR="/Users/farmbuilder/android/android-ndk-r9d", ANDROID_TOOLS_DIR ="/Users/farmbuilder/android/android-sdks/tools"。
那么,SessionCreate是什么东西?

在官方文档中,有这么几行字

sshd is a launchd daemon with the SessionCreate property set, which means that it runs in its own bootstrap namespace. Once a user logs in, the launchd PAM session module (/usr/lib/pam/pam_launchd.so, as configured by /etc/pam.d/sshd) moves the bootstrap namespace to within the appropriate per-user bootstrap namespace.
Uses the global bootstrap namespace unless the SessionCreate property is specified in the property list file, in which case the daemon runs in its own per-session bootstrap namespace.
Uses the global security context unless the SessionCreate property is specified in the property list file, in which case the daemon runs in its own per-session security context
Context Cross Refrence

原来,mac系统没用户登录时创建的namespace是叫做一个global bootstrap,当有用户登录时,sshd就会启动,sshd会创建用户自己的namespace, 并替代global bootstrap成为当前的namespace(security context 安全内容也如此,包含我们用到的codesign)。由于我们是创建的launchd daemon,如果不添加SessionCreate,那么默认是会用global bootstrap的。这个namespace,是肯定不会有我们的security context以及namespace的。

时间: 2024-10-30 08:38:34

OS X下让supervisor开机启动,以及权限、环境变量、codesign问题的相关文章

ubuntu-Ubuntu下如何每次开机启动运行/home/test.sh脚本

问题描述 Ubuntu下如何每次开机启动运行/home/test.sh脚本 Ubuntu下如何每次开机一启动就运行/home/test.sh脚本 解决方案 /etc/init.d/rc.local中添加上你的脚本完整路径. 解决方案二: 使用下面的命令在启动目录创建一个链接 ln -s /etc/rc.d/init.d/ /home/test.sh //建立软连接快捷方式 当然要确保脚本可执行,可以使用chmod +x命令设置

02_Weblogic课程之安装篇:RedHat下JDK安装,RedHat下Weblogic安装,目录结构,环境变量设置

 1  Weblogic的安装方式有三种: 一.GUI方式安装    (java –jar wls1035_generic.jar [-mode=gui])这是默认的 二.Console方式安装   (java –jar wls1035_generic.jar –mode=console) 三.Silent方式安装(静默方式) :这种方式不需要认为干预,默认安装的,适合作集群的时候使用,需要一个配置文件    (java –jar wls1035_generic.jar –mode=sile

OS X 下指定网页开机自启动

  众所周知,OS X 的开机启动项可以通过"系统偏好设置 - 帐户 - 登录项"进行设置.不过,你是否知道利用这个设置你甚至可以在开机时打开指定网页.对于每天打开电脑后需要浏览一些特定网站的朋友,这将是一个很棒的小贴士,而且它对于任何浏览器都有效. 将您要设置的网页地址从浏览器地址栏拖拽到桌面 将生成的 .webloc 文件保存到一个你喜欢的位置 打开系统偏好设置(System Preferences) - 帐户(Accounts) - 登录项(Login Items) 点击 + 按

mac下设置redis开机启动方法步骤_Redis

概述 装了redis有一段时间了,每次运行的时候都需要手动在命令行里启动redis,而且窗口不能关闭,感觉很麻烦,所以就想把redis设置为开机启动.由于google打不开(伟大的GFW啊),所以百度了几篇文章,照着教程一步一步做还是没有成功,怪自己太笨了. 这两天自己搭建了一个VPN,又能用google了,所以把这个问题解决了下,现在redis终于能开机启动了,High一下. 要设置redis开机启动,这里我使用的是mac的launchd系统,将redis作为用户守护(User Daemon)

win7 64位纯净版系统下怎么设置开机启动放大镜

  1.首先点击win7 64位纯净版系统桌面上的"开始--控制面板--轻松访问中心"; 2.在打开的"轻松访问中心"窗口中,找到并点击窗口下方的"使计算机更易查看"选项; 3.然后在出现的界面中,找到并勾选"启动放大镜",然后点击"确定"保存即可,这样就可以开机启动放大镜了,如果想要关闭放大镜开机自启动的话就可以将其取消勾选即可.

安卓开发-安卓应用无法开机启动

问题描述 安卓应用无法开机启动 最近在做一个电视看板.安装在安卓智能电视,或者电视盒子上.要求开机启动Activity. 收听开机广播的权限加了,receiver也已经声明.测试手机是Color os的一加手机.已经 将应用设置为开机启动项,但是收听不到开机广播,无法开机启动. 请问面对不同的定制系统该怎么做? 解决方案 Android 3.1之后,加入了一个Application的Stop State机制,如果App是这种状态,BOOT__COMPLETED是收不到, Application的

开机启动项中有好多选项,哪些选项可以关,哪些不能关

1.开机启动项,就是开机的时候系统会在前台或者后台运行的程序,一般我们主要说的是Windows系统电脑的开机启动项.   开机启动项设置常使用两种方法:一是系统下启用/禁用开机启动,二则是通过软件本身设置是否开机启动.   2.启动项全部都屏蔽不会影响系统的启动,只是会导致一些程序无法自动运行,需要手动开启.   下面介绍不同系统下启动项屏蔽的方法,和哪些启动项不建议屏蔽.   方法一:系统下调出"系统配置实用程序"功能,启用/禁用启动项:   Windows XP系统:   1.点击

java-linux下tomcat突然无法启动了

问题描述 linux下tomcat突然无法启动了 Java环境正确,可以正常编译运行Java程序,但是tomcat就是启动不了,都是直接从官网下载的 查了一下端口是被tomcat占用,但是就是curl不出来 参照@Davidtsang的方式试了依然不行 解决方案 查了一下端口是被tomcat占用,但是就是curl不出来 解决方案二: ps -ef |grep java kill -9 进程号 ./start.up 解决方案三: 那在Windows是否能正常启动呢??还是下面这种情况可以处理你的h

linux的几个内核镜像格式Image 和 u-boot启动内核和文件系统时的一些环境变量的设置

关于编译powerpc linux的几个Image参考原文 http://blog.sina.com.cn/s/blog_86a30b0c0100wfzt.html 转载▼   PowerPC架构 Linux和ARM,X86等平台有些差异,PowerPC平台HW参数不是通过命令行方式传递到Linux,而是通过传递Device tree文件的方式传递参数,所以PowerPC平台Linux需要编译dtb和uImage才能正常加载,另外PowerPC架构linux还提供simpleImage的方式加载