Merge "Fix i18n support for help and error messages in compute"

This commit is contained in:
Jenkins 2016-05-24 11:54:13 +00:00 committed by Gerrit Code Review
commit 086c3ab8fa
11 changed files with 184 additions and 133 deletions

View File

@ -19,6 +19,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
from openstackclient.i18n import _
class CreateAgent(command.ShowOne):
@ -29,28 +30,34 @@ class CreateAgent(command.ShowOne):
parser.add_argument(
"os",
metavar="<os>",
help="Type of OS")
help=_("Type of OS")
)
parser.add_argument(
"architecture",
metavar="<architecture>",
help="Type of architecture")
help=_("Type of architecture")
)
parser.add_argument(
"version",
metavar="<version>",
help="Version")
help=_("Version")
)
parser.add_argument(
"url",
metavar="<url>",
help="URL")
help=_("URL")
)
parser.add_argument(
"md5hash",
metavar="<md5hash>",
help="MD5 hash")
help=_("MD5 hash")
)
parser.add_argument(
"hypervisor",
metavar="<hypervisor>",
help="Type of hypervisor",
default="xen")
default="xen",
help=_("Type of hypervisor")
)
return parser
def take_action(self, parsed_args):
@ -75,7 +82,8 @@ class DeleteAgent(command.Command):
parser.add_argument(
"id",
metavar="<id>",
help="ID of agent to delete")
help=_("ID of agent to delete")
)
return parser
def take_action(self, parsed_args):
@ -91,7 +99,8 @@ class ListAgent(command.Lister):
parser.add_argument(
"--hypervisor",
metavar="<hypervisor>",
help="Type of hypervisor")
help=_("Type of hypervisor")
)
return parser
def take_action(self, parsed_args):
@ -120,19 +129,23 @@ class SetAgent(command.Command):
parser.add_argument(
"id",
metavar="<id>",
help="ID of the agent")
help=_("ID of the agent")
)
parser.add_argument(
"version",
metavar="<version>",
help="Version of the agent")
help=_("Version of the agent")
)
parser.add_argument(
"url",
metavar="<url>",
help="URL")
help=_("URL")
)
parser.add_argument(
"md5hash",
metavar="<md5hash>",
help="MD5 hash")
help=_("MD5 hash")
)
return parser
def take_action(self, parsed_args):

View File

@ -21,6 +21,7 @@ import six
from openstackclient.common import command
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.i18n import _
class AddAggregateHost(command.ShowOne):
@ -31,12 +32,12 @@ class AddAggregateHost(command.ShowOne):
parser.add_argument(
'aggregate',
metavar='<aggregate>',
help='Aggregate (name or ID)',
help=_("Aggregate (name or ID)")
)
parser.add_argument(
'host',
metavar='<host>',
help='Host to add to <aggregate>',
help=_("Host to add to <aggregate>")
)
return parser
@ -62,19 +63,19 @@ class CreateAggregate(command.ShowOne):
parser.add_argument(
"name",
metavar="<name>",
help="New aggregate name",
help=_("New aggregate name")
)
parser.add_argument(
"--zone",
metavar="<availability-zone>",
help="Availability zone name",
help=_("Availability zone name")
)
parser.add_argument(
"--property",
metavar="<key=value>",
action=parseractions.KeyValueAction,
help='Property to add to this aggregate '
'(repeat option to set multiple properties)',
help=_("Property to add to this aggregate "
"(repeat option to set multiple properties)")
)
return parser
@ -105,7 +106,7 @@ class DeleteAggregate(command.Command):
parser.add_argument(
'aggregate',
metavar='<aggregate>',
help='Aggregate to delete (name or ID)',
help=_("Aggregate to delete (name or ID)")
)
return parser
@ -128,7 +129,8 @@ class ListAggregate(command.Lister):
'--long',
action='store_true',
default=False,
help='List additional fields in output')
help=_("List additional fields in output")
)
return parser
def take_action(self, parsed_args):
@ -175,12 +177,12 @@ class RemoveAggregateHost(command.ShowOne):
parser.add_argument(
'aggregate',
metavar='<aggregate>',
help='Aggregate (name or ID)',
help=_("Aggregate (name or ID)")
)
parser.add_argument(
'host',
metavar='<host>',
help='Host to remove from <aggregate>',
help=_("Host to remove from <aggregate>")
)
return parser
@ -209,24 +211,24 @@ class SetAggregate(command.Command):
parser.add_argument(
'aggregate',
metavar='<aggregate>',
help='Aggregate to modify (name or ID)',
help=_("Aggregate to modify (name or ID)")
)
parser.add_argument(
'--name',
metavar='<name>',
help='Set aggregate name',
help=_("Set aggregate name")
)
parser.add_argument(
"--zone",
metavar="<availability-zone>",
help="Set availability zone name",
help=_("Set availability zone name")
)
parser.add_argument(
"--property",
metavar="<key=value>",
action=parseractions.KeyValueAction,
help='Property to set on <aggregate> '
'(repeat option to set multiple properties)',
help=_("Property to set on <aggregate> "
"(repeat option to set multiple properties)")
)
return parser
@ -264,7 +266,7 @@ class ShowAggregate(command.ShowOne):
parser.add_argument(
'aggregate',
metavar='<aggregate>',
help='Aggregate to display (name or ID)',
help=_("Aggregate to display (name or ID)")
)
return parser
@ -300,15 +302,15 @@ class UnsetAggregate(command.Command):
parser.add_argument(
"aggregate",
metavar="<aggregate>",
help="Aggregate to modify (name or ID)",
help=_("Aggregate to modify (name or ID)")
)
parser.add_argument(
"--property",
metavar="<key>",
action='append',
help='Property to remove from aggregate '
'(repeat option to remove multiple properties)',
required=True,
help=_("Property to remove from aggregate "
"(repeat option to remove multiple properties)")
)
return parser

View File

@ -21,6 +21,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.i18n import _
class ShowConsoleLog(command.Command):
@ -31,7 +32,7 @@ class ShowConsoleLog(command.Command):
parser.add_argument(
'server',
metavar='<server>',
help='Server to show console log (name or ID)',
help=_("Server to show console log (name or ID)")
)
parser.add_argument(
'--lines',
@ -39,8 +40,8 @@ class ShowConsoleLog(command.Command):
type=int,
default=None,
action=parseractions.NonNegativeAction,
help='Number of lines to display from the end of the log '
'(default=all)',
help=_("Number of lines to display from the end of the log "
"(default=all)")
)
return parser
@ -69,7 +70,7 @@ class ShowConsoleURL(command.ShowOne):
parser.add_argument(
'server',
metavar='<server>',
help='Server to show URL (name or ID)',
help=_("Server to show URL (name or ID)")
)
type_group = parser.add_mutually_exclusive_group()
type_group.add_argument(
@ -78,21 +79,21 @@ class ShowConsoleURL(command.ShowOne):
action='store_const',
const='novnc',
default='novnc',
help='Show noVNC console URL (default)',
help=_("Show noVNC console URL (default)")
)
type_group.add_argument(
'--xvpvnc',
dest='url_type',
action='store_const',
const='xvpvnc',
help='Show xpvnc console URL',
help=_("Show xpvnc console URL")
)
type_group.add_argument(
'--spice',
dest='url_type',
action='store_const',
const='spice',
help='Show SPICE console URL',
help=_("Show SPICE console URL")
)
return parser

View File

@ -21,6 +21,7 @@ from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.i18n import _
def _find_flavor(compute_client, flavor):
@ -35,7 +36,7 @@ def _find_flavor(compute_client, flavor):
return compute_client.flavors.find(name=flavor, is_public=None)
except Exception as ex:
if type(ex).__name__ == 'NotFound':
msg = "No flavor with a name or ID of '%s' exists." % flavor
msg = _("No flavor with a name or ID of '%s' exists.") % flavor
raise exceptions.CommandError(msg)
else:
raise
@ -49,56 +50,56 @@ class CreateFlavor(command.ShowOne):
parser.add_argument(
"name",
metavar="<flavor-name>",
help="New flavor name",
help=_("New flavor name")
)
parser.add_argument(
"--id",
metavar="<id>",
default='auto',
help="Unique flavor ID; 'auto' creates a UUID "
"(default: auto)",
help=_("Unique flavor ID; 'auto' creates a UUID "
"(default: auto)")
)
parser.add_argument(
"--ram",
type=int,
metavar="<size-mb>",
default=256,
help="Memory size in MB (default 256M)",
help=_("Memory size in MB (default 256M)")
)
parser.add_argument(
"--disk",
type=int,
metavar="<size-gb>",
default=0,
help="Disk size in GB (default 0G)",
help=_("Disk size in GB (default 0G)")
)
parser.add_argument(
"--ephemeral",
type=int,
metavar="<size-gb>",
default=0,
help="Ephemeral disk size in GB (default 0G)",
help=_("Ephemeral disk size in GB (default 0G)")
)
parser.add_argument(
"--swap",
type=int,
metavar="<size-gb>",
default=0,
help="Swap space size in GB (default 0G)",
help=_("Swap space size in GB (default 0G)")
)
parser.add_argument(
"--vcpus",
type=int,
metavar="<vcpus>",
default=1,
help="Number of vcpus (default 1)",
help=_("Number of vcpus (default 1)")
)
parser.add_argument(
"--rxtx-factor",
type=float,
metavar="<factor>",
default=1.0,
help="RX/TX factor (default 1.0)",
help=_("RX/TX factor (default 1.0)")
)
public_group = parser.add_mutually_exclusive_group()
public_group.add_argument(
@ -106,13 +107,13 @@ class CreateFlavor(command.ShowOne):
dest="public",
action="store_true",
default=True,
help="Flavor is available to other projects (default)",
help=_("Flavor is available to other projects (default)")
)
public_group.add_argument(
"--private",
dest="public",
action="store_false",
help="Flavor is not available to other projects",
help=_("Flavor is not available to other projects")
)
return parser
@ -145,7 +146,7 @@ class DeleteFlavor(command.Command):
parser.add_argument(
"flavor",
metavar="<flavor>",
help="Flavor to delete (name or ID)",
help=_("Flavor to delete (name or ID)")
)
return parser
@ -166,35 +167,38 @@ class ListFlavor(command.Lister):
dest="public",
action="store_true",
default=True,
help="List only public flavors (default)",
help=_("List only public flavors (default)")
)
public_group.add_argument(
"--private",
dest="public",
action="store_false",
help="List only private flavors",
help=_("List only private flavors")
)
public_group.add_argument(
"--all",
dest="all",
action="store_true",
default=False,
help="List all flavors, whether public or private",
help=_("List all flavors, whether public or private")
)
parser.add_argument(
'--long',
action='store_true',
default=False,
help='List additional fields in output')
help=_("List additional fields in output")
)
parser.add_argument(
'--marker',
metavar="<marker>",
help='The last flavor ID of the previous page')
help=_("The last flavor ID of the previous page")
)
parser.add_argument(
'--limit',
type=int,
metavar="<limit>",
help='Maximum number of flavors to display')
help=_("Maximum number of flavors to display")
)
return parser
def take_action(self, parsed_args):
@ -245,13 +249,13 @@ class SetFlavor(command.Command):
"--property",
metavar="<key=value>",
action=parseractions.KeyValueAction,
help='Property to add or modify for this flavor '
'(repeat option to set multiple properties)',
help=_("Property to add or modify for this flavor "
"(repeat option to set multiple properties)")
)
parser.add_argument(
"flavor",
metavar="<flavor>",
help="Flavor to modify (name or ID)",
help=_("Flavor to modify (name or ID)")
)
return parser
@ -269,7 +273,7 @@ class ShowFlavor(command.ShowOne):
parser.add_argument(
"flavor",
metavar="<flavor>",
help="Flavor to display (name or ID)",
help=_("Flavor to display (name or ID)")
)
return parser
@ -293,14 +297,14 @@ class UnsetFlavor(command.Command):
"--property",
metavar="<key>",
action='append',
help='Property to remove from flavor '
'(repeat option to unset multiple properties)',
required=True,
help=_("Property to remove from flavor "
"(repeat option to unset multiple properties)")
)
parser.add_argument(
"flavor",
metavar="<flavor>",
help="Flavor to modify (name or ID)",
help=_("Flavor to modify (name or ID)")
)
return parser

View File

@ -17,6 +17,7 @@
from openstackclient.common import command
from openstackclient.common import utils
from openstackclient.i18n import _
class ListHost(command.Lister):
@ -27,7 +28,8 @@ class ListHost(command.Lister):
parser.add_argument(
"--zone",
metavar="<zone>",
help="Only return hosts in the availability zone.")
help=_("Only return hosts in the availability zone")
)
return parser
def take_action(self, parsed_args):
@ -51,29 +53,29 @@ class SetHost(command.Command):
parser.add_argument(
"host",
metavar="<host>",
help="The host to modify (name or ID)"
help=_("The host to modify (name or ID)")
)
status = parser.add_mutually_exclusive_group()
status.add_argument(
'--enable',
action='store_true',
help='Enable the host'
help=_("Enable the host")
)
status.add_argument(
'--disable',
action='store_true',
help='Disable the host'
help=_("Disable the host")
)
maintenance = parser.add_mutually_exclusive_group()
maintenance.add_argument(
'--enable-maintenance',
action='store_true',
help='Enable maintenance mode for the host'
help=_("Enable maintenance mode for the host")
)
maintenance.add_argument(
'--disable-maintenance',
action='store_true',
help='Disable maintenance mode for the host',
help=_("Disable maintenance mode for the host")
)
return parser
@ -109,7 +111,8 @@ class ShowHost(command.Lister):
parser.add_argument(
"host",
metavar="<host>",
help="Name of host")
help=_("Name of host")
)
return parser
def take_action(self, parsed_args):

View File

@ -20,6 +20,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
from openstackclient.i18n import _
class ListHypervisor(command.Lister):
@ -30,7 +31,7 @@ class ListHypervisor(command.Lister):
parser.add_argument(
"--matching",
metavar="<hostname>",
help="Filter hypervisors using <hostname> substring",
help=_("Filter hypervisors using <hostname> substring")
)
return parser
@ -60,7 +61,8 @@ class ShowHypervisor(command.ShowOne):
parser.add_argument(
"hypervisor",
metavar="<hypervisor>",
help="Hypervisor to display (name or ID)")
help=_("Hypervisor to display (name or ID)")
)
return parser
def take_action(self, parsed_args):

View File

@ -23,6 +23,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.i18n import _
class CreateKeypair(command.ShowOne):
@ -33,12 +34,12 @@ class CreateKeypair(command.ShowOne):
parser.add_argument(
'name',
metavar='<name>',
help='New public key name',
help=_("New public key name")
)
parser.add_argument(
'--public-key',
metavar='<file>',
help='Filename for public key to add',
help=_("Filename for public key to add")
)
return parser
@ -51,9 +52,11 @@ class CreateKeypair(command.ShowOne):
with io.open(os.path.expanduser(parsed_args.public_key)) as p:
public_key = p.read()
except IOError as e:
msg = "Key file %s not found: %s"
raise exceptions.CommandError(msg
% (parsed_args.public_key, e))
msg = _("Key file %(public_key)s not found: %(exception)s")
raise exceptions.CommandError(
msg % {"public_key": parsed_args.public_key,
"exception": e}
)
keypair = compute_client.keypairs.create(
parsed_args.name,
@ -81,7 +84,7 @@ class DeleteKeypair(command.Command):
parser.add_argument(
'name',
metavar='<key>',
help='Public key to delete',
help=_("Public key to delete")
)
return parser
@ -115,13 +118,13 @@ class ShowKeypair(command.ShowOne):
parser.add_argument(
'name',
metavar='<key>',
help='Public key to display',
help=_("Public key to display")
)
parser.add_argument(
'--public-key',
action='store_true',
default=False,
help='Show only bare public key',
help=_("Show only bare public key")
)
return parser

View File

@ -102,9 +102,10 @@ def _get_ip_address(addresses, address_type, ip_address_family):
if addy['OS-EXT-IPS:type'] == new_address_type:
if int(addy['version']) in ip_address_family:
return addy['addr']
msg = _("ERROR: No %(type)s IP version %(family)s address found")
raise exceptions.CommandError(
"ERROR: No %s IP version %s address found" %
(address_type, ip_address_family)
msg % {"type": address_type,
"family": ip_address_family}
)
@ -417,7 +418,11 @@ class CreateServer(command.ShowOne):
try:
files[dst] = io.open(src, 'rb')
except IOError as e:
raise exceptions.CommandError("Can't open '%s': %s" % (src, e))
msg = _("Can't open '%(source)s': %(exception)s")
raise exceptions.CommandError(
msg % {"source": src,
"exception": e}
)
if parsed_args.min > parsed_args.max:
msg = _("min instances should be <= max instances")
@ -434,8 +439,11 @@ class CreateServer(command.ShowOne):
try:
userdata = io.open(parsed_args.user_data)
except IOError as e:
msg = "Can't open '%s': %s"
raise exceptions.CommandError(msg % (parsed_args.user_data, e))
msg = _("Can't open '%(data)s': %(exception)s")
raise exceptions.CommandError(
msg % {"data": parsed_args.user_data,
"exception": e}
)
block_device_mapping = {}
if volume:
@ -744,7 +752,8 @@ class ListServer(command.Lister):
parser.add_argument(
'--project',
metavar='<project>',
help="Search by project (admin only) (name or ID)")
help=_("Search by project (admin only) (name or ID)")
)
identity_common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--user',
@ -762,19 +771,19 @@ class ListServer(command.Lister):
'--marker',
metavar='<marker>',
default=None,
help=('The last server (name or ID) of the previous page. Display'
' list of servers after marker. Display all servers if not'
' specified.')
help=_('The last server (name or ID) of the previous page. Display'
' list of servers after marker. Display all servers if not'
' specified.')
)
parser.add_argument(
'--limit',
metavar='<limit>',
type=int,
default=None,
help=("Maximum number of servers to display. If limit equals -1,"
" all servers will be displayed. If limit is greater than"
" 'osapi_max_limit' option of Nova API,"
" 'osapi_max_limit' will be used instead."),
help=_("Maximum number of servers to display. If limit equals -1,"
" all servers will be displayed. If limit is greater than"
" 'osapi_max_limit' option of Nova API,"
" 'osapi_max_limit' will be used instead."),
)
return parser
@ -1101,7 +1110,7 @@ class RebuildServer(command.ShowOne):
parser.add_argument(
'--password',
metavar='<password>',
help="Set the password on the rebuilt instance",
help=_("Set the password on the rebuilt instance"),
)
parser.add_argument(
'--wait',

View File

@ -18,6 +18,7 @@
from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.i18n import _
_formatters = {
@ -43,15 +44,15 @@ class CreateServerGroup(command.ShowOne):
parser.add_argument(
'name',
metavar='<name>',
help='New server group name',
help=_("New server group name")
)
parser.add_argument(
'--policy',
metavar='<policy>',
action='append',
required=True,
help='Add a policy to <name> '
'(repeat option to add multiple policies)',
help=_("Add a policy to <name> "
"(repeat option to add multiple policies)")
)
return parser
@ -78,7 +79,7 @@ class DeleteServerGroup(command.Command):
'server_group',
metavar='<server-group>',
nargs='+',
help='server group(s) to delete (name or ID)',
help=_("server group(s) to delete (name or ID)")
)
return parser
@ -97,8 +98,11 @@ class DeleteServerGroup(command.Command):
if result > 0:
total = len(parsed_args.server_group)
msg = "%s of %s server groups failed to delete." % (result, total)
raise exceptions.CommandError(msg)
msg = _("%(result)s of %(total)s server groups failed to delete.")
raise exceptions.CommandError(
msg % {"result": result,
"total": total}
)
class ListServerGroup(command.Lister):
@ -110,13 +114,13 @@ class ListServerGroup(command.Lister):
'--all-projects',
action='store_true',
default=False,
help='Display information from all projects (admin only)',
help=_("Display information from all projects (admin only)")
)
parser.add_argument(
'--long',
action='store_true',
default=False,
help='List additional fields in output',
help=_("List additional fields in output")
)
return parser
@ -166,7 +170,7 @@ class ShowServerGroup(command.ShowOne):
parser.add_argument(
'server_group',
metavar='<server-group>',
help='server group to display (name or ID)',
help=_("server group to display (name or ID)")
)
return parser

View File

@ -28,7 +28,8 @@ class DeleteService(command.Command):
parser.add_argument(
"service",
metavar="<service>",
help="Compute service to delete (ID only)")
help=_("Compute service to delete (ID only)")
)
return parser
def take_action(self, parsed_args):
@ -45,16 +46,18 @@ class ListService(command.Lister):
parser.add_argument(
"--host",
metavar="<host>",
help="List services on specified host (name only)")
help=_("List services on specified host (name only)")
)
parser.add_argument(
"--service",
metavar="<service>",
help="List only specified service (name only)")
help=_("List only specified service (name only)")
)
parser.add_argument(
"--long",
action="store_true",
default=False,
help="List additional fields in output"
help=_("List additional fields in output")
)
return parser
@ -97,29 +100,34 @@ class SetService(command.Command):
parser.add_argument(
"host",
metavar="<host>",
help="Name of host")
help=_("Name of host")
)
parser.add_argument(
"service",
metavar="<service>",
help="Name of service")
help=_("Name of service")
)
enabled_group = parser.add_mutually_exclusive_group()
enabled_group.add_argument(
"--enable",
dest="enabled",
default=True,
help="Enable a service (default)",
action="store_true")
action="store_true",
help=_("Enable a service (default)")
)
enabled_group.add_argument(
"--disable",
dest="enabled",
help="Disable a service",
action="store_false")
action="store_false",
help=_("Disable a service")
)
parser.add_argument(
"--disable-reason",
default=None,
metavar="<reason>",
help="Reason for disabling the service (in quotas). Note that "
"when the service is enabled, this option is ignored.")
help=_("Reason for disabling the service (in quotas). Note that "
"when the service is enabled, this option is ignored.")
)
return parser
def take_action(self, parsed_args):

View File

@ -22,6 +22,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
from openstackclient.i18n import _
class ListUsage(command.Lister):
@ -33,14 +34,14 @@ class ListUsage(command.Lister):
"--start",
metavar="<start>",
default=None,
help="Usage range start date, ex 2012-01-20"
" (default: 4 weeks ago)"
help=_("Usage range start date, ex 2012-01-20"
" (default: 4 weeks ago)")
)
parser.add_argument(
"--end",
metavar="<end>",
default=None,
help="Usage range end date, ex 2012-01-20 (default: tomorrow)"
help=_("Usage range end date, ex 2012-01-20 (default: tomorrow)")
)
return parser
@ -95,10 +96,10 @@ class ListUsage(command.Lister):
pass
if parsed_args.formatter == 'table' and len(usage_list) > 0:
sys.stdout.write("Usage from %s to %s: \n" % (
start.strftime(dateformat),
end.strftime(dateformat),
))
sys.stdout.write(_("Usage from %(start)s to %(end)s: \n") % {
"start": start.strftime(dateformat),
"end": end.strftime(dateformat),
})
return (column_headers,
(utils.get_item_properties(
@ -122,20 +123,20 @@ class ShowUsage(command.ShowOne):
"--project",
metavar="<project>",
default=None,
help="Name or ID of project to show usage for"
help=_("Name or ID of project to show usage for")
)
parser.add_argument(
"--start",
metavar="<start>",
default=None,
help="Usage range start date, ex 2012-01-20"
" (default: 4 weeks ago)"
help=_("Usage range start date, ex 2012-01-20"
" (default: 4 weeks ago)")
)
parser.add_argument(
"--end",
metavar="<end>",
default=None,
help="Usage range end date, ex 2012-01-20 (default: tomorrow)"
help=_("Usage range end date, ex 2012-01-20 (default: tomorrow)")
)
return parser
@ -167,11 +168,12 @@ class ShowUsage(command.ShowOne):
usage = compute_client.usage.get(project, start, end)
if parsed_args.formatter == 'table':
sys.stdout.write("Usage from %s to %s on project %s: \n" % (
start.strftime(dateformat),
end.strftime(dateformat),
project
))
sys.stdout.write(_("Usage from %(start)s to %(end)s on "
"project %(project)s: \n") % {
"start": start.strftime(dateformat),
"end": end.strftime(dateformat),
"project": project,
})
info = {}
info['Servers'] = (