Simplify and clarify the Customize chapter

Address O'Reilly editor comments. Simplify and clarify the chapter.
Only have one localrc for DevStack. Make the program listings
easier to follow and remove new lines from the end of program
listings.

Change-Id: I4db68a494f82ccd55321d38bd8edb0848f88dcff
This commit is contained in:
Everett Toews 2014-02-17 11:21:16 -06:00 committed by Anne Gentle
parent afe62516ca
commit ac898429ac

View File

@ -13,8 +13,9 @@
<?dbhtml stop-chunking?>
<title>Customize</title>
<para>OpenStack might not do everything you need it to do out of
the box. In these cases, you can follow one of two major
paths. First, you can learn <link
the box. To add a new feature, you can follow one of two major
paths.</para>
<para>First, you can modify the OpenStack code directly. Learn <link
xlink:href="https://wiki.openstack.org/wiki/How_To_Contribute"
>How To Contribute</link>
(https://wiki.openstack.org/wiki/How_To_Contribute), follow
@ -22,39 +23,36 @@
xlink:href="https://wiki.openstack.org/wiki/GerritWorkflow"
>Code Review Workflow</link>
(https://wiki.openstack.org/wiki/GerritWorkflow), make your
changes and contribute them back to the upstream OpenStack
changes, and contribute them back to the upstream OpenStack
project. This path is recommended if the feature you need
requires deep integration with an existing project. The
community is always open to contributions and welcomes new
functionality that follows the feature development
guidelines.</para>
<para>Alternately, if the feature you need does not require deep
integration, there are other ways to customize OpenStack. If
the project where your feature would need to reside uses the
Python Paste framework, you can create middleware for it and
plug it in through configuration. There may also be specific
ways of customizing an project such as creating a new
scheduler for OpenStack Compute or a customized Dashboard.</para>
<para>Alternatively, you can write new features and plug them in using
changes to a configuration file. If the project where your feature would
need to reside uses the Python Paste framework, you can create
middleware for it and plug it in through configuration. There may also
be specific ways of customizing a project such as creating a new
scheduler driver for Compute or a custom tab for the Dashboard.</para>
<para>This chapter focuses on the second method of customizing
OpenStack and will follow to examples in detail, one for Swift and
OpenStack and will follow two examples in detail, one for Swift and
one for Nova. To customize OpenStack this way you'll need a development
environment. The best way to get an environment up and running
quickly is to run DevStack within your cloud.</para>
<section xml:id="devstack">
<title>DevStack</title>
<title>Create an OpenStack Development Environment</title>
<para>To create a development environment you can use DevStack. DevStack
is essentially a collection of shell scripts and configuration files
that will build an OpenStack development environment for you. We
will use it to create such an environment for developing a new
feature.</para>
<para>You can find all of the documentation at the <link
xlink:href="http://devstack.org/">DevStack</link>
(http://devstack.org/) website. Depending on which project
you would like to customize, either Object Storage (Swift)
or another project, you must configure DevStack
differently. For the <xref linkend="ip_whitelist"/> below, you must
install with the Object Store enabled.</para>
(http://devstack.org/) website.</para>
<procedure>
<title>To run DevStack for the stable Havana branch on an
instance:</title>
instance in your OpenStack cloud:</title>
<step>
<para>Boot an instance from the Dashboard or the nova
command-line interface (CLI) with the following
@ -67,8 +65,7 @@
<para>Image: Ubuntu 12.04 LTS</para>
</listitem>
<listitem>
<para>Memory Size: 4 GB RAM (you could
probably get away with 2 GB)</para>
<para>Memory Size: 4 GB RAM</para>
</listitem>
<listitem>
<para>Disk Size: minimum 5 GB</para>
@ -81,21 +78,20 @@
</step>
<step>
<para>Login and set up DevStack.</para>
<substeps>
<step>
<screen><userinput>ssh username@my.ip.v4.address</userinput></screen>
</step>
<step>
<screen><userinput>sudo apt-get -y update</userinput></screen>
</step>
<step>
<screen><userinput>sudo apt-get -y install git</userinput></screen>
</step>
<step>
<screen><userinput>git clone https://github.com/openstack-dev/devstack.git -b stable/havana devstack/</userinput></screen>
</step>
<step>
<screen><userinput>cd devstack</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Login to the instance
$ ssh username@my.instance.ip.address
# Update
$ sudo apt-get -y update
# Install git
$ sudo apt-get -y install git
# Clone the stable/havana branch of the devstack repository
$ git clone https://github.com/openstack-dev/devstack.git -b stable/havana devstack/
# Change to the devstack repository
$ cd devstack</programlisting>
</step>
<step performance="optional">
<para>(Optional) If you've logged in to your instance
@ -103,70 +99,49 @@
otherwise you'll run into permission issues. If
you've logged in as a user other than root, you
can skip these steps.</para>
<substeps>
<step>
<screen><userinput>tools/create-stack-user.sh</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Run the DevStack script to create the stack user
$ tools/create-stack-user.sh
# Give ownership of the devstack directory to the stack user
$ chown -R stack:stack /root/devstack
# Switch to the stack user
$ su stack
# Open up some permissions to you can view the DevStack screen later
$ sudo chmod o+rwx /dev/pts/0</programlisting>
</step>
<step>
<screen><userinput>chown -R stack:stack /root/devstack</userinput></screen>
<para>Edit the localrc configuration file that controls what
DevStack will deploy. Copy in the example localrc file at
the end of this section:</para>
<programlisting language="bash"><?db-font-size 75%?># Open localrc and copy in the example localrc file at the end of this section
$ vim localrc
# Run the stack script that will install OpenStack
$ ./stack.sh
# When the stack script is done you can open the screen session it started
# to view all of the running OpenStack services
$ screen -r stack
# Press Ctrl-A followed by pressing 0</programlisting>
</step>
<step>
<screen><userinput>su stack</userinput></screen>
</step>
<step>
<screen><userinput>sudo chmod o+rwx /dev/pts/0</userinput></screen>
</step>
</substeps>
</step>
<step>
<para>
<screen><userinput>vim localrc</userinput></screen>
<itemizedlist>
<listitem>
<para>For Swift only, used in the
<xref linkend="ip_whitelist"/>, see the
<xref linkend="swift_localrc"/>
below</para>
</listitem>
<listitem>
<para>For other projects, used in the
<xref linkend="ip_scheduler"/>, see the
<xref linkend="nova_localrc"/>
below</para>
</listitem>
</itemizedlist></para>
</step>
<step>
<screen><userinput>./stack.sh</userinput></screen>
</step>
<step>
<screen><userinput>screen -r stack</userinput></screen>
</step>
</substeps>
</procedure>
<note>
<para><itemizedlist>
<para>
<itemizedlist>
<listitem>
<para>The <code>stack.sh</code> script
takes a while to run. Perhaps take
this opportunity to <link
xlink:href="http://www.openstack.org/join/"
>join the OpenStack
foundation</link>
Foundation</link>
(http://www.openstack.org/join/).</para>
</listitem>
<listitem>
<para>When you run
<code>stack.sh</code>, you might
see an error message that reads
“ERROR: at least one RPC back-end
must be enabled”. Dont worry about
it; Swift and Keystone do not need
an RPC (AMQP) back-end. You can
also ignore any
<code>ImportErrors</code>.</para>
</listitem>
<listitem>
<para>Screen is a useful program for
<para><command>Screen</command> is a useful program for
viewing many related services at
once. For more information, see
<link
@ -174,79 +149,58 @@
>GNU screen quick reference</link>.
(http://aperiodic.net/screen/quick_reference)</para>
</listitem>
</itemizedlist></para>
</itemizedlist>
</para>
</note>
</step>
</procedure>
<para>Now that you have an OpenStack development environment,
you're free to hack around without worrying about damaging
your production deployment. Proceed to either the
<xref linkend="ip_whitelist"/> for a Swift-only environment, or the
<xref linkend="ip_scheduler"/> for other projects.</para>
your production deployment.</para>
<?hard-pagebreak?>
<example xml:id="swift_localrc">
<title>Swift only localrc</title>
<programlisting language="bash"><?db-font-size 75%?>ADMIN_PASSWORD=devstack
<example xml:id="localrc">
<title>localrc</title>
<programlisting language="bash"><?db-font-size 75%?># Credentials
ADMIN_PASSWORD=devstack
MYSQL_PASSWORD=devstack
RABBIT_PASSWORD=devstack
SERVICE_PASSWORD=devstack
SERVICE_TOKEN=devstack
# OpenStack Identity Service branch
KEYSTONE_BRANCH=stable/havana
# OpenStack Compute branch
NOVA_BRANCH=stable/havana
# OpenStack Block Storage branch
CINDER_BRANCH=stable/havana
# OpenStack Image Service branch
GLANCE_BRANCH=stable/havana
# OpenStack Dashboard branch
HORIZON_BRANCH=stable/havana
# OpenStack Object Storage branch
SWIFT_BRANCH=stable/havana
enable_service swift
# Object Storage Settings
SWIFT_HASH=66a3d6b56c1f479c8b4e70ab5c2000f5
SWIFT_REPLICAS=1
# OpenStack Identity Service
KEYSTONE_BRANCH=stable/havana
# OpenStack Object Storage
SWIFT_BRANCH=stable/havana
disable_all_services
enable_service key swift mysql
# Output
LOGFILE=/opt/stack/logs/stack.sh.log
VERBOSE=True
LOG_COLOR=False
SCREEN_LOGDIR=/opt/stack/logs
</programlisting>
</example>
<example xml:id="nova_localrc">
<title>Nova projects localrc</title>
<programlisting language="bash"><?db-font-size 75%?>ADMIN_PASSWORD=devstack
MYSQL_PASSWORD=devstack
RABBIT_PASSWORD=devstack
SERVICE_PASSWORD=devstack
SERVICE_TOKEN=devstack
# Block Storage Setting
VOLUME_BACKING_FILE_SIZE=20480M
# OpenStack Identity Service
KEYSTONE_BRANCH=stable/havana
# OpenStack Compute
NOVA_BRANCH=stable/havana
# OpenStack Block Storage
CINDER_BRANCH=stable/havana
# OpenStack Image Service
GLANCE_BRANCH=stable/havana
# OpenStack Dashboard
HORIZON_BRANCH=stable/havana
# Output
LOGFILE=/opt/stack/logs/stack.sh.log
VERBOSE=True
LOG_COLOR=False
SCREEN_LOGDIR=/opt/stack/logs
</programlisting>
SCREEN_LOGDIR=/opt/stack/logs</programlisting>
</example>
</section>
<section xml:id="middleware_example">
<title>Middleware Example</title>
<section xml:id="swift_middleware_example">
<title>Swift Middleware Example</title>
<para>Swift is based on the Python <link
xlink:href="http://pythonpaste.org/"
>Paste</link> (http://pythonpaste.org/) framework. The best
@ -274,10 +228,11 @@ SCREEN_LOGDIR=/opt/stack/logs
</warning>
<para>When you join the screen session that
<code>stack.sh</code> starts with <code>screen -r stack</code>,
you're greeted with three screens if you
used the localrc file with just Swift installed.</para>
you see a screen for each service running, which can be a few
or several depending on how many services you configured Devstack
to run.</para>
<para>The asterisk * indicates which screen you are on.</para>
<screen>0$ shell 1$ key 2$ s-proxy 3$ s-object 4$ s-container 5$ s-account*</screen>
<screen>0$ shell 1$ key* 2$ horizon 3$ s-proxy 4$ s-object 5$ s-container 6$ s-account</screen>
<para>The purpose of the screens are as follows.</para>
<itemizedlist>
<listitem>
@ -290,6 +245,11 @@ SCREEN_LOGDIR=/opt/stack/logs
<emphasis role="bold"><code>key</code></emphasis>
The Keystone service.</para>
</listitem>
<listitem>
<para>
<emphasis role="bold"><code>horizon</code></emphasis>
The Horizon dashboard web application.</para>
</listitem>
<listitem>
<para>
<emphasis role="bold"><code>s-*</code></emphasis>
@ -304,17 +264,17 @@ SCREEN_LOGDIR=/opt/stack/logs
<code>/opt/stack</code>. Go to the swift
directory in the <code>shell</code> screen and edit your
middleware module.</para>
<substeps>
<step>
<screen><userinput>cd /opt/stack/swift</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Change to the directory where Swift is installed
$ cd /opt/stack/swift
# Create the ip_whitelist.py Python source code file
$ vim swift/common/middleware/ip_whitelist.py</programlisting>
</step>
<step>
<screen><userinput>vim swift/common/middleware/ip_whitelist.py</userinput></screen>
</step>
</substeps>
</step>
<step>
<para>Copy in the following code. When you're done,
<para>The following code is a middleware example that will
restrict access to a container based on IP address as
explained at the beginning of the section. Copy the
following code into ip_whitelist.py. When you're done,
save and close the file.</para>
<example xml:id="ip_whitelist">
<title>ip_whitelist.py</title>
@ -381,7 +341,7 @@ class IPWhitelistMiddleware(object):
req.environ, self.app, swift_source='IPWhitelistMiddleware')
remote_ip = env['REMOTE_ADDR']
self.logger.debug(Remote IP: %(remote_ip)s",
self.logger.debug("Remote IP: %(remote_ip)s",
{'remote_ip': remote_ip})
meta = container_info['meta']
@ -412,8 +372,7 @@ def filter_factory(global_conf, **local_conf):
def ip_whitelist(app):
return IPWhitelistMiddleware(app, conf)
return ip_whitelist
</programlisting>
return ip_whitelist</programlisting>
</example>
<para>There is a lot of useful information in
<code>env</code> and <code>conf</code> that
@ -422,15 +381,16 @@ def filter_factory(global_conf, **local_conf):
available, you can insert the following log
statement into the <code>__init__</code>
method</para>
<programlisting><?db-font-size 75%?>self.logger.debug("conf = %(conf)s", locals())</programlisting>
<programlisting language="python"><?db-font-size 75%?>self.logger.debug("conf = %(conf)s", locals())</programlisting>
<para>and the following log statement into the
<code>__call__</code> method</para>
<programlisting><?db-font-size 75%?>self.logger.debug("env = %(env)s", locals())</programlisting>
<programlisting language="python"><?db-font-size 75%?>self.logger.debug("env = %(env)s", locals())</programlisting>
</step>
<step>
<para>To plug this middleware into the Swift pipeline
you'll need to edit one configuration file.</para>
<screen><userinput>vim /etc/swift/proxy-server.conf</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Edit the file proxy-server.conf
$ vim /etc/swift/proxy-server.conf</programlisting>
</step>
<step>
<para>Find the <code>[filter:ratelimit]</code> section
@ -459,18 +419,10 @@ pipeline = catch_errors healthcheck proxy-logging cache bulk slo ratelimit ip_wh
use your middleware. Start by switching to the
swift-proxy screen.</para>
<substeps>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 2</userinput></screen>
</step>
<step>
<screen><userinput>Press Ctrl-C to kill the service</userinput></screen>
</step>
<step>
<screen><userinput>Press Up Arrow to bring up the last command</userinput></screen>
</step>
<step>
<screen><userinput>Press Enter to run it</userinput></screen>
</step>
<step><para>Press Ctrl-A followed by pressing 3</para></step>
<step><para>Press Ctrl-C to kill the service</para></step>
<step><para>Press Up Arrow to bring up the last command</para></step>
<step><para>Press Enter to run it</para></step>
</substeps>
</step>
<step>
@ -478,29 +430,23 @@ pipeline = catch_errors healthcheck proxy-logging cache bulk slo ratelimit ip_wh
by switching to the shell screen and finish by
switching back to the <code>swift-proxy</code> screen
to check the log output.</para>
<substeps>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 0</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Press Ctrl-A followed by pressing 0
# Make sure you're in the devstack directory
$ cd /root/devstack
# Source openrc to setup your environment variables for the CLI
$ source openrc
# Create a container called middleware-test
$ swift post middleware-test
# Press Ctrl-A followed by pressing 3</programlisting>
</step>
<step>
<screen><userinput>cd ~/devstack</userinput></screen>
</step>
<step>
<screen><userinput>source openrc</userinput></screen>
</step>
<step>
<screen><userinput>swift post middleware-test</userinput></screen>
</step>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 2</userinput></screen>
</step>
</substeps>
</step>
<step>
<para>Among the log statements you'll see the
lines.</para>
<screen>proxy-server Remote IP: 203.0.113.68 (txn: ...)
proxy-server Allow IPs: set(['203.0.113.68']) (txn: ...)</screen>
<para>Among the log statements you'll see the lines.</para>
<screen>proxy-server Remote IP: my.instance.ip.address (txn: ...)
proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)</screen>
<para>These 2 statements are produced by
our middleware and show that the request was sent
from our DevStack instance and was allowed.</para>
@ -509,50 +455,46 @@ proxy-server Allow IPs: set(['203.0.113.68']) (txn: ...)</screen>
<para>Test the middleware from outside of DevStack on
a remote machine that has access to your DevStack
instance.</para>
<substeps>
<step>
<screen><userinput>swift --os-auth-url=http://203.0.113.68:5000/v2.0/ --os-region-name=RegionOne --os-username=demo:demo --os-password=devstack list middleware-test</userinput></screen>
</step>
<step>
<screen>Container GET failed: http://203.0.113.68:8080/v1/AUTH_.../middleware-test?format=json 403 Forbidden   You shall not pass!</screen>
</step>
</substeps>
<programlisting language="bash"><?db-font-size 75%?># Install the Keystone and Swift client on your local machine
$ sudo pip install python-keystoneclient python-swiftclient
# Attempt to list the objects in the middleware-test container
$ swift --os-auth-url=http://my.instance.ip.address:5000/v2.0/ --os-region-name=RegionOne --os-username=demo:demo --os-password=devstack list middleware-test
Container GET failed: http://my.instance.ip.address:8080/v1/AUTH_.../middleware-test?format=json 403 Forbidden   You shall not pass!</programlisting>
</step>
<step>
<para>Check the Swift log statements again and among
the log statements you'll see the lines.</para>
<screen>proxy-server Authorizing from an overriding middleware (i.e: tempurl) (txn: ...)
proxy-server ... IPWhitelistMiddleware
proxy-server Remote IP: 198.51.100.12 (txn: ...)
proxy-server Allow IPs: set(['203.0.113.68']) (txn: ...)
proxy-server IP 198.51.100.12 denied access to Account=AUTH_... Container=None. Not in set(['203.0.113.68']) (txn: ...)</screen>
proxy-server Remote IP: my.local.ip.address (txn: ...)
proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)
proxy-server IP my.local.ip.address denied access to Account=AUTH_... Container=None. Not in set(['my.instance.ip.address']) (txn: ...)</screen>
<para>Here we can see that the request was denied
because the remote IP address wasn't in the set of
allowed IPs.</para>
</step>
<step>
<para>Back on your DevStack instance add some metadata
to your container to allow the request from the
remote machine.</para>
<substeps>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 0</userinput></screen>
</step>
<step>
<screen><userinput>swift post --meta allow-dev:198.51.100.12 middleware-test</userinput></screen>
</step>
</substeps>
<para>Back in your DevStack instance on the shell screen add
some metadata to your container to allow the request from
the remote machine.</para>
<programlisting language="bash"><?db-font-size 75%?># Press Ctrl-A followed by pressing 0
# Add metadata to the container to allow the IP
$ swift post --meta allow-dev:my.local.ip.address middleware-test</programlisting>
</step>
<step>
<para>Now try the command from
<xref linkend="test_middleware_step"/> again and it
succeeds.</para>
succeeds. There are no objects in the container so there is
nothing to list, however there is also no error to report.</para>
</step>
</procedure>
<warning><para>Functional testing like this is not a replacement for
proper unit and integration testing but it serves to get
you started.</para></warning>
<para>A similar pattern can be followed in other projects
<para>You can follow a similar pattern in other projects
that use the Python Paste framework. Simply create a
middleware module and plug it in through configuration.
The middleware runs in sequence as part of that project's
@ -630,7 +572,7 @@ proxy-server IP 198.51.100.12 denied access to Account=AUTH_... Container=None.
<para>When you join the screen session that
<code>stack.sh</code> starts with <code>screen -r stack</code>,
you are greeted with many screens.</para>
<screen>0$ shell*  1$ key  2$ g-reg  3$ g-api  4$ n-api  5$ n-cpu  6$ n-crt  7$ n-net  8-$ n-sch ...</screen>
<screen>0$ shell*  1$ key  2$ horizon  ...  9$ n-api  ...  14$ n-sch ...</screen>
<itemizedlist>
<listitem>
<para>
@ -644,13 +586,8 @@ proxy-server IP 198.51.100.12 denied access to Account=AUTH_... Container=None.
</listitem>
<listitem>
<para>
<emphasis role="bold"><code>g-*</code></emphasis>
The Glance services.</para>
</listitem>
<listitem>
<para>
<emphasis role="bold"><code>c-*</code></emphasis>
The Cinder services.</para>
<emphasis role="bold"><code>horizon</code></emphasis>
The Horizon dashboard web application.</para>
</listitem>
<listitem>
<para>
@ -671,17 +608,17 @@ proxy-server IP 198.51.100.12 denied access to Account=AUTH_... Container=None.
<para>The code for OpenStack lives in
<code>/opt/stack</code> so go to the nova
directory and edit your scheduler module.</para>
<substeps>
<step>
<screen><userinput>cd /opt/stack/nova</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Change to the directory where Nova is installed
$ cd /opt/stack/nova
# Create the ip_scheduler.py Python source code file
$ vim nova/scheduler/ip_scheduler.py</programlisting>
</step>
<step>
<screen><userinput>vim nova/scheduler/ip_scheduler.py</userinput></screen>
</step>
</substeps>
</step>
<step>
<para>Copy in the following code. When you're done,
<para>The following code is a driver that will schedule
servers to hosts based on IP address as
explained at the beginning of the section. Copy the
following code into ip_scheduler.py. When you're done,
save and close the file.</para>
<example xml:id="ip_scheduler">
<title>ip_scheduler.py</title>
@ -808,8 +745,7 @@ class IPScheduler(driver.Scheduler):
# that all instances in the request get set to
# error properly
driver.handle_schedule_error(context, ex, instance_uuid,
request_spec)
</programlisting>
request_spec)</programlisting>
</example>
<para>There is a lot of useful information in
<code>context</code>,
@ -820,14 +756,15 @@ class IPScheduler(driver.Scheduler):
you can insert the following log statements into
the <code>schedule_run_instance</code> method of
the scheduler above.</para>
<programlisting><?db-font-size 65%?>LOG.debug("context = %(context)s" % {'context': context.__dict__})
<programlisting language="python"><?db-font-size 65%?>LOG.debug("context = %(context)s" % {'context': context.__dict__})
LOG.debug("request_spec = %(request_spec)s" % locals())
LOG.debug("filter_properties = %(filter_properties)s" % locals())</programlisting>
</step>
<step>
<para>To plug this scheduler into Nova you'll need to
edit one configuration file.</para>
<screen><userinput>vim /etc/nova/nova.conf</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Edit the Nova configuration file
$ vim /etc/nova/nova.conf</programlisting>
</step>
<step>
<para>Find the <code>scheduler_driver</code>
@ -839,21 +776,11 @@ LOG.debug("filter_properties = %(filter_properties)s" % locals())</programlistin
use your scheduler. Start by switching to the
<code>n-sch</code> screen.</para>
<substeps>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 9</userinput></screen>
</step>
<step>
<screen><userinput>Press Ctrl-A followed by pressing n</userinput></screen>
</step>
<step>
<screen><userinput>Press Ctrl-C to kill the service</userinput></screen>
</step>
<step>
<screen><userinput>Press Up Arrow to bring up the last command</userinput></screen>
</step>
<step>
<screen><userinput>Press Enter to run it</userinput></screen>
</step>
<step><para>Press Ctrl-A followed by pressing 9</para></step>
<step><para>Press Ctrl-A followed by pressing n until you reach the n-sch screen</para></step>
<step><para>Press Ctrl-C to kill the service</para></step>
<step><para>Press Up Arrow to bring up the last command</para></step>
<step><para>Press Enter to run it</para></step>
</substeps>
</step>
<step>
@ -861,30 +788,23 @@ LOG.debug("filter_properties = %(filter_properties)s" % locals())</programlistin
switching to the <code>shell</code> screen and finish by
switching back to the <code>n-sch</code> screen to
check the log output.</para>
<substeps>
<step>
<screen><userinput>Press Ctrl-A followed by pressing 0</userinput></screen>
<programlisting language="bash"><?db-font-size 75%?># Press Ctrl-A followed by pressing 0
# Make sure you're in the devstack directory
$ cd /root/devstack
# Source openrc to setup your environment variables for the CLI
$ source openrc
# Put the image ID for the only installed image into an environment variable
$ IMAGE_ID=`nova image-list | egrep cirros | egrep -v "kernel|ramdisk" | awk '{print $2}'`
# Boot a test server
$ nova boot --flavor 1 --image $IMAGE_ID scheduler-test</programlisting>
</step>
<step>
<screen><userinput>cd ~/devstack</userinput></screen>
</step>
<step>
<screen><userinput>source openrc</userinput></screen>
</step>
<step>
<screen><userinput>IMAGE_ID=`nova image-list | egrep cirros | egrep -v "kernel|ramdisk" | awk '{print $2}'`</userinput></screen>
</step>
<step>
<screen><userinput>nova boot --flavor 1 --image $IMAGE_ID scheduler-test</userinput></screen>
</step>
<step>
<para>Start by switching back to the
<code>n-sch</code> screen</para>
</step>
</substeps>
</step>
<step>
<para>Among the log statements you'll see the line.</para>
<para>Switch back to the <code>n-sch</code> screen. Among the
log statements you'll see the line.</para>
<screen>2014-01-23 19:57:47.262 DEBUG nova.scheduler.ip_scheduler [req-... demo demo] Request from 162.242.221.84 scheduled to devstack-havana _schedule /opt/stack/nova/nova/scheduler/ip_scheduler.py:76</screen>
</step>
</procedure>
@ -911,7 +831,7 @@ LOG.debug("filter_properties = %(filter_properties)s" % locals())</programlistin
>schedulers</link> (https://github.com/openstack/nova/tree/master/nova/scheduler).</para>
</section>
<section xml:id="ops_dashboard">
<title>Dashboard</title>
<title>Horizon Dashboard Example</title>
<para>The Dashboard is based on the Python
<link xlink:href="https://www.djangoproject.com/">Django</link>
(https://www.djangoproject.com/) web application framework. The
@ -927,7 +847,7 @@ LOG.debug("filter_properties = %(filter_properties)s" % locals())</programlistin
<para>When operating an OpenStack cloud you may discover that your
users can be quite demanding. If OpenStack doesn't do what your
users need, it may be up to you to fulfill those requirements.
This chapter provides you with some options for customization and
gives you the tools you need to get started.</para>
This chapter provided you with some options for customization and
gave you the tools you need to get started.</para>
</section>
</chapter>