Adds bin/glance-control program server daemonization wrapper

program based on Swift's swift-init script.

Adds a crap-ton of documentation on installing Glance and
controlling Glance's server programs.

This was necessary since when glance.common.server was removed
from Glance and paste.deploy used, we lost the ability to control
server daemonization with CLI options. This adds back some of that
functionality while still using paste.deploy like Swift does.
This commit is contained in:
jaypipes@gmail.com 2011-02-04 18:59:52 -05:00
parent 58d52ee3eb
commit 66f4b78234
10 changed files with 499 additions and 54 deletions

View File

@ -66,7 +66,6 @@ def create_options(parser):
store.add_options(parser)
config.add_common_options(parser)
config.add_daemon_options(parser)
config.add_log_options('glance-api', parser)

View File

@ -70,7 +70,6 @@ def create_options(parser):
store.add_options(parser)
db.add_options(parser)
config.add_common_options(parser)
config.add_daemon_options(parser)
config.add_log_options('glance-combined', parser)

217
bin/glance-control Executable file
View File

@ -0,0 +1,217 @@
#!/usr/bin/python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 OpenStack, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Helper script for starting/stopping/reloading Glance server programs.
Thanks for some of the code, Swifties ;)
"""
from __future__ import with_statement
import errno
import glob
import os
import optparse
import resource
import signal
import sys
import time
from glance import version
from glance.common import config
ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart',
'reload', 'force-reload']
ALL_SERVERS = ['glance-api', 'glance-registry']
GRACEFUL_SHUTDOWN_SERVERS = ['glance-api', 'glance-registry']
MAX_DESCRIPTORS = 32768
MAX_MEMORY = (1024 * 1024 * 1024) * 2 # 2 GB
USAGE = """%prog [options] <SERVER> <COMMAND> [CONFPATH]
Where <SERVER> is one of:
all, api, registry
And command is one of:
start, stop, shutdown, restart, reload, force-reload
And CONFPATH is the optional configuration file to use."""
def pid_files(server):
if os.path.exists('/var/run/glance/%s.pid' % server):
pid_files = ['/var/run/glance/%s.pid' % server]
else:
pid_files = glob.glob('/var/run/glance/%s/*.pid' % server)
for pid_file in pid_files:
pid = int(open(pid_file).read().strip())
yield pid_file, pid
def do_start(server, options, args):
server_type = '-'.join(server.split('-')[:-1])
for pid_file, pid in pid_files(server):
if os.path.exists('/proc/%s' % pid):
print "%s appears to already be running: %s" % (server, pid_file)
return
else:
print "Removing stale pid file %s" % pid_file
os.unlink(pid_file)
try:
resource.setrlimit(resource.RLIMIT_NOFILE,
(MAX_DESCRIPTORS, MAX_DESCRIPTORS))
resource.setrlimit(resource.RLIMIT_DATA,
(MAX_MEMORY, MAX_MEMORY))
except ValueError:
print "Unable to increase file descriptor limit. Running as non-root?"
os.environ['PYTHON_EGG_CACHE'] = '/tmp'
def write_pid_file(pid_file, pid):
dir, file = os.path.split(pid_file)
if not os.path.exists(dir):
try:
os.makedirs(dir)
except OSError, err:
if err.errno == errno.EACCES:
sys.exit('Unable to create %s. Running as non-root?'
% dir)
fp = open(pid_file, 'w')
fp.write('%d\n' % pid)
fp.close()
def launch(ini_file, pid_file):
args = [server, ini_file]
print 'Starting %s with %s' % (server, ini_file)
pid = os.fork()
if pid == 0:
os.setsid()
with open(os.devnull, 'r+b') as nullfile:
for desc in (0, 1, 2): # close stdio
try:
os.dup2(nullfile.fileno(), desc)
except OSError:
pass
try:
os.execlp('%s' % server, server, ini_file)
except OSError, e:
sys.exit('unable to launch %s. Got error: %s'
% (server, str(e)))
sys.exit(0)
else:
write_pid_file(pid_file, pid)
pid_file = '/var/run/glance/%s.pid' % server
conf_file = config.find_config_file(options, args)
if not conf_file:
sys.exit("Could not find any configuration file to use!")
launch_args = [(conf_file, pid_file)]
# start all servers
for conf_file, pid_file in launch_args:
launch(conf_file, pid_file)
def do_stop(server, options, args, graceful=False):
if graceful and server in GRACEFUL_SHUTDOWN_SERVERS:
sig = signal.SIGHUP
else:
sig = signal.SIGTERM
did_anything = False
pfiles = pid_files(server)
for pid_file, pid in pfiles:
did_anything = True
try:
print 'Stopping %s pid: %s signal: %s' % (server, pid, sig)
os.kill(pid, sig)
except OSError:
print "Process %d not running" % pid
try:
os.unlink(pid_file)
except OSError:
pass
for pid_file, pid in pfiles:
for _junk in xrange(150): # 15 seconds
if not os.path.exists('/proc/%s' % pid):
break
time.sleep(0.1)
else:
print 'Waited 15 seconds for pid %s (%s) to die; giving up' % \
(pid, pid_file)
if not did_anything:
print 'No %s running' % server
if __name__ == '__main__':
oparser = optparse.OptionParser(usage=USAGE, version='%%prog %s'
% version.version_string())
config.add_common_options(oparser)
conf_options = config.get_config_file_options()
(options, args) = config.parse_options(oparser, defaults=conf_options)
if len(args) < 2:
oparser.print_usage()
sys.exit(1)
server = args.pop(0).lower()
if server == 'all':
servers = ALL_SERVERS
else:
if not server.startswith('glance-'):
server = 'glance-%s' % server
if server not in ALL_SERVERS:
server_list = ", ".join([s.replace('glance-', '')
for s in ALL_SERVERS])
msg = ("Unknown server '%(server)s' specified. Please specify "
"all, or one of the servers: %(server_list)s" % locals())
sys.exit(msg)
servers = [server]
command = args.pop(0).lower()
if command not in ALL_COMMANDS:
command_list = ", ".join(ALL_COMMANDS)
msg = ("Unknown command %(command)s specified. Please specify a "
"command in this list: %(command_list)s" % locals())
sys.exit(msg)
if command == 'start':
for server in servers:
do_start(server, options, args)
if command == 'stop':
for server in servers:
do_stop(server, options, args)
if command == 'shutdown':
for server in servers:
do_stop(server, options, args, graceful=True)
if command == 'restart':
for server in servers:
do_stop(server, options, args)
for server in servers:
do_start(server, options, args)
if command == 'reload' or command == 'force-reload':
for server in servers:
do_stop(server, options, args, graceful=True)
do_start(server, options, args)

View File

@ -56,7 +56,6 @@ def create_options(parser):
glance.registry.db.add_options(parser)
config.add_common_options(parser)
config.add_daemon_options(parser)
config.add_log_options('glance-registry', parser)

View File

@ -0,0 +1,20 @@
..
Copyright 2011 OpenStack, LLC
All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Configuring Glance
==================
.. todo:: Complete details of configuration with paste.deploy config files

View File

@ -0,0 +1,150 @@
..
Copyright 2011 OpenStack, LLC
All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Controlling Glance Servers
==========================
This section describes the ways to start, stop, and reload Glance's server
programs.
Starting a server
-----------------
There are two ways to start a Glance server (either the API server or the
reference implementation registry server that ships with Glance):
* Manually calling the server program
* Using the ``glance-control`` server daemon wrapper program
Manually starting the server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The first is by directly calling the server program, passing in command-line
options and a single argument for the ``paste.deploy`` configuration file to
use when configuring the server application.
.. note::
Glance ships with an ``etc/`` directory that contains sample ``paste.deploy``
configuration files that you can copy to a standard configuation directory and
adapt for your own uses.
Here is an example showing how you can manually start the ``glance-api`` server
in a shell.::
$> sudo glance-api etc/glance.cnf.sample --debug
2011-02-04 17:12:28 DEBUG [root] ********************************************************************************
2011-02-04 17:12:28 DEBUG [root] Options:
2011-02-04 17:12:28 DEBUG [root] ========
2011-02-04 17:12:28 DEBUG [root] debug True
2011-02-04 17:12:28 DEBUG [root] default_store file
2011-02-04 17:12:28 DEBUG [root] filesystem_store_datadir /var/lib/glance/images/
2011-02-04 17:12:28 DEBUG [root] host 0.0.0.0
2011-02-04 17:12:28 DEBUG [root] log_config None
2011-02-04 17:12:28 DEBUG [root] log_date_format %Y-%m-%d %H:%M:%S
2011-02-04 17:12:28 DEBUG [root] log_dir None
2011-02-04 17:12:28 DEBUG [root] log_file glance-api.log
2011-02-04 17:12:28 DEBUG [root] log_handler stream
2011-02-04 17:12:28 DEBUG [root] port 9292
2011-02-04 17:12:28 DEBUG [root] registry_host 0.0.0.0
2011-02-04 17:12:28 DEBUG [root] registry_port 9191
2011-02-04 17:12:28 DEBUG [root] verbose False
2011-02-04 17:12:28 DEBUG [root] ********************************************************************************
2011-02-04 17:12:28 DEBUG [routes.middleware] Initialized with method overriding = True, and path info altering = True
(16940) wsgi starting up on http://0.0.0.0:9292/
Simply supply the configuration file as the first argument
(``etc/glance.cnf.sample`` in the above example) and then any options you
want to use (``--debug`` was used above to show some of the debugging
output that the server shows when starting up. Call the server program
with ``--help`` to see all available options you can specify on the
command line.
For more information on configuring the server via the ``paste.deploy``
configuration files, see the section entitled
:doc:`Configuring Glance servers <configuring>`
Note that the server does not `daemonize` itself when run manually
from the terminal. You can force the server to daemonize using the standard
shell backgrounding indicator, ``&``. However, for most use cases, we recommend
using the ``glance-control`` server daemon wrapper for daemonizing. See below
for more details on daemonization with ``glance-control``.
Using the ``glance-control`` program to start the server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The second way to start up a Glance server is to use the ``glance-control``
program. ``glance-control`` is a wrapper script that allows the user to
start, stop, restart, and reload the other Glance server programs in
a fashion that is more conducive to automation and scripting.
Servers started via the ``glance-control`` program are always `daemonized`,
meaning that the server program process runs in the background.
To start a Glance server with ``glance-control``, simply call
``glance-control`` with a server and the word "start", followed by
any command-line options you wish to provide. Start the server with ``glance-control``
in the following way::
$> sudo glance-control <SERVER> start [CONFPATH]
.. note::
You must use the ``sudo`` program to run ``glance-control`` currently, as the
pid files for the server programs are written to /var/run/glance/
Here is an example that shows how to start the ``glance-registry`` server
with the ``glance-control`` wrapper script. ::
$> sudo glance-control registry start etc/glance.cnf.sample
Starting glance-registry with /home/jpipes/repos/glance/trunk/etc/glance.cnf.sample
The same ``paste.deploy`` configuration files are used by ``glance-control``
to start the Glance server programs, and you can specify (as the example above
shows) a configuration file when starting the server.
.. note::
To start all the Glance servers (currently the glance-api and glance-registry
programs) at once, you can specify "all" for the <SERVER>
Stopping a server
-----------------
If you started a Glance server manually and did not use the ``&`` backgrounding
function, simply send a terminate signal to the server process by typing
``Ctrl-C``
If you started the Glance server using the ``glance-control`` program, you can
use the ``glance-control`` program to stop it. Simply do the following::
$> sudo glance-control <SERVER> stop
as this example shows::
jpipes@serialcoder:~$ sudo glance-control registry stop
Stopping glance-registry pid: 17602 signal: 15
Restarting a server
-------------------
You can restart a server with the ``glance-control`` program, as demonstrated
here::
$> sudo ./bin/glance-control registry restart etc/glance.cnf.sample
Stopping glance-registry pid: 17611 signal: 15
Starting glance-registry with /home/jpipes/repos/glance/use-paste-deploy/etc/glance.cnf.sample

View File

@ -76,48 +76,6 @@ Glance Registry Servers
Glance registry servers are servers that conform to the Glance Registry API.
Glance ships with a reference implementation of a registry server that
complies with this API (``bin/glance-registry``).
complies with this API (``glance-registry``).
Starting Up Glance's Servers
----------------------------
To get started using Glance, you must first start the Glance API server.
After installing Glance, starting up the Glance API server is easy. Simply
start the ``glance-api`` program, like so::
$> glance-api
Configuring the Glance API server
*********************************
There are a few options that can be supplied to the API server when
starting it up:
* ``verbose``
Show more verbose/debugging output
* ``api_host``
Address of the host the registry runs on. Defaults to 0.0.0.0.
* ``api_port``
Port the registry server listens on. Defaults to 9292.
* ``default_store``
The store that the Glance API server will use by default to store
images that are added to it. The default value is `filesystem`, and
possible choices are: `filesystem`, `swift`, and `s3`.
* ``filesystem_store_datadir``
Directory where the filesystem store can write images to. This directory
must be writeable by the user that runs ``glance-api``
.. todo::
Link to docs on the different stores when the documentation on Glance
stores is complete.
For more details on Glance's architecture see :doc:`here <architecture>`

View File

@ -58,6 +58,9 @@ Using Glance
:maxdepth: 1
gettingstarted
installing
controllingservers
configuring
glanceapi
client

100
doc/source/installing.rst Normal file
View File

@ -0,0 +1,100 @@
..
Copyright 2011 OpenStack, LLC
All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Installing Glance
=================
Installing from packages
~~~~~~~~~~~~~~~~~~~~~~~~
To install the latest version of Glance from the Launchpad Bazaar repositories,
following the following instructions.
Debian/Ubuntu
#############
1. Add the Glance PPA to your sources.lst::
$> sudo add-apt-repository ppa:glance-core/trunk
$> sudo apt-get update
2. Install Glance::
$> sudo apt-get install glance
RedHat/Fedora
#############
.. todo:: Need some help on this one...
Mac OSX
#######
.. todo:: No idea how to do install on Mac OSX. Somebody with a Mac should complete this section
Installing from source tarballs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To install the latest version of Glance from the Launchpad Bazaar repositories,
following the following instructions.
1. Grab the source tarball from `Launchpad <http://launchpad.net/glance/+download>`_
2. Untar the source tarball::
$> tar -xzf <FILE>
3. Change into the package directory and build/install::
$> cd glance-<RELEASE>
$> sudo python setup.py install
Installing from a Bazaar Branch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To install the latest version of Glance from the Launchpad Bazaar repositories,
following the following instructions.
Debian/Ubuntu
#############
1. Install Bazaar and build dependencies::
$> sudo apt-get install bzr python-eventlet python-routes python-greenlet
$> sudo apt-get install python-argparse python-sqlalchemy python-wsgiref python-pastedeploy
.. note::
If you want to build the Glance documentation locally, you will also want
to install the python-sphinx package
1. Branch Glance's trunk branch::
$> bzr branch lp:glance
1. Install Glance::
$> sudo python setup.py install
RedHat/Fedora
#############
.. todo:: Need some help on this one...
Mac OSX
#######
.. todo:: No idea how to do install on Mac OSX. Somebody with a Mac should complete this section

View File

@ -123,16 +123,16 @@ def add_daemon_options(parser):
"the daemonizing of this program."
group = optparse.OptionGroup(parser, "Daemon Options", help_text)
group.add_option('--config-file', default=None,
group.add_option('--config', default=None,
help="Configuration file to read when loading "
"application. If missing, the first argument is "
"used. If no arguments are found, then a set of "
"standard directories are searched for a config "
"file.")
group.add_option('--daemonize', default=False, action="store_true",
help="Daemonize this process")
group.add_option("--pidfile", default=None,
help="(Optional) Name of pid file for the server")
group.add_option("--pid-file", default=None, metavar="PATH",
help="(Optional) Name of pid file for the server. "
"If not specified, the pid file will be named "
"/var/run/glance/<SERVER>.pid.")
group.add_option("--uid", type=int, default=os.getuid(),
help="uid under which to run. Default: %default")
group.add_option("--gid", type=int, default=os.getgid(),
@ -325,9 +325,9 @@ def find_config_file(options, args):
:retval Full path to config file, or None if no config file found
"""
if getattr(options, 'config_file', None):
if getattr(options, 'config', None):
if os.path.exists(options.config_file):
return os.path.abspath(options.config_file)
return os.path.abspath(getattr(options, 'config'))
elif args:
if os.path.exists(args[0]):
return os.path.abspath(args[0])