There is some new glue in Lion Server to help manage infrastructure sharing between services, mostly targeted at web-related services referred to as web apps. This post aims to shed a bit of light on the ‘web apps’ layer to see how it interacts with the server admin tools and with launchd.
Much of what you need to know can be found in the man pages for webappctl and webapp.plist (the man page links only work on Lion Server). I won’t repeat what’s already there; go read them ;)
Going backwards
First, let’s take a look at a fairly vanilla config to demonstrate how to work backwards from a webapp configuration to find who / what it is. On a server with no (visibly configured) services enabled, let’s use webappctl to get a list of the web apps that are loaded:
bash-3.2# webappctl status - web:webAppState:_array_index:0:state = "RUNNING" web:webAppState:_array_index:0:virtualHostName = "" web:webAppState:_array_index:0:webAppName = "com.apple.webapp.ACSServer"
What is this ACSServer? Looking at the com.apple.webapp.ACSServer.plist, we see:
bash-3.2# /usr/libexec/PlistBuddy -c print \ /etc/apache2/webapps/com.apple.webapp.ACSServer.plist Dict { name = com.apple.webapp.ACSServer proxies = Dict { /AccountsConfigService/api/ = Dict { urls = Array { http://localhost:31415/AccountsConfigService/api } path = /AccountsConfigService/api/ } } sslPolicy = 1 requiredModuleNames = Array { mod_rewrite.so } includeFiles = Array { /etc/apache2/httpd_ACSServer.conf } launchKeys = Array { com.apple.AccountsConfigService } }
The “launchKeys” entry specifies the name of the associated launched job, com.apple.AccountsConfigService, so let’s look at that:
bash-3.2# /usr/libexec/PlistBuddy -c print \ /System/Library/LaunchDaemons/com.apple.AccountsConfigService.plist Dict {
Program = /usr/libexec/scsd OnDemand = true Disabled = true Sockets = Dict { Listeners = Array { Dict { SockFamily = IPv4 SockNodeName = 127.0.0.1 SockServiceName = 31415 SockType = stream } } } UserName = _scsd ProgramArguments = Array { /usr/libexec/scsd -l } GroupName = _scsd Label = com.apple.AccountsConfigService }
… lest you think this job should actually be disabled, don’t forget about the ol’ overrides file. Let’s query it to see if this job’s state is overridden there:
bash-3.2# /usr/libexec/PlistBuddy -c "print :com.apple.AccountsConfigService" \ /var/db/launchd.db/com.apple.launchd/overrides.plist
Dict { Disabled = false }
We’ve determined what the associated process is (scsd) and that this webapp should be loaded based on the launchd config. Since it’s configured to load on demand, we might not expect to see the scsd process running; it’s not running on my system. There is a tiny man page for scsd. Don’t stop things you didn’t start ;)
Going forward
webappctl has a method called ‘tree’ that “displays the hierarchy of webapps declared by the requiredWebApps property.” Let’s look:
bash-3.2# webappctl trees - | fold -s com.apple.webapp.ACSServer: com.apple.AccountsConfigService com.apple.webapp.auth: com.apple.collabauthd com.apple.webapp.collab: com.apple.collabcored1, com.apple.collabcored2, com.apple.collabcored3, com.apple.collabcored4, com.apple.collabsandboxd, com.apple.collabfeedd, com.apple.collabd, com.apple.collabd.notifications, com.apple.collabd.quicklook, org.postgresql.postgres . com.apple.webapp.auth: com.apple.collabauthd com.apple.webapp.devicemgr: com.apple.devicemanager, com.apple.DeviceManagement.SCEPHelper, org.postgresql.postgres . com.apple.webapp.auth: com.apple.collabauthd com.apple.webapp.mailman com.apple.webapp.passwordreset: com.apple.passwordreset com.apple.webapp.php: com.apple.webapp.podcastwikiui: com.apple.collabd.podcast-cache-updater com.apple.webapp.webcal: com.apple.wikid.compatibility . com.apple.webapp.auth: com.apple.collabauthd com.apple.webapp.webcalssl: com.apple.wikid.compatibility . com.apple.webapp.auth: com.apple.collabauthd com.apple.webapp.webdavsharing: com.apple.webapp.webmailserver: com.example.placeholder, org.postgresql.postgres . com.apple.webapp.php: org.calendarserver: org.calendarserver.calendarserver, org.postgresql.postgres
It might be tempting to think that the above is a complete expression of the dependency graph of related web apps. This is not true. For example, we see that org.calendarserver expresses dependencies on org.calendarserver.calendarserver and org.postgres.postgres. These two things are not web apps, but launchd jobs.
Diversion: just because you can…
So then, can we deduce that by starting the ‘org.calendarserver’ web app, we’d end up with a running calendar and postgres service? Well, we could, but we’d be wrong.
bash-3.2# webappctl start org.calendarserver web:state = "RUNNING"
bash-3.2# webappctl status - web:webAppState:_array_index:0:state = "RUNNING" web:webAppState:_array_index:0:virtualHostName = "" web:webAppState:_array_index:0:webAppName = "com.apple.webapp.ACSServer" web:webAppState:_array_index:1:state = "RUNNING" web:webAppState:_array_index:1:virtualHostName = "" web:webAppState:_array_index:1:webAppName = "org.calendarserver"
Where’s postgres? What gives?
bash-3.2# tail -n 4 /var/log/system.log | cut -d' ' -f6-20 Reading configuration from file: /etc/caldavd/caldavd.plist Neither EnableCalDAV nor EnableCardDAV are set to True. (org.calendarserver.calendarserver[11258]): Exited with code: 1 (org.calendarserver.calendarserver): Throttling respawn: Will start in 59 seconds
Not so fast, smart guy. What makes you think you can just go around using new and mostly unknown tools for starting and stopping services, without being given express permission?! Don’t tell me you read it on the Internet. The point is that things are becoming more complex, and you really need to use the highlest-level interface available for doing things. In this case, that means Server.app or the serveradmin command line tool. In this specific case, the same Calendar Server software can provide both CalDAV (for calendaring) and CardDAV (for address book) services, but each is only enabled when they are configured to be enabled (in /etc/caldavd/caldavd.plist). It is only through Server.app / serveradmin that these config keys get enabled prior to loading the launchd job.
What about that dep graph again?
Now that you are sufficiently chastised, let’s get back to our example and see what happens when we start calendar server the right way, after first undoing the damage from earlier:
bash-3.2# webappctl stop org.calendarserver web:state = "STOPPED"
bash-3.2# serveradmin start calendar calendar:state = "RUNNING" calendar:setStateVersion = 1 calendar:readWriteSettingsVersion = 1
bash-3.2# webappctl status - web:webAppState:_array_index:0:state = "RUNNING" web:webAppState:_array_index:0:virtualHostName = "" web:webAppState:_array_index:0:webAppName = "com.apple.webapp.ACSServer" web:webAppState:_array_index:1:state = "RUNNING" web:webAppState:_array_index:1:virtualHostName = "" web:webAppState:_array_index:1:webAppName = "com.apple.webapp.webcal" web:webAppState:_array_index:2:state = "RUNNING" web:webAppState:_array_index:2:virtualHostName = "" web:webAppState:_array_index:2:webAppName = "com.apple.webapp.auth" web:webAppState:_array_index:3:state = "RUNNING" web:webAppState:_array_index:3:virtualHostName = "" web:webAppState:_array_index:3:webAppName = "org.calendarserver"
Who said anything about com.apple.webapp.auth or com.apple.webapp.webcal, and where is postgres? Well, first of all remember that postgres won’t show up here, because ‘org.postgresql.postgres’ refers to a launchd job, not a web app. If we check launchd and a process listing, we see that postgres is indeed running:
bash-3.2# ps ax | grep -i post | fold -s 11452 ?? Ss 0:00.15 /usr/bin/postgres -D /var/pgsql -c listen_addresses= -c log_connections=on -c log_directory=/Library/Logs -c log_filename=PostgreSQL.log -c log_lock_waits=on -c log_statement=ddl -c log_line_prefix=%t -c logging_collector=on -c unix_socket_directory=/var/pgsql_socket -c unix_socket_group=_postgres -c unix_socket_permissions=0770 11459 ?? Ss 0:00.08 postgres: logger process 11461 ?? Ss 0:00.29 postgres: writer process 11462 ?? Ss 0:00.22 postgres: wal writer process 11463 ?? Ss 0:00.16 postgres: autovacuum launcher process 11464 ?? Ss 0:00.35 postgres: stats collector process 11837 s001 R+ 0:00.00 grep -i post
bash-3.2# launchctl list | grep -i postgres 11452 - org.postgresql.postgres
Ok, but what about the ‘auth’ and ‘webcal’ web apps? Well, calendar server is cool and has a nifty log that keeps track of what happens through its servermgrd bundle. Let’s see if it’s doing any webcal stuff:
bash-3.2# grep webcal /var/log/caldavd/servermgr_calendar.log | tail -n 1 [cal] 7/24/11 2:48:15 PM PDT : Changing com.apple.webapp.webcal WebAppState to START
We could then look at the webcal webapp plist to see that it also starts the ‘auth’ one. Whew, ok. Maybe you liked it better when it was mysterious and magical :)
The take home point here is that services can and do directly start web apps on their own. The policies controlling this behavior may be codified in the app, so you should have no expectation of being able to directly lay eyes on these policies, although you can get a good feel for it through experimentation. It’s probably a good idea not to use webappctl to twiddle the state of any web apps that you didn’t create, lest you invalidate somebody else’s expectations.
Pingback: Delving into Setting up a Web Server and Wiki on OS X Lion Server « pmcode
Pingback: Etherpad-Lite auf Mac OS-X Server | Tobias-Conradi