summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Hurley <gabriel@strikeawe.com>2011-10-31 11:31:05 -0700
committerGabriel Hurley <gabriel@strikeawe.com>2011-11-07 12:59:21 -0800
commit9742842795e964c7f260aec831665d5cb28cd420 (patch)
treeaa7de5eb8efbdaa466c4b3ce4f1f5f48517936d5
parent91ceb59bae8818e407614bb0ff32f21ced1eadaa (diff)
downloadtuskar-ui-9742842795e964c7f260aec831665d5cb28cd420.tar.gz
Re-architects the OpenStack Dashboard for modularity and extensibility.
Implements blueprint extensible-architecture. Implements blueprint improve-dev-documentation. Implements blueprint gettext-everywhere. Implements blueprint sphinx-docs. Complete re-architecture of the dashboard to transform it from a standalone django-openstack app to a Horizon framework for building dashboards. See the docs for more information. Incidentally fixes the following bugs: Fixes bug 845868 -- no PEP8 violations. Fixes bug 766096 -- the dashboard can now be installed at any arbitrary URL. Fixes bug 879111 -- tenant id is now controlled solely by the tenant switcher, not the url (which was disregarded anyway) Fixes bug 794754 -- output of venv installation is considerably reduced. Due to the scale and scope of this patch I recommend reviewing it on github: https://github.com/gabrielhurley/horizon/tree/extensible_architecture Change-Id: I8e63f7ea235f904247df40c33cb66338d973df9e
-rw-r--r--.bzrignore16
-rw-r--r--.gitignore23
-rw-r--r--README34
-rw-r--r--django-openstack/README56
-rw-r--r--django-openstack/django_openstack/api.py1093
-rw-r--r--django-openstack/django_openstack/context_processors.py48
-rw-r--r--django-openstack/django_openstack/dash/urls.py118
-rw-r--r--django-openstack/django_openstack/dash/views/containers.py95
-rw-r--r--django-openstack/django_openstack/dash/views/networks.py252
-rw-r--r--django-openstack/django_openstack/decorators.py42
-rw-r--r--django-openstack/django_openstack/exceptions.py8
-rw-r--r--django-openstack/django_openstack/locale/es/LC_MESSAGES/django.po1948
-rw-r--r--django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.po1948
-rw-r--r--django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.mobin2564 -> 0 bytes
-rw-r--r--django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.po1947
-rw-r--r--django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.po1947
-rw-r--r--django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.po1947
-rw-r--r--django-openstack/django_openstack/signals.py50
-rw-r--r--django-openstack/django_openstack/syspanel/urls.py78
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/auth/_login.html17
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html9
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html9
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html28
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/dash/containers/index.html19
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/dash/networks/detail.html31
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html18
-rw-r--r--django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/index.html19
-rw-r--r--django-openstack/django_openstack/templatetags/templatetags/sidebar_modules.py46
-rw-r--r--django-openstack/django_openstack/templatetags/templatetags/swift_paging.py15
-rw-r--r--django-openstack/django_openstack/test.py99
-rw-r--r--django-openstack/django_openstack/tests/api_tests.py1587
-rw-r--r--django-openstack/django_openstack/tests/broken/README2
-rw-r--r--django-openstack/django_openstack/tests/broken/base.py81
-rw-r--r--django-openstack/django_openstack/tests/broken/credential_tests.py70
-rw-r--r--django-openstack/django_openstack/tests/broken/image_tests.py237
-rw-r--r--django-openstack/django_openstack/tests/broken/instance_tests.py69
-rw-r--r--django-openstack/django_openstack/tests/broken/keypair_tests.py93
-rw-r--r--django-openstack/django_openstack/tests/broken/region_tests.py41
-rw-r--r--django-openstack/django_openstack/tests/broken/test_models.py187
-rw-r--r--django-openstack/django_openstack/tests/broken/volume_tests.py171
-rw-r--r--django-openstack/django_openstack/tests/context_processor_tests.py23
-rw-r--r--django-openstack/django_openstack/tests/templatetag_tests.py71
-rw-r--r--django-openstack/django_openstack/tests/view_tests/base.py77
-rw-r--r--django-openstack/django_openstack/tests/view_tests/dash/container_tests.py121
-rw-r--r--django-openstack/django_openstack/tests/view_tests/dash/port_tests.py104
-rw-r--r--django-openstack/django_openstack/urls.py38
-rw-r--r--django-openstack/django_openstack/utils.py48
-rwxr-xr-xdoc/generate_autodoc_index.py68
-rw-r--r--doc/source/index.rst69
-rw-r--r--doc/source/testing.rst32
-rw-r--r--docs/Makefile (renamed from doc/Makefile)0
-rw-r--r--docs/source/_static/.gitignore (renamed from django-openstack/django_openstack/__init__.py)0
-rw-r--r--docs/source/conf.py (renamed from doc/source/conf.py)96
-rw-r--r--docs/source/faq.rst37
-rw-r--r--docs/source/glossary.rst19
-rw-r--r--docs/source/index.rst101
-rw-r--r--docs/source/intro.rst124
-rw-r--r--docs/source/quickstart.rst146
-rw-r--r--docs/source/ref/context_processors.rst6
-rw-r--r--docs/source/ref/decorators.rst6
-rw-r--r--docs/source/ref/exceptions.rst6
-rw-r--r--docs/source/ref/forms.rst17
-rw-r--r--docs/source/ref/horizon.rst42
-rw-r--r--docs/source/ref/middleware.rst6
-rw-r--r--docs/source/ref/run_tests.rst100
-rw-r--r--docs/source/ref/users.rst6
-rw-r--r--docs/source/ref/views.rst12
-rw-r--r--docs/source/testing.rst62
-rw-r--r--horizon/LICENSE (renamed from django-openstack/LICENSE)0
-rw-r--r--horizon/Makefile (renamed from django-openstack/Makefile)4
-rw-r--r--horizon/README59
-rw-r--r--horizon/bootstrap.py (renamed from django-openstack/bootstrap.py)0
-rw-r--r--horizon/buildout.cfg (renamed from django-openstack/buildout.cfg)13
-rw-r--r--horizon/horizon/__init__.py50
-rw-r--r--horizon/horizon/api/__init__.py39
-rw-r--r--horizon/horizon/api/base.py118
-rw-r--r--horizon/horizon/api/deprecated.py95
-rw-r--r--horizon/horizon/api/glance.py89
-rw-r--r--horizon/horizon/api/keystone.py256
-rw-r--r--horizon/horizon/api/nova.py357
-rw-r--r--horizon/horizon/api/quantum.py133
-rw-r--r--horizon/horizon/api/swift.py132
-rw-r--r--horizon/horizon/base.py594
-rw-r--r--horizon/horizon/context_processors.py69
-rw-r--r--horizon/horizon/dashboards/__init__.py (renamed from django-openstack/django_openstack/auth/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/__init__.py (renamed from django-openstack/django_openstack/dash/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/containers/__init__.py (renamed from django-openstack/django_openstack/dash/views/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/containers/forms.py (renamed from django-openstack/django_openstack/dash/views/objects.py)119
-rw-r--r--horizon/horizon/dashboards/nova/containers/panel.py35
-rw-r--r--horizon/horizon/dashboards/nova/containers/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/object_tests.py)177
-rw-r--r--horizon/horizon/dashboards/nova/containers/urls.py36
-rw-r--r--horizon/horizon/dashboards/nova/containers/views.py134
-rw-r--r--horizon/horizon/dashboards/nova/dashboard.py33
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/__init__.py (renamed from django-openstack/django_openstack/middleware/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/forms.py (renamed from django-openstack/django_openstack/dash/views/floating_ips.py)72
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/floating_ip_tests.py)85
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/urls.py28
-rw-r--r--horizon/horizon/dashboards/nova/floating_ips/views.py88
-rw-r--r--horizon/horizon/dashboards/nova/images/__init__.py (renamed from django-openstack/django_openstack/syspanel/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/images/forms.py (renamed from django-openstack/django_openstack/dash/views/images.py)142
-rw-r--r--horizon/horizon/dashboards/nova/images/panel.py (renamed from django-openstack/django_openstack/syspanel/forms.py)11
-rw-r--r--horizon/horizon/dashboards/nova/images/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/images_tests.py)64
-rw-r--r--horizon/horizon/dashboards/nova/images/urls.py27
-rw-r--r--horizon/horizon/dashboards/nova/images/views.py163
-rw-r--r--horizon/horizon/dashboards/nova/instances/__init__.py (renamed from django-openstack/django_openstack/syspanel/views/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/instances/forms.py101
-rw-r--r--horizon/horizon/dashboards/nova/instances/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/instances/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/instance_tests.py)134
-rw-r--r--horizon/horizon/dashboards/nova/instances/urls.py33
-rw-r--r--horizon/horizon/dashboards/nova/instances/views.py (renamed from django-openstack/django_openstack/dash/views/instances.py)186
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/__init__.py (renamed from django-openstack/django_openstack/templatetags/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/forms.py (renamed from django-openstack/django_openstack/dash/views/keypairs.py)65
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/keypair_tests.py)50
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/urls.py28
-rw-r--r--horizon/horizon/dashboards/nova/keypairs/views.py80
-rw-r--r--horizon/horizon/dashboards/nova/models.py (renamed from django-openstack/django_openstack/models.py)0
-rw-r--r--horizon/horizon/dashboards/nova/networks/__init__.py (renamed from django-openstack/django_openstack/templatetags/templatetags/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/networks/forms.py (renamed from django-openstack/django_openstack/dash/views/ports.py)134
-rw-r--r--horizon/horizon/dashboards/nova/networks/panel.py33
-rw-r--r--horizon/horizon/dashboards/nova/networks/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/network_tests.py)118
-rw-r--r--horizon/horizon/dashboards/nova/networks/urls.py (renamed from django-openstack/django_openstack/tests/dependency_tests.py)28
-rw-r--r--horizon/horizon/dashboards/nova/networks/views.py231
-rw-r--r--horizon/horizon/dashboards/nova/overview/__init__.py (renamed from django-openstack/django_openstack/tests/view_tests/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/overview/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/overview/urls.py (renamed from django-openstack/django_openstack/auth/urls.py)10
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/__init__.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/forms.py (renamed from django-openstack/django_openstack/dash/views/security_groups.py)89
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/security_groups_tests.py)113
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/urls.py28
-rw-r--r--horizon/horizon/dashboards/nova/security_groups/views.py103
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/__init__.py (renamed from django-openstack/django_openstack/tests/view_tests/syspanel/__init__.py)0
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/forms.py57
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/panel.py30
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/dash/snapshots_tests.py)75
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/urls.py26
-rw-r--r--horizon/horizon/dashboards/nova/snapshots/views.py (renamed from django-openstack/django_openstack/dash/views/snapshots.py)64
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/base.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/base.html)11
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/containers/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/containers/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/containers/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/containers/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/containers/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/containers/_list.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/containers/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/containers/create.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/containers/index.html19
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/_allocate.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_allocate.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/_associate.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_associate.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/_disassociate.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_disassociate.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_list.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/_release.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_release.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/associate.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/associate.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/floating_ips/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/index.html)10
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/_launch.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/_launch.html)2
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/_launch_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/_launch_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/_list.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/index.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/launch.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/launch.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/images/update.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/images/update.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/_list.html)16
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/detail.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/detail.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/index.html)12
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/update.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/update.html)10
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/usage.csv (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.csv)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/instances/usage.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.html)10
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_list.html)2
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/create.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/import.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/import.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/keypairs/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/index.html)16
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_delete_port.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete_port.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_detach_port.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_detach_port.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_detail.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_detail.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_list.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_rename.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_rename_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/_toggle_port.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/_toggle_port.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/create.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/detail.html31
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/index.html)12
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/networks/rename.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/networks/rename.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_copy.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_copy.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_filter.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_filter.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_list.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/_paging.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/_paging.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/copy.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/copy.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/index.html)12
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/objects/upload.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/objects/upload.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/ports/_attach.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/ports/_attach.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/ports/_create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/ports/_create.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/ports/attach.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/ports/attach.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/ports/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/ports/create.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete_rule.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete_rule.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_list.html)4
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/create.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/edit_rules.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/edit_rules.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/security_groups/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/index.html)12
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/settings.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/settings.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/snapshots/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/snapshots/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/create.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/snapshots/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/index.html)10
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/_attach_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_attach_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/_detach_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_detach_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_form.html)0
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_list.html)10
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/attach.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/attach.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/create.html)8
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/detail.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/detail.html)6
-rw-r--r--horizon/horizon/dashboards/nova/templates/nova/volumes/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/dash/volumes/index.html)10
-rw-r--r--horizon/horizon/dashboards/nova/volumes/__init__.py (renamed from django-openstack/django_openstack/tests/templates/base-sidebar.html)0
-rw-r--r--horizon/horizon/dashboards/nova/volumes/forms.py (renamed from django-openstack/django_openstack/dash/views/volumes.py)92
-rw-r--r--horizon/horizon/dashboards/nova/volumes/panel.py26
-rw-r--r--horizon/horizon/dashboards/nova/volumes/tests.py0
-rw-r--r--horizon/horizon/dashboards/nova/volumes/urls.py25
-rw-r--r--horizon/horizon/dashboards/nova/volumes/views.py110
-rw-r--r--horizon/horizon/dashboards/settings/__init__.py0
-rw-r--r--horizon/horizon/dashboards/settings/dashboard.py30
-rw-r--r--horizon/horizon/dashboards/settings/models.py23
-rw-r--r--horizon/horizon/dashboards/settings/templates/settings/base.html13
-rw-r--r--horizon/horizon/dashboards/settings/templates/settings/user/settings.html32
-rw-r--r--horizon/horizon/dashboards/settings/user/__init__.py0
-rw-r--r--horizon/horizon/dashboards/settings/user/panel.py26
-rw-r--r--horizon/horizon/dashboards/settings/user/urls.py28
-rw-r--r--horizon/horizon/dashboards/syspanel/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/dashboard.py32
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/forms.py (renamed from django-openstack/django_openstack/syspanel/views/flavors.py)67
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/urls.py26
-rw-r--r--horizon/horizon/dashboards/syspanel/flavors/views.py77
-rw-r--r--horizon/horizon/dashboards/syspanel/images/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/images/forms.py83
-rw-r--r--horizon/horizon/dashboards/syspanel/images/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/images/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/images/urls.py26
-rw-r--r--horizon/horizon/dashboards/syspanel/images/views.py (renamed from django-openstack/django_openstack/syspanel/views/images.py)111
-rw-r--r--horizon/horizon/dashboards/syspanel/instances/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/instances/panel.py31
-rw-r--r--horizon/horizon/dashboards/syspanel/instances/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/instances/urls.py (renamed from django-openstack/django_openstack/tests/testurls.py)26
-rw-r--r--horizon/horizon/dashboards/syspanel/instances/views.py (renamed from django-openstack/django_openstack/syspanel/views/instances.py)138
-rw-r--r--horizon/horizon/dashboards/syspanel/models.py23
-rw-r--r--horizon/horizon/dashboards/syspanel/overview/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/overview/panel.py31
-rw-r--r--horizon/horizon/dashboards/syspanel/overview/urls.py26
-rw-r--r--horizon/horizon/dashboards/syspanel/quotas/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/quotas/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/quotas/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/quotas/urls.py25
-rw-r--r--horizon/horizon/dashboards/syspanel/quotas/views.py (renamed from django-openstack/django_openstack/syspanel/views/quotas.py)22
-rw-r--r--horizon/horizon/dashboards/syspanel/services/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/services/forms.py58
-rw-r--r--horizon/horizon/dashboards/syspanel/services/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/services/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/services/urls.py25
-rw-r--r--horizon/horizon/dashboards/syspanel/services/views.py (renamed from django-openstack/django_openstack/syspanel/views/services.py)59
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/base.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/base.html)11
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_create.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_create.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_form.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_list.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/create.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/index.html19
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_form.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_list.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/_toggle.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_toggle.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/index.html)8
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/images/update.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/images/update.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/_list.html)12
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/detail.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/detail.html)10
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/index.html)12
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.csv (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.csv)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.html)4
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.csv (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.csv)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/quotas/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/quotas/index.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/services/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/services/_list.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/services/_toggle.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/services/_toggle.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/services/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/services/index.html)8
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_add_user.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_add_user.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_create_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_create_form.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_form.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_list.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_list.html)8
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_quotas_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_quotas_form.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_remove_user.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_remove_user.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_form.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_quotas_form.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/create.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/index.html)10
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/quotas.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/quotas.html)8
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/update.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/update.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/users.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/users.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_create_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_create_form.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_delete.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_delete.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_enable_disable.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_enable_disable.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_form.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_toggle_enabled.html)0
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/_update_form.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_update_form.html)2
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/create.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/create.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/index.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/index.html)14
-rw-r--r--horizon/horizon/dashboards/syspanel/templates/syspanel/users/update.html (renamed from django-openstack/django_openstack/templates/django_openstack/syspanel/users/update.html)6
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/forms.py (renamed from django-openstack/django_openstack/syspanel/views/tenants.py)155
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/tests.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/urls.py29
-rw-r--r--horizon/horizon/dashboards/syspanel/tenants/views.py143
-rw-r--r--horizon/horizon/dashboards/syspanel/users/__init__.py0
-rw-r--r--horizon/horizon/dashboards/syspanel/users/forms.py102
-rw-r--r--horizon/horizon/dashboards/syspanel/users/panel.py30
-rw-r--r--horizon/horizon/dashboards/syspanel/users/tests.py (renamed from django-openstack/django_openstack/tests/view_tests/syspanel/users_tests.py)28
-rw-r--r--horizon/horizon/dashboards/syspanel/users/urls.py26
-rw-r--r--horizon/horizon/dashboards/syspanel/users/views.py (renamed from django-openstack/django_openstack/syspanel/views/users.py)148
-rw-r--r--horizon/horizon/decorators.py86
-rw-r--r--horizon/horizon/exceptions.py40
-rw-r--r--horizon/horizon/forms.py (renamed from django-openstack/django_openstack/forms.py)41
-rw-r--r--horizon/horizon/locale/es/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/es/LC_MESSAGES/django.mo)bin425 -> 425 bytes
-rw-r--r--horizon/horizon/locale/es/LC_MESSAGES/django.po1971
-rw-r--r--horizon/horizon/locale/fr/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.mo)bin420 -> 420 bytes
-rw-r--r--horizon/horizon/locale/fr/LC_MESSAGES/django.po1971
-rw-r--r--horizon/horizon/locale/ja/LC_MESSAGES/django.mobin0 -> 2528 bytes
-rw-r--r--horizon/horizon/locale/ja/LC_MESSAGES/django.po (renamed from django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.po)1846
-rw-r--r--horizon/horizon/locale/pl/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.mo)bin936 -> 936 bytes
-rw-r--r--horizon/horizon/locale/pl/LC_MESSAGES/django.po (renamed from django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.po)1822
-rw-r--r--horizon/horizon/locale/pt/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.mo)bin382 -> 382 bytes
-rw-r--r--horizon/horizon/locale/pt/LC_MESSAGES/django.po1970
-rw-r--r--horizon/horizon/locale/zh-cn/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.mo)bin382 -> 382 bytes
-rw-r--r--horizon/horizon/locale/zh-cn/LC_MESSAGES/django.po1970
-rw-r--r--horizon/horizon/locale/zh-tw/LC_MESSAGES/django.mo (renamed from django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.mo)bin382 -> 382 bytes
-rw-r--r--horizon/horizon/locale/zh-tw/LC_MESSAGES/django.po1970
-rw-r--r--horizon/horizon/middleware.py (renamed from django-openstack/django_openstack/middleware/keystone.py)55
-rw-r--r--horizon/horizon/models.py23
-rw-r--r--horizon/horizon/site_urls.py31
-rw-r--r--horizon/horizon/templates/horizon/_nav_list.html10
-rw-r--r--horizon/horizon/templates/horizon/_subnav_list.html14
-rw-r--r--horizon/horizon/templates/horizon/auth/_login.html17
-rw-r--r--horizon/horizon/templates/horizon/auth/_switch.html (renamed from django-openstack/django_openstack/templates/django_openstack/auth/_switch.html)12
-rw-r--r--horizon/horizon/templates/horizon/common/_page_header.html (renamed from django-openstack/django_openstack/templates/django_openstack/common/_page_header.html)6
-rw-r--r--horizon/horizon/templates/horizon/common/_sidebar.html5
-rw-r--r--horizon/horizon/templates/horizon/common/_sidebar_module.html (renamed from django-openstack/django_openstack/templates/django_openstack/common/_sidebar_module.html)4
-rw-r--r--horizon/horizon/templates/horizon/common/instances/_reboot.html9
-rw-r--r--horizon/horizon/templates/horizon/common/instances/_terminate.html9
-rw-r--r--horizon/horizon/templatetags/__init__.py0
-rw-r--r--horizon/horizon/templatetags/branding.py (renamed from django-openstack/django_openstack/templatetags/templatetags/branding.py)2
-rw-r--r--horizon/horizon/templatetags/horizon.py79
-rw-r--r--horizon/horizon/templatetags/parse_date.py (renamed from django-openstack/django_openstack/templatetags/templatetags/parse_date.py)0
-rw-r--r--horizon/horizon/templatetags/sizeformat.py (renamed from django-openstack/django_openstack/templatetags/templatetags/sizeformat.py)0
-rw-r--r--horizon/horizon/templatetags/swift_paging.py35
-rw-r--r--horizon/horizon/templatetags/truncate_filter.py (renamed from django-openstack/django_openstack/templatetags/templatetags/truncate_filter.py)0
-rw-r--r--horizon/horizon/test.py212
-rw-r--r--horizon/horizon/tests/__init__.py (renamed from django-openstack/django_openstack/tests/__init__.py)2
-rw-r--r--horizon/horizon/tests/api_tests/__init__.py29
-rw-r--r--horizon/horizon/tests/api_tests/base.py112
-rw-r--r--horizon/horizon/tests/api_tests/glance.py174
-rw-r--r--horizon/horizon/tests/api_tests/keystone.py366
-rw-r--r--horizon/horizon/tests/api_tests/nova.py697
-rw-r--r--horizon/horizon/tests/api_tests/swift.py260
-rw-r--r--horizon/horizon/tests/api_tests/utils.py99
-rw-r--r--horizon/horizon/tests/auth_tests.py (renamed from django-openstack/django_openstack/tests/view_tests/auth_tests.py)45
-rw-r--r--horizon/horizon/tests/base_tests.py133
-rw-r--r--horizon/horizon/tests/context_processor_tests.py45
-rw-r--r--horizon/horizon/tests/templates/base-sidebar.html0
-rw-r--r--horizon/horizon/tests/templates/base.html0
-rw-r--r--horizon/horizon/tests/templates/splash.html0
-rw-r--r--horizon/horizon/tests/templates/switch_tenants.html0
-rw-r--r--horizon/horizon/tests/templatetag_tests.py38
-rw-r--r--horizon/horizon/tests/testsettings.py (renamed from django-openstack/django_openstack/tests/testsettings.py)62
-rw-r--r--horizon/horizon/tests/testurls.py33
-rw-r--r--horizon/horizon/tests/views.py (renamed from django-openstack/django_openstack/tests/views.py)0
-rw-r--r--horizon/horizon/users.py123
-rw-r--r--horizon/horizon/version.py (renamed from django-openstack/django_openstack/version.py)0
-rw-r--r--horizon/horizon/views/__init__.py0
-rw-r--r--horizon/horizon/views/auth.py (renamed from django-openstack/django_openstack/auth/views.py)32
-rw-r--r--horizon/horizon/views/auth_forms.py141
-rw-r--r--[-rwxr-xr-x]horizon/setup.py (renamed from django-openstack/setup.py)11
-rw-r--r--openstack-dashboard/README49
-rwxr-xr-xopenstack-dashboard/dashboard/manage.py3
-rw-r--r--openstack-dashboard/dashboard/middleware.py1
-rw-r--r--openstack-dashboard/dashboard/settings.py20
-rw-r--r--openstack-dashboard/dashboard/static/dashboard/images/favicon.icobin0 -> 1150 bytes
-rw-r--r--openstack-dashboard/dashboard/templates/_login.html2
-rw-r--r--openstack-dashboard/dashboard/templates/_switch.html2
-rw-r--r--openstack-dashboard/dashboard/templates/_topbar.html22
-rw-r--r--openstack-dashboard/dashboard/templates/base.html1
-rw-r--r--openstack-dashboard/dashboard/templates/switch_tenants.html4
-rw-r--r--openstack-dashboard/dashboard/tests.py38
-rw-r--r--openstack-dashboard/dashboard/urls.py15
-rw-r--r--openstack-dashboard/dashboard/views.py20
-rw-r--r--openstack-dashboard/local/local_settings.py.example97
-rw-r--r--openstack-dashboard/tools/install_venv.py11
-rw-r--r--openstack-dashboard/tools/pip-requires22
-rwxr-xr-xopenstack-dashboard/tools/with_venv.sh1
-rwxr-xr-xrun_tests.sh75
406 files changed, 21603 insertions, 19216 deletions
diff --git a/.bzrignore b/.bzrignore
index cdd77172..cda7dea6 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,11 +1,11 @@
-django-openstack/.installed.cfg
-django-openstack/bin
-django-openstack/develop-eggs/
-django-openstack/downloads/
-django-openstack/eggs/
-django-openstack/parts/
-django-openstack/src/django_nova.egg-info
-django-openstack/src/django_openstack.egg-info
+horizon/.installed.cfg
+horizon/bin
+horizon/develop-eggs/
+horizon/downloads/
+horizon/eggs/
+horizon/parts/
+horizon/src/django_nova.egg-info
+horizon/src/django_openstack.egg-info
django-nova-syspanel/src/django_nova_syspanel.egg-info
openstack-dashboard/.dashboard-venv
openstack-dashboard/local/dashboard_openstack.sqlite3
diff --git a/.gitignore b/.gitignore
index e6bdfce9..b797b11f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,19 +5,20 @@ coverage.xml
pep8.txt
pylint.txt
reports
-django-openstack/.installed.cfg
-django-openstack/bin
-django-openstack/develop-eggs/
-django-openstack/downloads/
-django-openstack/eggs/
-django-openstack/htmlcov
-django-openstack/launchpad
-django-openstack/parts/
-django-openstack/django_nova.egg-info
-django-openstack/django_openstack.egg-info
+horizon/.installed.cfg
+horizon/bin
+horizon/develop-eggs/
+horizon/downloads/
+horizon/eggs/
+horizon/htmlcov
+horizon/launchpad
+horizon/parts/
+horizon/django_nova.egg-info
+horizon/horizon.egg-info
+horizon/django_openstack.egg-info
django-nova-syspanel/src/django_nova_syspanel.egg-info
openstack-dashboard/.dashboard-venv
openstack-dashboard/local/dashboard_openstack.sqlite3
openstack-dashboard/local/local_settings.py
build/
-doc/source/sourcecode
+docs/source/sourcecode
diff --git a/README b/README
index edbfb156..2492bc59 100644
--- a/README
+++ b/README
@@ -4,14 +4,14 @@ OpenStack Dashboard (Horizon)
The OpenStack Dashboard is a Django based reference implementation of a web
based management interface for OpenStack.
-It is based on django-openstack, which is designed to be a generic Django
-module that can be re-used in other sites.
+It is based on the ``horizon`` module, which is designed to be a generic Django
+app that can be re-used in other projects.
For more information about how to get started with the OpenStack Dashboard,
view the README file in the openstack-dashboard folder.
-For more information about working directly with django-openstack, see the
-README file in the django-openstack folder.
+For more information about working directly with ``horizon``, see the
+README file in the ``horizon`` folder.
For release management:
@@ -29,21 +29,21 @@ Project Structure and Testing:
------------------------------
This project is a bit different from other Openstack projects in that it has
-two very distinct components underneath it: django-openstack, and
-openstack-dashboard.
+two very distinct components underneath it: ``horizon``, and
+``openstack-dashboard``.
-django-openstack holds the generic libraries and components that can be
-used in any Django project. In testing, this component is set up with
-buildout (see run_tests.sh), and any dependencies that get added need to
-be added to the django-openstack/buildout.cfg file.
+The ``horizon`` directory holds the generic libraries and components that can
+be used in any Django project. In testing, this component is set up with
+buildout (see ``run_tests.sh``), and any dependencies that get added need to
+be added to the ``horizon/buildout.cfg`` file.
-openstack-dashboard is a reference django project that uses django-openstack
-and is built with a virtualenv and tested through that environment. If
-depdendencies are added that the reference django project needs, they
-should be added to openstack-dashboard/tools/pip-requires.
+The ``openstack-dashboard`` directory contains a reference Django project that
+uses ``horizon`` and is built with a virtualenv and tested through that
+environment. If dependencies are added that ``openstack-dashboard`` requires
+they should be added to ``openstack-dashboard/tools/pip-requires``.
-The run_tests.sh script invokes tests and analysis on both of these
-components in it's process, and is what Jenkins uses to verify the
+The ``run_tests.sh`` script invokes tests and analyses on both of these
+components in its process, and is what Jenkins uses to verify the
stability of the project.
To run the tests::
@@ -55,7 +55,7 @@ Building Contributor Documentation
This documentation is written by contributors, for contributors.
-The source is maintained in the `doc/source` folder using
+The source is maintained in the ``docs/source`` folder using
`reStructuredText`_ and built by `Sphinx`_
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
diff --git a/django-openstack/README b/django-openstack/README
deleted file mode 100644
index 0323e220..00000000
--- a/django-openstack/README
+++ /dev/null
@@ -1,56 +0,0 @@
-Django-OpenStack
----------------------
-
-The Django-OpenStack project is a Django module that is used to provide web based
-interactions with an OpenStack cloud.
-
-There is a reference implementation that uses this module located at:
-
- http://launchpad.net/horizon
-
-It is highly recommended that you make use of this reference implementation
-so that changes you make can be visualized effectively and are consistent.
-Using this reference implementation as a development environment will greatly
-simplify development of the django-openstack module.
-
-Of course, if you are developing your own Django site using django-openstack, then
-you can disregard this advice.
-
-
-
-Getting Started
----------------
-
-Django-OpenStack uses Buildout (http://www.buildout.org/) to manage local
-development. To configure your local Buildout environment first install the following
-system-level dependencies:
- * python-dev
- * git
- * bzr
-
-Then instantiate buildout with
-
- $ python bootstrap.py
- $ bin/buildout
-
-This will install all the dependencies of django-openstack and provide some useful
-scripts in the bin/ directory:
-
- bin/python provides a python shell for the current buildout.
- bin/django provides django functions for the current buildout.
-
-
-You should now be able to run unit tests as follows:
-
- $ bin/django test
-or
- $ bin/test
-
-You can run unit tests with code coverage on django_openstack by setting
-NOSE_WITH_COVERAGE:
-
- $ NOSE_WITH_COVERAGE=true bin/test
-
-Get even better coverage info by running coverage directly:
-
- $ coverage run --branch --source django_openstack bin/django test django_openstack && coverage html
diff --git a/django-openstack/django_openstack/api.py b/django-openstack/django_openstack/api.py
deleted file mode 100644
index 60b9f16e..00000000
--- a/django-openstack/django_openstack/api.py
+++ /dev/null
@@ -1,1093 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-"""
-Methods and interface objects used to interact with external apis.
-
-API method calls return objects that are in many cases objects with
-attributes that are direct maps to the data returned from the API http call.
-Unfortunately, these objects are also often constructed dynamically, making
-it difficult to know what data is available from the API object. Because of
-this, all API calls should wrap their returned object in one defined here,
-using only explicitly defined atributes and/or methods.
-
-In other words, django_openstack developers not working on django_openstack.api
-shouldn't need to understand the finer details of APIs for
-Keystone/Nova/Glance/Swift et. al.
-"""
-
-import httplib
-import json
-import logging
-import urlparse
-
-from django.conf import settings
-from django.contrib import messages
-
-import cloudfiles
-from django_openstack import exceptions
-import openstack.compute
-import openstackx.admin
-import openstackx.api.exceptions as api_exceptions
-import openstackx.extras
-import openstackx.auth
-from glance import client as glance_client
-from glance.common import exception as glance_exceptions
-from novaclient import client as base_nova_client
-from keystoneclient import exceptions as keystone_exceptions
-from keystoneclient.v2_0 import client as keystone_client
-from novaclient.v1_1 import client as nova_client
-from quantum import client as quantum_client
-
-LOG = logging.getLogger('django_openstack.api')
-
-
-class APIResourceWrapper(object):
- """ Simple wrapper for api objects
-
- Define _attrs on the child class and pass in the
- api object as the only argument to the constructor
- """
- _attrs = []
-
- def __init__(self, apiresource):
- self._apiresource = apiresource
-
- def __getattr__(self, attr):
- if attr in self._attrs:
- # __getattr__ won't find properties
- return self._apiresource.__getattribute__(attr)
- else:
- LOG.debug('Attempted to access unknown attribute "%s" on'
- ' APIResource object of type "%s" wrapping resource of'
- ' type "%s"' % (attr, self.__class__,
- self._apiresource.__class__))
- raise AttributeError(attr)
-
-
-class APIDictWrapper(object):
- """ Simple wrapper for api dictionaries
-
- Some api calls return dictionaries. This class provides identical
- behavior as APIResourceWrapper, except that it will also behave as a
- dictionary, in addition to attribute accesses.
-
- Attribute access is the preferred method of access, to be
- consistent with api resource objects from openstackx
- """
- def __init__(self, apidict):
- self._apidict = apidict
-
- def __getattr__(self, attr):
- if attr in self._attrs:
- try:
- return self._apidict[attr]
- except KeyError, e:
- raise AttributeError(e)
-
- else:
- LOG.debug('Attempted to access unknown item "%s" on'
- 'APIResource object of type "%s"'
- % (attr, self.__class__))
- raise AttributeError(attr)
-
- def __getitem__(self, item):
- try:
- return self.__getattr__(item)
- except AttributeError, e:
- # caller is expecting a KeyError
- raise KeyError(e)
-
- def get(self, item, default=None):
- try:
- return self.__getattr__(item)
- except AttributeError:
- return default
-
-
-class Container(APIResourceWrapper):
- """Simple wrapper around cloudfiles.container.Container"""
- _attrs = ['name']
-
-
-class Console(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.consoles.Console"""
- _attrs = ['id', 'output', 'type']
-
-
-class Flavor(APIResourceWrapper):
- """Simple wrapper around openstackx.admin.flavors.Flavor"""
- _attrs = ['disk', 'id', 'links', 'name', 'ram', 'vcpus']
-
-
-class FloatingIp(APIResourceWrapper):
- """Simple wrapper for floating ips"""
- _attrs = ['ip', 'fixed_ip', 'instance_id', 'id']
-
-
-class Image(APIDictWrapper):
- """Simple wrapper around glance image dictionary"""
- _attrs = ['checksum', 'container_format', 'created_at', 'deleted',
- 'deleted_at', 'disk_format', 'id', 'is_public', 'location',
- 'name', 'properties', 'size', 'status', 'updated_at', 'owner']
-
- def __getattr__(self, attrname):
- if attrname == "properties":
- return ImageProperties(super(Image, self).__getattr__(attrname))
- else:
- return super(Image, self).__getattr__(attrname)
-
-
-class ImageProperties(APIDictWrapper):
- """Simple wrapper around glance image properties dictionary"""
- _attrs = ['architecture', 'image_location', 'image_state', 'kernel_id',
- 'project_id', 'ramdisk_id']
-
-
-class KeyPair(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.keypairs.Keypair"""
- _attrs = ['fingerprint', 'name', 'private_key']
-
-
-class Volume(APIResourceWrapper):
- """Nova Volume representation"""
- _attrs = ['id', 'status', 'displayName', 'size', 'volumeType', 'createdAt',
- 'attachments', 'displayDescription']
-
-
-class Server(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.server.Server
-
- Preserves the request info so image name can later be retrieved
- """
- _attrs = ['addresses', 'attrs', 'hostId', 'id', 'image', 'links',
- 'metadata', 'name', 'private_ip', 'public_ip', 'status', 'uuid',
- 'image_name', 'VirtualInterfaces']
-
- def __init__(self, apiresource, request):
- super(Server, self).__init__(apiresource)
- self.request = request
-
- def __getattr__(self, attr):
- if attr == "attrs":
- return ServerAttributes(super(Server, self).__getattr__(attr))
- else:
- return super(Server, self).__getattr__(attr)
-
- @property
- def image_name(self):
- try:
- image = image_get(self.request, self.image['id'])
- return image.name
- except glance_exceptions.NotFound:
- return "(not found)"
-
- def reboot(self, hardness=openstack.compute.servers.REBOOT_HARD):
- compute_api(self.request).servers.reboot(self.id, hardness)
-
-
-class ServerAttributes(APIDictWrapper):
- """Simple wrapper around openstackx.extras.server.Server attributes
-
- Preserves the request info so image name can later be retrieved
- """
- _attrs = ['description', 'disk_gb', 'host', 'image_ref', 'kernel_id',
- 'key_name', 'launched_at', 'mac_address', 'memory_mb', 'name',
- 'os_type', 'tenant_id', 'ramdisk_id', 'scheduled_at',
- 'terminated_at', 'user_data', 'user_id', 'vcpus', 'hostname',
- 'security_groups']
-
-
-class Services(APIResourceWrapper):
- _attrs = ['disabled', 'host', 'id', 'last_update', 'stats', 'type', 'up',
- 'zone']
-
-
-class SwiftObject(APIResourceWrapper):
- _attrs = ['name']
-
-
-class Tenant(APIResourceWrapper):
- """Simple wrapper around keystoneclient.tenants.Tenant"""
- _attrs = ['id', 'description', 'enabled', 'name']
-
-
-class Token(APIResourceWrapper):
- """Simple wrapper around keystoneclient.tokens.Tenant"""
- _attrs = ['id', 'user', 'serviceCatalog', 'tenant']
-
-
-class Usage(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.usage.Usage"""
- _attrs = ['begin', 'instances', 'stop', 'tenant_id',
- 'total_active_disk_size', 'total_active_instances',
- 'total_active_ram_size', 'total_active_vcpus', 'total_cpu_usage',
- 'total_disk_usage', 'total_hours', 'total_ram_usage']
-
-
-class User(APIResourceWrapper):
- """Simple wrapper around keystoneclient.users.User"""
- _attrs = ['email', 'enabled', 'id', 'tenantId', 'name']
-
-
-class Role(APIResourceWrapper):
- """Wrapper around keystoneclient.roles.role"""
- _attrs = ['id', 'name', 'description', 'service_id']
-
-
-class SecurityGroup(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.security_groups.SecurityGroup"""
- _attrs = ['id', 'name', 'description', 'tenant_id', 'rules']
-
-
-class SecurityGroupRule(APIResourceWrapper):
- """Simple wrapper around
- openstackx.extras.security_groups.SecurityGroupRule"""
- _attrs = ['id', 'parent_group_id', 'group_id', 'ip_protocol',
- 'from_port', 'to_port', 'groups', 'ip_ranges']
-
-
-class SecurityGroupRule(APIResourceWrapper):
- """Simple wrapper around openstackx.extras.users.User"""
- _attrs = ['id', 'name', 'description', 'tenant_id', 'security_group_rules']
-
-
-class SwiftAuthentication(object):
- """Auth container to pass CloudFiles storage URL and token from
- session.
- """
- def __init__(self, storage_url, auth_token):
- self.storage_url = storage_url
- self.auth_token = auth_token
-
- def authenticate(self):
- return (self.storage_url, '', self.auth_token)
-
-
-class ServiceCatalogException(api_exceptions.ApiException):
- def __init__(self, service_name):
- message = 'Invalid service catalog service: %s' % service_name
- super(ServiceCatalogException, self).__init__(404, message)
-
-
-class VirtualInterface(APIResourceWrapper):
- _attrs = ['id', 'mac_address']
-
-
-def get_service_from_catalog(catalog, service_type):
- for service in catalog:
- if service['type'] == service_type:
- return service
- return None
-
-
-def url_for(request, service_type, admin=False):
- catalog = request.user.service_catalog
- service = get_service_from_catalog(catalog, service_type)
- if service:
- try:
- if admin:
- return service['endpoints'][0]['adminURL']
- else:
- return service['endpoints'][0]['internalURL']
- except (IndexError, KeyError):
- raise ServiceCatalogException(service_type)
- else:
- raise ServiceCatalogException(service_type)
-
-
-def check_openstackx(f):
- """Decorator that adds extra info to api exceptions
-
- The OpenStack Dashboard currently depends on openstackx extensions
- being present in Nova. Error messages depending for views depending
- on these extensions do not lead to the conclusion that Nova is missing
- extensions.
-
- This decorator should be dropped and removed after Keystone and
- Horizon more gracefully handle extensions and openstackx extensions
- aren't required by Horizon in Nova.
- """
- def inner(*args, **kwargs):
- try:
- return f(*args, **kwargs)
- except api_exceptions.NotFound, e:
- e.message = e.details or ''
- e.message += ' This error may be caused by a misconfigured' \
- ' Nova url in keystone\'s service catalog, or ' \
- ' by missing openstackx extensions in Nova. ' \
- ' See the Horizon README.'
- raise
-
- return inner
-
-
-def compute_api(request):
- compute = openstack.compute.Compute(
- auth_token=request.user.token,
- management_url=url_for(request, 'compute'))
- # this below hack is necessary to make the jacobian compute client work
- # TODO(mgius): It looks like this is unused now?
- compute.client.auth_token = request.user.token
- compute.client.management_url = url_for(request, 'compute')
- LOG.debug('compute_api connection created using token "%s"'
- ' and url "%s"' %
- (request.user.token, url_for(request, 'compute')))
- return compute
-
-
-def glance_api(request):
- o = urlparse.urlparse(url_for(request, 'image'))
- LOG.debug('glance_api connection created for host "%s:%d"' %
- (o.hostname, o.port))
- return glance_client.Client(o.hostname,
- o.port,
- auth_tok=request.user.token)
-
-
-def admin_api(request):
- LOG.debug('admin_api connection created using token "%s"'
- ' and url "%s"' %
- (request.user.token, url_for(request, 'compute', True)))
- return openstackx.admin.Admin(auth_token=request.user.token,
- management_url=url_for(request, 'compute', True))
-
-
-def extras_api(request):
- LOG.debug('extras_api connection created using token "%s"'
- ' and url "%s"' %
- (request.user.token, url_for(request, 'compute')))
- return openstackx.extras.Extras(auth_token=request.user.token,
- management_url=url_for(request, 'compute'))
-
-
-def novaclient(request):
- LOG.debug('novaclient connection created using token "%s" and url "%s"' %
- (request.user.token, url_for(request, 'compute')))
- c = nova_client.Client(username=request.user.username,
- api_key=request.user.token,
- project_id=request.user.tenant_id,
- auth_url=url_for(request, 'compute'))
- c.client.auth_token = request.user.token
- c.client.management_url = url_for(request, 'compute')
- return c
-
-
-def keystoneclient(request, username=None, password=None, tenant_id=None,
- token_id=None, endpoint=None):
- """Returns a client connected to the Keystone backend.
-
- Several forms of authentication are supported:
-
- * Username + password -> Unscoped authentication
- * Username + password + tenant id -> Scoped authentication
- * Unscoped token -> Unscoped authentication
- * Unscoped token + tenant id -> Scoped authentication
- * Scoped token -> Scoped authentication
-
- Available services and data from the backend will vary depending on
- whether the authentication was scoped or unscoped.
-
- Lazy authentication if an ``endpoint`` parameter is provided.
-
- The client is cached so that subsequent API calls during the same
- request/response cycle don't have to be re-authenticated.
- """
- # Take care of client connection caching/fetching a new client
- user = request.user
- if (hasattr(request, '_keystone') and
- request._keystone.auth_token == user.token):
- conn = request._keystone
- else:
- conn = keystone_client.Client(username=username or user.username,
- password=password,
- project_id=tenant_id or user.tenant_id,
- token=token_id or user.token,
- auth_url=settings.OPENSTACK_KEYSTONE_URL,
- endpoint=endpoint)
- request._keystone = conn
-
- # Fetch the correct endpoint for the user type
- catalog = getattr(conn, 'service_catalog', None)
- if catalog and "serviceCatalog" in catalog.catalog.keys():
- if user.is_admin():
- endpoint = catalog.url_for(service_type='identity',
- endpoint_type='adminURL')
- else:
- endpoint = catalog.url_for(service_type='identity',
- endpoint_type='publicURL')
- else:
- endpoint = settings.OPENSTACK_KEYSTONE_URL
- conn.management_url = endpoint
-
- return conn
-
-
-def swift_api(request):
- LOG.debug('object store connection created using token "%s"'
- ' and url "%s"' %
- (request.session['token'], url_for(request, 'object-store')))
- auth = SwiftAuthentication(url_for(request, 'object-store'),
- request.session['token'])
- return cloudfiles.get_connection(auth=auth)
-
-
-def quantum_api(request):
- tenant = None
- if hasattr(request, 'user'):
- tenant = request.user.tenant_id
- else:
- tenant = settings.QUANTUM_TENANT
-
- return quantum_client.Client(settings.QUANTUM_URL, settings.QUANTUM_PORT,
- False, tenant, 'json')
-
-
-def console_create(request, instance_id, kind='text'):
- return Console(extras_api(request).consoles.create(instance_id, kind))
-
-
-def flavor_create(request, name, memory, vcpu, disk, flavor_id):
- # TODO -- convert to novaclient when novaclient adds create support
- return Flavor(admin_api(request).flavors.create(
- name, int(memory), int(vcpu), int(disk), flavor_id))
-
-
-def flavor_delete(request, flavor_id, purge=False):
- # TODO -- convert to novaclient when novaclient adds delete support
- admin_api(request).flavors.delete(flavor_id, purge)
-
-
-def flavor_get(request, flavor_id):
- return Flavor(novaclient(request).flavors.get(flavor_id))
-
-
-def flavor_list(request):
- return [Flavor(f) for f in novaclient(request).flavors.list()]
-
-
-def tenant_floating_ip_list(request):
- """
- Fetches a list of all floating ips.
- """
- return [FloatingIp(ip) for ip in novaclient(request).floating_ips.list()]
-
-
-def tenant_floating_ip_get(request, floating_ip_id):
- """
- Fetches a floating ip.
- """
- return novaclient(request).floating_ips.get(floating_ip_id)
-
-
-def tenant_floating_ip_allocate(request):
- """
- Allocates a floating ip to tenant.
- """
- return novaclient(request).floating_ips.create()
-
-
-def tenant_floating_ip_release(request, floating_ip_id):
- """
- Releases floating ip from the pool of a tenant.
- """
- return novaclient(request).floating_ips.delete(floating_ip_id)
-
-
-def image_create(request, image_meta, image_file):
- return Image(glance_api(request).add_image(image_meta, image_file))
-
-
-def image_delete(request, image_id):
- return glance_api(request).delete_image(image_id)
-
-
-def image_get(request, image_id):
- return Image(glance_api(request).get_image(image_id)[0])
-
-
-def image_list_detailed(request):
- return [Image(i) for i in glance_api(request).get_images_detailed()]
-
-
-def snapshot_list_detailed(request):
- filters = {}
- filters['property-image_type'] = 'snapshot'
- filters['is_public'] = 'none'
- return [Image(i) for i in glance_api(request)
- .get_images_detailed(filters=filters)]
-
-
-def snapshot_create(request, instance_id, name):
- return novaclient(request).servers.create_image(instance_id, name)
-
-
-def image_update(request, image_id, image_meta=None):
- image_meta = image_meta and image_meta or {}
- return Image(glance_api(request).update_image(image_id,
- image_meta=image_meta))
-
-
-def keypair_create(request, name):
- return KeyPair(novaclient(request).keypairs.create(name))
-
-
-def keypair_import(request, name, public_key):
- return KeyPair(novaclient(request).keypairs.create(name, public_key))
-
-
-def keypair_delete(request, keypair_id):
- novaclient(request).keypairs.delete(keypair_id)
-
-
-def keypair_list(request):
- return [KeyPair(key) for key in novaclient(request).keypairs.list()]
-
-
-def volume_list(request):
- return [Volume(vol) for vol in novaclient(request).volumes.list()]
-
-
-def volume_get(request, volume_id):
- return Volume(novaclient(request).volumes.get(volume_id))
-
-
-def volume_instance_list(request, instance_id):
- return novaclient(request).volumes.get_server_volumes(instance_id)
-
-
-def volume_create(request, size, name, description):
- return Volume(novaclient(request).volumes.create(
- size, name, description))
-
-
-def volume_delete(request, volume_id):
- novaclient(request).volumes.delete(volume_id)
-
-
-def volume_attach(request, volume_id, instance_id, device):
- novaclient(request).volumes.create_server_volume(
- instance_id, volume_id, device)
-
-
-def volume_detach(request, instance_id, attachment_id):
- novaclient(request).volumes.delete_server_volume(
- instance_id, attachment_id)
-
-
-def server_create(request, name, image, flavor,
- key_name, user_data, security_groups):
- return Server(novaclient(request).servers.create(
- name, image, flavor, userdata=user_data,
- security_groups=security_groups,
- key_name=key_name), request)
-
-
-def server_delete(request, instance):
- compute_api(request).servers.delete(instance)
-
-
-def server_get(request, instance_id):
- return Server(extras_api(request).servers.get(instance_id), request)
-
-
-@check_openstackx
-def server_list(request):
- return [Server(s, request) for s in extras_api(request).servers.list()]
-
-
-@check_openstackx
-def admin_server_list(request):
- return [Server(s, request) for s in admin_api(request).servers.list()]
-
-
-def server_reboot(request,
- instance_id,
- hardness=openstack.compute.servers.REBOOT_HARD):
- server = server_get(request, instance_id)
- server.reboot(hardness)
-
-
-def server_update(request, instance_id, name, description):
- return extras_api(request).servers.update(instance_id,
- name=name,
- description=description)
-
-
-def server_add_floating_ip(request, server, address):
- """
- Associates floating IP to server's fixed IP.
- """
- server = novaclient(request).servers.get(server)
- fip = novaclient(request).floating_ips.get(address)
-
- return novaclient(request).servers.add_floating_ip(server, fip)
-
-
-def server_remove_floating_ip(request, server, address):
- """
- Removes relationship between floating and server's fixed ip.
- """
- fip = novaclient(request).floating_ips.get(address)
- server = novaclient(request).servers.get(fip.instance_id)
-
- return novaclient(request).servers.remove_floating_ip(server, fip)
-
-
-def service_get(request, name):
- return Services(admin_api(request).services.get(name))
-
-
-@check_openstackx
-def service_list(request):
- return [Services(s) for s in admin_api(request).services.list()]
-
-
-def service_update(request, name, enabled):
- return Services(admin_api(request).services.update(name, enabled))
-
-
-def tenant_create(request, tenant_name, description, enabled):
- return Tenant(keystoneclient(request).tenants.create(tenant_name,
- description,
- enabled))
-
-
-def tenant_get(request, tenant_id):
- return Tenant(keystoneclient(request).tenants.get(tenant_id))
-
-
-def tenant_delete(request, tenant_id):
- keystoneclient(request).tenants.delete(tenant_id)
-
-
-def tenant_list(request):
- return [Tenant(t) for t in keystoneclient(request).tenants.list()]
-
-
-def tenant_update(request, tenant_id, tenant_name, description, enabled):
- return Tenant(keystoneclient(request).tenants.update(tenant_id,
- tenant_name,
- description,
- enabled))
-
-
-def tenant_delete(request, tenant_id):
- keystoneclient(request).tenants.delete(tenant_id)
-
-
-def tenant_list_for_token(request, token):
- c = keystoneclient(request, token_id=token,
- endpoint=settings.OPENSTACK_KEYSTONE_URL)
- return [Tenant(t) for t in c.tenants.list()]
-
-
-def token_create(request, tenant, username, password):
- '''
- Creates a token using the username and password provided. If tenant
- is provided it will retrieve a scoped token and the service catalog for
- the given tenant. Otherwise it will return an unscoped token and without
- a service catalog.
- '''
- c = keystoneclient(request, username=username, password=password,
- tenant_id=tenant,
- endpoint=settings.OPENSTACK_KEYSTONE_URL)
- token = c.tokens.authenticate(username=username,
- password=password,
- tenant=tenant)
- return Token(token)
-
-
-def token_create_scoped(request, tenant, token):
- '''
- Creates a scoped token using the tenant id and unscoped token; retrieves
- the service catalog for the given tenant.
- '''
- if hasattr(request, '_keystone'):
- del request._keystone
- c = keystoneclient(request, tenant_id=tenant, token_id=token,
- endpoint=settings.OPENSTACK_KEYSTONE_URL)
- scoped_token = c.tokens.authenticate(tenant=tenant, token=token)
- return Token(scoped_token)
-
-
-def tenant_quota_get(request, tenant):
- return novaclient(request).quotas.get(tenant)
-
-
-@check_openstackx
-def usage_get(request, tenant_id, start, end):
- return Usage(extras_api(request).usage.get(tenant_id, start, end))
-
-
-@check_openstackx
-def usage_list(request, start, end):
- return [Usage(u) for u in extras_api(request).usage.list(start, end)]
-
-
-def security_group_list(request):
- return [SecurityGroup(g) for g in novaclient(request).\
- security_groups.list()]
-
-
-def security_group_get(request, security_group_id):
- return SecurityGroup(novaclient(request).\
- security_groups.get(security_group_id))
-
-
-def security_group_create(request, name, description):
- return SecurityGroup(novaclient(request).\
- security_groups.create(name, description))
-
-
-def security_group_delete(request, security_group_id):
- novaclient(request).security_groups.delete(security_group_id)
-
-
-def security_group_rule_create(request, parent_group_id, ip_protocol=None,
- from_port=None, to_port=None, cidr=None,
- group_id=None):
- return SecurityGroup(novaclient(request).\
- security_group_rules.create(parent_group_id,
- ip_protocol,
- from_port,
- to_port,
- cidr,
- group_id))
-
-
-def security_group_rule_delete(request, security_group_rule_id):
- novaclient(request).security_group_rules.delete(security_group_rule_id)
-
-
-def user_list(request, tenant_id=None):
- return [User(u) for u in
- keystoneclient(request).users.list(tenant_id=tenant_id)]
-
-
-def user_create(request, user_id, email, password, tenant_id, enabled):
- return User(keystoneclient(request).users.create(
- user_id, password, email, tenant_id, enabled))
-
-
-def user_delete(request, user_id):
- keystoneclient(request).users.delete(user_id)
-
-
-def user_get(request, user_id):
- return User(keystoneclient(request).users.get(user_id))
-
-
-def user_update_email(request, user_id, email):
- return User(keystoneclient(request).users.update_email(user_id, email))
-
-
-def user_update_enabled(request, user_id, enabled):
- return User(keystoneclient(request).users.update_enabled(user_id, enabled))
-
-
-def user_update_password(request, user_id, password):
- return User(keystoneclient(request).users.update_password(user_id,
- password))
-
-
-def user_update_tenant(request, user_id, tenant_id):
- return User(keystoneclient(request).users.update_tenant(user_id,
- tenant_id))
-
-
-def _get_role(request, name):
- roles = keystoneclient(request).roles.list()
- for role in roles:
- if role.name.lower() == name.lower():
- return role
-
- raise Exception(_('Role does not exist: %s') % name)
-
-
-def _get_roleref(request, user_id, tenant_id, role):
- rolerefs = keystoneclient(request).roles.get_user_role_refs(user_id)
- for roleref in rolerefs:
- if roleref.roleId == role.id and roleref.tenantId == tenant_id:
- return roleref
- raise Exception(_('Role "%s" does not exist for that user on this tenant.')
- % role.name)
-
-
-def role_add_for_tenant_user(request, tenant_id, user_id, role):
- role = _get_role(request, role)
- return keystoneclient(request).roles.add_user_to_tenant(tenant_id,
- user_id,
- role.id)
-
-
-def role_delete_for_tenant_user(request, tenant_id, user_id, role):
- role = _get_role(request, role)
- roleref = _get_roleref(request, user_id, tenant_id, role)
- return keystoneclient(request).roles.remove_user_from_tenant(tenant_id,
- user_id,
- roleref.id)
-
-
-def swift_container_exists(request, container_name):
- try:
- swift_api(request).get_container(container_name)
- return True
- except cloudfiles.errors.NoSuchContainer:
- return False
-
-
-def swift_object_exists(request, container_name, object_name):
- container = swift_api(request).get_container(container_name)
-
- try:
- container.get_object(object_name)
- return True
- except cloudfiles.errors.NoSuchObject:
- return False
-
-
-def swift_get_containers(request, marker=None):
- return [Container(c) for c in swift_api(request).get_all_containers(
- limit=getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000),
- marker=marker)]
-
-
-def swift_create_container(request, name):
- if swift_container_exists(request, name):
- raise Exception('Container with name %s already exists.' % (name))
-
- return Container(swift_api(request).create_container(name))
-
-
-def swift_delete_container(request, name):
- swift_api(request).delete_container(name)
-
-
-def swift_get_objects(request, container_name, prefix=None, marker=None):
- container = swift_api(request).get_container(container_name)
- objects = container.get_objects(prefix=prefix, marker=marker,
- limit=getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000))
- return [SwiftObject(o) for o in objects]
-
-
-def swift_copy_object(request, orig_container_name, orig_object_name,
- new_container_name, new_object_name):
-
- container = swift_api(request).get_container(orig_container_name)
-
- if swift_object_exists(request,
- new_container_name,
- new_object_name) == True:
- raise Exception('Object with name %s already exists in container %s'
- % (new_object_name, new_container_name))
-
- orig_obj = container.get_object(orig_object_name)
- return orig_obj.copy_to(new_container_name, new_object_name)
-
-
-def swift_upload_object(request, container_name, object_name, object_data):
- container = swift_api(request).get_container(container_name)
- obj = container.create_object(object_name)
- obj.write(object_data)
-
-
-def swift_delete_object(request, container_name, object_name):
- container = swift_api(request).get_container(container_name)
- container.delete_object(object_name)
-
-
-def swift_get_object_data(request, container_name, object_name):
- container = swift_api(request).get_container(container_name)
- return container.get_object(object_name).stream()
-
-
-def quantum_list_networks(request):
- return quantum_api(request).list_networks()
-
-
-def quantum_network_details(request, network_id):
- return quantum_api(request).show_network_details(network_id)
-
-
-def quantum_list_ports(request, network_id):
- return quantum_api(request).list_ports(network_id)
-
-
-def quantum_port_details(request, network_id, port_id):
- return quantum_api(request).show_port_details(network_id, port_id)
-
-
-def quantum_create_network(request, data):
- return quantum_api(request).create_network(data)
-
-
-def quantum_delete_network(request, network_id):
- return quantum_api(request).delete_network(network_id)
-
-
-def quantum_update_network(request, network_id, data):
- return quantum_api(request).update_network(network_id, data)
-
-
-def quantum_create_port(request, network_id):
- return quantum_api(request).create_port(network_id)
-
-
-def quantum_delete_port(request, network_id, port_id):
- return quantum_api(request).delete_port(network_id, port_id)
-
-
-def quantum_attach_port(request, network_id, port_id, data):
- return quantum_api(request).attach_resource(network_id, port_id, data)
-
-
-def quantum_detach_port(request, network_id, port_id):
- return quantum_api(request).detach_resource(network_id, port_id)
-
-
-def quantum_set_port_state(request, network_id, port_id, data):
- return quantum_api(request).set_port_state(network_id, port_id, data)
-
-
-def quantum_port_attachment(request, network_id, port_id):
- return quantum_api(request).show_port_attachment(network_id, port_id)
-
-
-def get_vif_ids(request):
- vifs = []
- attached_vifs = []
- # Get a list of all networks
- networks_list = quantum_api(request).list_networks()
- for network in networks_list['networks']:
- ports = quantum_api(request).list_ports(network['id'])
- # Get port attachments
- for port in ports['ports']:
- port_attachment = quantum_api(request).show_port_attachment(
- network['id'],
- port['id'])
- if port_attachment['attachment']:
- attached_vifs.append(
- port_attachment['attachment']['id'].encode('ascii'))
- # Get all instances
- instances = server_list(request)
- # Get virtual interface ids by instance
- for instance in instances:
- id = instance.id
- instance_vifs = extras_api(request).virtual_interfaces.list(id)
- for vif in instance_vifs:
- # Check if this VIF is already connected to any port
- if str(vif.id) in attached_vifs:
- vifs.append({
- 'id': vif.id,
- 'instance': instance.id,
- 'instance_name': instance.name,
- 'available': False})
- else:
- vifs.append({
- 'id': vif.id,
- 'instance': instance.id,
- 'instance_name': instance.name,
- 'available': True})
- return vifs
-
-
-class GlobalSummary(object):
- node_resources = ['vcpus', 'disk_size', 'ram_size']
- unit_mem_size = {'disk_size': ['GiB', 'TiB'], 'ram_size': ['MiB', 'GiB']}
- node_resource_info = ['', 'active_', 'avail_']
-
- def __init__(self, request):
- self.summary = {}
- for rsrc in GlobalSummary.node_resources:
- for info in GlobalSummary.node_resource_info:
- self.summary['total_' + info + rsrc] = 0
- self.request = request
- self.service_list = []
- self.usage_list = []
-
- def service(self):
- try:
- self.service_list = service_list(self.request)
- except api_exceptions.ApiException, e:
- self.service_list = []
- LOG.exception('ApiException fetching service list in instance '
- 'usage')
- messages.error(self.request,
- _('Unable to get service info: %s') % e.message)
- return
-
- for service in self.service_list:
- if service.type == 'nova-compute':
- self.summary['total_vcpus'] += min(service.stats['max_vcpus'],
- service.stats.get('vcpus', 0))
- self.summary['total_disk_size'] += min(
- service.stats['max_gigabytes'],
- service.stats.get('local_gb', 0))
- self.summary['total_ram_size'] += min(
- service.stats['max_ram'],
- service.stats['memory_mb']) if 'max_ram' \
- in service.stats \
- else service.stats.get('memory_mb', 0)
-
- def usage(self, datetime_start, datetime_end):
- try:
- self.usage_list = usage_list(self.request, datetime_start,
- datetime_end)
- except api_exceptions.ApiException, e:
- self.usage_list = []
- LOG.exception('ApiException fetching usage list in instance usage'
- ' on date range "%s to %s"' % (datetime_start,
- datetime_end))
- messages.error(self.request,
- _('Unable to get usage info: %s') % e.message)
- return
-
- for usage in self.usage_list:
- # FIXME: api needs a simpler dict interface (with iteration)
- # - anthony
- # NOTE(mgius): Changed this on the api end. Not too much
- # neater, but at least its not going into private member
- # data of an external class anymore
- # usage = usage._info
- for k in usage._attrs:
- v = usage.__getattr__(k)
- if type(v) in [float, int]:
- if not k in self.summary:
- self.summary[k] = 0
- self.summary[k] += v
-
- def human_readable(self, rsrc):
- if self.summary['total_' + rsrc] > 1023:
- self.summary['unit_' + rsrc] = GlobalSummary.unit_mem_size[rsrc][1]
- mult = 1024.0
- else:
- self.summary['unit_' + rsrc] = GlobalSummary.unit_mem_size[rsrc][0]
- mult = 1.0
-
- for kind in GlobalSummary.node_resource_info:
- self.summary['total_' + kind + rsrc + '_hr'] = \
- self.summary['total_' + kind + rsrc] / mult
-
- def avail(self):
- for rsrc in GlobalSummary.node_resources:
- self.summary['total_avail_' + rsrc] = \
- self.summary['total_' + rsrc] - \
- self.summary['total_active_' + rsrc]
diff --git a/django-openstack/django_openstack/context_processors.py b/django-openstack/django_openstack/context_processors.py
deleted file mode 100644
index 1d1b0a5b..00000000
--- a/django-openstack/django_openstack/context_processors.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django.conf import settings
-from django_openstack import api
-from django.contrib import messages
-from openstackx.api import exceptions as api_exceptions
-
-
-def tenants(request):
- if not request.user or not request.user.is_authenticated():
- return {}
-
- try:
- return {'tenants': api.tenant_list_for_token(request,
- request.user.token)}
- except api_exceptions.BadRequest, e:
- messages.error(request, _("Unable to retrieve tenant list from\
- keystone: %s") % e.message)
- return {'tenants': []}
-
-
-def object_store(request):
- catalog = getattr(request.user, 'service_catalog', [])
- object_store = catalog and api.get_service_from_catalog(catalog,
- 'object-store')
- return {'object_store_configured': object_store}
-
-
-def quantum(request):
- return {'quantum_configured': settings.QUANTUM_ENABLED}
diff --git a/django-openstack/django_openstack/dash/urls.py b/django-openstack/django_openstack/dash/urls.py
deleted file mode 100644
index 82c3a5f2..00000000
--- a/django-openstack/django_openstack/dash/urls.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django.conf.urls.defaults import *
-
-SECURITY_GROUPS = r'^(?P<tenant_id>[^/]+)/security_groups/' \
- '(?P<security_group_id>[^/]+)/%s$'
-INSTANCES = r'^(?P<tenant_id>[^/]+)/instances/(?P<instance_id>[^/]+)/%s$'
-IMAGES = r'^(?P<tenant_id>[^/]+)/images/(?P<image_id>[^/]+)/%s$'
-KEYPAIRS = r'^(?P<tenant_id>[^/]+)/keypairs/%s$'
-SNAPSHOTS = r'^(?P<tenant_id>[^/]+)/snapshots/(?P<instance_id>[^/]+)/%s$'
-VOLUMES = r'^(?P<tenant_id>[^/]+)/volumes/(?P<volume_id>[^/]+)/%s$'
-CONTAINERS = r'^(?P<tenant_id>[^/]+)/containers/%s$'
-FLOATING_IPS = r'^(?P<tenant_id>[^/]+)/floating_ips/(?P<ip_id>[^/]+)/%s$'
-OBJECTS = r'^(?P<tenant_id>[^/]+)/containers/(?P<container_name>[^/]+)/%s$'
-NETWORKS = r'^(?P<tenant_id>[^/]+)/networks/%s$'
-PORTS = r'^(?P<tenant_id>[^/]+)/networks/(?P<network_id>[^/]+)/ports/%s$'
-
-urlpatterns = patterns('django_openstack.dash.views.instances',
- url(r'^(?P<tenant_id>[^/]+)/$', 'usage', name='dash_usage'),
- url(r'^(?P<tenant_id>[^/]+)/instances/$', 'index', name='dash_instances'),
- url(r'^(?P<tenant_id>[^/]+)/instances/refresh$', 'refresh',
- name='dash_instances_refresh'),
- url(INSTANCES % 'detail', 'detail', name='dash_instances_detail'),
- url(INSTANCES % 'console', 'console', name='dash_instances_console'),
- url(INSTANCES % 'vnc', 'vnc', name='dash_instances_vnc'),
- url(INSTANCES % 'update', 'update', name='dash_instances_update'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.security_groups',
- url(r'^(?P<tenant_id>[^/]+)/security_groups/$', 'index',
- name='dash_security_groups'),
- url(r'^(?P<tenant_id>[^/]+)/security_groups/create$', 'create',
- name='dash_security_groups_create'),
- url(SECURITY_GROUPS % 'edit_rules', 'edit_rules',
- name='dash_security_groups_edit_rules'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.images',
- url(r'^(?P<tenant_id>[^/]+)/images/$', 'index', name='dash_images'),
- url(IMAGES % 'launch', 'launch', name='dash_images_launch'),
- url(IMAGES % 'update', 'update', name='dash_images_update'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.keypairs',
- url(r'^(?P<tenant_id>[^/]+)/keypairs/$', 'index', name='dash_keypairs'),
- url(KEYPAIRS % 'create', 'create', name='dash_keypairs_create'),
- url(KEYPAIRS % 'import', 'import_keypair', name='dash_keypairs_import'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.floating_ips',
- url(r'^(?P<tenant_id>[^/]+)/floating_ips/$', 'index',
- name='dash_floating_ips'),
- url(FLOATING_IPS % 'associate', 'associate',
- name='dash_floating_ips_associate'),
- url(FLOATING_IPS % 'disassociate', 'disassociate',
- name='dash_floating_ips_disassociate'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.snapshots',
- url(r'^(?P<tenant_id>[^/]+)/snapshots/$', 'index', name='dash_snapshots'),
- url(SNAPSHOTS % 'create', 'create', name='dash_snapshots_create'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.volumes',
- url(r'^(?P<tenant_id>[^/]+)/volumes/$', 'index', name='dash_volumes'),
- url(r'^(?P<tenant_id>[^/]+)/volumes/create', 'create',
- name='dash_volumes_create'),
- url(VOLUMES % 'attach', 'attach', name='dash_volumes_attach'),
- url(VOLUMES % 'detail', 'detail', name='dash_volumes_detail'),
-)
-
-# Swift containers and objects.
-urlpatterns += patterns('django_openstack.dash.views.containers',
- url(CONTAINERS % '', 'index', name='dash_containers'),
- url(CONTAINERS % 'create', 'create', name='dash_containers_create'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.objects',
- url(OBJECTS % '', 'index', name='dash_objects'),
- url(OBJECTS % 'upload', 'upload', name='dash_objects_upload'),
- url(OBJECTS % '(?P<object_name>[^/]+)/copy',
- 'copy', name='dash_object_copy'),
- url(OBJECTS % '(?P<object_name>[^/]+)/download',
- 'download', name='dash_objects_download'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.networks',
- url(r'^(?P<tenant_id>[^/]+)/networks/$', 'index', name='dash_networks'),
- url(NETWORKS % 'create', 'create', name='dash_network_create'),
- url(NETWORKS % '(?P<network_id>[^/]+)/detail', 'detail',
- name='dash_networks_detail'),
- url(NETWORKS % '(?P<network_id>[^/]+)/rename', 'rename',
- name='dash_network_rename'),
-)
-
-urlpatterns += patterns('django_openstack.dash.views.ports',
- url(PORTS % 'create', 'create', name='dash_ports_create'),
- url(PORTS % '(?P<port_id>[^/]+)/attach', 'attach',
- name='dash_ports_attach'),
-)
diff --git a/django-openstack/django_openstack/dash/views/containers.py b/django-openstack/django_openstack/dash/views/containers.py
deleted file mode 100644
index fada57e5..00000000
--- a/django-openstack/django_openstack/dash/views/containers.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-"""
-Views for managing Swift containers.
-"""
-import logging
-
-from django import template
-from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django import shortcuts
-from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
-
-from cloudfiles.errors import ContainerNotEmpty
-
-
-LOG = logging.getLogger('django_openstack.dash')
-
-
-class DeleteContainer(forms.SelfHandlingForm):
- container_name = forms.CharField(widget=forms.HiddenInput())
-
- def handle(self, request, data):
- try:
- api.swift_delete_container(request, data['container_name'])
- except ContainerNotEmpty, e:
- messages.error(request,
- _('Unable to delete non-empty container: %s') %
- data['container_name'])
- LOG.exception('Unable to delete container "%s". Exception: "%s"' %
- (data['container_name'], str(e)))
- else:
- messages.info(request,
- _('Successfully deleted container: %s') % \
- data['container_name'])
- return shortcuts.redirect(request.build_absolute_uri())
-
-
-class CreateContainer(forms.SelfHandlingForm):
- name = forms.CharField(max_length="255", label=_("Container Name"))
-
- def handle(self, request, data):
- api.swift_create_container(request, data['name'])
- messages.success(request, _("Container was successfully created."))
- return shortcuts.redirect("dash_containers", request.user.tenant_id)
-
-
-@login_required
-def index(request, tenant_id):
- marker = request.GET.get('marker', None)
-
- delete_form, handled = DeleteContainer.maybe_handle(request)
- if handled:
- return handled
-
- containers = api.swift_get_containers(request, marker=marker)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/containers/index.html', {
- 'containers': containers,
- 'delete_form': delete_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def create(request, tenant_id):
- form, handled = CreateContainer.maybe_handle(request)
- if handled:
- return handled
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/containers/create.html', {
- 'create_form': form,
- }, context_instance=template.RequestContext(request))
diff --git a/django-openstack/django_openstack/dash/views/networks.py b/django-openstack/django_openstack/dash/views/networks.py
deleted file mode 100644
index 95682197..00000000
--- a/django-openstack/django_openstack/dash/views/networks.py
+++ /dev/null
@@ -1,252 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-"""
-Views for managing api.quantum_api(request) networks.
-"""
-import logging
-
-from django import http
-from django import shortcuts
-from django import template
-from django.conf import settings
-from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django.utils import simplejson
-from django.utils.translation import ugettext as _
-
-from django_openstack import forms
-from django_openstack import api
-
-from django_openstack.dash.views.ports import DeletePort
-from django_openstack.dash.views.ports import DetachPort
-from django_openstack.dash.views.ports import TogglePort
-
-import warnings
-
-
-LOG = logging.getLogger('django_openstack.dash.views.networks')
-
-
-class CreateNetwork(forms.SelfHandlingForm):
- name = forms.CharField(required=True, label=_("Network Name"))
-
- def handle(self, request, data):
- network_name = data['name']
-
- try:
- LOG.info('Creating network %s ' % network_name)
- send_data = {'network': {'name': '%s' % network_name}}
- api.quantum_create_network(request, send_data)
- except Exception, e:
- messages.error(request,
- _('Unable to create network %(network)s: %(msg)s') %
- {"network": network_name, "msg": e.message})
- return shortcuts.redirect(request.build_absolute_uri())
- else:
- msg = _('Network %s has been created.') % network_name
- LOG.info(msg)
- messages.success(request, msg)
- return shortcuts.redirect('dash_networks',
- tenant_id=request.user.tenant_id)
-
-
-class DeleteNetwork(forms.SelfHandlingForm):
- network = forms.CharField(widget=forms.HiddenInput())
-
- def handle(self, request, data):
- try:
- LOG.info('Deleting network %s ' % data['network'])
- api.quantum_delete_network(request, data['network'])
- except Exception, e:
- messages.error(request,
- _('Unable to delete network %(network)s: %(msg)s') %
- {"network": data['network'], "msg": e.message})
- else:
- msg = _('Network %s has been deleted.') % data['network']
- LOG.info(msg)
- messages.success(request, msg)
-
- return shortcuts.redirect(request.build_absolute_uri())
-
-
-class RenameNetwork(forms.SelfHandlingForm):
- network = forms.CharField(widget=forms.HiddenInput())
- new_name = forms.CharField(required=True)
-
- def handle(self, request, data):
- try:
- LOG.info('Renaming network %s to %s' %
- (data['network'], data['new_name']))
- send_data = {'network': {'name': '%s' % data['new_name']}}
- api.quantum_update_network(request, data['network'], send_data)
- except Exception, e:
- messages.error(request,
- _('Unable to rename network %(network)s: %(msg)s') %
- {"network": data['network'], "msg": e.message})
- else:
- msg = _('Network %(net)s has been renamed to %(new_name)s.') % {
- "net": data['network'], "new_name": data['new_name']}
- LOG.info(msg)
- messages.success(request, msg)
-
- return shortcuts.redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id):
- delete_form, delete_handled = DeleteNetwork.maybe_handle(request)
-
- networks = []
- instances = []
-
- try:
- networks_list = api.quantum_list_networks(request)
- details = []
- for network in networks_list['networks']:
- net_stats = _calc_network_stats(request, tenant_id, network['id'])
- # Get network details like name and id
- details = api.quantum_network_details(request, network['id'])
- networks.append({
- 'name': details['network']['name'],
- 'id': network['id'],
- 'total': net_stats['total'],
- 'available': net_stats['available'],
- 'used': net_stats['used'],
- 'tenant': tenant_id
- })
-
- except Exception, e:
- messages.error(request,
- _('Unable to get network list: %s') % e.message)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/networks/index.html', {
- 'networks': networks,
- 'delete_form': delete_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def create(request, tenant_id):
- network_form, handled = CreateNetwork.maybe_handle(request)
- if handled:
- return shortcuts.redirect('dash_networks', request.user.tenant_id)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/networks/create.html', {
- 'network_form': network_form
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def detail(request, tenant_id, network_id):
- delete_port_form, delete_handled = DeletePort.maybe_handle(request)
- detach_port_form, detach_handled = DetachPort.maybe_handle(request)
- toggle_port_form, port_toggle_handled = TogglePort.maybe_handle(request)
-
- network = {}
-
- try:
- network_details = api.quantum_network_details(request, network_id)
- network['name'] = network_details['network']['name']
- network['id'] = network_id
- network['ports'] = _get_port_states(request, tenant_id, network_id)
- except Exception, e:
- messages.error(request,
- _('Unable to get network details: %s') % e.message)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/networks/detail.html', {
- 'network': network,
- 'tenant': tenant_id,
- 'delete_port_form': delete_port_form,
- 'detach_port_form': detach_port_form,
- 'toggle_port_form': toggle_port_form
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def rename(request, tenant_id, network_id):
- rename_form, handled = RenameNetwork.maybe_handle(request)
- network_details = api.quantum_network_details(request, network_id)
-
- if handled:
- return shortcuts.redirect('dash_networks', request.user.tenant_id)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/networks/rename.html', {
- 'network': network_details,
- 'rename_form': rename_form
- }, context_instance=template.RequestContext(request))
-
-
-def _get_port_states(request, tenant_id, network_id):
- """
- Helper method to find port states for a network
- """
- network_ports = []
- # Get all vifs for comparison with port attachments
- vifs = api.get_vif_ids(request)
-
- # Get all ports on this network
- ports = api.quantum_list_ports(request, network_id)
- for port in ports['ports']:
- port_details = api.quantum_port_details(request,
- network_id, port['id'])
- # Get port attachments
- port_attachment = api.quantum_port_attachment(request,
- network_id, port['id'])
- # Find instance the attachment belongs to
- connected_instance = None
- if port_attachment['attachment']:
- for vif in vifs:
- if str(vif['id']) == str(port_attachment['attachment']['id']):
- connected_instance = vif['instance_name']
- break
- network_ports.append({
- 'id': port_details['port']['id'],
- 'state': port_details['port']['state'],
- 'attachment': port_attachment['attachment'],
- 'instance': connected_instance
- })
- return network_ports
-
-
-def _calc_network_stats(request, tenant_id, network_id):
- """
- Helper method to calculate statistics for a network
- """
- # Get all ports statistics for the network
- total = 0
- available = 0
- used = 0
- ports = api.quantum_list_ports(request, network_id)
- for port in ports['ports']:
- total += 1
- # Get port attachment
- port_attachment = api.quantum_port_attachment(request,
- network_id, port['id'])
- if port_attachment['attachment']:
- used += 1
- else:
- available += 1
-
- return {'total': total, 'used': used, 'available': available}
diff --git a/django-openstack/django_openstack/decorators.py b/django-openstack/django_openstack/decorators.py
deleted file mode 100644
index a56e819c..00000000
--- a/django-openstack/django_openstack/decorators.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 CRS4
-#
-# 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.
-
-"""
-Simple decorator container for general purpose
-"""
-
-from django.shortcuts import redirect
-import logging
-
-
-LOG = logging.getLogger('django_openstack.syspanel')
-
-
-def enforce_admin_access(fn):
- """ Preserve unauthorized bypass typing directly the URL and redirects to
- the overview dash page """
- def dec(*args, **kwargs):
- if args[0].user.is_admin():
- return fn(*args, **kwargs)
- else:
- LOG.warn('Redirecting user "%s" from syspanel to dash ( %s )' %
- (args[0].user.username, fn.__name__))
- return redirect('dash_overview')
- return dec
diff --git a/django-openstack/django_openstack/exceptions.py b/django-openstack/django_openstack/exceptions.py
deleted file mode 100644
index 09856350..00000000
--- a/django-openstack/django_openstack/exceptions.py
+++ /dev/null
@@ -1,8 +0,0 @@
-""" Standardized exception classes for the OpenStack Dashboard. """
-
-from novaclient import exceptions as nova_exceptions
-
-
-class Unauthorized(nova_exceptions.Unauthorized):
- """ A wrapper around novaclient's Unauthorized exception. """
- pass
diff --git a/django-openstack/django_openstack/locale/es/LC_MESSAGES/django.po b/django-openstack/django_openstack/locale/es/LC_MESSAGES/django.po
deleted file mode 100644
index 2e3e9635..00000000
--- a/django-openstack/django_openstack/locale/es/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,1948 +0,0 @@
-# Translations of Dashboard for OpenStack User Interface.
-# Copyright 2011 Midokura KK
-# This file is distributed under the same license as the Dashboard for OpenStack.
-# FIRST AUTHOR Jeffrey Wilcox, 2011.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: openstack-dashboard\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: api.py:1002 syspanel/views/services.py:88
-#, python-format
-msgid "Unable to get service info: %s"
-msgstr ""
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, python-format
-msgid "Unable to get usage info: %s"
-msgstr ""
-
-#: context_processors.py:34
-#, python-format
-msgid ""
-"Unable to retrieve tenant list from "
-"keystone: %s"
-msgstr ""
-
-#: forms.py:180
-#, python-format
-msgid "Unexpected error: %s"
-msgstr ""
-
-#: auth/views.py:38
-msgid "User Name"
-msgstr ""
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
-msgstr ""
-
-#: auth/views.py:105
-#, python-format
-msgid "Error authenticating: %s"
-msgstr ""
-
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
-msgstr ""
-
-#: dash/views/containers.py:49
-#, python-format
-msgid "Unable to delete non-empty container: %s"
-msgstr ""
-
-#: dash/views/containers.py:55
-#, python-format
-msgid "Successfully deleted container: %s"
-msgstr ""
-
-#: dash/views/containers.py:61
-msgid "Container Name"
-msgstr ""
-
-#: dash/views/containers.py:65
-msgid "Container was successfully created."
-msgstr ""
-
-#: dash/views/floating_ips.py:47
-#, python-format
-msgid "Successfully released Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:51
-#, python-format
-msgid "Error releasing Floating IP from tenant: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
-msgid "Instance"
-msgstr ""
-
-#: dash/views/floating_ips.py:76
-#, python-format
-msgid ""
-"Successfully associated Floating IP: "
-"%(ip)s with Instance: %(inst)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:82
-#, python-format
-msgid "Error associating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:99
-#, python-format
-msgid "Successfully disassociated Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:103
-#, python-format
-msgid "Error disassociating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:118
-#, python-format
-msgid ""
-"Successfully allocated Floating IP \"%(ip)s\" "
-"to tenant \"%(tenant)s\""
-msgstr ""
-
-#: dash/views/floating_ips.py:124
-#, python-format
-msgid ""
-"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
-"\": %(msg)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:142
-#, python-format
-msgid "Error fetching floating ips: %s"
-msgstr ""
-
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
-msgid "Name"
-msgstr ""
-
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
-msgid "Kernel ID"
-msgstr ""
-
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
-msgid "Ramdisk ID"
-msgstr ""
-
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
-msgid "Architecture"
-msgstr ""
-
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
-msgid "Container Format"
-msgstr ""
-
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
-msgid "Disk Format"
-msgstr ""
-
-#: dash/views/images.py:59 dash/views/images.py:233
-#, python-format
-msgid "Unable to retreive image info from glance: %s"
-msgstr ""
-
-#: dash/views/images.py:61
-#, python-format
-msgid "Error updating image with id: %s"
-msgstr ""
-
-#: dash/views/images.py:66 dash/views/images.py:95
-msgid "Error connecting to glance"
-msgstr ""
-
-#: dash/views/images.py:92 syspanel/views/images.py:159
-msgid "Image was successfully updated."
-msgstr ""
-
-#: dash/views/images.py:101
-msgid "Unspecified Exception in image update"
-msgstr ""
-
-#: dash/views/images.py:105
-msgid ""
-"Unable to update image. You are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:111
-msgid "Server Name"
-msgstr ""
-
-#: dash/views/images.py:115
-msgid "User Data"
-msgstr ""
-
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
-msgid "Flavor"
-msgstr ""
-
-#: dash/views/images.py:130
-msgid "Key Name"
-msgstr ""
-
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
-msgid "Security Groups"
-msgstr ""
-
-#: dash/views/images.py:169
-msgid "Instance was successfully launched"
-msgstr ""
-
-#: dash/views/images.py:178
-#, python-format
-msgid "Unable to launch instance: %s"
-msgstr ""
-
-#: dash/views/images.py:192
-msgid ""
-"Unable to delete image, you are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
-#, python-format
-msgid "Error connecting to glance: %s"
-msgstr ""
-
-#: dash/views/images.py:202
-msgid "Error deleting image: %(image)s: %i(msg)s"
-msgstr ""
-
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
-msgid "There are currently no images."
-msgstr ""
-
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
-#, python-format
-msgid "Error retrieving image list: %s"
-msgstr ""
-
-#: dash/views/images.py:290
-#, python-format
-msgid "Error parsing quota for %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/images.py:323 syspanel/views/images.py:134
-#, python-format
-msgid "Error retrieving image %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:55
-#, python-format
-msgid "ApiException while terminating instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:58
-#, python-format
-msgid "Unable to terminate %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:61
-#, python-format
-msgid "Instance %s has been terminated."
-msgstr ""
-
-#: dash/views/instances.py:75
-msgid "Instance rebooting"
-msgstr ""
-
-#: dash/views/instances.py:77
-#, python-format
-msgid "ApiException while rebooting instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:80
-#, python-format
-msgid "Unable to reboot instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:83
-#, python-format
-msgid "Instance %s has been rebooted."
-msgstr ""
-
-#: dash/views/instances.py:105
-#, python-format
-msgid "Instance '%s' updated"
-msgstr ""
-
-#: dash/views/instances.py:109
-#, python-format
-msgid "Unable to update instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:124
-msgid "Exception in instance index"
-msgstr ""
-
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
-#, python-format
-msgid "Unable to get instance list: %s"
-msgstr ""
-
-#: dash/views/instances.py:178
-msgid "ApiException in instance usage"
-msgstr ""
-
-#: dash/views/instances.py:241
-msgid "ApiException while fetching instance console"
-msgstr ""
-
-#: dash/views/instances.py:243
-#, python-format
-msgid "Unable to get log for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:256
-msgid "ApiException while fetching instance vnc connection"
-msgstr ""
-
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:268 dash/views/instances.py:307
-msgid "ApiException while fetching instance info"
-msgstr ""
-
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:300
-msgid ""
-"ApiException while fetching instance vnc "
-"connection"
-msgstr ""
-
-#: dash/views/instances.py:303
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:309
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/keypairs.py:49
-#, python-format
-msgid "Successfully deleted keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:54
-#, python-format
-msgid "Error deleting keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
-msgid "Keypair Name"
-msgstr ""
-
-#: dash/views/keypairs.py:75
-#, python-format
-msgid "Error Creating Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:83
-msgid "Public Key"
-msgstr ""
-
-#: dash/views/keypairs.py:89
-#, python-format
-msgid "Successfully imported public key: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:95
-#, python-format
-msgid "Error Importing Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:111
-#, python-format
-msgid "Error fetching keypairs: %s"
-msgstr ""
-
-#: dash/views/networks.py:49
-msgid "Network Name"
-msgstr ""
-
-#: dash/views/networks.py:60
-#, python-format
-msgid "Unable to create network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:64
-#, python-format
-msgid "Network %s has been created."
-msgstr ""
-
-#: dash/views/networks.py:80
-#, python-format
-msgid "Unable to delete network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:83
-#, python-format
-msgid "Network %s has been deleted."
-msgstr ""
-
-#: dash/views/networks.py:102
-#, python-format
-msgid "Unable to rename network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:105
-#, python-format
-msgid "Network %(net)s has been renamed to %(new_name)s."
-msgstr ""
-
-#: dash/views/networks.py:138
-#, python-format
-msgid "Unable to get network list: %s"
-msgstr ""
-
-#: dash/views/networks.py:174
-#, python-format
-msgid "Unable to get network details: %s"
-msgstr ""
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, python-format
-msgid "Successfully deleted object: %s"
-msgstr ""
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-msgid "Object was successfully uploaded."
-msgstr ""
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
-msgid "Number of Ports"
-msgstr ""
-
-#: dash/views/ports.py:53
-#, python-format
-msgid "Unable to create ports on network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:56
-#, python-format
-msgid "%(num_ports)s ports created on network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:75
-#, python-format
-msgid "Unable to delete port %(port)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:78
-#, python-format
-msgid "Port %(port)s deleted from network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:89
-msgid "Select VIF to connect"
-msgstr ""
-
-#: dash/views/ports.py:100
-#, python-format
-msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:103
-#, python-format
-msgid "Port %(port)s connected to VIF %(vif)s."
-msgstr ""
-
-#: dash/views/ports.py:120
-#, python-format
-msgid "Unable to detach port %(port)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:123
-#, python-format
-msgid "Port %s detached."
-msgstr ""
-
-#: dash/views/ports.py:142
-#, python-format
-msgid "Unable to set port state to %(state)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:145
-#, python-format
-msgid "Port %(port)s state set to %(state)s."
-msgstr ""
-
-#: dash/views/security_groups.py:56
-#, python-format
-msgid "Successfully created security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:62
-#, python-format
-msgid "Error creating security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:76
-#, python-format
-msgid "Successfully deleted security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:80
-#, python-format
-msgid "Error deleting security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:109
-#, python-format
-msgid "Successfully added rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:113
-#, python-format
-msgid "Error adding rule security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:131
-#, python-format
-msgid "Successfully deleted rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:135
-#, python-format
-msgid "Error authorizing security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:153
-#, python-format
-msgid "Error fetching security_groups: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:181
-#, python-format
-msgid "Error getting security_group: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:51
-msgid "Snapshot Name"
-msgstr ""
-
-#: dash/views/snapshots.py:62
-#, python-format
-msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
-msgstr ""
-
-#: dash/views/snapshots.py:66
-#, python-format
-msgid "Error Creating Snapshot: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:104
-#, python-format
-msgid "Unable to retreive instance: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:111
-#, python-format
-msgid ""
-"To snapshot, instance state must be one of "
-"the following: %s"
-msgstr ""
-
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, python-format
-msgid "%s was successfully added to flavors."
-msgstr ""
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, python-format
-msgid "Unable to delete flavor: %s"
-msgstr ""
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, python-format
-msgid "Error updating image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-msgid "Image was successfully uploaded."
-msgstr ""
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, python-format
-msgid "Service '%s' has been enabled"
-msgstr ""
-
-#: syspanel/views/services.py:62
-#, python-format
-msgid "Service '%s' has been disabled"
-msgstr ""
-
-#: syspanel/views/services.py:68
-#, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr ""
-
-#: syspanel/views/tenants.py:57
-#, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:60
-#, python-format
-msgid "Unable to create user association: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:77
-#, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, python-format
-msgid "Unable to create tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, python-format
-msgid "%s was successfully created."
-msgstr ""
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, python-format
-msgid "%s was successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, python-format
-msgid "Unable to update tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr ""
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr ""
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:173
-#, python-format
-msgid "Unable to update quotas: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:183
-#, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:188
-#, python-format
-msgid "Error deleting tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:206
-#, python-format
-msgid "Unable to get tenant info: %s"
-msgstr ""
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, python-format
-msgid "%(user)s was successfully deleted."
-msgstr ""
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr ""
-
-#: syspanel/views/users.py:128
-#, python-format
-msgid "Unable to list users: %s"
-msgstr ""
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-msgid "Unable to update user, please try again."
-msgstr ""
-
-#: syspanel/views/users.py:194
-#, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr ""
-
-#: syspanel/views/users.py:212
-#, python-format
-msgid "User \"%s\" was successfully created."
-msgstr ""
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, python-format
-msgid "Error creating user: %s"
-msgstr ""
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
-msgid "Dashboard Settings"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:26
-msgid "Dashboard User Interface Language"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:38
-msgid "Select Language"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
-msgid "Delete"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_form.html:10
-msgid "Create Container"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
-msgid "Actions"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:17
-msgid "List Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
-msgid "Upload Object"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
-msgid "Create Tenant"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:22
-msgid ""
-"A container is a storage compartment for your data and provides a way for "
-"you to organize your data. You can think of a container as a folder in "
-"Windows® or a directory in UNIX®. The primary difference between a container "
-"and these other file system concepts is that containers cannot be nested. "
-"You can, however, create an unlimited number of containers within your "
-"account. Data must be stored in a container so you must have at least one "
-"container defined in your account prior to uploading data."
-msgstr ""
-
-#: templates/django_openstack/dash/containers/index.html:18
-msgid "Create New Container"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
-msgid "Allocate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
-msgid "Associate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
-msgid "Disassociate"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:14
-msgid "Instance ID:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:15
-msgid "Fixed IP:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:28
-msgid "Associate to instance"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_release.html:8
-msgid "Release"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:12
-msgid "Associate Floating IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
-msgid "Description:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:23
-msgid "Associate a floating ip with an instance."
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
-msgid "Info"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:22
-msgid "There are currently no floating ips assigned to your tenant."
-msgstr ""
-
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
-msgid "Update Image"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
-msgid "Launch Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
-msgid "Created"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
-msgid "Updated"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
-msgid "Status"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
-msgid "Edit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:24
-msgid "Launch"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:22
-msgid ""
-"Specify the details for launching an instance. Also please make note of the "
-"table below; all tenants have quotas which define the limit of resources you "
-"are allowed to provision."
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
-msgid "Quota Name"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
-msgid "Limit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:29
-msgid "RAM (MB)"
-msgstr ""
-
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
-msgid "From here you can modify different properties of an image."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
-msgid "Update Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:8
-msgid "Groups"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
-msgid "Image"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
-msgid "Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
-msgid "IPs"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
-msgid "State"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:66
-msgid "Log"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
-msgid "VNC Console"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:69
-msgid "Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:19
-msgid "Return to Instances List"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:24
-msgid "Update the name and description of your instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
-msgid "Download CSV"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:50
-msgid "Hide Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:52
-msgid "Show Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
-msgid "User"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
-msgid "Ram Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
-msgid "Disk Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
-msgid "Uptime"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:89
-msgid "No active instances."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:98
-#, python-format
-msgid ""
-"There are currently no instances.<br/><br/>You can launch an instance from "
-"the <a href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_form.html:10
-msgid "Add Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_list.html:5
-msgid "Fingerprint"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
-msgid "Create Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:30
-msgid "Your private key is being downloaded."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
-msgid "Return to keypairs list"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
-msgid ""
-"Keypairs are ssh credentials which are injected into images when they are "
-"launched. Creating a new key pair registers the public key and downloads the "
-"private key (a .pem file)."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
-msgid "Protect and use the key as you would any normal ssh private key."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
-msgid "Add New Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
-msgid "Import Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:24
-msgid "There are currently no keypairs."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detach_port.html:9
-msgid "Detach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:6
-msgid "Attachment"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:8
-msgid "Extensions"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:20
-msgid "VIF Id"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:36
-msgid "Attach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
-msgid "Create Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:6
-msgid "Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:7
-msgid "Available"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:8
-msgid "Used"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:9
-msgid "Action"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
-msgid "Rename"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
-msgid "Rename Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
-msgid "Port UP"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
-msgid "Port DOWN"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
-msgid "Return to networks list"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:24
-msgid "Networks provide layer 2 connectivity to your instances."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "Create Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "There are currently no ports in this network."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:20
-msgid "Create New Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "There are currently no networks."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "Create A Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/rename.html:32
-msgid "Enter a new name for your network."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
-msgid "Copy Object"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_filter.html:7
-msgid "Filter"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:16
-msgid "Copy"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:18
-msgid "Download"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
-msgid "Return to objects list"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:26
-msgid ""
-"You may make a new copy of an existing object to store in this or another "
-"container."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:31
-#, python-format
-msgid ""
-"There are currently no objects in the container %(container_name)s. You can "
-"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
-"Page &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:34
-msgid "Upload New Object &gt;&gt;"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:11
-msgid "Upload Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:25
-msgid ""
-"An object is the basic storage entity and any optional metadata that "
-"represents the files you store in the OpenStack Object Storage system. When "
-"you upload data to OpenStack Object Storage, the data is stored as-is (no "
-"compression or encryption) and consists of a location (container), the "
-"object's name, and any metadata consisting of key/value pairs."
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:12
-msgid "Attach Port"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
-msgid "Return to network detail"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:42
-msgid ""
-"<p>Select an interface from the list on the left to attach it to this port.</"
-"p>\n"
-" <p>Only interfaces that are not connected to any existing port are "
-"shown</p>\n"
-" <p>If you want to reconnect a connected interface, please detach it "
-"first</p>"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/create.html:24
-msgid ""
-"You can plug virtual interfaces from your instances to ports created in the "
-"network"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
-msgid "Create Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_list.html:14
-msgid "Edit Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/create.html:22
-msgid "From here you can create a new security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
-msgid "Edit Security Group Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
-msgid "Rules for Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
-msgid "IP Protocol"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
-msgid "From Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
-msgid "To Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
-msgid "CIDR"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
-msgid "No rules for this security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
-msgid "Add a rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
-msgid "Add Rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/index.html:25
-#, python-format
-msgid ""
-"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
-"Security Group &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/_form.html:11
-msgid "Create Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:19
-msgid "Create a Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:25
-msgid "Choose a name for your snapshot."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:27
-msgid "Return to snapshots list"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:32
-msgid "Snapshots preserve the disk state of a running instance."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/index.html:23
-#, python-format
-msgid ""
-"There are currently no snapshots. You can create snapshots from running "
-"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:5
-msgid "System Panel"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
-msgid "Create Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
-msgid "Id"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:7
-msgid "Memory"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
-msgid "Disk"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/create.html:37
-msgid "From here you can define the sizing of a new flavor."
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/index.html:18
-msgid "Create New Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:9
-msgid "Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:35
-msgid "Location"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:40
-msgid "Project ID"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_toggle.html:8
-msgid "Toggle Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
-msgid "Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:8
-msgid "Host"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:48
-msgid "Console Log"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_image_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
-msgid "System Panel Overview"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
-msgid "Active Instances"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
-msgid "This month's VCPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
-msgid "This month's GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
-msgid "Tenant Usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:23
-msgid "Monitoring"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:34
-msgid "Select a month to query its usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:71
-msgid "Server Usage Summary"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:80
-msgid "RAM"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:81
-msgid "VCPU CPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:82
-msgid "Disk GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/quotas/index.html:13
-msgid "Default Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:5
-msgid "Service"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:6
-msgid "System Stats"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:8
-msgid "Up"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:22
-msgid "Hypervisor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:25
-msgid "Allocable Cores"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:30
-msgid "Allocable Storage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:35
-msgid "System Ram"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
-msgid "Enable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
-msgid "Disable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
-msgid "Add"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
-msgid "Options"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:20
-msgid "View Members"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:21
-msgid "Modify Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
-msgid "Remove"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
-msgid "Update Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
-msgid "Update Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/create.html:22
-msgid "From here you can create a new tenant (aka project) to organize users."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/index.html:18
-msgid "Create New Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
-msgid "Update Tenant Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/update.html:22
-msgid "From here you can edit a tenant."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:12
-msgid "Users for Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:45
-msgid "here are currently no users for this tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:49
-msgid "Add new users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
-msgid "Create User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
-msgid "Update User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/create.html:23
-msgid ""
-"From here you can create a new user and assign them to a tenant (aka "
-"project)."
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:23
-msgid "Default Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:42
-msgid "Create New User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/update.html:23
-msgid ""
-"From here you can edit users by changing their usernames, emails, passwords, "
-"and tenants."
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:46
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:50
-#, python-format
-msgid "%(size)d"
-msgid_plural "%(size)d"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:53
-#, python-format
-msgid "%s KB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:56
-#, python-format
-msgid "%s MB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:59
-#, python-format
-msgid "%s GB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:62
-#, python-format
-msgid "%s TB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:64
-#, python-format
-msgid "%s PB"
-msgstr ""
diff --git a/django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.po b/django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.po
deleted file mode 100644
index da68a58f..00000000
--- a/django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,1948 +0,0 @@
-# Translations of Dashboard for OpenStack User Interface.
-# Copyright 2011 Midokura KK
-# This file is distributed under the same license as the Dashboard for OpenStack.
-# FIRST AUTHOR Jeffrey Wilcox, 2011.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: openstack-dashboard\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n>1;\n"
-
-#: api.py:1002 syspanel/views/services.py:88
-#, python-format
-msgid "Unable to get service info: %s"
-msgstr ""
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, python-format
-msgid "Unable to get usage info: %s"
-msgstr ""
-
-#: context_processors.py:34
-#, python-format
-msgid ""
-"Unable to retrieve tenant list from "
-"keystone: %s"
-msgstr ""
-
-#: forms.py:180
-#, python-format
-msgid "Unexpected error: %s"
-msgstr ""
-
-#: auth/views.py:38
-msgid "User Name"
-msgstr ""
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
-msgstr ""
-
-#: auth/views.py:105
-#, python-format
-msgid "Error authenticating: %s"
-msgstr ""
-
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
-msgstr ""
-
-#: dash/views/containers.py:49
-#, python-format
-msgid "Unable to delete non-empty container: %s"
-msgstr ""
-
-#: dash/views/containers.py:55
-#, python-format
-msgid "Successfully deleted container: %s"
-msgstr ""
-
-#: dash/views/containers.py:61
-msgid "Container Name"
-msgstr ""
-
-#: dash/views/containers.py:65
-msgid "Container was successfully created."
-msgstr ""
-
-#: dash/views/floating_ips.py:47
-#, python-format
-msgid "Successfully released Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:51
-#, python-format
-msgid "Error releasing Floating IP from tenant: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
-msgid "Instance"
-msgstr ""
-
-#: dash/views/floating_ips.py:76
-#, python-format
-msgid ""
-"Successfully associated Floating IP: "
-"%(ip)s with Instance: %(inst)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:82
-#, python-format
-msgid "Error associating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:99
-#, python-format
-msgid "Successfully disassociated Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:103
-#, python-format
-msgid "Error disassociating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:118
-#, python-format
-msgid ""
-"Successfully allocated Floating IP \"%(ip)s\" "
-"to tenant \"%(tenant)s\""
-msgstr ""
-
-#: dash/views/floating_ips.py:124
-#, python-format
-msgid ""
-"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
-"\": %(msg)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:142
-#, python-format
-msgid "Error fetching floating ips: %s"
-msgstr ""
-
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
-msgid "Name"
-msgstr ""
-
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
-msgid "Kernel ID"
-msgstr ""
-
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
-msgid "Ramdisk ID"
-msgstr ""
-
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
-msgid "Architecture"
-msgstr ""
-
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
-msgid "Container Format"
-msgstr ""
-
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
-msgid "Disk Format"
-msgstr ""
-
-#: dash/views/images.py:59 dash/views/images.py:233
-#, python-format
-msgid "Unable to retreive image info from glance: %s"
-msgstr ""
-
-#: dash/views/images.py:61
-#, python-format
-msgid "Error updating image with id: %s"
-msgstr ""
-
-#: dash/views/images.py:66 dash/views/images.py:95
-msgid "Error connecting to glance"
-msgstr ""
-
-#: dash/views/images.py:92 syspanel/views/images.py:159
-msgid "Image was successfully updated."
-msgstr ""
-
-#: dash/views/images.py:101
-msgid "Unspecified Exception in image update"
-msgstr ""
-
-#: dash/views/images.py:105
-msgid ""
-"Unable to update image. You are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:111
-msgid "Server Name"
-msgstr ""
-
-#: dash/views/images.py:115
-msgid "User Data"
-msgstr ""
-
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
-msgid "Flavor"
-msgstr ""
-
-#: dash/views/images.py:130
-msgid "Key Name"
-msgstr ""
-
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
-msgid "Security Groups"
-msgstr ""
-
-#: dash/views/images.py:169
-msgid "Instance was successfully launched"
-msgstr ""
-
-#: dash/views/images.py:178
-#, python-format
-msgid "Unable to launch instance: %s"
-msgstr ""
-
-#: dash/views/images.py:192
-msgid ""
-"Unable to delete image, you are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
-#, python-format
-msgid "Error connecting to glance: %s"
-msgstr ""
-
-#: dash/views/images.py:202
-msgid "Error deleting image: %(image)s: %i(msg)s"
-msgstr ""
-
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
-msgid "There are currently no images."
-msgstr ""
-
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
-#, python-format
-msgid "Error retrieving image list: %s"
-msgstr ""
-
-#: dash/views/images.py:290
-#, python-format
-msgid "Error parsing quota for %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/images.py:323 syspanel/views/images.py:134
-#, python-format
-msgid "Error retrieving image %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:55
-#, python-format
-msgid "ApiException while terminating instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:58
-#, python-format
-msgid "Unable to terminate %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:61
-#, python-format
-msgid "Instance %s has been terminated."
-msgstr ""
-
-#: dash/views/instances.py:75
-msgid "Instance rebooting"
-msgstr ""
-
-#: dash/views/instances.py:77
-#, python-format
-msgid "ApiException while rebooting instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:80
-#, python-format
-msgid "Unable to reboot instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:83
-#, python-format
-msgid "Instance %s has been rebooted."
-msgstr ""
-
-#: dash/views/instances.py:105
-#, python-format
-msgid "Instance '%s' updated"
-msgstr ""
-
-#: dash/views/instances.py:109
-#, python-format
-msgid "Unable to update instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:124
-msgid "Exception in instance index"
-msgstr ""
-
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
-#, python-format
-msgid "Unable to get instance list: %s"
-msgstr ""
-
-#: dash/views/instances.py:178
-msgid "ApiException in instance usage"
-msgstr ""
-
-#: dash/views/instances.py:241
-msgid "ApiException while fetching instance console"
-msgstr ""
-
-#: dash/views/instances.py:243
-#, python-format
-msgid "Unable to get log for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:256
-msgid "ApiException while fetching instance vnc connection"
-msgstr ""
-
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:268 dash/views/instances.py:307
-msgid "ApiException while fetching instance info"
-msgstr ""
-
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:300
-msgid ""
-"ApiException while fetching instance vnc "
-"connection"
-msgstr ""
-
-#: dash/views/instances.py:303
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:309
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/keypairs.py:49
-#, python-format
-msgid "Successfully deleted keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:54
-#, python-format
-msgid "Error deleting keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
-msgid "Keypair Name"
-msgstr ""
-
-#: dash/views/keypairs.py:75
-#, python-format
-msgid "Error Creating Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:83
-msgid "Public Key"
-msgstr ""
-
-#: dash/views/keypairs.py:89
-#, python-format
-msgid "Successfully imported public key: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:95
-#, python-format
-msgid "Error Importing Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:111
-#, python-format
-msgid "Error fetching keypairs: %s"
-msgstr ""
-
-#: dash/views/networks.py:49
-msgid "Network Name"
-msgstr ""
-
-#: dash/views/networks.py:60
-#, python-format
-msgid "Unable to create network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:64
-#, python-format
-msgid "Network %s has been created."
-msgstr ""
-
-#: dash/views/networks.py:80
-#, python-format
-msgid "Unable to delete network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:83
-#, python-format
-msgid "Network %s has been deleted."
-msgstr ""
-
-#: dash/views/networks.py:102
-#, python-format
-msgid "Unable to rename network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:105
-#, python-format
-msgid "Network %(net)s has been renamed to %(new_name)s."
-msgstr ""
-
-#: dash/views/networks.py:138
-#, python-format
-msgid "Unable to get network list: %s"
-msgstr ""
-
-#: dash/views/networks.py:174
-#, python-format
-msgid "Unable to get network details: %s"
-msgstr ""
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, python-format
-msgid "Successfully deleted object: %s"
-msgstr ""
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-msgid "Object was successfully uploaded."
-msgstr ""
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
-msgid "Number of Ports"
-msgstr ""
-
-#: dash/views/ports.py:53
-#, python-format
-msgid "Unable to create ports on network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:56
-#, python-format
-msgid "%(num_ports)s ports created on network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:75
-#, python-format
-msgid "Unable to delete port %(port)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:78
-#, python-format
-msgid "Port %(port)s deleted from network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:89
-msgid "Select VIF to connect"
-msgstr ""
-
-#: dash/views/ports.py:100
-#, python-format
-msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:103
-#, python-format
-msgid "Port %(port)s connected to VIF %(vif)s."
-msgstr ""
-
-#: dash/views/ports.py:120
-#, python-format
-msgid "Unable to detach port %(port)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:123
-#, python-format
-msgid "Port %s detached."
-msgstr ""
-
-#: dash/views/ports.py:142
-#, python-format
-msgid "Unable to set port state to %(state)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:145
-#, python-format
-msgid "Port %(port)s state set to %(state)s."
-msgstr ""
-
-#: dash/views/security_groups.py:56
-#, python-format
-msgid "Successfully created security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:62
-#, python-format
-msgid "Error creating security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:76
-#, python-format
-msgid "Successfully deleted security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:80
-#, python-format
-msgid "Error deleting security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:109
-#, python-format
-msgid "Successfully added rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:113
-#, python-format
-msgid "Error adding rule security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:131
-#, python-format
-msgid "Successfully deleted rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:135
-#, python-format
-msgid "Error authorizing security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:153
-#, python-format
-msgid "Error fetching security_groups: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:181
-#, python-format
-msgid "Error getting security_group: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:51
-msgid "Snapshot Name"
-msgstr ""
-
-#: dash/views/snapshots.py:62
-#, python-format
-msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
-msgstr ""
-
-#: dash/views/snapshots.py:66
-#, python-format
-msgid "Error Creating Snapshot: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:104
-#, python-format
-msgid "Unable to retreive instance: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:111
-#, python-format
-msgid ""
-"To snapshot, instance state must be one of "
-"the following: %s"
-msgstr ""
-
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, python-format
-msgid "%s was successfully added to flavors."
-msgstr ""
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, python-format
-msgid "Unable to delete flavor: %s"
-msgstr ""
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, python-format
-msgid "Error updating image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-msgid "Image was successfully uploaded."
-msgstr ""
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, python-format
-msgid "Service '%s' has been enabled"
-msgstr ""
-
-#: syspanel/views/services.py:62
-#, python-format
-msgid "Service '%s' has been disabled"
-msgstr ""
-
-#: syspanel/views/services.py:68
-#, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr ""
-
-#: syspanel/views/tenants.py:57
-#, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:60
-#, python-format
-msgid "Unable to create user association: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:77
-#, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, python-format
-msgid "Unable to create tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, python-format
-msgid "%s was successfully created."
-msgstr ""
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, python-format
-msgid "%s was successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, python-format
-msgid "Unable to update tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr ""
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr ""
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:173
-#, python-format
-msgid "Unable to update quotas: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:183
-#, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:188
-#, python-format
-msgid "Error deleting tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:206
-#, python-format
-msgid "Unable to get tenant info: %s"
-msgstr ""
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, python-format
-msgid "%(user)s was successfully deleted."
-msgstr ""
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr ""
-
-#: syspanel/views/users.py:128
-#, python-format
-msgid "Unable to list users: %s"
-msgstr ""
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-msgid "Unable to update user, please try again."
-msgstr ""
-
-#: syspanel/views/users.py:194
-#, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr ""
-
-#: syspanel/views/users.py:212
-#, python-format
-msgid "User \"%s\" was successfully created."
-msgstr ""
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, python-format
-msgid "Error creating user: %s"
-msgstr ""
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
-msgid "Dashboard Settings"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:26
-msgid "Dashboard User Interface Language"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:38
-msgid "Select Language"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
-msgid "Delete"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_form.html:10
-msgid "Create Container"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
-msgid "Actions"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:17
-msgid "List Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
-msgid "Upload Object"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
-msgid "Create Tenant"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:22
-msgid ""
-"A container is a storage compartment for your data and provides a way for "
-"you to organize your data. You can think of a container as a folder in "
-"Windows® or a directory in UNIX®. The primary difference between a container "
-"and these other file system concepts is that containers cannot be nested. "
-"You can, however, create an unlimited number of containers within your "
-"account. Data must be stored in a container so you must have at least one "
-"container defined in your account prior to uploading data."
-msgstr ""
-
-#: templates/django_openstack/dash/containers/index.html:18
-msgid "Create New Container"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
-msgid "Allocate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
-msgid "Associate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
-msgid "Disassociate"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:14
-msgid "Instance ID:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:15
-msgid "Fixed IP:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:28
-msgid "Associate to instance"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_release.html:8
-msgid "Release"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:12
-msgid "Associate Floating IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
-msgid "Description:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:23
-msgid "Associate a floating ip with an instance."
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
-msgid "Info"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:22
-msgid "There are currently no floating ips assigned to your tenant."
-msgstr ""
-
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
-msgid "Update Image"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
-msgid "Launch Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
-msgid "Created"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
-msgid "Updated"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
-msgid "Status"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
-msgid "Edit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:24
-msgid "Launch"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:22
-msgid ""
-"Specify the details for launching an instance. Also please make note of the "
-"table below; all tenants have quotas which define the limit of resources you "
-"are allowed to provision."
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
-msgid "Quota Name"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
-msgid "Limit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:29
-msgid "RAM (MB)"
-msgstr ""
-
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
-msgid "From here you can modify different properties of an image."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
-msgid "Update Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:8
-msgid "Groups"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
-msgid "Image"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
-msgid "Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
-msgid "IPs"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
-msgid "State"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:66
-msgid "Log"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
-msgid "VNC Console"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:69
-msgid "Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:19
-msgid "Return to Instances List"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:24
-msgid "Update the name and description of your instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
-msgid "Download CSV"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:50
-msgid "Hide Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:52
-msgid "Show Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
-msgid "User"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
-msgid "Ram Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
-msgid "Disk Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
-msgid "Uptime"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:89
-msgid "No active instances."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:98
-#, python-format
-msgid ""
-"There are currently no instances.<br/><br/>You can launch an instance from "
-"the <a href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_form.html:10
-msgid "Add Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_list.html:5
-msgid "Fingerprint"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
-msgid "Create Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:30
-msgid "Your private key is being downloaded."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
-msgid "Return to keypairs list"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
-msgid ""
-"Keypairs are ssh credentials which are injected into images when they are "
-"launched. Creating a new key pair registers the public key and downloads the "
-"private key (a .pem file)."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
-msgid "Protect and use the key as you would any normal ssh private key."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
-msgid "Add New Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
-msgid "Import Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:24
-msgid "There are currently no keypairs."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detach_port.html:9
-msgid "Detach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:6
-msgid "Attachment"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:8
-msgid "Extensions"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:20
-msgid "VIF Id"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:36
-msgid "Attach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
-msgid "Create Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:6
-msgid "Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:7
-msgid "Available"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:8
-msgid "Used"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:9
-msgid "Action"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
-msgid "Rename"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
-msgid "Rename Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
-msgid "Port UP"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
-msgid "Port DOWN"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
-msgid "Return to networks list"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:24
-msgid "Networks provide layer 2 connectivity to your instances."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "Create Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "There are currently no ports in this network."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:20
-msgid "Create New Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "There are currently no networks."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "Create A Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/rename.html:32
-msgid "Enter a new name for your network."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
-msgid "Copy Object"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_filter.html:7
-msgid "Filter"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:16
-msgid "Copy"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:18
-msgid "Download"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
-msgid "Return to objects list"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:26
-msgid ""
-"You may make a new copy of an existing object to store in this or another "
-"container."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:31
-#, python-format
-msgid ""
-"There are currently no objects in the container %(container_name)s. You can "
-"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
-"Page &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:34
-msgid "Upload New Object &gt;&gt;"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:11
-msgid "Upload Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:25
-msgid ""
-"An object is the basic storage entity and any optional metadata that "
-"represents the files you store in the OpenStack Object Storage system. When "
-"you upload data to OpenStack Object Storage, the data is stored as-is (no "
-"compression or encryption) and consists of a location (container), the "
-"object's name, and any metadata consisting of key/value pairs."
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:12
-msgid "Attach Port"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
-msgid "Return to network detail"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:42
-msgid ""
-"<p>Select an interface from the list on the left to attach it to this port.</"
-"p>\n"
-" <p>Only interfaces that are not connected to any existing port are "
-"shown</p>\n"
-" <p>If you want to reconnect a connected interface, please detach it "
-"first</p>"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/create.html:24
-msgid ""
-"You can plug virtual interfaces from your instances to ports created in the "
-"network"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
-msgid "Create Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_list.html:14
-msgid "Edit Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/create.html:22
-msgid "From here you can create a new security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
-msgid "Edit Security Group Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
-msgid "Rules for Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
-msgid "IP Protocol"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
-msgid "From Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
-msgid "To Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
-msgid "CIDR"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
-msgid "No rules for this security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
-msgid "Add a rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
-msgid "Add Rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/index.html:25
-#, python-format
-msgid ""
-"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
-"Security Group &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/_form.html:11
-msgid "Create Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:19
-msgid "Create a Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:25
-msgid "Choose a name for your snapshot."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:27
-msgid "Return to snapshots list"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:32
-msgid "Snapshots preserve the disk state of a running instance."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/index.html:23
-#, python-format
-msgid ""
-"There are currently no snapshots. You can create snapshots from running "
-"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:5
-msgid "System Panel"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
-msgid "Create Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
-msgid "Id"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:7
-msgid "Memory"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
-msgid "Disk"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/create.html:37
-msgid "From here you can define the sizing of a new flavor."
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/index.html:18
-msgid "Create New Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:9
-msgid "Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:35
-msgid "Location"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:40
-msgid "Project ID"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_toggle.html:8
-msgid "Toggle Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
-msgid "Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:8
-msgid "Host"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:48
-msgid "Console Log"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_image_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
-msgid "System Panel Overview"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
-msgid "Active Instances"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
-msgid "This month's VCPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
-msgid "This month's GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
-msgid "Tenant Usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:23
-msgid "Monitoring"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:34
-msgid "Select a month to query its usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:71
-msgid "Server Usage Summary"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:80
-msgid "RAM"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:81
-msgid "VCPU CPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:82
-msgid "Disk GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/quotas/index.html:13
-msgid "Default Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:5
-msgid "Service"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:6
-msgid "System Stats"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:8
-msgid "Up"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:22
-msgid "Hypervisor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:25
-msgid "Allocable Cores"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:30
-msgid "Allocable Storage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:35
-msgid "System Ram"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
-msgid "Enable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
-msgid "Disable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
-msgid "Add"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
-msgid "Options"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:20
-msgid "View Members"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:21
-msgid "Modify Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
-msgid "Remove"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
-msgid "Update Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
-msgid "Update Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/create.html:22
-msgid "From here you can create a new tenant (aka project) to organize users."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/index.html:18
-msgid "Create New Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
-msgid "Update Tenant Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/update.html:22
-msgid "From here you can edit a tenant."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:12
-msgid "Users for Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:45
-msgid "here are currently no users for this tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:49
-msgid "Add new users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
-msgid "Create User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
-msgid "Update User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/create.html:23
-msgid ""
-"From here you can create a new user and assign them to a tenant (aka "
-"project)."
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:23
-msgid "Default Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:42
-msgid "Create New User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/update.html:23
-msgid ""
-"From here you can edit users by changing their usernames, emails, passwords, "
-"and tenants."
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:46
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:50
-#, python-format
-msgid "%(size)d"
-msgid_plural "%(size)d"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:53
-#, python-format
-msgid "%s KB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:56
-#, python-format
-msgid "%s MB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:59
-#, python-format
-msgid "%s GB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:62
-#, python-format
-msgid "%s TB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:64
-#, python-format
-msgid "%s PB"
-msgstr ""
diff --git a/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.mo b/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.mo
deleted file mode 100644
index 0a426594..00000000
--- a/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.mo
+++ /dev/null
Binary files differ
diff --git a/django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.po b/django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.po
deleted file mode 100644
index 21c8f5b2..00000000
--- a/django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,1947 +0,0 @@
-# Translations of Dashboard for OpenStack User Interface.
-# Copyright 2011 Midokura KK
-# This file is distributed under the same license as the Dashboard for OpenStack.
-# FIRST AUTHOR Jeffrey Wilcox, 2011.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: openstack-dashboard\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: api.py:1002 syspanel/views/services.py:88
-#, python-format
-msgid "Unable to get service info: %s"
-msgstr ""
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, python-format
-msgid "Unable to get usage info: %s"
-msgstr ""
-
-#: context_processors.py:34
-#, python-format
-msgid ""
-"Unable to retrieve tenant list from "
-"keystone: %s"
-msgstr ""
-
-#: forms.py:180
-#, python-format
-msgid "Unexpected error: %s"
-msgstr ""
-
-#: auth/views.py:38
-msgid "User Name"
-msgstr ""
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
-msgstr ""
-
-#: auth/views.py:105
-#, python-format
-msgid "Error authenticating: %s"
-msgstr ""
-
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
-msgstr ""
-
-#: dash/views/containers.py:49
-#, python-format
-msgid "Unable to delete non-empty container: %s"
-msgstr ""
-
-#: dash/views/containers.py:55
-#, python-format
-msgid "Successfully deleted container: %s"
-msgstr ""
-
-#: dash/views/containers.py:61
-msgid "Container Name"
-msgstr ""
-
-#: dash/views/containers.py:65
-msgid "Container was successfully created."
-msgstr ""
-
-#: dash/views/floating_ips.py:47
-#, python-format
-msgid "Successfully released Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:51
-#, python-format
-msgid "Error releasing Floating IP from tenant: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
-msgid "Instance"
-msgstr ""
-
-#: dash/views/floating_ips.py:76
-#, python-format
-msgid ""
-"Successfully associated Floating IP: "
-"%(ip)s with Instance: %(inst)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:82
-#, python-format
-msgid "Error associating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:99
-#, python-format
-msgid "Successfully disassociated Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:103
-#, python-format
-msgid "Error disassociating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:118
-#, python-format
-msgid ""
-"Successfully allocated Floating IP \"%(ip)s\" "
-"to tenant \"%(tenant)s\""
-msgstr ""
-
-#: dash/views/floating_ips.py:124
-#, python-format
-msgid ""
-"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
-"\": %(msg)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:142
-#, python-format
-msgid "Error fetching floating ips: %s"
-msgstr ""
-
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
-msgid "Name"
-msgstr ""
-
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
-msgid "Kernel ID"
-msgstr ""
-
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
-msgid "Ramdisk ID"
-msgstr ""
-
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
-msgid "Architecture"
-msgstr ""
-
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
-msgid "Container Format"
-msgstr ""
-
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
-msgid "Disk Format"
-msgstr ""
-
-#: dash/views/images.py:59 dash/views/images.py:233
-#, python-format
-msgid "Unable to retreive image info from glance: %s"
-msgstr ""
-
-#: dash/views/images.py:61
-#, python-format
-msgid "Error updating image with id: %s"
-msgstr ""
-
-#: dash/views/images.py:66 dash/views/images.py:95
-msgid "Error connecting to glance"
-msgstr ""
-
-#: dash/views/images.py:92 syspanel/views/images.py:159
-msgid "Image was successfully updated."
-msgstr ""
-
-#: dash/views/images.py:101
-msgid "Unspecified Exception in image update"
-msgstr ""
-
-#: dash/views/images.py:105
-msgid ""
-"Unable to update image. You are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:111
-msgid "Server Name"
-msgstr ""
-
-#: dash/views/images.py:115
-msgid "User Data"
-msgstr ""
-
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
-msgid "Flavor"
-msgstr ""
-
-#: dash/views/images.py:130
-msgid "Key Name"
-msgstr ""
-
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
-msgid "Security Groups"
-msgstr ""
-
-#: dash/views/images.py:169
-msgid "Instance was successfully launched"
-msgstr ""
-
-#: dash/views/images.py:178
-#, python-format
-msgid "Unable to launch instance: %s"
-msgstr ""
-
-#: dash/views/images.py:192
-msgid ""
-"Unable to delete image, you are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
-#, python-format
-msgid "Error connecting to glance: %s"
-msgstr ""
-
-#: dash/views/images.py:202
-msgid "Error deleting image: %(image)s: %i(msg)s"
-msgstr ""
-
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
-msgid "There are currently no images."
-msgstr ""
-
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
-#, python-format
-msgid "Error retrieving image list: %s"
-msgstr ""
-
-#: dash/views/images.py:290
-#, python-format
-msgid "Error parsing quota for %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/images.py:323 syspanel/views/images.py:134
-#, python-format
-msgid "Error retrieving image %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:55
-#, python-format
-msgid "ApiException while terminating instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:58
-#, python-format
-msgid "Unable to terminate %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:61
-#, python-format
-msgid "Instance %s has been terminated."
-msgstr ""
-
-#: dash/views/instances.py:75
-msgid "Instance rebooting"
-msgstr ""
-
-#: dash/views/instances.py:77
-#, python-format
-msgid "ApiException while rebooting instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:80
-#, python-format
-msgid "Unable to reboot instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:83
-#, python-format
-msgid "Instance %s has been rebooted."
-msgstr ""
-
-#: dash/views/instances.py:105
-#, python-format
-msgid "Instance '%s' updated"
-msgstr ""
-
-#: dash/views/instances.py:109
-#, python-format
-msgid "Unable to update instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:124
-msgid "Exception in instance index"
-msgstr ""
-
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
-#, python-format
-msgid "Unable to get instance list: %s"
-msgstr ""
-
-#: dash/views/instances.py:178
-msgid "ApiException in instance usage"
-msgstr ""
-
-#: dash/views/instances.py:241
-msgid "ApiException while fetching instance console"
-msgstr ""
-
-#: dash/views/instances.py:243
-#, python-format
-msgid "Unable to get log for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:256
-msgid "ApiException while fetching instance vnc connection"
-msgstr ""
-
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:268 dash/views/instances.py:307
-msgid "ApiException while fetching instance info"
-msgstr ""
-
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:300
-msgid ""
-"ApiException while fetching instance vnc "
-"connection"
-msgstr ""
-
-#: dash/views/instances.py:303
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:309
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/keypairs.py:49
-#, python-format
-msgid "Successfully deleted keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:54
-#, python-format
-msgid "Error deleting keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
-msgid "Keypair Name"
-msgstr ""
-
-#: dash/views/keypairs.py:75
-#, python-format
-msgid "Error Creating Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:83
-msgid "Public Key"
-msgstr ""
-
-#: dash/views/keypairs.py:89
-#, python-format
-msgid "Successfully imported public key: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:95
-#, python-format
-msgid "Error Importing Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:111
-#, python-format
-msgid "Error fetching keypairs: %s"
-msgstr ""
-
-#: dash/views/networks.py:49
-msgid "Network Name"
-msgstr ""
-
-#: dash/views/networks.py:60
-#, python-format
-msgid "Unable to create network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:64
-#, python-format
-msgid "Network %s has been created."
-msgstr ""
-
-#: dash/views/networks.py:80
-#, python-format
-msgid "Unable to delete network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:83
-#, python-format
-msgid "Network %s has been deleted."
-msgstr ""
-
-#: dash/views/networks.py:102
-#, python-format
-msgid "Unable to rename network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:105
-#, python-format
-msgid "Network %(net)s has been renamed to %(new_name)s."
-msgstr ""
-
-#: dash/views/networks.py:138
-#, python-format
-msgid "Unable to get network list: %s"
-msgstr ""
-
-#: dash/views/networks.py:174
-#, python-format
-msgid "Unable to get network details: %s"
-msgstr ""
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, python-format
-msgid "Successfully deleted object: %s"
-msgstr ""
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-msgid "Object was successfully uploaded."
-msgstr ""
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
-msgid "Number of Ports"
-msgstr ""
-
-#: dash/views/ports.py:53
-#, python-format
-msgid "Unable to create ports on network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:56
-#, python-format
-msgid "%(num_ports)s ports created on network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:75
-#, python-format
-msgid "Unable to delete port %(port)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:78
-#, python-format
-msgid "Port %(port)s deleted from network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:89
-msgid "Select VIF to connect"
-msgstr ""
-
-#: dash/views/ports.py:100
-#, python-format
-msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:103
-#, python-format
-msgid "Port %(port)s connected to VIF %(vif)s."
-msgstr ""
-
-#: dash/views/ports.py:120
-#, python-format
-msgid "Unable to detach port %(port)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:123
-#, python-format
-msgid "Port %s detached."
-msgstr ""
-
-#: dash/views/ports.py:142
-#, python-format
-msgid "Unable to set port state to %(state)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:145
-#, python-format
-msgid "Port %(port)s state set to %(state)s."
-msgstr ""
-
-#: dash/views/security_groups.py:56
-#, python-format
-msgid "Successfully created security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:62
-#, python-format
-msgid "Error creating security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:76
-#, python-format
-msgid "Successfully deleted security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:80
-#, python-format
-msgid "Error deleting security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:109
-#, python-format
-msgid "Successfully added rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:113
-#, python-format
-msgid "Error adding rule security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:131
-#, python-format
-msgid "Successfully deleted rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:135
-#, python-format
-msgid "Error authorizing security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:153
-#, python-format
-msgid "Error fetching security_groups: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:181
-#, python-format
-msgid "Error getting security_group: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:51
-msgid "Snapshot Name"
-msgstr ""
-
-#: dash/views/snapshots.py:62
-#, python-format
-msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
-msgstr ""
-
-#: dash/views/snapshots.py:66
-#, python-format
-msgid "Error Creating Snapshot: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:104
-#, python-format
-msgid "Unable to retreive instance: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:111
-#, python-format
-msgid ""
-"To snapshot, instance state must be one of "
-"the following: %s"
-msgstr ""
-
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, python-format
-msgid "%s was successfully added to flavors."
-msgstr ""
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, python-format
-msgid "Unable to delete flavor: %s"
-msgstr ""
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, python-format
-msgid "Error updating image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-msgid "Image was successfully uploaded."
-msgstr ""
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, python-format
-msgid "Service '%s' has been enabled"
-msgstr ""
-
-#: syspanel/views/services.py:62
-#, python-format
-msgid "Service '%s' has been disabled"
-msgstr ""
-
-#: syspanel/views/services.py:68
-#, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr ""
-
-#: syspanel/views/tenants.py:57
-#, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:60
-#, python-format
-msgid "Unable to create user association: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:77
-#, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, python-format
-msgid "Unable to create tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, python-format
-msgid "%s was successfully created."
-msgstr ""
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, python-format
-msgid "%s was successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, python-format
-msgid "Unable to update tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr ""
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr ""
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:173
-#, python-format
-msgid "Unable to update quotas: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:183
-#, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:188
-#, python-format
-msgid "Error deleting tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:206
-#, python-format
-msgid "Unable to get tenant info: %s"
-msgstr ""
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, python-format
-msgid "%(user)s was successfully deleted."
-msgstr ""
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr ""
-
-#: syspanel/views/users.py:128
-#, python-format
-msgid "Unable to list users: %s"
-msgstr ""
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-msgid "Unable to update user, please try again."
-msgstr ""
-
-#: syspanel/views/users.py:194
-#, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr ""
-
-#: syspanel/views/users.py:212
-#, python-format
-msgid "User \"%s\" was successfully created."
-msgstr ""
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, python-format
-msgid "Error creating user: %s"
-msgstr ""
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
-msgid "Dashboard Settings"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:26
-msgid "Dashboard User Interface Language"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:38
-msgid "Select Language"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
-msgid "Delete"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_form.html:10
-msgid "Create Container"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
-msgid "Actions"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:17
-msgid "List Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
-msgid "Upload Object"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
-msgid "Create Tenant"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:22
-msgid ""
-"A container is a storage compartment for your data and provides a way for "
-"you to organize your data. You can think of a container as a folder in "
-"Windows® or a directory in UNIX®. The primary difference between a container "
-"and these other file system concepts is that containers cannot be nested. "
-"You can, however, create an unlimited number of containers within your "
-"account. Data must be stored in a container so you must have at least one "
-"container defined in your account prior to uploading data."
-msgstr ""
-
-#: templates/django_openstack/dash/containers/index.html:18
-msgid "Create New Container"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
-msgid "Allocate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
-msgid "Associate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
-msgid "Disassociate"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:14
-msgid "Instance ID:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:15
-msgid "Fixed IP:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:28
-msgid "Associate to instance"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_release.html:8
-msgid "Release"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:12
-msgid "Associate Floating IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
-msgid "Description:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:23
-msgid "Associate a floating ip with an instance."
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
-msgid "Info"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:22
-msgid "There are currently no floating ips assigned to your tenant."
-msgstr ""
-
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
-msgid "Update Image"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
-msgid "Launch Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
-msgid "Created"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
-msgid "Updated"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
-msgid "Status"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
-msgid "Edit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:24
-msgid "Launch"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:22
-msgid ""
-"Specify the details for launching an instance. Also please make note of the "
-"table below; all tenants have quotas which define the limit of resources you "
-"are allowed to provision."
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
-msgid "Quota Name"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
-msgid "Limit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:29
-msgid "RAM (MB)"
-msgstr ""
-
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
-msgid "From here you can modify different properties of an image."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
-msgid "Update Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:8
-msgid "Groups"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
-msgid "Image"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
-msgid "Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
-msgid "IPs"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
-msgid "State"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:66
-msgid "Log"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
-msgid "VNC Console"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:69
-msgid "Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:19
-msgid "Return to Instances List"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:24
-msgid "Update the name and description of your instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
-msgid "Download CSV"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:50
-msgid "Hide Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:52
-msgid "Show Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
-msgid "User"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
-msgid "Ram Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
-msgid "Disk Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
-msgid "Uptime"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:89
-msgid "No active instances."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:98
-#, python-format
-msgid ""
-"There are currently no instances.<br/><br/>You can launch an instance from "
-"the <a href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_form.html:10
-msgid "Add Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_list.html:5
-msgid "Fingerprint"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
-msgid "Create Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:30
-msgid "Your private key is being downloaded."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
-msgid "Return to keypairs list"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
-msgid ""
-"Keypairs are ssh credentials which are injected into images when they are "
-"launched. Creating a new key pair registers the public key and downloads the "
-"private key (a .pem file)."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
-msgid "Protect and use the key as you would any normal ssh private key."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
-msgid "Add New Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
-msgid "Import Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:24
-msgid "There are currently no keypairs."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detach_port.html:9
-msgid "Detach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:6
-msgid "Attachment"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:8
-msgid "Extensions"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:20
-msgid "VIF Id"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:36
-msgid "Attach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
-msgid "Create Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:6
-msgid "Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:7
-msgid "Available"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:8
-msgid "Used"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:9
-msgid "Action"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
-msgid "Rename"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
-msgid "Rename Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
-msgid "Port UP"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
-msgid "Port DOWN"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
-msgid "Return to networks list"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:24
-msgid "Networks provide layer 2 connectivity to your instances."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "Create Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "There are currently no ports in this network."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:20
-msgid "Create New Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "There are currently no networks."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "Create A Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/rename.html:32
-msgid "Enter a new name for your network."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
-msgid "Copy Object"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_filter.html:7
-msgid "Filter"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:16
-msgid "Copy"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:18
-msgid "Download"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
-msgid "Return to objects list"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:26
-msgid ""
-"You may make a new copy of an existing object to store in this or another "
-"container."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:31
-#, python-format
-msgid ""
-"There are currently no objects in the container %(container_name)s. You can "
-"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
-"Page &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:34
-msgid "Upload New Object &gt;&gt;"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:11
-msgid "Upload Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:25
-msgid ""
-"An object is the basic storage entity and any optional metadata that "
-"represents the files you store in the OpenStack Object Storage system. When "
-"you upload data to OpenStack Object Storage, the data is stored as-is (no "
-"compression or encryption) and consists of a location (container), the "
-"object's name, and any metadata consisting of key/value pairs."
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:12
-msgid "Attach Port"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
-msgid "Return to network detail"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:42
-msgid ""
-"<p>Select an interface from the list on the left to attach it to this port.</"
-"p>\n"
-" <p>Only interfaces that are not connected to any existing port are "
-"shown</p>\n"
-" <p>If you want to reconnect a connected interface, please detach it "
-"first</p>"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/create.html:24
-msgid ""
-"You can plug virtual interfaces from your instances to ports created in the "
-"network"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
-msgid "Create Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_list.html:14
-msgid "Edit Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/create.html:22
-msgid "From here you can create a new security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
-msgid "Edit Security Group Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
-msgid "Rules for Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
-msgid "IP Protocol"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
-msgid "From Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
-msgid "To Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
-msgid "CIDR"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
-msgid "No rules for this security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
-msgid "Add a rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
-msgid "Add Rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/index.html:25
-#, python-format
-msgid ""
-"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
-"Security Group &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/_form.html:11
-msgid "Create Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:19
-msgid "Create a Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:25
-msgid "Choose a name for your snapshot."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:27
-msgid "Return to snapshots list"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:32
-msgid "Snapshots preserve the disk state of a running instance."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/index.html:23
-#, python-format
-msgid ""
-"There are currently no snapshots. You can create snapshots from running "
-"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:5
-msgid "System Panel"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
-msgid "Create Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
-msgid "Id"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:7
-msgid "Memory"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
-msgid "Disk"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/create.html:37
-msgid "From here you can define the sizing of a new flavor."
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/index.html:18
-msgid "Create New Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:9
-msgid "Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:35
-msgid "Location"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:40
-msgid "Project ID"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_toggle.html:8
-msgid "Toggle Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
-msgid "Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:8
-msgid "Host"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:48
-msgid "Console Log"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_image_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
-msgid "System Panel Overview"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
-msgid "Active Instances"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
-msgid "This month's VCPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
-msgid "This month's GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
-msgid "Tenant Usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:23
-msgid "Monitoring"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:34
-msgid "Select a month to query its usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:71
-msgid "Server Usage Summary"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:80
-msgid "RAM"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:81
-msgid "VCPU CPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:82
-msgid "Disk GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/quotas/index.html:13
-msgid "Default Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:5
-msgid "Service"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:6
-msgid "System Stats"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:8
-msgid "Up"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:22
-msgid "Hypervisor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:25
-msgid "Allocable Cores"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:30
-msgid "Allocable Storage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:35
-msgid "System Ram"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
-msgid "Enable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
-msgid "Disable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
-msgid "Add"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
-msgid "Options"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:20
-msgid "View Members"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:21
-msgid "Modify Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
-msgid "Remove"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
-msgid "Update Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
-msgid "Update Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/create.html:22
-msgid "From here you can create a new tenant (aka project) to organize users."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/index.html:18
-msgid "Create New Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
-msgid "Update Tenant Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/update.html:22
-msgid "From here you can edit a tenant."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:12
-msgid "Users for Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:45
-msgid "here are currently no users for this tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:49
-msgid "Add new users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
-msgid "Create User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
-msgid "Update User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/create.html:23
-msgid ""
-"From here you can create a new user and assign them to a tenant (aka "
-"project)."
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:23
-msgid "Default Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:42
-msgid "Create New User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/update.html:23
-msgid ""
-"From here you can edit users by changing their usernames, emails, passwords, "
-"and tenants."
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:46
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:50
-#, python-format
-msgid "%(size)d"
-msgid_plural "%(size)d"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:53
-#, python-format
-msgid "%s KB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:56
-#, python-format
-msgid "%s MB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:59
-#, python-format
-msgid "%s GB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:62
-#, python-format
-msgid "%s TB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:64
-#, python-format
-msgid "%s PB"
-msgstr ""
diff --git a/django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.po b/django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.po
deleted file mode 100644
index 21c8f5b2..00000000
--- a/django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,1947 +0,0 @@
-# Translations of Dashboard for OpenStack User Interface.
-# Copyright 2011 Midokura KK
-# This file is distributed under the same license as the Dashboard for OpenStack.
-# FIRST AUTHOR Jeffrey Wilcox, 2011.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: openstack-dashboard\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: api.py:1002 syspanel/views/services.py:88
-#, python-format
-msgid "Unable to get service info: %s"
-msgstr ""
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, python-format
-msgid "Unable to get usage info: %s"
-msgstr ""
-
-#: context_processors.py:34
-#, python-format
-msgid ""
-"Unable to retrieve tenant list from "
-"keystone: %s"
-msgstr ""
-
-#: forms.py:180
-#, python-format
-msgid "Unexpected error: %s"
-msgstr ""
-
-#: auth/views.py:38
-msgid "User Name"
-msgstr ""
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
-msgstr ""
-
-#: auth/views.py:105
-#, python-format
-msgid "Error authenticating: %s"
-msgstr ""
-
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
-msgstr ""
-
-#: dash/views/containers.py:49
-#, python-format
-msgid "Unable to delete non-empty container: %s"
-msgstr ""
-
-#: dash/views/containers.py:55
-#, python-format
-msgid "Successfully deleted container: %s"
-msgstr ""
-
-#: dash/views/containers.py:61
-msgid "Container Name"
-msgstr ""
-
-#: dash/views/containers.py:65
-msgid "Container was successfully created."
-msgstr ""
-
-#: dash/views/floating_ips.py:47
-#, python-format
-msgid "Successfully released Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:51
-#, python-format
-msgid "Error releasing Floating IP from tenant: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
-msgid "Instance"
-msgstr ""
-
-#: dash/views/floating_ips.py:76
-#, python-format
-msgid ""
-"Successfully associated Floating IP: "
-"%(ip)s with Instance: %(inst)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:82
-#, python-format
-msgid "Error associating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:99
-#, python-format
-msgid "Successfully disassociated Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:103
-#, python-format
-msgid "Error disassociating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:118
-#, python-format
-msgid ""
-"Successfully allocated Floating IP \"%(ip)s\" "
-"to tenant \"%(tenant)s\""
-msgstr ""
-
-#: dash/views/floating_ips.py:124
-#, python-format
-msgid ""
-"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
-"\": %(msg)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:142
-#, python-format
-msgid "Error fetching floating ips: %s"
-msgstr ""
-
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
-msgid "Name"
-msgstr ""
-
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
-msgid "Kernel ID"
-msgstr ""
-
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
-msgid "Ramdisk ID"
-msgstr ""
-
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
-msgid "Architecture"
-msgstr ""
-
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
-msgid "Container Format"
-msgstr ""
-
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
-msgid "Disk Format"
-msgstr ""
-
-#: dash/views/images.py:59 dash/views/images.py:233
-#, python-format
-msgid "Unable to retreive image info from glance: %s"
-msgstr ""
-
-#: dash/views/images.py:61
-#, python-format
-msgid "Error updating image with id: %s"
-msgstr ""
-
-#: dash/views/images.py:66 dash/views/images.py:95
-msgid "Error connecting to glance"
-msgstr ""
-
-#: dash/views/images.py:92 syspanel/views/images.py:159
-msgid "Image was successfully updated."
-msgstr ""
-
-#: dash/views/images.py:101
-msgid "Unspecified Exception in image update"
-msgstr ""
-
-#: dash/views/images.py:105
-msgid ""
-"Unable to update image. You are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:111
-msgid "Server Name"
-msgstr ""
-
-#: dash/views/images.py:115
-msgid "User Data"
-msgstr ""
-
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
-msgid "Flavor"
-msgstr ""
-
-#: dash/views/images.py:130
-msgid "Key Name"
-msgstr ""
-
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
-msgid "Security Groups"
-msgstr ""
-
-#: dash/views/images.py:169
-msgid "Instance was successfully launched"
-msgstr ""
-
-#: dash/views/images.py:178
-#, python-format
-msgid "Unable to launch instance: %s"
-msgstr ""
-
-#: dash/views/images.py:192
-msgid ""
-"Unable to delete image, you are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
-#, python-format
-msgid "Error connecting to glance: %s"
-msgstr ""
-
-#: dash/views/images.py:202
-msgid "Error deleting image: %(image)s: %i(msg)s"
-msgstr ""
-
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
-msgid "There are currently no images."
-msgstr ""
-
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
-#, python-format
-msgid "Error retrieving image list: %s"
-msgstr ""
-
-#: dash/views/images.py:290
-#, python-format
-msgid "Error parsing quota for %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/images.py:323 syspanel/views/images.py:134
-#, python-format
-msgid "Error retrieving image %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:55
-#, python-format
-msgid "ApiException while terminating instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:58
-#, python-format
-msgid "Unable to terminate %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:61
-#, python-format
-msgid "Instance %s has been terminated."
-msgstr ""
-
-#: dash/views/instances.py:75
-msgid "Instance rebooting"
-msgstr ""
-
-#: dash/views/instances.py:77
-#, python-format
-msgid "ApiException while rebooting instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:80
-#, python-format
-msgid "Unable to reboot instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:83
-#, python-format
-msgid "Instance %s has been rebooted."
-msgstr ""
-
-#: dash/views/instances.py:105
-#, python-format
-msgid "Instance '%s' updated"
-msgstr ""
-
-#: dash/views/instances.py:109
-#, python-format
-msgid "Unable to update instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:124
-msgid "Exception in instance index"
-msgstr ""
-
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
-#, python-format
-msgid "Unable to get instance list: %s"
-msgstr ""
-
-#: dash/views/instances.py:178
-msgid "ApiException in instance usage"
-msgstr ""
-
-#: dash/views/instances.py:241
-msgid "ApiException while fetching instance console"
-msgstr ""
-
-#: dash/views/instances.py:243
-#, python-format
-msgid "Unable to get log for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:256
-msgid "ApiException while fetching instance vnc connection"
-msgstr ""
-
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:268 dash/views/instances.py:307
-msgid "ApiException while fetching instance info"
-msgstr ""
-
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:300
-msgid ""
-"ApiException while fetching instance vnc "
-"connection"
-msgstr ""
-
-#: dash/views/instances.py:303
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:309
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/keypairs.py:49
-#, python-format
-msgid "Successfully deleted keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:54
-#, python-format
-msgid "Error deleting keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
-msgid "Keypair Name"
-msgstr ""
-
-#: dash/views/keypairs.py:75
-#, python-format
-msgid "Error Creating Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:83
-msgid "Public Key"
-msgstr ""
-
-#: dash/views/keypairs.py:89
-#, python-format
-msgid "Successfully imported public key: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:95
-#, python-format
-msgid "Error Importing Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:111
-#, python-format
-msgid "Error fetching keypairs: %s"
-msgstr ""
-
-#: dash/views/networks.py:49
-msgid "Network Name"
-msgstr ""
-
-#: dash/views/networks.py:60
-#, python-format
-msgid "Unable to create network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:64
-#, python-format
-msgid "Network %s has been created."
-msgstr ""
-
-#: dash/views/networks.py:80
-#, python-format
-msgid "Unable to delete network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:83
-#, python-format
-msgid "Network %s has been deleted."
-msgstr ""
-
-#: dash/views/networks.py:102
-#, python-format
-msgid "Unable to rename network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:105
-#, python-format
-msgid "Network %(net)s has been renamed to %(new_name)s."
-msgstr ""
-
-#: dash/views/networks.py:138
-#, python-format
-msgid "Unable to get network list: %s"
-msgstr ""
-
-#: dash/views/networks.py:174
-#, python-format
-msgid "Unable to get network details: %s"
-msgstr ""
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, python-format
-msgid "Successfully deleted object: %s"
-msgstr ""
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-msgid "Object was successfully uploaded."
-msgstr ""
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
-msgid "Number of Ports"
-msgstr ""
-
-#: dash/views/ports.py:53
-#, python-format
-msgid "Unable to create ports on network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:56
-#, python-format
-msgid "%(num_ports)s ports created on network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:75
-#, python-format
-msgid "Unable to delete port %(port)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:78
-#, python-format
-msgid "Port %(port)s deleted from network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:89
-msgid "Select VIF to connect"
-msgstr ""
-
-#: dash/views/ports.py:100
-#, python-format
-msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:103
-#, python-format
-msgid "Port %(port)s connected to VIF %(vif)s."
-msgstr ""
-
-#: dash/views/ports.py:120
-#, python-format
-msgid "Unable to detach port %(port)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:123
-#, python-format
-msgid "Port %s detached."
-msgstr ""
-
-#: dash/views/ports.py:142
-#, python-format
-msgid "Unable to set port state to %(state)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:145
-#, python-format
-msgid "Port %(port)s state set to %(state)s."
-msgstr ""
-
-#: dash/views/security_groups.py:56
-#, python-format
-msgid "Successfully created security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:62
-#, python-format
-msgid "Error creating security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:76
-#, python-format
-msgid "Successfully deleted security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:80
-#, python-format
-msgid "Error deleting security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:109
-#, python-format
-msgid "Successfully added rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:113
-#, python-format
-msgid "Error adding rule security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:131
-#, python-format
-msgid "Successfully deleted rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:135
-#, python-format
-msgid "Error authorizing security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:153
-#, python-format
-msgid "Error fetching security_groups: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:181
-#, python-format
-msgid "Error getting security_group: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:51
-msgid "Snapshot Name"
-msgstr ""
-
-#: dash/views/snapshots.py:62
-#, python-format
-msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
-msgstr ""
-
-#: dash/views/snapshots.py:66
-#, python-format
-msgid "Error Creating Snapshot: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:104
-#, python-format
-msgid "Unable to retreive instance: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:111
-#, python-format
-msgid ""
-"To snapshot, instance state must be one of "
-"the following: %s"
-msgstr ""
-
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, python-format
-msgid "%s was successfully added to flavors."
-msgstr ""
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, python-format
-msgid "Unable to delete flavor: %s"
-msgstr ""
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, python-format
-msgid "Error updating image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-msgid "Image was successfully uploaded."
-msgstr ""
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, python-format
-msgid "Service '%s' has been enabled"
-msgstr ""
-
-#: syspanel/views/services.py:62
-#, python-format
-msgid "Service '%s' has been disabled"
-msgstr ""
-
-#: syspanel/views/services.py:68
-#, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr ""
-
-#: syspanel/views/tenants.py:57
-#, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:60
-#, python-format
-msgid "Unable to create user association: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:77
-#, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, python-format
-msgid "Unable to create tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, python-format
-msgid "%s was successfully created."
-msgstr ""
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, python-format
-msgid "%s was successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, python-format
-msgid "Unable to update tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr ""
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr ""
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:173
-#, python-format
-msgid "Unable to update quotas: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:183
-#, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:188
-#, python-format
-msgid "Error deleting tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:206
-#, python-format
-msgid "Unable to get tenant info: %s"
-msgstr ""
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, python-format
-msgid "%(user)s was successfully deleted."
-msgstr ""
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr ""
-
-#: syspanel/views/users.py:128
-#, python-format
-msgid "Unable to list users: %s"
-msgstr ""
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-msgid "Unable to update user, please try again."
-msgstr ""
-
-#: syspanel/views/users.py:194
-#, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr ""
-
-#: syspanel/views/users.py:212
-#, python-format
-msgid "User \"%s\" was successfully created."
-msgstr ""
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, python-format
-msgid "Error creating user: %s"
-msgstr ""
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
-msgid "Dashboard Settings"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:26
-msgid "Dashboard User Interface Language"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:38
-msgid "Select Language"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
-msgid "Delete"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_form.html:10
-msgid "Create Container"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
-msgid "Actions"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:17
-msgid "List Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
-msgid "Upload Object"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
-msgid "Create Tenant"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:22
-msgid ""
-"A container is a storage compartment for your data and provides a way for "
-"you to organize your data. You can think of a container as a folder in "
-"Windows® or a directory in UNIX®. The primary difference between a container "
-"and these other file system concepts is that containers cannot be nested. "
-"You can, however, create an unlimited number of containers within your "
-"account. Data must be stored in a container so you must have at least one "
-"container defined in your account prior to uploading data."
-msgstr ""
-
-#: templates/django_openstack/dash/containers/index.html:18
-msgid "Create New Container"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
-msgid "Allocate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
-msgid "Associate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
-msgid "Disassociate"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:14
-msgid "Instance ID:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:15
-msgid "Fixed IP:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:28
-msgid "Associate to instance"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_release.html:8
-msgid "Release"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:12
-msgid "Associate Floating IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
-msgid "Description:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:23
-msgid "Associate a floating ip with an instance."
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
-msgid "Info"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:22
-msgid "There are currently no floating ips assigned to your tenant."
-msgstr ""
-
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
-msgid "Update Image"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
-msgid "Launch Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
-msgid "Created"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
-msgid "Updated"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
-msgid "Status"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
-msgid "Edit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:24
-msgid "Launch"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:22
-msgid ""
-"Specify the details for launching an instance. Also please make note of the "
-"table below; all tenants have quotas which define the limit of resources you "
-"are allowed to provision."
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
-msgid "Quota Name"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
-msgid "Limit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:29
-msgid "RAM (MB)"
-msgstr ""
-
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
-msgid "From here you can modify different properties of an image."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
-msgid "Update Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:8
-msgid "Groups"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
-msgid "Image"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
-msgid "Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
-msgid "IPs"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
-msgid "State"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:66
-msgid "Log"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
-msgid "VNC Console"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:69
-msgid "Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:19
-msgid "Return to Instances List"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:24
-msgid "Update the name and description of your instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
-msgid "Download CSV"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:50
-msgid "Hide Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:52
-msgid "Show Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
-msgid "User"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
-msgid "Ram Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
-msgid "Disk Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
-msgid "Uptime"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:89
-msgid "No active instances."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:98
-#, python-format
-msgid ""
-"There are currently no instances.<br/><br/>You can launch an instance from "
-"the <a href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_form.html:10
-msgid "Add Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_list.html:5
-msgid "Fingerprint"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
-msgid "Create Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:30
-msgid "Your private key is being downloaded."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
-msgid "Return to keypairs list"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
-msgid ""
-"Keypairs are ssh credentials which are injected into images when they are "
-"launched. Creating a new key pair registers the public key and downloads the "
-"private key (a .pem file)."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
-msgid "Protect and use the key as you would any normal ssh private key."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
-msgid "Add New Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
-msgid "Import Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:24
-msgid "There are currently no keypairs."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detach_port.html:9
-msgid "Detach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:6
-msgid "Attachment"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:8
-msgid "Extensions"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:20
-msgid "VIF Id"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:36
-msgid "Attach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
-msgid "Create Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:6
-msgid "Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:7
-msgid "Available"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:8
-msgid "Used"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:9
-msgid "Action"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
-msgid "Rename"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
-msgid "Rename Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
-msgid "Port UP"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
-msgid "Port DOWN"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
-msgid "Return to networks list"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:24
-msgid "Networks provide layer 2 connectivity to your instances."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "Create Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "There are currently no ports in this network."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:20
-msgid "Create New Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "There are currently no networks."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "Create A Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/rename.html:32
-msgid "Enter a new name for your network."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
-msgid "Copy Object"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_filter.html:7
-msgid "Filter"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:16
-msgid "Copy"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:18
-msgid "Download"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
-msgid "Return to objects list"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:26
-msgid ""
-"You may make a new copy of an existing object to store in this or another "
-"container."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:31
-#, python-format
-msgid ""
-"There are currently no objects in the container %(container_name)s. You can "
-"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
-"Page &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:34
-msgid "Upload New Object &gt;&gt;"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:11
-msgid "Upload Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:25
-msgid ""
-"An object is the basic storage entity and any optional metadata that "
-"represents the files you store in the OpenStack Object Storage system. When "
-"you upload data to OpenStack Object Storage, the data is stored as-is (no "
-"compression or encryption) and consists of a location (container), the "
-"object's name, and any metadata consisting of key/value pairs."
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:12
-msgid "Attach Port"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
-msgid "Return to network detail"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:42
-msgid ""
-"<p>Select an interface from the list on the left to attach it to this port.</"
-"p>\n"
-" <p>Only interfaces that are not connected to any existing port are "
-"shown</p>\n"
-" <p>If you want to reconnect a connected interface, please detach it "
-"first</p>"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/create.html:24
-msgid ""
-"You can plug virtual interfaces from your instances to ports created in the "
-"network"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
-msgid "Create Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_list.html:14
-msgid "Edit Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/create.html:22
-msgid "From here you can create a new security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
-msgid "Edit Security Group Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
-msgid "Rules for Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
-msgid "IP Protocol"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
-msgid "From Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
-msgid "To Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
-msgid "CIDR"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
-msgid "No rules for this security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
-msgid "Add a rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
-msgid "Add Rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/index.html:25
-#, python-format
-msgid ""
-"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
-"Security Group &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/_form.html:11
-msgid "Create Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:19
-msgid "Create a Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:25
-msgid "Choose a name for your snapshot."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:27
-msgid "Return to snapshots list"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:32
-msgid "Snapshots preserve the disk state of a running instance."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/index.html:23
-#, python-format
-msgid ""
-"There are currently no snapshots. You can create snapshots from running "
-"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:5
-msgid "System Panel"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
-msgid "Create Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
-msgid "Id"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:7
-msgid "Memory"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
-msgid "Disk"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/create.html:37
-msgid "From here you can define the sizing of a new flavor."
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/index.html:18
-msgid "Create New Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:9
-msgid "Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:35
-msgid "Location"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:40
-msgid "Project ID"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_toggle.html:8
-msgid "Toggle Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
-msgid "Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:8
-msgid "Host"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:48
-msgid "Console Log"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_image_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
-msgid "System Panel Overview"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
-msgid "Active Instances"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
-msgid "This month's VCPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
-msgid "This month's GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
-msgid "Tenant Usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:23
-msgid "Monitoring"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:34
-msgid "Select a month to query its usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:71
-msgid "Server Usage Summary"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:80
-msgid "RAM"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:81
-msgid "VCPU CPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:82
-msgid "Disk GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/quotas/index.html:13
-msgid "Default Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:5
-msgid "Service"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:6
-msgid "System Stats"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:8
-msgid "Up"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:22
-msgid "Hypervisor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:25
-msgid "Allocable Cores"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:30
-msgid "Allocable Storage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:35
-msgid "System Ram"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
-msgid "Enable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
-msgid "Disable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
-msgid "Add"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
-msgid "Options"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:20
-msgid "View Members"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:21
-msgid "Modify Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
-msgid "Remove"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
-msgid "Update Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
-msgid "Update Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/create.html:22
-msgid "From here you can create a new tenant (aka project) to organize users."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/index.html:18
-msgid "Create New Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
-msgid "Update Tenant Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/update.html:22
-msgid "From here you can edit a tenant."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:12
-msgid "Users for Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:45
-msgid "here are currently no users for this tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:49
-msgid "Add new users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
-msgid "Create User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
-msgid "Update User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/create.html:23
-msgid ""
-"From here you can create a new user and assign them to a tenant (aka "
-"project)."
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:23
-msgid "Default Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:42
-msgid "Create New User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/update.html:23
-msgid ""
-"From here you can edit users by changing their usernames, emails, passwords, "
-"and tenants."
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:46
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:50
-#, python-format
-msgid "%(size)d"
-msgid_plural "%(size)d"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:53
-#, python-format
-msgid "%s KB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:56
-#, python-format
-msgid "%s MB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:59
-#, python-format
-msgid "%s GB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:62
-#, python-format
-msgid "%s TB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:64
-#, python-format
-msgid "%s PB"
-msgstr ""
diff --git a/django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.po b/django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.po
deleted file mode 100644
index 21c8f5b2..00000000
--- a/django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,1947 +0,0 @@
-# Translations of Dashboard for OpenStack User Interface.
-# Copyright 2011 Midokura KK
-# This file is distributed under the same license as the Dashboard for OpenStack.
-# FIRST AUTHOR Jeffrey Wilcox, 2011.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: openstack-dashboard\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: api.py:1002 syspanel/views/services.py:88
-#, python-format
-msgid "Unable to get service info: %s"
-msgstr ""
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, python-format
-msgid "Unable to get usage info: %s"
-msgstr ""
-
-#: context_processors.py:34
-#, python-format
-msgid ""
-"Unable to retrieve tenant list from "
-"keystone: %s"
-msgstr ""
-
-#: forms.py:180
-#, python-format
-msgid "Unexpected error: %s"
-msgstr ""
-
-#: auth/views.py:38
-msgid "User Name"
-msgstr ""
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
-msgstr ""
-
-#: auth/views.py:105
-#, python-format
-msgid "Error authenticating: %s"
-msgstr ""
-
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
-msgstr ""
-
-#: dash/views/containers.py:49
-#, python-format
-msgid "Unable to delete non-empty container: %s"
-msgstr ""
-
-#: dash/views/containers.py:55
-#, python-format
-msgid "Successfully deleted container: %s"
-msgstr ""
-
-#: dash/views/containers.py:61
-msgid "Container Name"
-msgstr ""
-
-#: dash/views/containers.py:65
-msgid "Container was successfully created."
-msgstr ""
-
-#: dash/views/floating_ips.py:47
-#, python-format
-msgid "Successfully released Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:51
-#, python-format
-msgid "Error releasing Floating IP from tenant: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
-msgid "Instance"
-msgstr ""
-
-#: dash/views/floating_ips.py:76
-#, python-format
-msgid ""
-"Successfully associated Floating IP: "
-"%(ip)s with Instance: %(inst)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:82
-#, python-format
-msgid "Error associating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:99
-#, python-format
-msgid "Successfully disassociated Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:103
-#, python-format
-msgid "Error disassociating Floating IP: %s"
-msgstr ""
-
-#: dash/views/floating_ips.py:118
-#, python-format
-msgid ""
-"Successfully allocated Floating IP \"%(ip)s\" "
-"to tenant \"%(tenant)s\""
-msgstr ""
-
-#: dash/views/floating_ips.py:124
-#, python-format
-msgid ""
-"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
-"\": %(msg)s"
-msgstr ""
-
-#: dash/views/floating_ips.py:142
-#, python-format
-msgid "Error fetching floating ips: %s"
-msgstr ""
-
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
-msgid "Name"
-msgstr ""
-
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
-msgid "Kernel ID"
-msgstr ""
-
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
-msgid "Ramdisk ID"
-msgstr ""
-
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
-msgid "Architecture"
-msgstr ""
-
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
-msgid "Container Format"
-msgstr ""
-
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
-msgid "Disk Format"
-msgstr ""
-
-#: dash/views/images.py:59 dash/views/images.py:233
-#, python-format
-msgid "Unable to retreive image info from glance: %s"
-msgstr ""
-
-#: dash/views/images.py:61
-#, python-format
-msgid "Error updating image with id: %s"
-msgstr ""
-
-#: dash/views/images.py:66 dash/views/images.py:95
-msgid "Error connecting to glance"
-msgstr ""
-
-#: dash/views/images.py:92 syspanel/views/images.py:159
-msgid "Image was successfully updated."
-msgstr ""
-
-#: dash/views/images.py:101
-msgid "Unspecified Exception in image update"
-msgstr ""
-
-#: dash/views/images.py:105
-msgid ""
-"Unable to update image. You are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:111
-msgid "Server Name"
-msgstr ""
-
-#: dash/views/images.py:115
-msgid "User Data"
-msgstr ""
-
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
-msgid "Flavor"
-msgstr ""
-
-#: dash/views/images.py:130
-msgid "Key Name"
-msgstr ""
-
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
-msgid "Security Groups"
-msgstr ""
-
-#: dash/views/images.py:169
-msgid "Instance was successfully launched"
-msgstr ""
-
-#: dash/views/images.py:178
-#, python-format
-msgid "Unable to launch instance: %s"
-msgstr ""
-
-#: dash/views/images.py:192
-msgid ""
-"Unable to delete image, you are not "
-"its owner."
-msgstr ""
-
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
-#, python-format
-msgid "Error connecting to glance: %s"
-msgstr ""
-
-#: dash/views/images.py:202
-msgid "Error deleting image: %(image)s: %i(msg)s"
-msgstr ""
-
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
-msgid "There are currently no images."
-msgstr ""
-
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
-#, python-format
-msgid "Error retrieving image list: %s"
-msgstr ""
-
-#: dash/views/images.py:290
-#, python-format
-msgid "Error parsing quota for %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/images.py:323 syspanel/views/images.py:134
-#, python-format
-msgid "Error retrieving image %(image)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:55
-#, python-format
-msgid "ApiException while terminating instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:58
-#, python-format
-msgid "Unable to terminate %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:61
-#, python-format
-msgid "Instance %s has been terminated."
-msgstr ""
-
-#: dash/views/instances.py:75
-msgid "Instance rebooting"
-msgstr ""
-
-#: dash/views/instances.py:77
-#, python-format
-msgid "ApiException while rebooting instance \"%s\""
-msgstr ""
-
-#: dash/views/instances.py:80
-#, python-format
-msgid "Unable to reboot instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:83
-#, python-format
-msgid "Instance %s has been rebooted."
-msgstr ""
-
-#: dash/views/instances.py:105
-#, python-format
-msgid "Instance '%s' updated"
-msgstr ""
-
-#: dash/views/instances.py:109
-#, python-format
-msgid "Unable to update instance: %s"
-msgstr ""
-
-#: dash/views/instances.py:124
-msgid "Exception in instance index"
-msgstr ""
-
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
-#, python-format
-msgid "Unable to get instance list: %s"
-msgstr ""
-
-#: dash/views/instances.py:178
-msgid "ApiException in instance usage"
-msgstr ""
-
-#: dash/views/instances.py:241
-msgid "ApiException while fetching instance console"
-msgstr ""
-
-#: dash/views/instances.py:243
-#, python-format
-msgid "Unable to get log for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:256
-msgid "ApiException while fetching instance vnc connection"
-msgstr ""
-
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:268 dash/views/instances.py:307
-msgid "ApiException while fetching instance info"
-msgstr ""
-
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(message)s"
-msgstr ""
-
-#: dash/views/instances.py:300
-msgid ""
-"ApiException while fetching instance vnc "
-"connection"
-msgstr ""
-
-#: dash/views/instances.py:303
-#, python-format
-msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/instances.py:309
-#, python-format
-msgid "Unable to get information for instance %(inst)s: %(msg)s"
-msgstr ""
-
-#: dash/views/keypairs.py:49
-#, python-format
-msgid "Successfully deleted keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:54
-#, python-format
-msgid "Error deleting keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
-msgid "Keypair Name"
-msgstr ""
-
-#: dash/views/keypairs.py:75
-#, python-format
-msgid "Error Creating Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:83
-msgid "Public Key"
-msgstr ""
-
-#: dash/views/keypairs.py:89
-#, python-format
-msgid "Successfully imported public key: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:95
-#, python-format
-msgid "Error Importing Keypair: %s"
-msgstr ""
-
-#: dash/views/keypairs.py:111
-#, python-format
-msgid "Error fetching keypairs: %s"
-msgstr ""
-
-#: dash/views/networks.py:49
-msgid "Network Name"
-msgstr ""
-
-#: dash/views/networks.py:60
-#, python-format
-msgid "Unable to create network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:64
-#, python-format
-msgid "Network %s has been created."
-msgstr ""
-
-#: dash/views/networks.py:80
-#, python-format
-msgid "Unable to delete network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:83
-#, python-format
-msgid "Network %s has been deleted."
-msgstr ""
-
-#: dash/views/networks.py:102
-#, python-format
-msgid "Unable to rename network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/networks.py:105
-#, python-format
-msgid "Network %(net)s has been renamed to %(new_name)s."
-msgstr ""
-
-#: dash/views/networks.py:138
-#, python-format
-msgid "Unable to get network list: %s"
-msgstr ""
-
-#: dash/views/networks.py:174
-#, python-format
-msgid "Unable to get network details: %s"
-msgstr ""
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, python-format
-msgid "Successfully deleted object: %s"
-msgstr ""
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-msgid "Object was successfully uploaded."
-msgstr ""
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
-msgid "Number of Ports"
-msgstr ""
-
-#: dash/views/ports.py:53
-#, python-format
-msgid "Unable to create ports on network %(network)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:56
-#, python-format
-msgid "%(num_ports)s ports created on network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:75
-#, python-format
-msgid "Unable to delete port %(port)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:78
-#, python-format
-msgid "Port %(port)s deleted from network %(network)s."
-msgstr ""
-
-#: dash/views/ports.py:89
-msgid "Select VIF to connect"
-msgstr ""
-
-#: dash/views/ports.py:100
-#, python-format
-msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
-msgstr ""
-
-#: dash/views/ports.py:103
-#, python-format
-msgid "Port %(port)s connected to VIF %(vif)s."
-msgstr ""
-
-#: dash/views/ports.py:120
-#, python-format
-msgid "Unable to detach port %(port)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:123
-#, python-format
-msgid "Port %s detached."
-msgstr ""
-
-#: dash/views/ports.py:142
-#, python-format
-msgid "Unable to set port state to %(state)s: %(message)s"
-msgstr ""
-
-#: dash/views/ports.py:145
-#, python-format
-msgid "Port %(port)s state set to %(state)s."
-msgstr ""
-
-#: dash/views/security_groups.py:56
-#, python-format
-msgid "Successfully created security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:62
-#, python-format
-msgid "Error creating security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:76
-#, python-format
-msgid "Successfully deleted security_group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:80
-#, python-format
-msgid "Error deleting security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:109
-#, python-format
-msgid "Successfully added rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:113
-#, python-format
-msgid "Error adding rule security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:131
-#, python-format
-msgid "Successfully deleted rule: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:135
-#, python-format
-msgid "Error authorizing security group: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:153
-#, python-format
-msgid "Error fetching security_groups: %s"
-msgstr ""
-
-#: dash/views/security_groups.py:181
-#, python-format
-msgid "Error getting security_group: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:51
-msgid "Snapshot Name"
-msgstr ""
-
-#: dash/views/snapshots.py:62
-#, python-format
-msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
-msgstr ""
-
-#: dash/views/snapshots.py:66
-#, python-format
-msgid "Error Creating Snapshot: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:104
-#, python-format
-msgid "Unable to retreive instance: %s"
-msgstr ""
-
-#: dash/views/snapshots.py:111
-#, python-format
-msgid ""
-"To snapshot, instance state must be one of "
-"the following: %s"
-msgstr ""
-
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, python-format
-msgid "%s was successfully added to flavors."
-msgstr ""
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, python-format
-msgid "Unable to delete flavor: %s"
-msgstr ""
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, python-format
-msgid "Error updating image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-msgid "Image was successfully uploaded."
-msgstr ""
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, python-format
-msgid "Service '%s' has been enabled"
-msgstr ""
-
-#: syspanel/views/services.py:62
-#, python-format
-msgid "Service '%s' has been disabled"
-msgstr ""
-
-#: syspanel/views/services.py:68
-#, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr ""
-
-#: syspanel/views/tenants.py:57
-#, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:60
-#, python-format
-msgid "Unable to create user association: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:77
-#, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, python-format
-msgid "Unable to create tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, python-format
-msgid "%s was successfully created."
-msgstr ""
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, python-format
-msgid "%s was successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, python-format
-msgid "Unable to update tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr ""
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr ""
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr ""
-
-#: syspanel/views/tenants.py:173
-#, python-format
-msgid "Unable to update quotas: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:183
-#, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr ""
-
-#: syspanel/views/tenants.py:188
-#, python-format
-msgid "Error deleting tenant: %s"
-msgstr ""
-
-#: syspanel/views/tenants.py:206
-#, python-format
-msgid "Unable to get tenant info: %s"
-msgstr ""
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, python-format
-msgid "%(user)s was successfully deleted."
-msgstr ""
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr ""
-
-#: syspanel/views/users.py:128
-#, python-format
-msgid "Unable to list users: %s"
-msgstr ""
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-msgid "Unable to update user, please try again."
-msgstr ""
-
-#: syspanel/views/users.py:194
-#, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr ""
-
-#: syspanel/views/users.py:212
-#, python-format
-msgid "User \"%s\" was successfully created."
-msgstr ""
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, python-format
-msgid "Error creating user: %s"
-msgstr ""
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
-msgid "Dashboard Settings"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:26
-msgid "Dashboard User Interface Language"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:38
-msgid "Select Language"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
-msgid "Delete"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_form.html:10
-msgid "Create Container"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
-msgid "Actions"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:17
-msgid "List Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
-msgid "Upload Object"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
-msgid "Create Tenant"
-msgstr ""
-
-#: templates/django_openstack/dash/containers/create.html:22
-msgid ""
-"A container is a storage compartment for your data and provides a way for "
-"you to organize your data. You can think of a container as a folder in "
-"Windows® or a directory in UNIX®. The primary difference between a container "
-"and these other file system concepts is that containers cannot be nested. "
-"You can, however, create an unlimited number of containers within your "
-"account. Data must be stored in a container so you must have at least one "
-"container defined in your account prior to uploading data."
-msgstr ""
-
-#: templates/django_openstack/dash/containers/index.html:18
-msgid "Create New Container"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
-msgid "Allocate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
-msgid "Associate IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
-msgid "Disassociate"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:14
-msgid "Instance ID:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:15
-msgid "Fixed IP:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_list.html:28
-msgid "Associate to instance"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/_release.html:8
-msgid "Release"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:12
-msgid "Associate Floating IP"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
-msgid "Description:"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/associate.html:23
-msgid "Associate a floating ip with an instance."
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
-msgid "Info"
-msgstr ""
-
-#: templates/django_openstack/dash/floating_ips/index.html:22
-msgid "There are currently no floating ips assigned to your tenant."
-msgstr ""
-
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
-msgid "Update Image"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
-msgid "Launch Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
-msgid "Created"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
-msgid "Updated"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
-msgid "Status"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
-msgid "Edit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/_list.html:24
-msgid "Launch"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:22
-msgid ""
-"Specify the details for launching an instance. Also please make note of the "
-"table below; all tenants have quotas which define the limit of resources you "
-"are allowed to provision."
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
-msgid "Quota Name"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
-msgid "Limit"
-msgstr ""
-
-#: templates/django_openstack/dash/images/launch.html:29
-msgid "RAM (MB)"
-msgstr ""
-
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
-msgid "From here you can modify different properties of an image."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
-msgid "Update Instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:8
-msgid "Groups"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
-msgid "Image"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
-msgid "Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
-msgid "IPs"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
-msgid "State"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:66
-msgid "Log"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
-msgid "VNC Console"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/_list.html:69
-msgid "Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:19
-msgid "Return to Instances List"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/update.html:24
-msgid "Update the name and description of your instance"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
-msgid "Download CSV"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:50
-msgid "Hide Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:52
-msgid "Show Terminated"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
-msgid "User"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
-msgid "Ram Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
-msgid "Disk Size"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
-msgid "Uptime"
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:89
-msgid "No active instances."
-msgstr ""
-
-#: templates/django_openstack/dash/instances/usage.html:98
-#, python-format
-msgid ""
-"There are currently no instances.<br/><br/>You can launch an instance from "
-"the <a href='%(dash_img_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_form.html:10
-msgid "Add Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/_list.html:5
-msgid "Fingerprint"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
-msgid "Create Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:30
-msgid "Your private key is being downloaded."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
-msgid "Return to keypairs list"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
-msgid ""
-"Keypairs are ssh credentials which are injected into images when they are "
-"launched. Creating a new key pair registers the public key and downloads the "
-"private key (a .pem file)."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
-msgid "Protect and use the key as you would any normal ssh private key."
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
-msgid "Add New Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
-msgid "Import Keypair"
-msgstr ""
-
-#: templates/django_openstack/dash/keypairs/index.html:24
-msgid "There are currently no keypairs."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detach_port.html:9
-msgid "Detach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:6
-msgid "Attachment"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:8
-msgid "Extensions"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:20
-msgid "VIF Id"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_detail.html:36
-msgid "Attach"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
-msgid "Create Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:6
-msgid "Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:7
-msgid "Available"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:8
-msgid "Used"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:9
-msgid "Action"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
-msgid "Rename"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
-msgid "Rename Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
-msgid "Port UP"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
-msgid "Port DOWN"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
-msgid "Return to networks list"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/create.html:24
-msgid "Networks provide layer 2 connectivity to your instances."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "Create Ports"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/detail.html:28
-msgid "There are currently no ports in this network."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:20
-msgid "Create New Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "There are currently no networks."
-msgstr ""
-
-#: templates/django_openstack/dash/networks/index.html:24
-msgid "Create A Network"
-msgstr ""
-
-#: templates/django_openstack/dash/networks/rename.html:32
-msgid "Enter a new name for your network."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
-msgid "Copy Object"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_filter.html:7
-msgid "Filter"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:16
-msgid "Copy"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/_list.html:18
-msgid "Download"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
-msgid "Return to objects list"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/copy.html:26
-msgid ""
-"You may make a new copy of an existing object to store in this or another "
-"container."
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:31
-#, python-format
-msgid ""
-"There are currently no objects in the container %(container_name)s. You can "
-"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
-"Page &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/index.html:34
-msgid "Upload New Object &gt;&gt;"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:11
-msgid "Upload Objects"
-msgstr ""
-
-#: templates/django_openstack/dash/objects/upload.html:25
-msgid ""
-"An object is the basic storage entity and any optional metadata that "
-"represents the files you store in the OpenStack Object Storage system. When "
-"you upload data to OpenStack Object Storage, the data is stored as-is (no "
-"compression or encryption) and consists of a location (container), the "
-"object's name, and any metadata consisting of key/value pairs."
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:12
-msgid "Attach Port"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
-msgid "Return to network detail"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/attach.html:42
-msgid ""
-"<p>Select an interface from the list on the left to attach it to this port.</"
-"p>\n"
-" <p>Only interfaces that are not connected to any existing port are "
-"shown</p>\n"
-" <p>If you want to reconnect a connected interface, please detach it "
-"first</p>"
-msgstr ""
-
-#: templates/django_openstack/dash/ports/create.html:24
-msgid ""
-"You can plug virtual interfaces from your instances to ports created in the "
-"network"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
-msgid "Create Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/_list.html:14
-msgid "Edit Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/create.html:22
-msgid "From here you can create a new security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
-msgid "Edit Security Group Rules"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
-msgid "Rules for Security Group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
-msgid "IP Protocol"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
-msgid "From Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
-msgid "To Port"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
-msgid "CIDR"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
-msgid "No rules for this security group"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
-msgid "Add a rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
-msgid "Add Rule"
-msgstr ""
-
-#: templates/django_openstack/dash/security_groups/index.html:25
-#, python-format
-msgid ""
-"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
-"Security Group &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/_form.html:11
-msgid "Create Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:19
-msgid "Create a Snapshot"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:25
-msgid "Choose a name for your snapshot."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:27
-msgid "Return to snapshots list"
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/create.html:32
-msgid "Snapshots preserve the disk state of a running instance."
-msgstr ""
-
-#: templates/django_openstack/dash/snapshots/index.html:23
-#, python-format
-msgid ""
-"There are currently no snapshots. You can create snapshots from running "
-"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:5
-msgid "System Panel"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
-msgid "Create Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
-msgid "Id"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:7
-msgid "Memory"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
-msgid "Disk"
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/create.html:37
-msgid "From here you can define the sizing of a new flavor."
-msgstr ""
-
-#: templates/django_openstack/syspanel/flavors/index.html:18
-msgid "Create New Flavor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:9
-msgid "Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:35
-msgid "Location"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_list.html:40
-msgid "Project ID"
-msgstr ""
-
-#: templates/django_openstack/syspanel/images/_toggle.html:8
-msgid "Toggle Public"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
-msgid "Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:8
-msgid "Host"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/_list.html:48
-msgid "Console Log"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/index.html:23
-#, python-format
-msgid ""
-"There are currently no instances. You can launch an instance from the <a "
-"href='%(dash_image_url)s'>Images Page.</a>"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
-msgid "System Panel Overview"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
-msgid "Active Instances"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
-msgid "This month's VCPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
-msgid "This month's GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
-msgid "Tenant Usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:23
-msgid "Monitoring"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:34
-msgid "Select a month to query its usage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:71
-msgid "Server Usage Summary"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:80
-msgid "RAM"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:81
-msgid "VCPU CPU-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/instances/usage.html:82
-msgid "Disk GB-Hours"
-msgstr ""
-
-#: templates/django_openstack/syspanel/quotas/index.html:13
-msgid "Default Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:5
-msgid "Service"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:6
-msgid "System Stats"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:8
-msgid "Up"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:22
-msgid "Hypervisor"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:25
-msgid "Allocable Cores"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:30
-msgid "Allocable Storage"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_list.html:35
-msgid "System Ram"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
-msgid "Enable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
-msgid "Disable"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
-msgid "Add"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
-msgid "Options"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:20
-msgid "View Members"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_list.html:21
-msgid "Modify Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
-msgid "Remove"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
-msgid "Update Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
-msgid "Update Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/create.html:22
-msgid "From here you can create a new tenant (aka project) to organize users."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/index.html:18
-msgid "Create New Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
-msgid "Update Tenant Quotas"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/update.html:22
-msgid "From here you can edit a tenant."
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:12
-msgid "Users for Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:45
-msgid "here are currently no users for this tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/tenants/users.html:49
-msgid "Add new users"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
-msgid "Create User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
-msgid "Update User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/create.html:23
-msgid ""
-"From here you can create a new user and assign them to a tenant (aka "
-"project)."
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:23
-msgid "Default Tenant"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/index.html:42
-msgid "Create New User"
-msgstr ""
-
-#: templates/django_openstack/syspanel/users/update.html:23
-msgid ""
-"From here you can edit users by changing their usernames, emails, passwords, "
-"and tenants."
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:46
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:50
-#, python-format
-msgid "%(size)d"
-msgid_plural "%(size)d"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templatetags/templatetags/sizeformat.py:53
-#, python-format
-msgid "%s KB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:56
-#, python-format
-msgid "%s MB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:59
-#, python-format
-msgid "%s GB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:62
-#, python-format
-msgid "%s TB"
-msgstr ""
-
-#: templatetags/templatetags/sizeformat.py:64
-#, python-format
-msgid "%s PB"
-msgstr ""
diff --git a/django-openstack/django_openstack/signals.py b/django-openstack/django_openstack/signals.py
deleted file mode 100644
index ada0e929..00000000
--- a/django-openstack/django_openstack/signals.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-import django.dispatch
-from django.dispatch import receiver
-
-dash_modules_ping = django.dispatch.Signal()
-dash_modules_urls = django.dispatch.Signal()
-
-
-def dash_modules_detect():
- """
- Sends a pinging signal to the app, all listening modules will reply with
- items for the sidebar.
-
- The response is a tuple of the Signal object instance, and a dictionary.
- The values within the dictionary containing links and a title which should
- be added to the sidebar navigation.
-
- Example: (<dash_apps_ping>,
- {'title': 'Nixon',
- 'links': [{'url':'/syspanel/nixon/google',
- 'text':'Google', 'active_text': 'google'}],
- 'type': syspanel})
- """
- return dash_modules_ping.send(sender=dash_modules_ping)
-
-
-def dash_app_setup_urls():
- """
- Adds urls from modules
- """
- return dash_modules_urls.send(sender=dash_modules_urls)
diff --git a/django-openstack/django_openstack/syspanel/urls.py b/django-openstack/django_openstack/syspanel/urls.py
deleted file mode 100644
index 48dba7a7..00000000
--- a/django-openstack/django_openstack/syspanel/urls.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django.conf.urls.defaults import *
-from django.conf import settings
-
-
-INSTANCES = r'^instances/(?P<instance_id>[^/]+)/%s$'
-IMAGES = r'^images/(?P<image_id>[^/]+)/%s$'
-USERS = r'^users/(?P<user_id>[^/]+)/%s$'
-TENANTS = r'^tenants/(?P<tenant_id>[^/]+)/%s$'
-
-
-urlpatterns = patterns('django_openstack.syspanel.views.instances',
- url(r'^usage/(?P<tenant_id>[^/]+)$', 'tenant_usage',
- name='syspanel_tenant_usage'),
- url(r'^instances/$', 'index', name='syspanel_instances'),
- url(r'^instances/refresh$', 'refresh', name='syspanel_instances_refresh'),
- url(INSTANCES % 'detail', 'detail', name='syspanel_instances_detail'),
- # NOTE(termie): currently just using the 'dash' versions
- #url(INSTANCES % 'console', 'console', name='syspanel_instances_console'),
- #url(INSTANCES % 'vnc', 'vnc', name='syspanel_instances_vnc'),
-)
-
-
-urlpatterns += patterns('django_openstack.syspanel.views.images',
- url(r'^images/$', 'index', name='syspanel_images'),
- url(IMAGES % 'update', 'update', name='syspanel_images_update'),
- #url(INSTANCES % 'vnc', 'vnc', name='syspanel_instances_vnc'),
-)
-
-
-urlpatterns += patterns('django_openstack.syspanel.views.quotas',
- url(r'^quotas/$', 'index', name='syspanel_quotas'),
-)
-
-urlpatterns += patterns('django_openstack.syspanel.views.flavors',
- url(r'^flavors/$', 'index', name='syspanel_flavors'),
- url(r'^flavors/create/$', 'create', name='syspanel_flavors_create'),
-)
-
-
-urlpatterns += patterns('django_openstack.syspanel.views.users',
- url(r'^users/$', 'index', name='syspanel_users'),
- url(USERS % 'update', 'update', name='syspanel_users_update'),
- url(r'^users/create$', 'create', name='syspanel_users_create'),
-)
-
-
-urlpatterns += patterns('django_openstack.syspanel.views.services',
- url(r'^services/$', 'index', name='syspanel_services'),
-)
-
-
-urlpatterns += patterns('django_openstack.syspanel.views.tenants',
- url(r'^tenants/$', 'index', name='syspanel_tenants'),
- url(r'^tenants/create$', 'create', name='syspanel_tenants_create'),
- url(TENANTS % 'update', 'update', name='syspanel_tenant_update'),
- url(TENANTS % 'users', 'users', name='syspanel_tenant_users'),
- url(TENANTS % 'quotas', 'quotas', name='syspanel_tenant_quotas'),
-)
diff --git a/django-openstack/django_openstack/templates/django_openstack/auth/_login.html b/django-openstack/django_openstack/templates/django_openstack/auth/_login.html
deleted file mode 100644
index af8d4d20..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/auth/_login.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{%load i18n%}
-<form action="" method="post">
- {% csrf_token %}
- <fieldset>
- {% for hidden in form.hidden_fields %}
- {{hidden}}
- {% endfor %}
- {% for field in form.visible_fields %}
- {{field.label_tag}}
- {{field.errors}}
- {{field}}
- {% endfor %}
- {% block submit %}
- <input type="submit" value="{%trans "Login"%}" />
- {% endblock %}
- </fieldset>
-</form>
diff --git a/django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html b/django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html
deleted file mode 100644
index 3758e1d8..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{%load i18n%}
-<form id="form_reboot_{{instance.id}}" class="form-reboot" method="post">
- {% csrf_token %}
- {% for hidden in form.hidden_fields %}
- {{hidden}}
- {% endfor %}
- <input name="instance" type="hidden" value="{{instance.id}}" />
- <input id="reboot_{{instance.id}}" class="reboot" title="Instance: {{instance.name}}" type="submit" value="{%trans "Reboot"%}" />
-</form>
diff --git a/django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html b/django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html
deleted file mode 100644
index aea97246..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{%load i18n%}
-<form id="form_terminate_{{instance.id}}" class="form-terminate" method="post">
- {% csrf_token %}
- {% for hidden in form.hidden_fields %}
- {{hidden}}
- {% endfor %}
- <input name="instance" type="hidden" value="{{instance.id}}" />
- <input id="terminate_{{instance.id}}" class="terminate" title="{{instance.name}}" type="submit" value="{%trans "Terminate"%}" />
-</form>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html b/django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html
deleted file mode 100644
index 3a398a3f..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{% load sidebar_modules %}
-{%load i18n%}
-
-<div id='sidebar'>
- <h3>{% trans "Manage Compute"%}</h3>
- <ul class='sub_nav'>
- <li><a {% if current_sidebar == "overview" %} class="active" {% endif %} href="{% url dash_overview %}">{% trans "Overview"%}</a></li>
- <li><a {% if current_sidebar == "instances" %} class="active" {% endif %} href="{% url dash_instances request.user.tenant_id %}">{% trans "Instances"%}</a></li>
- <li><a {% if current_sidebar == "images" %} class="active" {% endif %} href="{% url dash_images request.user.tenant_id %}">{% trans "Images"%}</a></li>
- <li><a {% if current_sidebar == "snapshots" %} class="active" {% endif %} href="{% url dash_snapshots request.user.tenant_id %}">{% trans "Snapshots"%}</a></li>
- <li><a {% if current_sidebar == "keypairs" %} class="active" {% endif %} href="{% url dash_keypairs request.user.tenant_id %}">{% trans "Keypairs"%}</a></li>
- <li><a {% if current_sidebar == "floatingips" %} class="active" {% endif %} href="{% url dash_floating_ips request.user.tenant_id %}">{% trans "Floating IPs"%}</a></li>
- <li><a {% if current_sidebar == "security_groups" %} class="active" {% endif %} href="{% url dash_security_groups request.user.tenant_id %}">{% trans "Security Groups"%}</a></li>
- <li><a {% if current_sidebar == "volumes" %} class="active" {% endif %} href="{% url dash_volumes request.user.tenant_id %}">{% trans "Volumes"%}</a></li>
- {% if quantum_configured %}
- <li><a {% if current_sidebar == "networks" %} class="active" {% endif %} href="{% url dash_networks request.user.tenant_id %}">{% trans "Networks"%}</a></li>
- {% endif %}
- </ul>
- {% if object_store_configured %}
- <h3>{% trans "Manage Object Store"%}</h3>
- <ul class='sub_nav'>
- <li><a {% if current_sidebar == "containers" %} class="active" {% endif %} href="{% url dash_containers request.user.tenant_id %}">{% trans "Containers"%}</a></li>
- </ul>
- {% endif %}
-
- {% dash_sidebar_modules request %}
-
-</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/index.html b/django-openstack/django_openstack/templates/django_openstack/dash/containers/index.html
deleted file mode 100644
index 6230c26f..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/dash/containers/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends 'django_openstack/dash/base.html' %}
-{%load i18n%}
-
-{% block sidebar %}
- {% with current_sidebar="containers" %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
-
-{% block page_header %}
- {% url dash_images request.user.tenant_id as refresh_link %}
- {# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Containers") refresh_link=refresh_link searchable="true" %}
-{% endblock page_header %}
-
-{% block dash_main %}
- {% include 'django_openstack/dash/containers/_list.html' %}
- <a class="action_link large-rounded" href="{% url dash_containers_create request.user.tenant_id %}">{% trans "Create New Container"%} &gt;&gt;</a>
-{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/detail.html b/django-openstack/django_openstack/templates/django_openstack/dash/networks/detail.html
deleted file mode 100644
index 2898d822..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/detail.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends 'django_openstack/dash/base.html' %}
-{%load i18n%}
-
-{% block sidebar %}
- {% with current_sidebar="networks" %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
-
-{% block page_header %}
- {% url dash_networks_detail request.user.tenant_id network.id as refresh_link %}
- {# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=network.name refresh_link=refresh_link searchable="true" %}
-{% endblock page_header %}
-
-{% block breadcrumbs %}
- <a href="{% url dash_networks tenant %}">Networks</a>&nbsp;&raquo;&nbsp;
- <a href="{% url dash_networks_detail tenant network.id %}">{{network.name}}</a>
-{% endblock %}
-
-{% block dash_main %}
- {% if network.ports %}
- {% include 'django_openstack/dash/networks/_detail.html' %}
- <a id="network_create_link" class="action_link large-rounded" href="{% url dash_ports_create request.user.tenant_id network.id %}">{% trans "Create Ports"%}</a>
- {% else %}
- <div class="message_box info">
- <h2>{% trans "Info"%}</h2>
- <p>{% trans "There are currently no ports in this network."%} <a href="{% url dash_ports_create request.user.tenant_id network.id %}">{% trans "Create Ports"%} &gt;&gt;</a></p>
- </div>
- {% endif %}
-{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html b/django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html
deleted file mode 100644
index 4068f8c3..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% load sidebar_modules %}
-{%load i18n%}
-
-<div id='sidebar'>
- <h3>{% trans "System Panel"%}</h3>
- <ul class='sub_nav'>
- <li><a {% if current_sidebar == "overview" %} class="active" {% endif %} href="{% url syspanel_overview %}">{% trans "Overview"%}</a></li>
- <li><a {% if current_sidebar == "services" %} class="active" {% endif %} href="{% url syspanel_services %}">{% trans "Services"%}</a></li>
- <li><a {% if current_sidebar == "instances" %} class="active" {% endif %} href="{% url syspanel_instances %}">{% trans "Instances"%}</a></li>
- <li><a {% if current_sidebar == "flavors" %} class="active" {% endif %} href="{% url syspanel_flavors %}">{% trans "Flavors"%}</a></li>
- <li><a {% if current_sidebar == "images" %} class="active" {% endif %} href="{% url syspanel_images %}">{% trans "Images"%}</a></li>
- <li><a {% if current_sidebar == "tenants" %} class="active" {% endif %} href="{% url syspanel_tenants %}">{% trans "Tenants"%}</a></li>
- <li><a {% if current_sidebar == "users" %} class="active" {% endif %} href="{% url syspanel_users %}">{% trans "Users"%}</a></li>
- <li><a {% if current_sidebar == "quotas" %} class="active" {% endif %} href="{% url syspanel_quotas %}">{% trans "Quotas"%}</a></li>
- </ul>
-
- {% syspanel_sidebar_modules request %}
-</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/index.html b/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/index.html
deleted file mode 100644
index f592f654..00000000
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends 'django_openstack/syspanel/base.html' %}
-{%load i18n%}
-
-{% block sidebar %}
- {% with current_sidebar="flavors" %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
-
-{% block page_header %}
- {% url syspanel_flavors as refresh_link %}
- {# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Flavors") refresh_link=refresh_link searchable="true" %}
-{% endblock page_header %}
-
-{% block syspanel_main %}
- {% include "django_openstack/syspanel/flavors/_list.html" %}
- <a id="flavor_create_link" class="action_link large-rounded" href="{% url syspanel_flavors_create %}">{% trans "Create New Flavor"%}</a>
-{% endblock %}
diff --git a/django-openstack/django_openstack/templatetags/templatetags/sidebar_modules.py b/django-openstack/django_openstack/templatetags/templatetags/sidebar_modules.py
deleted file mode 100644
index c4172e22..00000000
--- a/django-openstack/django_openstack/templatetags/templatetags/sidebar_modules.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django import template
-from django_openstack import signals
-
-register = template.Library()
-
-
-@register.inclusion_tag('django_openstack/common/_sidebar_module.html')
-def dash_sidebar_modules(request):
- signals_call = signals.dash_modules_detect()
- if signals_call:
- return {'modules': [module[1] for module in signals_call
- if module[1]['type'] == "dash"],
- 'request': request}
- else:
- return {}
-
-
-@register.inclusion_tag('django_openstack/common/_sidebar_module.html')
-def syspanel_sidebar_modules(request):
- signals_call = signals.dash_modules_detect()
- if signals_call:
- return {'modules': [module[1] for module in signals_call
- if module[1]['type'] == "syspanel"],
- 'request': request}
- else:
- return {}
diff --git a/django-openstack/django_openstack/templatetags/templatetags/swift_paging.py b/django-openstack/django_openstack/templatetags/templatetags/swift_paging.py
deleted file mode 100644
index 774f6040..00000000
--- a/django-openstack/django_openstack/templatetags/templatetags/swift_paging.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from django import template
-from django.conf import settings
-from django.utils import http
-
-register = template.Library()
-
-
-@register.inclusion_tag('django_openstack/dash/objects/_paging.html')
-def object_paging(objects):
- marker = None
- if objects and not \
- len(objects) < getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000):
- last_object = objects[-1]
- marker = http.urlquote_plus(last_object.name)
- return {'marker': marker}
diff --git a/django-openstack/django_openstack/test.py b/django-openstack/django_openstack/test.py
deleted file mode 100644
index 3cc4b716..00000000
--- a/django-openstack/django_openstack/test.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django import http
-from django import test
-import mox
-
-from django_openstack.middleware import keystone
-
-
-class TestCase(test.TestCase):
- TEST_STAFF_USER = 'staffUser'
- TEST_TENANT = '1'
- TEST_TENANT_NAME = 'aTenant'
- TEST_TOKEN = 'aToken'
- TEST_USER = 'test'
-
- TEST_SERVICE_CATALOG = [{
- "endpoints": [{
- "adminURL": "http://cdn.admin-nets.local:8774/v1.0",
- "region": "RegionOne",
- "internalURL": "http://127.0.0.1:8774/v1.0",
- "publicURL": "http://cdn.admin-nets.local:8774/v1.0/"
- }],
- "type": "nova_compat",
- "name": "nova_compat"
- }, {
- "endpoints": [{
- "adminURL": "http://nova/novapi/admin",
- "region": "RegionOne",
- "internalURL": "http://nova/novapi/internal",
- "publicURL": "http://nova/novapi/public"
- }],
- "type": "compute",
- "name": "nova"
- }, {
- "endpoints": [{
- "adminURL": "http://glance/glanceapi/admin",
- "region": "RegionOne",
- "internalURL": "http://glance/glanceapi/internal",
- "publicURL": "http://glance/glanceapi/public"
- }],
- "type": "image",
- "name": "glance"
- }, {
- "endpoints": [{
- "adminURL": "http://cdn.admin-nets.local:35357/v2.0",
- "region": "RegionOne",
- "internalURL": "http://127.0.0.1:5000/v2.0",
- "publicURL": "http://cdn.admin-nets.local:5000/v2.0"
- }],
- "type": "identity",
- "name": "identity"
- }, {
- "endpoints": [{
- "adminURL": "http://swift/swiftapi/admin",
- "region": "RegionOne",
- "internalURL": "http://swift/swiftapi/internal",
- "publicURL": "http://swift/swiftapi/public"
- }],
- "type": "object-store",
- "name": "swift"
- }]
-
- def setUp(self):
- self.mox = mox.Mox()
-
- self._real_get_user_from_request = keystone.get_user_from_request
- self.setActiveUser(self.TEST_TOKEN, self.TEST_USER, self.TEST_TENANT,
- True, self.TEST_SERVICE_CATALOG)
- self.request = http.HttpRequest()
- keystone.AuthenticationMiddleware().process_request(self.request)
-
- def tearDown(self):
- self.mox.UnsetStubs()
- keystone.get_user_from_request = self._real_get_user_from_request
-
- def setActiveUser(self, token=None, username=None, tenant_id=None,
- is_admin=None, service_catalog=None, tenant_name=None):
- keystone.get_user_from_request = \
- lambda x: keystone.User(token, username, tenant_id,
- is_admin, service_catalog, tenant_name)
diff --git a/django-openstack/django_openstack/tests/api_tests.py b/django-openstack/django_openstack/tests/api_tests.py
deleted file mode 100644
index f50d214a..00000000
--- a/django-openstack/django_openstack/tests/api_tests.py
+++ /dev/null
@@ -1,1587 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-import cloudfiles
-import httplib
-import json
-import mox
-
-from django import http
-from django.conf import settings
-from django_openstack import api
-from glance import client as glance_client
-from mox import IsA
-from novaclient import service_catalog, client as base_client
-from novaclient.keystone import client as keystone_client
-from novaclient.v1_1 import client as nova_client
-from openstack import compute as OSCompute
-from openstackx import admin as OSAdmin
-from openstackx import auth as OSAuth
-from openstackx import extras as OSExtras
-
-
-from django_openstack import test
-from django_openstack.middleware import keystone
-
-
-TEST_CONSOLE_KIND = 'vnc'
-TEST_EMAIL = 'test@test.com'
-TEST_HOSTNAME = 'hostname'
-TEST_INSTANCE_ID = '2'
-TEST_PASSWORD = '12345'
-TEST_PORT = 8000
-TEST_RETURN = 'retValue'
-TEST_TENANT_DESCRIPTION = 'tenantDescription'
-TEST_TENANT_ID = '1234'
-TEST_TENANT_NAME = 'foo'
-TEST_TOKEN = 'aToken'
-TEST_TOKEN_ID = 'userId'
-TEST_URL = 'http://%s:%s/something/v1.0' % (TEST_HOSTNAME, TEST_PORT)
-TEST_USERNAME = 'testUser'
-
-
-class Server(object):
- """ More or less fakes what the api is looking for """
- def __init__(self, id, image, attrs=None):
- self.id = id
-
- self.image = image
- if attrs is not None:
- self.attrs = attrs
-
- def __eq__(self, other):
- if self.id != other.id or \
- self.image['id'] != other.image['id']:
- return False
-
- for k in self.attrs:
- if other.attrs.__getattr__(k) != v:
- return False
-
- return True
-
- def __ne__(self, other):
- return not self == other
-
-
-class Tenant(object):
- """ More or less fakes what the api is looking for """
- def __init__(self, id, description, enabled):
- self.id = id
- self.description = description
- self.enabled = enabled
-
- def __eq__(self, other):
- return self.id == other.id and \
- self.description == other.description and \
- self.enabled == other.enabled
-
- def __ne__(self, other):
- return not self == other
-
-
-class Token(object):
- """ More or less fakes what the api is looking for """
- def __init__(self, id, username, tenant_id, tenant_name,
- serviceCatalog=None):
- self.id = id
- self.user = {'name': username}
- self.tenant = {'id': tenant_id, 'name': tenant_name}
- self.serviceCatalog = serviceCatalog
-
- def __eq__(self, other):
- return self.id == other.id and \
- self.user['name'] == other.user['name'] and \
- self.tenant_id == other.tenant_id and \
- self.serviceCatalog == other.serviceCatalog
-
- def __ne__(self, other):
- return not self == other
-
-
-class APIResource(api.APIResourceWrapper):
- """ Simple APIResource for testing """
- _attrs = ['foo', 'bar', 'baz']
-
- @staticmethod
- def get_instance(innerObject=None):
- if innerObject is None:
- class InnerAPIResource(object):
- pass
- innerObject = InnerAPIResource()
- innerObject.foo = 'foo'
- innerObject.bar = 'bar'
- return APIResource(innerObject)
-
-
-class APIDict(api.APIDictWrapper):
- """ Simple APIDict for testing """
- _attrs = ['foo', 'bar', 'baz']
-
- @staticmethod
- def get_instance(innerDict=None):
- if innerDict is None:
- innerDict = {'foo': 'foo',
- 'bar': 'bar'}
- return APIDict(innerDict)
-
-
-class APITestCase(test.TestCase):
- def setUp(self):
- def fake_keystoneclient(request, username=None, password=None,
- tenant_id=None, token_id=None, endpoint=None):
- return self.stub_keystoneclient()
- super(APITestCase, self).setUp()
- self._original_keystoneclient = api.keystoneclient
- self._original_novaclient = api.novaclient
- api.keystoneclient = fake_keystoneclient
- api.novaclient = lambda request: self.stub_novaclient()
-
- def stub_novaclient(self):
- if not hasattr(self, "novaclient"):
- self.mox.StubOutWithMock(nova_client, 'Client')
- self.novaclient = self.mox.CreateMock(nova_client.Client)
- return self.novaclient
-
- def stub_keystoneclient(self):
- if not hasattr(self, "keystoneclient"):
- self.mox.StubOutWithMock(keystone_client, 'Client')
- self.keystoneclient = self.mox.CreateMock(keystone_client.Client)
- return self.keystoneclient
-
- def tearDown(self):
- super(APITestCase, self).tearDown()
- api.novaclient = self._original_novaclient
- api.keystoneclient = self._original_keystoneclient
-
-
-class APIResourceWrapperTests(test.TestCase):
- def test_get_attribute(self):
- resource = APIResource.get_instance()
- self.assertEqual(resource.foo, 'foo')
-
- def test_get_invalid_attribute(self):
- resource = APIResource.get_instance()
- self.assertNotIn('missing', resource._attrs,
- msg="Test assumption broken. Find new missing attribute")
- with self.assertRaises(AttributeError):
- resource.missing
-
- def test_get_inner_missing_attribute(self):
- resource = APIResource.get_instance()
- with self.assertRaises(AttributeError):
- resource.baz
-
-
-class APIDictWrapperTests(test.TestCase):
- # APIDict allows for both attribute access and dictionary style [element]
- # style access. Test both
- def test_get_item(self):
- resource = APIDict.get_instance()
- self.assertEqual(resource.foo, 'foo')
- self.assertEqual(resource['foo'], 'foo')
-
- def test_get_invalid_item(self):
- resource = APIDict.get_instance()
- self.assertNotIn('missing', resource._attrs,
- msg="Test assumption broken. Find new missing attribute")
- with self.assertRaises(AttributeError):
- resource.missing
- with self.assertRaises(KeyError):
- resource['missing']
-
- def test_get_inner_missing_attribute(self):
- resource = APIDict.get_instance()
- with self.assertRaises(AttributeError):
- resource.baz
- with self.assertRaises(KeyError):
- resource['baz']
-
- def test_get_with_default(self):
- resource = APIDict.get_instance()
-
- self.assertEqual(resource.get('foo'), 'foo')
-
- self.assertIsNone(resource.get('baz'))
-
- self.assertEqual('retValue', resource.get('baz', 'retValue'))
-
-
-# Wrapper classes that only define _attrs don't need extra testing.
-# Wrapper classes that have other attributes or methods need testing
-class ImageWrapperTests(test.TestCase):
- dict_with_properties = {
- 'properties':
- {'image_state': 'running'},
- 'size': 100,
- }
- dict_without_properties = {
- 'size': 100,
- }
-
- def test_get_properties(self):
- image = api.Image(self.dict_with_properties)
- image_props = image.properties
- self.assertIsInstance(image_props, api.ImageProperties)
- self.assertEqual(image_props.image_state, 'running')
-
- def test_get_other(self):
- image = api.Image(self.dict_with_properties)
- self.assertEqual(image.size, 100)
-
- def test_get_properties_missing(self):
- image = api.Image(self.dict_without_properties)
- with self.assertRaises(AttributeError):
- image.properties
-
- def test_get_other_missing(self):
- image = api.Image(self.dict_without_properties)
- with self.assertRaises(AttributeError):
- self.assertNotIn('missing', image._attrs,
- msg="Test assumption broken. Find new missing attribute")
- image.missing
-
-
-class ServerWrapperTests(test.TestCase):
- HOST = 'hostname'
- ID = '1'
- IMAGE_NAME = 'imageName'
- IMAGE_OBJ = {'id': '3', 'links': [{'href': '3', u'rel': u'bookmark'}]}
-
- def setUp(self):
- super(ServerWrapperTests, self).setUp()
-
- # these are all objects "fetched" from the api
- self.inner_attrs = {'host': self.HOST}
-
- self.inner_server = Server(self.ID, self.IMAGE_OBJ, self.inner_attrs)
- self.inner_server_no_attrs = Server(self.ID, self.IMAGE_OBJ)
-
- #self.request = self.mox.CreateMock(http.HttpRequest)
-
- def test_get_attrs(self):
- server = api.Server(self.inner_server, self.request)
- attrs = server.attrs
- # for every attribute in the "inner" object passed to the api wrapper,
- # see if it can be accessed through the api.ServerAttribute instance
- for k in self.inner_attrs:
- self.assertEqual(attrs.__getattr__(k), self.inner_attrs[k])
-
- def test_get_other(self):
- server = api.Server(self.inner_server, self.request)
- self.assertEqual(server.id, self.ID)
-
- def test_get_attrs_missing(self):
- server = api.Server(self.inner_server_no_attrs, self.request)
- with self.assertRaises(AttributeError):
- server.attrs
-
- def test_get_other_missing(self):
- server = api.Server(self.inner_server, self.request)
- with self.assertRaises(AttributeError):
- self.assertNotIn('missing', server._attrs,
- msg="Test assumption broken. Find new missing attribute")
- server.missing
-
- def test_image_name(self):
- self.mox.StubOutWithMock(api, 'image_get')
- api.image_get(IsA(http.HttpRequest),
- self.IMAGE_OBJ['id']
- ).AndReturn(api.Image({'name': self.IMAGE_NAME}))
-
- server = api.Server(self.inner_server, self.request)
-
- self.mox.ReplayAll()
-
- image_name = server.image_name
-
- self.assertEqual(image_name, self.IMAGE_NAME)
-
- self.mox.VerifyAll()
-
-
-class ApiHelperTests(test.TestCase):
- """ Tests for functions that don't use one of the api objects """
-
- def test_url_for(self):
- GLANCE_URL = 'http://glance/glanceapi/'
- NOVA_URL = 'http://nova/novapi/'
-
- url = api.url_for(self.request, 'image')
- self.assertEqual(url, GLANCE_URL + 'internal')
-
- url = api.url_for(self.request, 'image', admin=False)
- self.assertEqual(url, GLANCE_URL + 'internal')
-
- url = api.url_for(self.request, 'image', admin=True)
- self.assertEqual(url, GLANCE_URL + 'admin')
-
- url = api.url_for(self.request, 'compute')
- self.assertEqual(url, NOVA_URL + 'internal')
-
- url = api.url_for(self.request, 'compute', admin=False)
- self.assertEqual(url, NOVA_URL + 'internal')
-
- url = api.url_for(self.request, 'compute', admin=True)
- self.assertEqual(url, NOVA_URL + 'admin')
-
- self.assertNotIn('notAnApi', self.request.user.service_catalog,
- 'Select a new nonexistent service catalog key')
- with self.assertRaises(api.ServiceCatalogException):
- url = api.url_for(self.request, 'notAnApi')
-
-
-class TenantAPITests(APITestCase):
- def test_tenant_create(self):
- DESCRIPTION = 'aDescription'
- ENABLED = True
-
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.tenants = self.mox.CreateMockAnything()
- keystoneclient.tenants.create(TEST_TENANT_ID, DESCRIPTION,
- ENABLED).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.tenant_create(self.request, TEST_TENANT_ID,
- DESCRIPTION, ENABLED)
-
- self.assertIsInstance(ret_val, api.Tenant)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_tenant_get(self):
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.tenants = self.mox.CreateMockAnything()
- keystoneclient.tenants.get(TEST_TENANT_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.tenant_get(self.request, TEST_TENANT_ID)
-
- self.assertIsInstance(ret_val, api.Tenant)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_tenant_list(self):
- tenants = (TEST_RETURN, TEST_RETURN + '2')
-
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.tenants = self.mox.CreateMockAnything()
- keystoneclient.tenants.list().AndReturn(tenants)
-
- self.mox.ReplayAll()
-
- ret_val = api.tenant_list(self.request)
-
- self.assertEqual(len(ret_val), len(tenants))
- for tenant in ret_val:
- self.assertIsInstance(tenant, api.Tenant)
- self.assertIn(tenant._apiresource, tenants)
-
- self.mox.VerifyAll()
-
- def test_tenant_update(self):
- DESCRIPTION = 'aDescription'
- ENABLED = True
-
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.tenants = self.mox.CreateMockAnything()
- keystoneclient.tenants.update(TEST_TENANT_ID, TEST_TENANT_NAME,
- DESCRIPTION, ENABLED).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.tenant_update(self.request, TEST_TENANT_ID,
- TEST_TENANT_NAME, DESCRIPTION, ENABLED)
-
- self.assertIsInstance(ret_val, api.Tenant)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class UserAPITests(APITestCase):
- def test_user_create(self):
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.create(TEST_USERNAME, TEST_PASSWORD, TEST_EMAIL,
- TEST_TENANT_ID, True).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_create(self.request, TEST_USERNAME, TEST_EMAIL,
- TEST_PASSWORD, TEST_TENANT_ID, True)
-
- self.assertIsInstance(ret_val, api.User)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_user_delete(self):
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.delete(TEST_USERNAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_delete(self.request, TEST_USERNAME)
-
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_user_get(self):
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.get(TEST_USERNAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_get(self.request, TEST_USERNAME)
-
- self.assertIsInstance(ret_val, api.User)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_user_list(self):
- users = (TEST_USERNAME, TEST_USERNAME + '2')
-
- keystoneclient = self.stub_keystoneclient()
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.list(tenant_id=None).AndReturn(users)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_list(self.request)
-
- self.assertEqual(len(ret_val), len(users))
- for user in ret_val:
- self.assertIsInstance(user, api.User)
- self.assertIn(user._apiresource, users)
-
- self.mox.VerifyAll()
-
- def test_user_update_email(self):
- keystoneclient = self.stub_keystoneclient()
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.update_email(TEST_USERNAME,
- TEST_EMAIL).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_update_email(self.request, TEST_USERNAME,
- TEST_EMAIL)
-
- self.assertIsInstance(ret_val, api.User)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_user_update_password(self):
- keystoneclient = self.stub_keystoneclient()
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.update_password(TEST_USERNAME,
- TEST_PASSWORD).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_update_password(self.request, TEST_USERNAME,
- TEST_PASSWORD)
-
- self.assertIsInstance(ret_val, api.User)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_user_update_tenant(self):
- keystoneclient = self.stub_keystoneclient()
- keystoneclient.users = self.mox.CreateMockAnything()
- keystoneclient.users.update_tenant(TEST_USERNAME,
- TEST_TENANT_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.user_update_tenant(self.request, TEST_USERNAME,
- TEST_TENANT_ID)
-
- self.assertIsInstance(ret_val, api.User)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class RoleAPITests(APITestCase):
- def test_role_add_for_tenant_user(self):
- keystoneclient = self.stub_keystoneclient()
-
- role = api.Role(APIResource.get_instance())
- role.id = TEST_RETURN
- role.name = TEST_RETURN
-
- keystoneclient.roles = self.mox.CreateMockAnything()
- keystoneclient.roles.add_user_to_tenant(TEST_TENANT_ID,
- TEST_USERNAME,
- TEST_RETURN).AndReturn(role)
- api._get_role = self.mox.CreateMockAnything()
- api._get_role(IsA(http.HttpRequest), IsA(str)).AndReturn(role)
-
- self.mox.ReplayAll()
- ret_val = api.role_add_for_tenant_user(self.request,
- TEST_TENANT_ID,
- TEST_USERNAME,
- TEST_RETURN)
- self.assertEqual(ret_val, role)
-
- self.mox.VerifyAll()
-
-
-class AdminApiTests(APITestCase):
- def stub_admin_api(self, count=1):
- self.mox.StubOutWithMock(api, 'admin_api')
- admin_api = self.mox.CreateMock(OSAdmin.Admin)
- for i in range(count):
- api.admin_api(IsA(http.HttpRequest)).AndReturn(admin_api)
- return admin_api
-
- def test_get_admin_api(self):
- self.mox.StubOutClassWithMocks(OSAdmin, 'Admin')
- OSAdmin.Admin(auth_token=TEST_TOKEN, management_url=TEST_URL)
-
- self.mox.StubOutWithMock(api, 'url_for')
- api.url_for(IsA(http.HttpRequest), 'compute', True).AndReturn(TEST_URL)
- api.url_for(IsA(http.HttpRequest), 'compute', True).AndReturn(TEST_URL)
-
- self.mox.ReplayAll()
-
- self.assertIsNotNone(api.admin_api(self.request))
-
- self.mox.VerifyAll()
-
- def test_flavor_create(self):
- FLAVOR_DISK = 1000
- FLAVOR_ID = 6
- FLAVOR_MEMORY = 1024
- FLAVOR_NAME = 'newFlavor'
- FLAVOR_VCPU = 2
-
- admin_api = self.stub_admin_api()
-
- admin_api.flavors = self.mox.CreateMockAnything()
- admin_api.flavors.create(FLAVOR_NAME, FLAVOR_MEMORY, FLAVOR_VCPU,
- FLAVOR_DISK, FLAVOR_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.flavor_create(self.request, FLAVOR_NAME,
- str(FLAVOR_MEMORY), str(FLAVOR_VCPU),
- str(FLAVOR_DISK), FLAVOR_ID)
-
- self.assertIsInstance(ret_val, api.Flavor)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_flavor_delete(self):
- FLAVOR_ID = 6
-
- admin_api = self.stub_admin_api(count=2)
-
- admin_api.flavors = self.mox.CreateMockAnything()
- admin_api.flavors.delete(FLAVOR_ID, False).AndReturn(TEST_RETURN)
- admin_api.flavors.delete(FLAVOR_ID, True).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.flavor_delete(self.request, FLAVOR_ID)
- self.assertIsNone(ret_val)
-
- ret_val = api.flavor_delete(self.request, FLAVOR_ID, purge=True)
- self.assertIsNone(ret_val)
-
- def test_service_get(self):
- NAME = 'serviceName'
-
- admin_api = self.stub_admin_api()
- admin_api.services = self.mox.CreateMockAnything()
- admin_api.services.get(NAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.service_get(self.request, NAME)
-
- self.assertIsInstance(ret_val, api.Services)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_service_list(self):
- services = (TEST_RETURN, TEST_RETURN + '2')
-
- admin_api = self.stub_admin_api()
- admin_api.services = self.mox.CreateMockAnything()
- admin_api.services.list().AndReturn(services)
-
- self.mox.ReplayAll()
-
- ret_val = api.service_list(self.request)
-
- for service in ret_val:
- self.assertIsInstance(service, api.Services)
- self.assertIn(service._apiresource, services)
-
- self.mox.VerifyAll()
-
- def test_service_update(self):
- ENABLED = True
- NAME = 'serviceName'
-
- admin_api = self.stub_admin_api()
- admin_api.services = self.mox.CreateMockAnything()
- admin_api.services.update(NAME, ENABLED).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.service_update(self.request, NAME, ENABLED)
-
- self.assertIsInstance(ret_val, api.Services)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class TokenApiTests(APITestCase):
- def setUp(self):
- super(TokenApiTests, self).setUp()
- self._prev_OPENSTACK_KEYSTONE_URL = getattr(settings,
- 'OPENSTACK_KEYSTONE_URL',
- None)
- settings.OPENSTACK_KEYSTONE_URL = TEST_URL
-
- def tearDown(self):
- super(TokenApiTests, self).tearDown()
- settings.OPENSTACK_KEYSTONE_URL = self._prev_OPENSTACK_KEYSTONE_URL
-
- def test_token_create(self):
- catalog = {
- 'access': {
- 'token': {
- 'id': TEST_TOKEN_ID,
- },
- 'user': {
- 'roles': [],
- }
- }
- }
- test_token = Token(TEST_TOKEN_ID, TEST_USERNAME,
- TEST_TENANT_ID, TEST_TENANT_NAME)
-
- keystoneclient = self.stub_keystoneclient()
-
- keystoneclient.tokens = self.mox.CreateMockAnything()
- keystoneclient.tokens.authenticate(username=TEST_USERNAME,
- password=TEST_PASSWORD,
- tenant=TEST_TENANT_ID
- ).AndReturn(test_token)
-
- self.mox.ReplayAll()
-
- ret_val = api.token_create(self.request, TEST_TENANT_ID,
- TEST_USERNAME, TEST_PASSWORD)
-
- self.assertEqual(test_token.tenant['id'], ret_val.tenant['id'])
-
- self.mox.VerifyAll()
-
-
-class ComputeApiTests(APITestCase):
- def stub_compute_api(self, count=1):
- self.mox.StubOutWithMock(api, 'compute_api')
- compute_api = self.mox.CreateMock(OSCompute.Compute)
- for i in range(count):
- api.compute_api(IsA(http.HttpRequest)).AndReturn(compute_api)
- return compute_api
-
- def test_get_compute_api(self):
- class ComputeClient(object):
- __slots__ = ['auth_token', 'management_url']
-
- self.mox.StubOutClassWithMocks(OSCompute, 'Compute')
- compute_api = OSCompute.Compute(auth_token=TEST_TOKEN,
- management_url=TEST_URL)
-
- compute_api.client = ComputeClient()
-
- self.mox.StubOutWithMock(api, 'url_for')
- # called three times? Looks like a good place for optimization
- api.url_for(IsA(http.HttpRequest), 'compute').AndReturn(TEST_URL)
- api.url_for(IsA(http.HttpRequest), 'compute').AndReturn(TEST_URL)
- api.url_for(IsA(http.HttpRequest), 'compute').AndReturn(TEST_URL)
-
- self.mox.ReplayAll()
-
- compute_api = api.compute_api(self.request)
-
- self.assertIsNotNone(compute_api)
- self.assertEqual(compute_api.client.auth_token, TEST_TOKEN)
- self.assertEqual(compute_api.client.management_url, TEST_URL)
-
- self.mox.VerifyAll()
-
- def test_flavor_get(self):
- FLAVOR_ID = 6
-
- novaclient = self.stub_novaclient()
-
- novaclient.flavors = self.mox.CreateMockAnything()
- novaclient.flavors.get(FLAVOR_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.flavor_get(self.request, FLAVOR_ID)
- self.assertIsInstance(ret_val, api.Flavor)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_server_delete(self):
- INSTANCE = 'anInstance'
-
- compute_api = self.stub_compute_api()
-
- compute_api.servers = self.mox.CreateMockAnything()
- compute_api.servers.delete(INSTANCE).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.server_delete(self.request, INSTANCE)
-
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_server_reboot(self):
- INSTANCE_ID = '2'
- HARDNESS = 'diamond'
-
- self.mox.StubOutWithMock(api, 'server_get')
-
- server = self.mox.CreateMock(OSCompute.Server)
- server.reboot(OSCompute.servers.REBOOT_HARD).AndReturn(TEST_RETURN)
- api.server_get(IsA(http.HttpRequest), INSTANCE_ID).AndReturn(server)
-
- server = self.mox.CreateMock(OSCompute.Server)
- server.reboot(HARDNESS).AndReturn(TEST_RETURN)
- api.server_get(IsA(http.HttpRequest), INSTANCE_ID).AndReturn(server)
-
- self.mox.ReplayAll()
-
- ret_val = api.server_reboot(self.request, INSTANCE_ID)
- self.assertIsNone(ret_val)
-
- ret_val = api.server_reboot(self.request, INSTANCE_ID,
- hardness=HARDNESS)
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_server_create(self):
- NAME = 'server'
- IMAGE = 'anImage'
- FLAVOR = 'cherry'
- USER_DATA = {'nuts': 'berries'}
- KEY = 'user'
- SECGROUP = self.mox.CreateMock(api.SecurityGroup)
-
- server = self.mox.CreateMock(OSCompute.Server)
- novaclient = self.stub_novaclient()
- novaclient.servers = self.mox.CreateMockAnything()
- novaclient.servers.create(NAME, IMAGE, FLAVOR, userdata=USER_DATA,
- security_groups=[SECGROUP], key_name=KEY)\
- .AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.server_create(self.request, NAME, IMAGE, FLAVOR,
- KEY, USER_DATA, [SECGROUP])
-
- self.assertIsInstance(ret_val, api.Server)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class ExtrasApiTests(APITestCase):
-
- def stub_extras_api(self, count=1):
- self.mox.StubOutWithMock(api, 'extras_api')
- extras_api = self.mox.CreateMock(OSExtras.Extras)
- for i in range(count):
- api.extras_api(IsA(http.HttpRequest)).AndReturn(extras_api)
- return extras_api
-
- def test_get_extras_api(self):
- self.mox.StubOutClassWithMocks(OSExtras, 'Extras')
- OSExtras.Extras(auth_token=TEST_TOKEN, management_url=TEST_URL)
-
- self.mox.StubOutWithMock(api, 'url_for')
- api.url_for(IsA(http.HttpRequest), 'compute').AndReturn(TEST_URL)
- api.url_for(IsA(http.HttpRequest), 'compute').AndReturn(TEST_URL)
-
- self.mox.ReplayAll()
-
- self.assertIsNotNone(api.extras_api(self.request))
-
- self.mox.VerifyAll()
-
- def test_console_create(self):
- extras_api = self.stub_extras_api(count=2)
- extras_api.consoles = self.mox.CreateMockAnything()
- extras_api.consoles.create(
- TEST_INSTANCE_ID, TEST_CONSOLE_KIND).AndReturn(TEST_RETURN)
- extras_api.consoles.create(
- TEST_INSTANCE_ID, 'text').AndReturn(TEST_RETURN + '2')
-
- self.mox.ReplayAll()
-
- ret_val = api.console_create(self.request,
- TEST_INSTANCE_ID,
- TEST_CONSOLE_KIND)
- self.assertIsInstance(ret_val, api.Console)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- ret_val = api.console_create(self.request, TEST_INSTANCE_ID)
- self.assertIsInstance(ret_val, api.Console)
- self.assertEqual(ret_val._apiresource, TEST_RETURN + '2')
-
- self.mox.VerifyAll()
-
- def test_flavor_list(self):
- flavors = (TEST_RETURN, TEST_RETURN + '2')
- novaclient = self.stub_novaclient()
- novaclient.flavors = self.mox.CreateMockAnything()
- novaclient.flavors.list().AndReturn(flavors)
-
- self.mox.ReplayAll()
-
- ret_val = api.flavor_list(self.request)
-
- self.assertEqual(len(ret_val), len(flavors))
- for flavor in ret_val:
- self.assertIsInstance(flavor, api.Flavor)
- self.assertIn(flavor._apiresource, flavors)
-
- self.mox.VerifyAll()
-
- def test_server_list(self):
- servers = (TEST_RETURN, TEST_RETURN + '2')
-
- extras_api = self.stub_extras_api()
-
- extras_api.servers = self.mox.CreateMockAnything()
- extras_api.servers.list().AndReturn(servers)
-
- self.mox.ReplayAll()
-
- ret_val = api.server_list(self.request)
-
- self.assertEqual(len(ret_val), len(servers))
- for server in ret_val:
- self.assertIsInstance(server, api.Server)
- self.assertIn(server._apiresource, servers)
-
- self.mox.VerifyAll()
-
- def test_usage_get(self):
- extras_api = self.stub_extras_api()
-
- extras_api.usage = self.mox.CreateMockAnything()
- extras_api.usage.get(TEST_TENANT_ID, 'start',
- 'end').AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.usage_get(self.request, TEST_TENANT_ID, 'start', 'end')
-
- self.assertIsInstance(ret_val, api.Usage)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_usage_list(self):
- usages = (TEST_RETURN, TEST_RETURN + '2')
-
- extras_api = self.stub_extras_api()
-
- extras_api.usage = self.mox.CreateMockAnything()
- extras_api.usage.list('start', 'end').AndReturn(usages)
-
- self.mox.ReplayAll()
-
- ret_val = api.usage_list(self.request, 'start', 'end')
-
- self.assertEqual(len(ret_val), len(usages))
- for usage in ret_val:
- self.assertIsInstance(usage, api.Usage)
- self.assertIn(usage._apiresource, usages)
-
- self.mox.VerifyAll()
-
- def test_server_get(self):
- INSTANCE_ID = '2'
-
- extras_api = self.stub_extras_api()
- extras_api.servers = self.mox.CreateMockAnything()
- extras_api.servers.get(INSTANCE_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.server_get(self.request, INSTANCE_ID)
-
- self.assertIsInstance(ret_val, api.Server)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class VolumeTests(APITestCase):
- def setUp(self):
- super(VolumeTests, self).setUp()
- volume = api.Volume(APIResource.get_instance())
- volume.id = 1
- volume.displayName = "displayName"
- volume.attachments = [{"device": "/dev/vdb",
- "serverId": 1,
- "id": 1,
- "volumeId": 1}]
- self.volume = volume
- self.volumes = [volume, ]
-
- self.novaclient = self.stub_novaclient()
- self.novaclient.volumes = self.mox.CreateMockAnything()
-
- def test_volume_list(self):
- self.novaclient.volumes.list().AndReturn(self.volumes)
- self.mox.ReplayAll()
-
- volumes = api.volume_list(self.request)
-
- self.assertIsInstance(volumes[0], api.Volume)
- self.mox.VerifyAll()
-
- def test_volume_get(self):
- self.novaclient.volumes.get(IsA(int)).AndReturn(self.volume)
- self.mox.ReplayAll()
-
- volume = api.volume_get(self.request, 1)
-
- self.assertIsInstance(volume, api.Volume)
- self.mox.VerifyAll()
-
- def test_volume_instance_list(self):
- self.novaclient.volumes.get_server_volumes(IsA(int)).AndReturn(
- self.volume.attachments)
- self.mox.ReplayAll()
-
- attachments = api.volume_instance_list(self.request, 1)
-
- self.assertEqual(attachments, self.volume.attachments)
- self.mox.VerifyAll()
-
- def test_volume_create(self):
- self.novaclient.volumes.create(IsA(int), IsA(str), IsA(str)).AndReturn(
- self.volume)
- self.mox.ReplayAll()
-
- new_volume = api.volume_create(self.request,
- 10,
- "new volume",
- "new description")
-
- self.assertIsInstance(new_volume, api.Volume)
- self.mox.VerifyAll()
-
- def test_volume_delete(self):
- self.novaclient.volumes.delete(IsA(int))
- self.mox.ReplayAll()
-
- ret_val = api.volume_delete(self.request, 1)
-
- self.assertIsNone(ret_val)
- self.mox.VerifyAll()
-
- def test_volume_attach(self):
- self.novaclient.volumes.create_server_volume(
- IsA(int), IsA(int), IsA(str))
- self.mox.ReplayAll()
-
- ret_val = api.volume_attach(self.request, 1, 1, "/dev/vdb")
-
- self.assertIsNone(ret_val)
- self.mox.VerifyAll()
-
- def test_volume_detach(self):
- self.novaclient.volumes.delete_server_volume(IsA(int), IsA(int))
- self.mox.ReplayAll()
-
- ret_val = api.volume_detach(self.request, 1, 1)
-
- self.assertIsNone(ret_val)
- self.mox.VerifyAll()
-
-
-class APIExtensionTests(APITestCase):
-
- def setUp(self):
- super(APIExtensionTests, self).setUp()
- keypair = api.KeyPair(APIResource.get_instance())
- keypair.id = 1
- keypair.name = TEST_RETURN
-
- self.keypair = keypair
- self.keypairs = [keypair, ]
-
- floating_ip = api.FloatingIp(APIResource.get_instance())
- floating_ip.id = 1
- floating_ip.fixed_ip = '10.0.0.4'
- floating_ip.instance_id = 1
- floating_ip.ip = '58.58.58.58'
-
- self.floating_ip = floating_ip
- self.floating_ips = [floating_ip, ]
-
- server = api.Server(APIResource.get_instance(), self.request)
- server.id = 1
-
- self.server = server
- self.servers = [server, ]
-
- def test_server_snapshot_create(self):
- novaclient = self.stub_novaclient()
-
- novaclient.servers = self.mox.CreateMockAnything()
- novaclient.servers.create_image(IsA(int), IsA(str)).\
- AndReturn(self.server)
- self.mox.ReplayAll()
-
- server = api.snapshot_create(self.request, 1, 'test-snapshot')
-
- self.assertIsInstance(server, api.Server)
- self.mox.VerifyAll()
-
- def test_tenant_floating_ip_list(self):
- novaclient = self.stub_novaclient()
-
- novaclient.floating_ips = self.mox.CreateMockAnything()
- novaclient.floating_ips.list().AndReturn(self.floating_ips)
- self.mox.ReplayAll()
-
- floating_ips = api.tenant_floating_ip_list(self.request)
-
- self.assertEqual(len(floating_ips), len(self.floating_ips))
- self.assertIsInstance(floating_ips[0], api.FloatingIp)
- self.mox.VerifyAll()
-
- def test_tenant_floating_ip_get(self):
- novaclient = self.stub_novaclient()
-
- novaclient.floating_ips = self.mox.CreateMockAnything()
- novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
- self.mox.ReplayAll()
-
- floating_ip = api.tenant_floating_ip_get(self.request, 1)
-
- self.assertIsInstance(floating_ip, api.FloatingIp)
- self.mox.VerifyAll()
-
- def test_tenant_floating_ip_allocate(self):
- novaclient = self.stub_novaclient()
-
- novaclient.floating_ips = self.mox.CreateMockAnything()
- novaclient.floating_ips.create().AndReturn(self.floating_ip)
- self.mox.ReplayAll()
-
- floating_ip = api.tenant_floating_ip_allocate(self.request)
-
- self.assertIsInstance(floating_ip, api.FloatingIp)
- self.mox.VerifyAll()
-
- def test_tenant_floating_ip_release(self):
- novaclient = self.stub_novaclient()
-
- novaclient.floating_ips = self.mox.CreateMockAnything()
- novaclient.floating_ips.delete(1).AndReturn(self.floating_ip)
- self.mox.ReplayAll()
-
- floating_ip = api.tenant_floating_ip_release(self.request, 1)
-
- self.assertIsInstance(floating_ip, api.FloatingIp)
- self.mox.VerifyAll()
-
- def test_server_remove_floating_ip(self):
- novaclient = self.stub_novaclient()
-
- novaclient.servers = self.mox.CreateMockAnything()
- novaclient.floating_ips = self.mox.CreateMockAnything()
-
- novaclient.servers.get(IsA(int)).AndReturn(self.server)
- novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
- novaclient.servers.remove_floating_ip(IsA(self.server.__class__),
- IsA(self.floating_ip.__class__)) \
- .AndReturn(self.server)
- self.mox.ReplayAll()
-
- server = api.server_remove_floating_ip(self.request, 1, 1)
-
- self.assertIsInstance(server, api.Server)
- self.mox.VerifyAll()
-
- def test_server_add_floating_ip(self):
- novaclient = self.stub_novaclient()
-
- novaclient.floating_ips = self.mox.CreateMockAnything()
- novaclient.servers = self.mox.CreateMockAnything()
-
- novaclient.servers.get(IsA(int)).AndReturn(self.server)
- novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
- novaclient.servers.add_floating_ip(IsA(self.server.__class__),
- IsA(self.floating_ip.__class__)) \
- .AndReturn(self.server)
- self.mox.ReplayAll()
-
- server = api.server_add_floating_ip(self.request, 1, 1)
-
- self.assertIsInstance(server, api.Server)
- self.mox.VerifyAll()
-
- def test_keypair_create(self):
- novaclient = self.stub_novaclient()
-
- novaclient.keypairs = self.mox.CreateMockAnything()
- novaclient.keypairs.create(IsA(str)).AndReturn(self.keypair)
- self.mox.ReplayAll()
-
- ret_val = api.keypair_create(self.request, TEST_RETURN)
- self.assertIsInstance(ret_val, api.KeyPair)
- self.assertEqual(ret_val.name, self.keypair.name)
-
- self.mox.VerifyAll()
-
- def test_keypair_import(self):
- novaclient = self.stub_novaclient()
-
- novaclient.keypairs = self.mox.CreateMockAnything()
- novaclient.keypairs.create(IsA(str), IsA(str)).AndReturn(self.keypair)
- self.mox.ReplayAll()
-
- ret_val = api.keypair_import(self.request, TEST_RETURN, TEST_RETURN)
- self.assertIsInstance(ret_val, api.KeyPair)
- self.assertEqual(ret_val.name, self.keypair.name)
-
- self.mox.VerifyAll()
-
- def test_keypair_delete(self):
- novaclient = self.stub_novaclient()
-
- novaclient.keypairs = self.mox.CreateMockAnything()
- novaclient.keypairs.delete(IsA(int))
-
- self.mox.ReplayAll()
-
- ret_val = api.keypair_delete(self.request, self.keypair.id)
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_keypair_list(self):
- novaclient = self.stub_novaclient()
-
- novaclient.keypairs = self.mox.CreateMockAnything()
- novaclient.keypairs.list().AndReturn(self.keypairs)
-
- self.mox.ReplayAll()
-
- ret_val = api.keypair_list(self.request)
-
- self.assertEqual(len(ret_val), len(self.keypairs))
- for keypair in ret_val:
- self.assertIsInstance(keypair, api.KeyPair)
-
- self.mox.VerifyAll()
-
-
-class GlanceApiTests(APITestCase):
- def stub_glance_api(self, count=1):
- self.mox.StubOutWithMock(api, 'glance_api')
- glance_api = self.mox.CreateMock(glance_client.Client)
- glance_api.token = TEST_TOKEN
- for i in range(count):
- api.glance_api(IsA(http.HttpRequest)).AndReturn(glance_api)
- return glance_api
-
- def test_get_glance_api(self):
- self.mox.StubOutClassWithMocks(glance_client, 'Client')
- client_instance = glance_client.Client(TEST_HOSTNAME, TEST_PORT,
- auth_tok=TEST_TOKEN)
- # Normally ``auth_tok`` is set in ``Client.__init__``, but mox doesn't
- # duplicate that behavior so we set it manually.
- client_instance.auth_tok = TEST_TOKEN
-
- self.mox.StubOutWithMock(api, 'url_for')
- api.url_for(IsA(http.HttpRequest), 'image').AndReturn(TEST_URL)
-
- self.mox.ReplayAll()
-
- ret_val = api.glance_api(self.request)
- self.assertIsNotNone(ret_val)
- self.assertEqual(ret_val.auth_tok, TEST_TOKEN)
-
- self.mox.VerifyAll()
-
- def test_image_create(self):
- IMAGE_FILE = 'someData'
- IMAGE_META = {'metadata': 'foo'}
-
- glance_api = self.stub_glance_api()
- glance_api.add_image(IMAGE_META, IMAGE_FILE).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.image_create(self.request, IMAGE_META, IMAGE_FILE)
-
- self.assertIsInstance(ret_val, api.Image)
- self.assertEqual(ret_val._apidict, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_image_delete(self):
- IMAGE_ID = '1'
-
- glance_api = self.stub_glance_api()
- glance_api.delete_image(IMAGE_ID).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.image_delete(self.request, IMAGE_ID)
-
- self.assertEqual(ret_val, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_image_get(self):
- IMAGE_ID = '1'
-
- glance_api = self.stub_glance_api()
- glance_api.get_image(IMAGE_ID).AndReturn([TEST_RETURN])
-
- self.mox.ReplayAll()
-
- ret_val = api.image_get(self.request, IMAGE_ID)
-
- self.assertIsInstance(ret_val, api.Image)
- self.assertEqual(ret_val._apidict, TEST_RETURN)
-
- def test_image_list_detailed(self):
- images = (TEST_RETURN, TEST_RETURN + '2')
- glance_api = self.stub_glance_api()
- glance_api.get_images_detailed().AndReturn(images)
-
- self.mox.ReplayAll()
-
- ret_val = api.image_list_detailed(self.request)
-
- self.assertEqual(len(ret_val), len(images))
- for image in ret_val:
- self.assertIsInstance(image, api.Image)
- self.assertIn(image._apidict, images)
-
- self.mox.VerifyAll()
-
- def test_image_update(self):
- IMAGE_ID = '1'
- IMAGE_META = {'metadata': 'foobar'}
-
- glance_api = self.stub_glance_api(count=2)
- glance_api.update_image(IMAGE_ID, image_meta={}).AndReturn(TEST_RETURN)
- glance_api.update_image(IMAGE_ID,
- image_meta=IMAGE_META).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.image_update(self.request, IMAGE_ID)
-
- self.assertIsInstance(ret_val, api.Image)
- self.assertEqual(ret_val._apidict, TEST_RETURN)
-
- ret_val = api.image_update(self.request,
- IMAGE_ID,
- image_meta=IMAGE_META)
-
- self.assertIsInstance(ret_val, api.Image)
- self.assertEqual(ret_val._apidict, TEST_RETURN)
-
- self.mox.VerifyAll()
-
-
-class SwiftApiTests(APITestCase):
- def setUp(self):
- self.mox = mox.Mox()
-
- self.request = http.HttpRequest()
- self.request.session = dict()
- self.request.session['token'] = TEST_TOKEN
-
- def tearDown(self):
- self.mox.UnsetStubs()
-
- def stub_swift_api(self, count=1):
- self.mox.StubOutWithMock(api, 'swift_api')
- swift_api = self.mox.CreateMock(cloudfiles.connection.Connection)
- for i in range(count):
- api.swift_api(IsA(http.HttpRequest)).AndReturn(swift_api)
- return swift_api
-
- def test_swift_get_containers(self):
- containers = (TEST_RETURN, TEST_RETURN + '2')
-
- swift_api = self.stub_swift_api()
-
- swift_api.get_all_containers(limit=10000,
- marker=None).AndReturn(containers)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_get_containers(self.request)
-
- self.assertEqual(len(ret_val), len(containers))
- for container in ret_val:
- self.assertIsInstance(container, api.Container)
- self.assertIn(container._apiresource, containers)
-
- self.mox.VerifyAll()
-
- def test_swift_create_container(self):
- NAME = 'containerName'
-
- swift_api = self.stub_swift_api()
- self.mox.StubOutWithMock(api, 'swift_container_exists')
-
- api.swift_container_exists(self.request,
- NAME).AndReturn(False)
- swift_api.create_container(NAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_create_container(self.request, NAME)
-
- self.assertIsInstance(ret_val, api.Container)
- self.assertEqual(ret_val._apiresource, TEST_RETURN)
-
- self.mox.VerifyAll()
-
- def test_swift_delete_container(self):
- NAME = 'containerName'
-
- swift_api = self.stub_swift_api()
-
- swift_api.delete_container(NAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_delete_container(self.request, NAME)
-
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_swift_get_objects(self):
- NAME = 'containerName'
-
- swift_objects = (TEST_RETURN, TEST_RETURN + '2')
- container = self.mox.CreateMock(cloudfiles.container.Container)
- container.get_objects(limit=10000,
- marker=None,
- prefix=None).AndReturn(swift_objects)
-
- swift_api = self.stub_swift_api()
-
- swift_api.get_container(NAME).AndReturn(container)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_get_objects(self.request, NAME)
-
- self.assertEqual(len(ret_val), len(swift_objects))
- for swift_object in ret_val:
- self.assertIsInstance(swift_object, api.SwiftObject)
- self.assertIn(swift_object._apiresource, swift_objects)
-
- self.mox.VerifyAll()
-
- def test_swift_get_objects_with_prefix(self):
- NAME = 'containerName'
- PREFIX = 'prefacedWith'
-
- swift_objects = (TEST_RETURN, TEST_RETURN + '2')
- container = self.mox.CreateMock(cloudfiles.container.Container)
- container.get_objects(limit=10000,
- marker=None,
- prefix=PREFIX).AndReturn(swift_objects)
-
- swift_api = self.stub_swift_api()
-
- swift_api.get_container(NAME).AndReturn(container)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_get_objects(self.request,
- NAME,
- prefix=PREFIX)
-
- self.assertEqual(len(ret_val), len(swift_objects))
- for swift_object in ret_val:
- self.assertIsInstance(swift_object, api.SwiftObject)
- self.assertIn(swift_object._apiresource, swift_objects)
-
- self.mox.VerifyAll()
-
- def test_swift_upload_object(self):
- CONTAINER_NAME = 'containerName'
- OBJECT_NAME = 'objectName'
- OBJECT_DATA = 'someData'
-
- swift_api = self.stub_swift_api()
- container = self.mox.CreateMock(cloudfiles.container.Container)
- swift_object = self.mox.CreateMock(cloudfiles.storage_object.Object)
-
- swift_api.get_container(CONTAINER_NAME).AndReturn(container)
- container.create_object(OBJECT_NAME).AndReturn(swift_object)
- swift_object.write(OBJECT_DATA).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_upload_object(self.request,
- CONTAINER_NAME,
- OBJECT_NAME,
- OBJECT_DATA)
-
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_swift_delete_object(self):
- CONTAINER_NAME = 'containerName'
- OBJECT_NAME = 'objectName'
-
- swift_api = self.stub_swift_api()
- container = self.mox.CreateMock(cloudfiles.container.Container)
-
- swift_api.get_container(CONTAINER_NAME).AndReturn(container)
- container.delete_object(OBJECT_NAME).AndReturn(TEST_RETURN)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_delete_object(self.request,
- CONTAINER_NAME,
- OBJECT_NAME)
-
- self.assertIsNone(ret_val)
-
- self.mox.VerifyAll()
-
- def test_swift_get_object_data(self):
- CONTAINER_NAME = 'containerName'
- OBJECT_NAME = 'objectName'
- OBJECT_DATA = 'objectData'
-
- swift_api = self.stub_swift_api()
- container = self.mox.CreateMock(cloudfiles.container.Container)
- swift_object = self.mox.CreateMock(cloudfiles.storage_object.Object)
-
- swift_api.get_container(CONTAINER_NAME).AndReturn(container)
- container.get_object(OBJECT_NAME).AndReturn(swift_object)
- swift_object.stream().AndReturn(OBJECT_DATA)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_get_object_data(self.request,
- CONTAINER_NAME,
- OBJECT_NAME)
-
- self.assertEqual(ret_val, OBJECT_DATA)
-
- self.mox.VerifyAll()
-
- def test_swift_object_exists(self):
- CONTAINER_NAME = 'containerName'
- OBJECT_NAME = 'objectName'
-
- swift_api = self.stub_swift_api()
- container = self.mox.CreateMock(cloudfiles.container.Container)
- swift_object = self.mox.CreateMock(cloudfiles.Object)
-
- swift_api.get_container(CONTAINER_NAME).AndReturn(container)
- container.get_object(OBJECT_NAME).AndReturn(swift_object)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_object_exists(self.request,
- CONTAINER_NAME,
- OBJECT_NAME)
- self.assertTrue(ret_val)
-
- self.mox.VerifyAll()
-
- def test_swift_copy_object(self):
- CONTAINER_NAME = 'containerName'
- OBJECT_NAME = 'objectName'
-
- swift_api = self.stub_swift_api()
- container = self.mox.CreateMock(cloudfiles.container.Container)
- self.mox.StubOutWithMock(api, 'swift_object_exists')
-
- swift_object = self.mox.CreateMock(cloudfiles.Object)
-
- swift_api.get_container(CONTAINER_NAME).AndReturn(container)
- api.swift_object_exists(self.request,
- CONTAINER_NAME,
- OBJECT_NAME).AndReturn(False)
-
- container.get_object(OBJECT_NAME).AndReturn(swift_object)
- swift_object.copy_to(CONTAINER_NAME, OBJECT_NAME)
-
- self.mox.ReplayAll()
-
- ret_val = api.swift_copy_object(self.request, CONTAINER_NAME,
- OBJECT_NAME, CONTAINER_NAME,
- OBJECT_NAME)
-
- self.assertIsNone(ret_val)
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/broken/README b/django-openstack/django_openstack/tests/broken/README
deleted file mode 100644
index a2eec652..00000000
--- a/django-openstack/django_openstack/tests/broken/README
+++ /dev/null
@@ -1,2 +0,0 @@
-Intentionally not a python module so that test runner won't find
-these broken tests
diff --git a/django-openstack/django_openstack/tests/broken/base.py b/django-openstack/django_openstack/tests/broken/base.py
deleted file mode 100644
index 9947931f..00000000
--- a/django-openstack/django_openstack/tests/broken/base.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Base classes for view based unit tests.
-"""
-
-import mox
-import nova_adminclient as adminclient
-
-from django import test
-from django.conf import settings
-from django.contrib.auth import models as auth_models
-
-
-TEST_PROJECT = 'test'
-TEST_USER = 'test'
-TEST_REGION = 'test'
-
-
-class BaseViewTests(test.TestCase):
- def setUp(self):
- self.mox = mox.Mox()
-
- def tearDown(self):
- self.mox.UnsetStubs()
-
- def assertRedirectsNoFollow(self, response, expected_url):
- self.assertEqual(response._headers['location'],
- ('Location', settings.TESTSERVER + expected_url))
- self.assertEqual(response.status_code, 302)
-
- def authenticateTestUser(self):
- user = auth_models.User.objects.create_user(TEST_USER,
- 'test@test.com',
- password='test')
- login = self.client.login(username=TEST_USER, password='test')
- self.failUnless(login, 'Unable to login')
- return user
-
-
-class BaseProjectViewTests(BaseViewTests):
- def setUp(self):
- super(BaseProjectViewTests, self).setUp()
-
- project = adminclient.ProjectInfo()
- project.projectname = TEST_PROJECT
- project.projectManagerId = TEST_USER
-
- self.user = self.authenticateTestUser()
- self.region = adminclient.RegionInfo(name=TEST_REGION,
- endpoint='http://test:8773/')
-
- def create_key_pair_choices(self, key_names):
- return [(k, k) for k in key_names]
-
- def create_instance_type_choices(self):
- return [('m1.medium', 'm1.medium'),
- ('m1.large', 'm1.large')]
-
- def create_instance_choices(self, instance_ids):
- return [(id, id) for id in instance_ids]
-
- def create_available_volume_choices(self, volumes):
- return [(v.id, '%s %s - %dGB' % (v.id, v.displayName, v.size)) \
- for v in volumes]
diff --git a/django-openstack/django_openstack/tests/broken/credential_tests.py b/django-openstack/django_openstack/tests/broken/credential_tests.py
deleted file mode 100644
index 23ac9777..00000000
--- a/django-openstack/django_openstack/tests/broken/credential_tests.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for credential views.
-"""
-
-from django.conf import settings
-from django.core.urlresolvers import reverse
-from django_openstack import models
-from django_openstack.nova.tests.base import BaseViewTests
-
-
-class CredentialViewTests(BaseViewTests):
- def test_download_expired_credentials(self):
- auth_token = 'expired'
- self.mox.StubOutWithMock(models.CredentialsAuthorization,
- 'get_by_token')
- models.CredentialsAuthorization.get_by_token(auth_token) \
- .AndReturn(None)
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_credentials_authorize',
- args=[auth_token]))
- self.assertTemplateUsed(res,
- 'django_openstack/nova/credentials/expired.html')
-
- self.mox.VerifyAll()
-
- def test_download_good_credentials(self):
- auth_token = 'good'
-
- creds = models.CredentialsAuthorization()
- creds.username = 'test'
- creds.project = 'test'
- creds.auth_token = auth_token
-
- self.mox.StubOutWithMock(models.CredentialsAuthorization,
- 'get_by_token')
- self.mox.StubOutWithMock(creds, 'get_zip')
- models.CredentialsAuthorization.get_by_token(auth_token) \
- .AndReturn(creds)
- creds.get_zip().AndReturn('zip')
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_credentials_authorize',
- args=[auth_token]))
- self.assertEqual(res.status_code, 200)
- self.assertEqual(res['Content-Disposition'],
- 'attachment; filename=%s-test-test-x509.zip' %
- settings.SITE_NAME)
- self.assertContains(res, 'zip')
-
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/broken/image_tests.py b/django-openstack/django_openstack/tests/broken/image_tests.py
deleted file mode 100644
index a2b6769d..00000000
--- a/django-openstack/django_openstack/tests/broken/image_tests.py
+++ /dev/null
@@ -1,237 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for image views.
-"""
-
-import boto.ec2.image
-import boto.ec2.instance
-import mox
-
-from django.core.urlresolvers import reverse
-from django_openstack.nova import forms
-from django_openstack.nova import shortcuts
-from django_openstack.nova.tests.base import (BaseProjectViewTests,
- TEST_PROJECT)
-
-
-TEST_IMAGE_ID = 'ami_test'
-TEST_INSTANCE_ID = 'i-abcdefg'
-TEST_KEY = 'foo'
-
-
-class ImageViewTests(BaseProjectViewTests):
- def setUp(self):
- self.ami = boto.ec2.image.Image()
- self.ami.id = TEST_IMAGE_ID
- setattr(self.ami, 'displayName', TEST_IMAGE_ID)
- setattr(self.ami, 'description', TEST_IMAGE_ID)
- super(ImageViewTests, self).setUp()
-
- def test_index(self):
- self.mox.StubOutWithMock(self.project, 'get_images')
- self.mox.StubOutWithMock(forms, 'get_key_pair_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_type_choices')
-
- self.project.get_images().AndReturn([])
- forms.get_key_pair_choices(self.project).AndReturn([])
- forms.get_instance_type_choices().AndReturn([])
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_images', args=[TEST_PROJECT]))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res, 'django_openstack/nova/images/index.html')
- self.assertEqual(len(res.context['image_lists']), 3)
-
- self.mox.VerifyAll()
-
- def test_launch_form(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.StubOutWithMock(forms, 'get_key_pair_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_type_choices')
-
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- forms.get_key_pair_choices(self.project).AndReturn([])
- forms.get_instance_type_choices().AndReturn([])
-
- self.mox.ReplayAll()
-
- args = [TEST_PROJECT, TEST_IMAGE_ID]
- res = self.client.get(reverse('nova_images_launch', args=args))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res,
- 'django_openstack/nova/images/launch.html')
- self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID)
-
- self.mox.VerifyAll()
-
- def test_launch(self):
- instance = boto.ec2.instance.Instance()
- instance.id = TEST_INSTANCE_ID
- instance.image_id = TEST_IMAGE_ID
- reservation = boto.ec2.instance.Reservation()
- reservation.instances = [instance]
-
- conn = self.mox.CreateMockAnything()
-
- self.mox.StubOutWithMock(forms, 'get_key_pair_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_type_choices')
- self.mox.StubOutWithMock(self.project, 'get_openstack_connection')
-
- self.project.get_openstack_connection().AndReturn(conn)
-
- forms.get_key_pair_choices(self.project).AndReturn(
- self.create_key_pair_choices([TEST_KEY]))
- forms.get_instance_type_choices().AndReturn(
- self.create_instance_type_choices())
-
- params = {'addressing_type': 'private',
- 'UserData': '', 'display_name': u'name',
- 'MinCount': '1', 'key_name': TEST_KEY,
- 'MaxCount': '1', 'InstanceType': 'm1.medium',
- 'ImageId': TEST_IMAGE_ID}
- conn.get_object('RunInstances', params, boto.ec2.instance.Reservation,
- verb='POST').AndReturn(reservation)
-
- self.mox.ReplayAll()
-
- url = reverse('nova_images_launch', args=[TEST_PROJECT, TEST_IMAGE_ID])
- data = {'key_name': TEST_KEY,
- 'count': '1',
- 'size': 'm1.medium',
- 'display_name': 'name',
- 'user_data': ''}
- res = self.client.post(url, data)
- self.assertRedirectsNoFollow(res, reverse('nova_instances',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_detail(self):
- self.mox.StubOutWithMock(self.project, 'get_images')
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.StubOutWithMock(shortcuts, 'get_user_image_permissions')
- self.mox.StubOutWithMock(forms, 'get_key_pair_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_type_choices')
-
- self.project.get_images().AndReturn([self.ami])
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- forms.get_key_pair_choices(self.project).AndReturn(
- self.create_key_pair_choices([TEST_KEY]))
- forms.get_instance_type_choices().AndReturn(
- self.create_instance_type_choices())
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_images_detail',
- args=[TEST_PROJECT, TEST_IMAGE_ID]))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res, 'django_openstack/nova/images/index.html')
- self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID)
-
- self.mox.VerifyAll()
-
- def test_remove_form(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_images_remove',
- args=[TEST_PROJECT, TEST_IMAGE_ID]))
- self.assertRedirectsNoFollow(res, reverse('nova_images',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_remove(self):
- self.mox.StubOutWithMock(self.project, 'deregister_image')
- self.project.deregister_image(TEST_IMAGE_ID).AndReturn(True)
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('nova_images_remove',
- args=[TEST_PROJECT, TEST_IMAGE_ID]))
- self.assertRedirectsNoFollow(res, reverse('nova_images',
- args=[TEST_PROJECT]))
-
- self.mox.VerifyAll()
-
- def test_make_public(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.StubOutWithMock(self.project, 'modify_image_attribute')
-
- self.ami.is_public = False
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- self.project.modify_image_attribute(TEST_IMAGE_ID,
- attribute='launchPermission',
- operation='add').AndReturn(True)
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('nova_images_privacy',
- args=[TEST_PROJECT, TEST_IMAGE_ID]))
- self.assertRedirectsNoFollow(res, reverse('nova_images_detail',
- args=[TEST_PROJECT, TEST_IMAGE_ID]))
- self.mox.VerifyAll()
-
- def test_make_private(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.StubOutWithMock(self.project, 'modify_image_attribute')
-
- self.ami.is_public = True
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- self.project.modify_image_attribute(TEST_IMAGE_ID,
- attribute='launchPermission',
- operation='remove').AndReturn(True)
- self.mox.ReplayAll()
-
- args = [TEST_PROJECT, TEST_IMAGE_ID]
- res = self.client.post(reverse('nova_images_privacy', args=args))
- self.assertRedirectsNoFollow(res, reverse('nova_images_detail',
- args=args))
- self.mox.VerifyAll()
-
- def test_update_form(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- self.mox.ReplayAll()
-
- args = [TEST_PROJECT, TEST_IMAGE_ID]
- res = self.client.get(reverse('nova_images_update', args=args))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res, 'django_openstack/nova/images/edit.html')
- self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID)
-
- self.mox.VerifyAll()
-
- def test_update(self):
- self.mox.StubOutWithMock(self.project, 'get_image')
- self.mox.StubOutWithMock(self.project, 'update_image')
-
- self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
- self.project.update_image(TEST_IMAGE_ID, 'test', 'test') \
- .AndReturn(True)
-
- self.mox.ReplayAll()
-
- args = [TEST_PROJECT, TEST_IMAGE_ID]
- data = {'nickname': 'test',
- 'description': 'test'}
- url = reverse('nova_images_update', args=args)
- res = self.client.post(url, data)
- expected_url = reverse('nova_images_detail', args=args)
- self.assertRedirectsNoFollow(res, expected_url)
-
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/broken/instance_tests.py b/django-openstack/django_openstack/tests/broken/instance_tests.py
deleted file mode 100644
index 7f407d42..00000000
--- a/django-openstack/django_openstack/tests/broken/instance_tests.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for instance views.
-"""
-
-import boto.ec2.instance
-import mox
-
-from django.core.urlresolvers import reverse
-from django_openstack.nova.tests.base import (BaseProjectViewTests,
- TEST_PROJECT)
-
-
-TEST_INSTANCE_ID = 'i-abcdefgh'
-
-
-class InstanceViewTests(BaseProjectViewTests):
- def test_index(self):
- self.mox.StubOutWithMock(self.project, 'get_instances')
- self.project.get_instances().AndReturn([])
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_instances', args=[TEST_PROJECT]))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res,
- 'django_openstack/nova/instances/index.html')
- self.assertEqual(len(res.context['instances']), 0)
-
- self.mox.VerifyAll()
-
- def test_detail(self):
- instance = boto.ec2.instance.Instance()
- instance.id = TEST_INSTANCE_ID
- instance.displayName = instance.id
- instance.displayDescription = instance.id
-
- self.mox.StubOutWithMock(self.project, 'get_instance')
- self.project.get_instance(instance.id).AndReturn(instance)
- self.mox.StubOutWithMock(self.project, 'get_instances')
- self.project.get_instances().AndReturn([instance])
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_instances_detail',
- args=[TEST_PROJECT, TEST_INSTANCE_ID]))
- self.assertEqual(res.status_code, 200)
- self.assertTemplateUsed(res,
- 'django_openstack/nova/instances/index.html')
- self.assertEqual(res.context['selected_instance'].id, instance.id)
-
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/broken/keypair_tests.py b/django-openstack/django_openstack/tests/broken/keypair_tests.py
deleted file mode 100644
index 130e2feb..00000000
--- a/django-openstack/django_openstack/tests/broken/keypair_tests.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for key pair views.
-"""
-
-import boto.ec2.keypair
-import mox
-
-from django.core.urlresolvers import reverse
-from django_openstack.nova.tests.base import (BaseProjectViewTests,
- TEST_PROJECT)
-
-
-TEST_KEY = 'test_key'
-
-
-class KeyPairViewTests(BaseProjectViewTests):
- def test_index(self):
- self.mox.StubOutWithMock(self.project, 'get_key_pairs')
- self.project.get_key_pairs().AndReturn([])
-
- self.mox.ReplayAll()
-
- response = self.client.get(reverse('nova_keypairs',
- args=[TEST_PROJECT]))
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(response,
- 'django_openstack/nova/keypairs/index.html')
- self.assertEqual(len(response.context['keypairs']), 0)
-
- self.mox.VerifyAll()
-
- def test_add_keypair(self):
- key = boto.ec2.keypair.KeyPair()
- key.name = TEST_KEY
-
- self.mox.StubOutWithMock(self.project, 'create_key_pair')
- self.project.create_key_pair(key.name).AndReturn(key)
- self.mox.StubOutWithMock(self.project, 'has_key_pair')
- self.project.has_key_pair(key.name).AndReturn(False)
-
- self.mox.ReplayAll()
-
- url = reverse('nova_keypairs_add', args=[TEST_PROJECT])
- data = {'js': '0', 'name': key.name}
- res = self.client.post(url, data)
- self.assertEqual(res.status_code, 200)
- self.assertEqual(res['Content-Type'], 'application/binary')
-
- self.mox.VerifyAll()
-
- def test_delete_keypair(self):
- self.mox.StubOutWithMock(self.project, 'delete_key_pair')
- self.project.delete_key_pair(TEST_KEY).AndReturn(None)
-
- self.mox.ReplayAll()
-
- data = {'key_name': TEST_KEY}
- url = reverse('nova_keypairs_delete', args=[TEST_PROJECT])
- res = self.client.post(url, data)
- self.assertRedirectsNoFollow(res, reverse('nova_keypairs',
- args=[TEST_PROJECT]))
-
- self.mox.VerifyAll()
-
- def test_download_keypair(self):
- material = 'abcdefgh'
- session = self.client.session
- session['key.%s' % TEST_KEY] = material
- session.save()
-
- res = self.client.get(reverse('nova_keypairs_download',
- args=['test', TEST_KEY]))
- self.assertEqual(res.status_code, 200)
- self.assertEqual(res['Content-Type'], 'application/binary')
- self.assertContains(res, material)
diff --git a/django-openstack/django_openstack/tests/broken/region_tests.py b/django-openstack/django_openstack/tests/broken/region_tests.py
deleted file mode 100644
index bf49cc57..00000000
--- a/django-openstack/django_openstack/tests/broken/region_tests.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for region views.
-"""
-
-from django.core.urlresolvers import reverse
-from django_openstack.nova.tests.base import BaseViewTests
-
-
-TEST_REGION = 'one'
-
-
-class RegionViewTests(BaseViewTests):
- def test_change(self):
- self.authenticateTestUser()
- session = self.client.session
- session['region'] = 'two'
- session.save()
-
- data = {'redirect_url': '/',
- 'region': TEST_REGION}
- res = self.client.post(reverse('region_change'), data)
- self.assertEqual(self.client.session['region'], TEST_REGION)
- self.assertRedirectsNoFollow(res, '/')
diff --git a/django-openstack/django_openstack/tests/broken/test_models.py b/django-openstack/django_openstack/tests/broken/test_models.py
deleted file mode 100644
index 8fed2501..00000000
--- a/django-openstack/django_openstack/tests/broken/test_models.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-import datetime
-import hashlib
-import mox
-import random
-
-from django import test
-from django.conf import settings
-from django.db.models.signals import post_save
-from django_openstack import models as nova_models
-from django_openstack import utils
-from django_openstack.core import connection
-from nova_adminclient import NovaAdminClient
-
-
-TEST_USER = 'testUser'
-TEST_PROJECT = 'testProject'
-TEST_AUTH_TOKEN = hashlib.sha1('').hexdigest()
-TEST_AUTH_DATE = utils.utcnow()
-TEST_BAD_AUTH_TOKEN = 'badToken'
-
-HOUR = datetime.timedelta(seconds=3600)
-AUTH_EXPIRATION_LENGTH = \
- datetime.timedelta(days=int(settings.CREDENTIAL_AUTHORIZATION_DAYS))
-
-
-class CredentialsAuthorizationTests(test.TestCase):
- @classmethod
- def setUpClass(cls):
- # these post_save methods interact with external resources, shut them
- # down to test credentials
- post_save.disconnect(sender=nova_models.CredentialsAuthorization,
- dispatch_uid='django_openstack.CredentialsAuthorization.post_save')
- post_save.disconnect(sender=nova_models.CredentialsAuthorization,
- dispatch_uid='django_openstack.User.post_save')
-
- def setUp(self):
- test_cred = nova_models.CredentialsAuthorization()
- test_cred.username = TEST_USER
- test_cred.project = TEST_PROJECT
- test_cred.auth_date = TEST_AUTH_DATE
- test_cred.auth_token = TEST_AUTH_TOKEN
- test_cred.save()
-
- badTestCred = nova_models.CredentialsAuthorization()
- badTestCred.username = TEST_USER
- badTestCred.project = TEST_PROJECT
- badTestCred.auth_date = TEST_AUTH_DATE
- badTestCred.auth_token = TEST_BAD_AUTH_TOKEN
- badTestCred.save()
-
- self.mox = mox.Mox()
-
- def tearDown(self):
- self.mox.UnsetStubs()
-
- def test_get_by_token(self):
- TEST_MISSING_AUTH_TOKEN = hashlib.sha1('notAToken').hexdigest()
-
- # Token not a sha1, but exists in system
- cred = nova_models.CredentialsAuthorization.get_by_token(
- TEST_BAD_AUTH_TOKEN)
- self.assertTrue(cred is None)
-
- # Token doesn't exist
- cred = nova_models.CredentialsAuthorization.get_by_token(
- TEST_MISSING_AUTH_TOKEN)
- self.assertTrue(cred is None)
-
- # Good token
- cred = nova_models.CredentialsAuthorization.get_by_token(
- TEST_AUTH_TOKEN)
- self.assertTrue(cred is not None)
-
- # Expire the token
- cred.auth_date = utils.utcnow() - AUTH_EXPIRATION_LENGTH \
- - HOUR
- cred.save()
-
- # Expired token
- cred = nova_models.CredentialsAuthorization.get_by_token(
- TEST_AUTH_TOKEN)
- self.assertTrue(cred is None)
-
- def test_authorize(self):
- TEST_USER2 = TEST_USER + '2'
- TEST_AUTH_TOKEN_2 = hashlib.sha1('token2').hexdigest()
-
- cred_class = nova_models.CredentialsAuthorization
- self.mox.StubOutWithMock(cred_class, 'create_auth_token')
- cred_class.create_auth_token(TEST_USER2).AndReturn(
- TEST_AUTH_TOKEN_2)
-
- self.mox.ReplayAll()
-
- cred = cred_class.authorize(TEST_USER2, TEST_PROJECT)
-
- self.mox.VerifyAll()
-
- self.assertTrue(cred is not None)
- self.assertEqual(cred.username, TEST_USER2)
- self.assertEqual(cred.project, TEST_PROJECT)
- self.assertEqual(cred.auth_token, TEST_AUTH_TOKEN_2)
- self.assertFalse(cred.auth_token_expired())
-
- cred = cred_class.get_by_token(TEST_AUTH_TOKEN_2)
- self.assertTrue(cred is not None)
-
- def test_create_auth_token(self):
- rand_state = random.getstate()
- expected_salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
- expected_token = hashlib.sha1(expected_salt + TEST_USER).hexdigest()
-
- random.setstate(rand_state)
- auth_token = \
- nova_models.CredentialsAuthorization.create_auth_token(TEST_USER)
- self.assertEqual(expected_token, auth_token)
-
- def test_auth_token_expired(self):
- '''
- Test expired in past, expires in future, expires _right now_
- '''
- cred = \
- nova_models.CredentialsAuthorization.get_by_token(TEST_AUTH_TOKEN)
-
- cred.auth_date = utils.utcnow() - AUTH_EXPIRATION_LENGTH \
- - HOUR
- self.assertTrue(cred.auth_token_expired())
-
- cred.auth_date = utils.utcnow()
-
- self.assertFalse(cred.auth_token_expired())
-
- # testing with time is tricky. Mock out "right now" test to avoid
- # timing issues
- time = utils.utcnow.override_time = utils.utcnow()
- cred.auth_date = time - AUTH_EXPIRATION_LENGTH
-
- self.assertTrue(cred.auth_token_expired())
-
- utils.utcnow.override_time = None
-
- def test_get_download_url(self):
- cred = \
- nova_models.CredentialsAuthorization.get_by_token(TEST_AUTH_TOKEN)
-
- expected_url = settings.CREDENTIAL_DOWNLOAD_URL + TEST_AUTH_TOKEN
- self.assertEqual(expected_url, cred.get_download_url())
-
- def test_get_zip(self):
- cred = \
- nova_models.CredentialsAuthorization.get_by_token(TEST_AUTH_TOKEN)
-
- admin_mock = self.mox.CreateMock(NovaAdminClient)
-
- self.mox.StubOutWithMock(connection, 'get_nova_admin_connection')
- connection.get_nova_admin_connection().AndReturn(admin_mock)
-
- admin_mock.get_zip(TEST_USER, TEST_PROJECT)
-
- self.mox.ReplayAll()
-
- cred.get_zip()
-
- self.mox.VerifyAll()
-
- cred = \
- nova_models.CredentialsAuthorization.get_by_token(TEST_AUTH_TOKEN)
-
- self.assertTrue(cred is None)
diff --git a/django-openstack/django_openstack/tests/broken/volume_tests.py b/django-openstack/django_openstack/tests/broken/volume_tests.py
deleted file mode 100644
index b4ca10e3..00000000
--- a/django-openstack/django_openstack/tests/broken/volume_tests.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# 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.
-
-"""
-Unit tests for volume views.
-"""
-
-import boto.ec2.volume
-import mox
-
-from django.core.urlresolvers import reverse
-from django_openstack.nova import forms
-from django_openstack.nova.tests.base import (BaseProjectViewTests,
- TEST_PROJECT)
-
-
-TEST_VOLUME = 'vol-0000001'
-
-
-class VolumeTests(BaseProjectViewTests):
- def test_index(self):
- instance_id = 'i-abcdefgh'
-
- volume = boto.ec2.volume.Volume()
- volume.id = TEST_VOLUME
- volume.displayName = TEST_VOLUME
- volume.size = 1
-
- self.mox.StubOutWithMock(self.project, 'get_volumes')
- self.mox.StubOutWithMock(forms, 'get_available_volume_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_choices')
- self.project.get_volumes().AndReturn([])
- forms.get_available_volume_choices(mox.IgnoreArg()).AndReturn(
- self.create_available_volume_choices([volume]))
- forms.get_instance_choices(mox.IgnoreArg()).AndReturn(
- self.create_instance_choices([instance_id]))
-
- self.mox.ReplayAll()
-
- response = self.client.get(reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.assertEqual(response.status_code, 200)
- self.assertTemplateUsed(response,
- 'django_openstack/nova/volumes/index.html')
- self.assertEqual(len(response.context['volumes']), 0)
-
- self.mox.VerifyAll()
-
- def test_add_get(self):
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_volumes_add', args=[TEST_PROJECT]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_add_post(self):
- vol = boto.ec2.volume.Volume()
- vol.name = TEST_VOLUME
- vol.displayName = TEST_VOLUME
- vol.size = 1
-
- self.mox.StubOutWithMock(self.project, 'create_volume')
- self.project.create_volume(vol.size, vol.name, vol.name).AndReturn(vol)
-
- self.mox.ReplayAll()
-
- url = reverse('nova_volumes_add', args=[TEST_PROJECT])
- data = {'size': '1',
- 'nickname': TEST_VOLUME,
- 'description': TEST_VOLUME}
- res = self.client.post(url, data)
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_delete_get(self):
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_volumes_delete',
- args=[TEST_PROJECT, TEST_VOLUME]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_delete_post(self):
- self.mox.StubOutWithMock(self.project, 'delete_volume')
- self.project.delete_volume(TEST_VOLUME).AndReturn(True)
-
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('nova_volumes_delete',
- args=[TEST_PROJECT, TEST_VOLUME]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_attach_get(self):
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_volumes_attach',
- args=[TEST_PROJECT]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_attach_post(self):
- volume = boto.ec2.volume.Volume()
- volume.id = TEST_VOLUME
- volume.displayName = TEST_VOLUME
- volume.size = 1
-
- instance_id = 'i-abcdefgh'
- device = '/dev/vdb'
-
- self.mox.StubOutWithMock(self.project, 'attach_volume')
- self.mox.StubOutWithMock(forms, 'get_available_volume_choices')
- self.mox.StubOutWithMock(forms, 'get_instance_choices')
- self.project.attach_volume(TEST_VOLUME, instance_id, device) \
- .AndReturn(True)
- forms.get_available_volume_choices(mox.IgnoreArg()).AndReturn(
- self.create_available_volume_choices([volume]))
- forms.get_instance_choices(mox.IgnoreArg()).AndReturn(
- self.create_instance_choices([instance_id]))
-
- self.mox.ReplayAll()
-
- url = reverse('nova_volumes_attach', args=[TEST_PROJECT])
- data = {'volume': TEST_VOLUME,
- 'instance': instance_id,
- 'device': device}
- res = self.client.post(url, data)
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_detach_get(self):
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('nova_volumes_detach',
- args=[TEST_PROJECT, TEST_VOLUME]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
-
- def test_detach_post(self):
- self.mox.StubOutWithMock(self.project, 'detach_volume')
- self.project.detach_volume(TEST_VOLUME).AndReturn(True)
-
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('nova_volumes_detach',
- args=[TEST_PROJECT, TEST_VOLUME]))
- self.assertRedirectsNoFollow(res, reverse('nova_volumes',
- args=[TEST_PROJECT]))
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/context_processor_tests.py b/django-openstack/django_openstack/tests/context_processor_tests.py
deleted file mode 100644
index 33584586..00000000
--- a/django-openstack/django_openstack/tests/context_processor_tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from django_openstack import context_processors, test
-
-
-class ContextProcessorTests(test.TestCase):
- def setUp(self):
- super(ContextProcessorTests, self).setUp()
- self._prev_catalog = self.request.user.service_catalog
-
- def tearDown(self):
- super(ContextProcessorTests, self).tearDown()
- self.request.user.service_catalog = self._prev_catalog
-
- def test_object_store(self):
- # Returns the object store service data when it's in the catalog
- object_store = context_processors.object_store(self.request)
- self.assertNotEqual(None, object_store['object_store_configured'])
-
- # Returns None when the object store is not in the catalog
- new_catalog = [service for service in self.request.user.service_catalog
- if service['type'] != 'object-store']
- self.request.user.service_catalog = new_catalog
- object_store = context_processors.object_store(self.request)
- self.assertEqual(None, object_store['object_store_configured'])
diff --git a/django-openstack/django_openstack/tests/templatetag_tests.py b/django-openstack/django_openstack/tests/templatetag_tests.py
deleted file mode 100644
index 7ca198e2..00000000
--- a/django-openstack/django_openstack/tests/templatetag_tests.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import re
-
-from django import dispatch, http, template
-from django.utils.text import normalize_newlines
-
-from django_openstack import signals, test
-
-
-def single_line(text):
- ''' Quick utility to make comparing template output easier. '''
- return re.sub(' +',
- ' ',
- normalize_newlines(text).replace('\n', '')).strip()
-
-
-class TemplateTagTests(test.TestCase):
- def setUp(self):
- super(TemplateTagTests, self).setUp()
- self._signal = self.mox.CreateMock(dispatch.Signal)
-
- def test_sidebar_modules(self):
- '''
- Tests for the sidebar module registration mechanism.
-
- The standard "ping" signal return value looks like this:
-
- tuple(<dash_apps_ping>, {
- 'title': 'Nixon',
- 'links': [{'url':'/syspanel/nixon/google',
- 'text':'Google', 'active_text': 'google'}],
- 'type': 'syspanel',
- })
- '''
- self.mox.StubOutWithMock(signals, 'dash_modules_detect')
- signals_call = (
- (self._signal, {
- 'title': 'Nixon',
- 'links': [{'url':'/dash/nixon/google',
- 'text':'Google', 'active_text': 'google'}],
- 'type': 'dash',
- }),
- (self._signal, {
- 'title': 'Nixon',
- 'links': [{'url':'/syspanel/nixon/google',
- 'text':'Google', 'active_text': 'google'}],
- 'type': 'syspanel',
- }),
- )
- signals.dash_modules_detect().AndReturn(signals_call)
- signals.dash_modules_detect().AndReturn(signals_call)
- self.mox.ReplayAll()
-
- context = template.Context({'request': self.request})
-
- # Dash module is rendered correctly, and only in dash sidebar
- ttext = '{% load sidebar_modules %}{% dash_sidebar_modules request %}'
- t = template.Template(ttext)
- self.assertEqual(single_line(t.render(context)),
- '<h3>Nixon</h3> <ul class="sub_nav"> <li>'
- '<a href="/dash/nixon/google">Google</a></li> </ul>')
-
- # Syspanel module is rendered correctly and only in syspanel sidebar
- ttext = ('{% load sidebar_modules %}'
- '{% syspanel_sidebar_modules request %}')
- t = template.Template(ttext)
- self.assertEqual(single_line(t.render(context)),
- '<h3>Nixon</h3> <ul class="sub_nav"> <li>'
- '<a href="/syspanel/nixon/google">Google</a></li>'
- ' </ul>')
-
- self.mox.VerifyAll()
diff --git a/django-openstack/django_openstack/tests/view_tests/base.py b/django-openstack/django_openstack/tests/view_tests/base.py
deleted file mode 100644
index 8ec5f419..00000000
--- a/django-openstack/django_openstack/tests/view_tests/base.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula Inc.
-#
-# 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.
-
-"""
-Base classes for view based unit tests.
-"""
-from django import http
-from django import shortcuts
-from django import test as django_test
-from django import template as django_template
-from django.conf import settings
-from django_openstack import test
-
-
-def fake_render_to_response(template_name, context, context_instance=None,
- mimetype='text/html'):
- """Replacement for render_to_response so that views can be tested
- without having to stub out templates that belong in the frontend
- implementation.
-
- Should be able to be tested using the django unit test assertions like a
- normal render_to_response return value can be.
- """
- class Template(object):
- def __init__(self, name):
- self.name = name
-
- if context_instance is None:
- context_instance = django_template.Context(context)
- else:
- context_instance.update(context)
-
- resp = http.HttpResponse()
- template = Template(template_name)
-
- resp.write('<html><body><p>'
- 'This is a fake httpresponse for testing purposes only'
- '</p></body></html>')
-
- # Allows django.test.client to populate fields on the response object
- django_test.signals.template_rendered.send(template, template=template,
- context=context_instance)
-
- return resp
-
-
-class BaseViewTests(test.TestCase):
- def setUp(self):
- super(BaseViewTests, self).setUp()
- self._real_render_to_response = shortcuts.render_to_response
- shortcuts.render_to_response = fake_render_to_response
-
- def tearDown(self):
- super(BaseViewTests, self).tearDown()
- shortcuts.render_to_response = self._real_render_to_response
-
- def assertRedirectsNoFollow(self, response, expected_url):
- self.assertEqual(response._headers['location'],
- ('Location', settings.TESTSERVER + expected_url))
- self.assertEqual(response.status_code, 302)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/container_tests.py b/django-openstack/django_openstack/tests/view_tests/dash/container_tests.py
deleted file mode 100644
index f9b03ea7..00000000
--- a/django-openstack/django_openstack/tests/view_tests/dash/container_tests.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from cloudfiles.errors import ContainerNotEmpty
-from django import http
-from django.contrib import messages
-from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
-from mox import IgnoreArg, IsA
-
-
-class ContainerViewTests(base.BaseViewTests):
- def setUp(self):
- super(ContainerViewTests, self).setUp()
- self.container = self.mox.CreateMock(api.Container)
- self.container.name = 'containerName'
-
- def test_index(self):
- self.mox.StubOutWithMock(api, 'swift_get_containers')
- api.swift_get_containers(
- IsA(http.HttpRequest), marker=None).AndReturn([self.container])
-
- self.mox.ReplayAll()
-
- res = self.client.get(reverse('dash_containers', args=['tenant']))
-
- self.assertTemplateUsed(res,
- 'django_openstack/dash/containers/index.html')
- self.assertIn('containers', res.context)
- containers = res.context['containers']
-
- self.assertEqual(len(containers), 1)
- self.assertEqual(containers[0].name, 'containerName')
-
- self.mox.VerifyAll()
-
- def test_delete_container(self):
- formData = {'container_name': 'containerName',
- 'method': 'DeleteContainer'}
-
- self.mox.StubOutWithMock(api, 'swift_delete_container')
- api.swift_delete_container(IsA(http.HttpRequest),
- 'containerName')
-
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('dash_containers', args=['tenant']),
- formData)
-
- self.assertRedirectsNoFollow(res, reverse('dash_containers',
- args=['tenant']))
-
- self.mox.VerifyAll()
-
- def test_delete_container_nonempty(self):
- formData = {'container_name': 'containerName',
- 'method': 'DeleteContainer'}
-
- exception = ContainerNotEmpty('containerNotEmpty')
-
- self.mox.StubOutWithMock(api, 'swift_delete_container')
- api.swift_delete_container(
- IsA(http.HttpRequest),
- 'containerName').AndRaise(exception)
-
- self.mox.StubOutWithMock(messages, 'error')
-
- messages.error(IgnoreArg(), IsA(unicode))
-
- self.mox.ReplayAll()
-
- res = self.client.post(reverse('dash_containers', args=['tenant']),
- formData)
-
- self.assertRedirectsNoFollow(res, reverse('dash_containers',
- args=['tenant']))
-
- self.mox.VerifyAll()
-
- def test_create_container_get(self):
- res = self.client.get(reverse('dash_containers_create',
- args=['tenant']))
-
- self.assertTemplateUsed(res,
- 'django_openstack/dash/containers/create.html')
-
- def test_create_container_post(self):
- formData = {'name': 'containerName',
- 'method': 'CreateContainer'}
-
- self.mox.StubOutWithMock(api, 'swift_create_container')
- api.swift_create_container(
- IsA(http.HttpRequest), 'CreateContainer')
-
- self.mox.StubOutWithMock(messages, 'success')
- messages.success(IgnoreArg(), IsA(basestring))
-
- res = self.client.post(reverse('dash_containers_create',
- args=[self.request.user.tenant_id]),
- formData)
-
- self.assertRedirectsNoFollow(res, reverse('dash_containers',
- args=[self.request.user.tenant_id]))
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/port_tests.py b/django-openstack/django_openstack/tests/view_tests/dash/port_tests.py
deleted file mode 100644
index 5d5d827d..00000000
--- a/django-openstack/django_openstack/tests/view_tests/dash/port_tests.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django import http
-from django.contrib import messages
-from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
-from mox import IgnoreArg, IsA
-import quantum.client
-
-
-class PortViewTests(base.BaseViewTests):
- def setUp(self):
- super(PortViewTests, self).setUp()
-
- def test_port_create(self):
- self.mox.StubOutWithMock(api, "quantum_create_port")
- api.quantum_create_port(IsA(http.HttpRequest), 'n1').AndReturn(True)
-
- formData = {'ports_num': 1,
- 'network': 'n1',
- 'method': 'CreatePort'}
-
- self.mox.StubOutWithMock(messages, 'success')
- messages.success(IgnoreArg(), IsA(basestring))
-
- res = self.client.post(reverse('dash_ports_create',
- args=[self.request.user.tenant_id, "n1"]),
- formData)
-
- self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
- args=[self.request.user.tenant_id,
- "n1"]))
-
- def test_port_delete(self):
- self.mox.StubOutWithMock(api, "quantum_delete_port")
- api.quantum_delete_port(IsA(http.HttpRequest),
- 'n1', 'p1').AndReturn(True)
-
- formData = {'port': 'p1',
- 'network': 'n1',
- 'method': 'DeletePort'}
-
- self.mox.StubOutWithMock(messages, 'success')
- messages.success(IgnoreArg(), IsA(basestring))
-
- res = self.client.post(reverse('dash_networks_detail',
- args=[self.request.user.tenant_id, "n1"]),
- formData)
-
- def test_port_attach(self):
- self.mox.StubOutWithMock(api, "quantum_attach_port")
- api.quantum_attach_port(IsA(http.HttpRequest),
- 'n1', 'p1', dict).AndReturn(True)
-
- formData = {'port': 'p1',
- 'network': 'n1',
- 'vif_id': 'v1',
- 'method': 'AttachPort'}
-
- self.mox.StubOutWithMock(messages, 'success')
- messages.success(IgnoreArg(), IsA(basestring))
-
- res = self.client.post(reverse('dash_ports_attach',
- args=[self.request.user.tenant_id, "n1", "p1"]),
- formData)
-
- self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
- args=[self.request.user.tenant_id,
- "n1"]))
-
- def test_port_detach(self):
- self.mox.StubOutWithMock(api, "quantum_detach_port")
- api.quantum_detach_port(IsA(http.HttpRequest),
- 'n1', 'p1').AndReturn(True)
-
- formData = {'port': 'p1',
- 'network': 'n1',
- 'method': 'DetachPort'}
-
- self.mox.StubOutWithMock(messages, 'success')
- messages.success(IgnoreArg(), IsA(basestring))
-
- res = self.client.post(reverse('dash_networks_detail',
- args=[self.request.user.tenant_id, "n1"]),
- formData)
diff --git a/django-openstack/django_openstack/urls.py b/django-openstack/django_openstack/urls.py
deleted file mode 100644
index d3b1f505..00000000
--- a/django-openstack/django_openstack/urls.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-from django.conf.urls.defaults import patterns, url, include
-from django.conf import settings
-from django_openstack.signals import *
-from django.views.generic import TemplateView
-
-urlpatterns = patterns('',
- url(r'^auth/', include('django_openstack.auth.urls')),
- url(r'^dash/', include('django_openstack.dash.urls')),
- url(r'^syspanel/', include('django_openstack.syspanel.urls')),
- url(r'^settings/$', TemplateView.as_view(
- template_name='django_openstack/dash/settings.html'),
- name='dashboard_settings')
-
-)
-
-# import urls from modules
-for module_urls in dash_modules_urls.send(sender=dash_modules_urls):
- urlpatterns += module_urls[1].urlpatterns
diff --git a/django-openstack/django_openstack/utils.py b/django-openstack/django_openstack/utils.py
deleted file mode 100644
index 573e7be4..00000000
--- a/django-openstack/django_openstack/utils.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-import datetime
-
-
-def time():
- '''Overrideable version of datetime.datetime.today'''
- if time.override_time:
- return time.override_time
- return datetime.time()
-
-time.override_time = None
-
-
-def today():
- '''Overridable version of datetime.datetime.today'''
- if today.override_time:
- return today.override_time
- return datetime.datetime.today()
-
-today.override_time = None
-
-
-def utcnow():
- '''Overridable version of datetime.datetime.utcnow'''
- if utcnow.override_time:
- return utcnow.override_time
- return datetime.datetime.utcnow()
-
-utcnow.override_time = None
diff --git a/doc/generate_autodoc_index.py b/doc/generate_autodoc_index.py
deleted file mode 100755
index 8abbeaf8..00000000
--- a/doc/generate_autodoc_index.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-"""Generates files for sphinx documentation using a simple Autodoc based
-template.
-
-To use, just run as a script:
- $ python doc/generate_autodoc_index.py
-"""
-
-import os
-
-
-base_dir = os.path.dirname(os.path.abspath(__file__))
-RSTDIR = os.path.join(base_dir, "source", "sourcecode")
-SRCS = {'dashboard': os.path.join(base_dir, "..", "openstack-dashboard"),
- 'django_openstack': os.path.join(base_dir, "..", "django-openstack")}
-
-
-def find_autodoc_modules(module_name, sourcedir):
- """returns a list of modules in the SOURCE directory"""
- modlist = []
- os.chdir(os.path.join(sourcedir, module_name))
- print "SEARCHING %s" % sourcedir
- for root, dirs, files in os.walk("."):
- for filename in files:
- if filename.endswith(".py"):
- # root = ./dashboard/test/unit
- # filename = base.py
- # remove the pieces of the root
- elements = root.split(os.path.sep)
- # replace the leading "." with the module name
- elements[0] = module_name
- # and get the base module name
- base, extension = os.path.splitext(filename)
- if not (base == "__init__"):
- elements.append(base)
- result = ".".join(elements)
- #print result
- modlist.append(result)
- return modlist
-
-if not(os.path.exists(RSTDIR)):
- os.mkdir(RSTDIR)
-
-INDEXOUT = open("%s/autoindex.rst" % RSTDIR, "w")
-INDEXOUT.write("Source Code Index\n")
-INDEXOUT.write("=================\n")
-INDEXOUT.write(".. toctree::\n")
-INDEXOUT.write(" :maxdepth: 1\n")
-INDEXOUT.write("\n")
-
-for modulename in SRCS:
- for module in find_autodoc_modules(modulename, SRCS[modulename]):
- generated_file = "%s/%s.rst" % (RSTDIR, module)
- print "Generating %s" % generated_file
-
- INDEXOUT.write(" %s\n" % module)
- FILEOUT = open(generated_file, "w")
- FILEOUT.write("The :mod:`%s` Module\n" % module)
- FILEOUT.write("=============================="
- "=============================="
- "==============================\n")
- FILEOUT.write(".. automodule:: %s\n" % module)
- FILEOUT.write(" :members:\n")
- FILEOUT.write(" :undoc-members:\n")
- FILEOUT.write(" :show-inheritance:\n")
- FILEOUT.close()
-
-INDEXOUT.close()
diff --git a/doc/source/index.rst b/doc/source/index.rst
deleted file mode 100644
index cb6e3278..00000000
--- a/doc/source/index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-..
- 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.
-
-========================
-Horizon for Contributors
-========================
-
-Horizon is the canonical implementation of `Openstack's Dashboard
-<https://github.com/openstack/horizon>`_, which provides a web based user
-interface to OpenStack services including Nova, Swift, Keystone, and Quantum.
-
-This document describes horizon for contributors of the project.
-
-Project Structure
-=================
-
-This project is a bit different from other Openstack projects in that it has
-two very distinct components underneath it:
-
-* django-openstack
-* openstack-dashboard
-
-Django-openstack holds the generic libraries and components that can be
-used in any Django project. In testing, this component is set up with
-buildout (see run_tests.sh), and any dependencies that get added need to
-be added to the django-openstack/buildout.cfg file.
-
-Openstack-dashboard is a reference django project that uses django-openstack
-and is built with a virtualenv and tested through that environment. If
-depdendencies are added that the reference django project needs, they
-should be added to openstack-dashboard/tools/pip-requires.
-
-Contents:
----------
-
-.. toctree::
- :maxdepth: 1
-
- testing
-
-Developer Docs
---------------
-
-.. toctree::
- :maxdepth: 1
-
- sourcecode/autoindex
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
diff --git a/doc/source/testing.rst b/doc/source/testing.rst
deleted file mode 100644
index bab32a82..00000000
--- a/doc/source/testing.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-..
- 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.
-
-=====================
-Testing the Dashboard
-=====================
-
-Testing the dashbaord is a bit more complex due to having the two projects
-in the same repository.
-
-The run_tests.sh script invokes tests and analysis on both of these
-components in it's process, and is what Jenkins uses to verify the
-stability of the project.
-
-To run the tests::
-
- $ ./run_tests.sh
-
-
diff --git a/doc/Makefile b/docs/Makefile
index 986ad3df..986ad3df 100644
--- a/doc/Makefile
+++ b/docs/Makefile
diff --git a/django-openstack/django_openstack/__init__.py b/docs/source/_static/.gitignore
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/__init__.py
+++ b/docs/source/_static/.gitignore
diff --git a/doc/source/conf.py b/docs/source/conf.py
index 164c6560..a1f7a3a8 100644
--- a/doc/source/conf.py
+++ b/docs/source/conf.py
@@ -12,7 +12,93 @@
# serve to show the default.
import sys, os
-from django_openstack import version as horizon_version
+import horizon.version
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+HORIZON_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "horizon"))
+DASHBOARD_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "openstack-dashboard"))
+
+sys.path.insert(0, HORIZON_DIR)
+sys.path.insert(0, DASHBOARD_DIR)
+
+def write_autodoc_index():
+
+ def find_autodoc_modules(module_name, sourcedir):
+ """returns a list of modules in the SOURCE directory"""
+ modlist = []
+ os.chdir(os.path.join(sourcedir, module_name))
+ print "SEARCHING %s" % sourcedir
+ for root, dirs, files in os.walk("."):
+ for filename in files:
+ if filename.endswith(".py"):
+ # root = ./dashboard/test/unit
+ # filename = base.py
+ # remove the pieces of the root
+ elements = root.split(os.path.sep)
+ # replace the leading "." with the module name
+ elements[0] = module_name
+ # and get the base module name
+ base, extension = os.path.splitext(filename)
+ if not (base == "__init__"):
+ elements.append(base)
+ result = ".".join(elements)
+ #print result
+ modlist.append(result)
+ return modlist
+
+ RSTDIR = os.path.abspath(os.path.join(BASE_DIR, "sourcecode"))
+ SRCS = {'horizon': HORIZON_DIR,
+ 'dashboard': DASHBOARD_DIR}
+
+ if not(os.path.exists(RSTDIR)):
+ os.mkdir(RSTDIR)
+
+ INDEXOUT = open(os.path.join(RSTDIR, "autoindex.rst"), "w")
+ INDEXOUT.write("=================\n")
+ INDEXOUT.write("Source Code Index\n")
+ INDEXOUT.write("=================\n")
+
+ for modulename, path in SRCS.items():
+ sys.stdout.write("Generating source documentation for %s\n" % modulename)
+ INDEXOUT.write("\n%s\n" % modulename.capitalize())
+ INDEXOUT.write("%s\n" % ("=" * len(modulename),))
+ INDEXOUT.write(".. toctree::\n")
+ INDEXOUT.write(" :maxdepth: 1\n")
+ INDEXOUT.write("\n")
+ if not(os.path.exists(os.path.join(RSTDIR, modulename))):
+ os.mkdir(os.path.join(RSTDIR, modulename))
+ for module in find_autodoc_modules(modulename, path):
+ mod_path = os.path.join(path, *module.split("."))
+ generated_file = os.path.join(RSTDIR, modulename, "%s.rst" % module)
+
+ INDEXOUT.write(" %s/%s\n" % (modulename, module))
+
+ # Find the __init__.py module if this is a directory
+ if os.path.isdir(mod_path):
+ source_file = ".".join((os.path.join(mod_path, "__init__"), "py",))
+ else:
+ source_file = ".".join((os.path.join(mod_path), "py"))
+
+ # Only generate a new file if the source has changed or we don't
+ # have a doc file to begin with.
+ if not os.access(generated_file, os.F_OK) or \
+ os.stat(generated_file).st_mtime < os.stat(source_file).st_mtime:
+ print "Module %s updated, generating new documentation." % module
+ FILEOUT = open(generated_file, "w")
+ header = "The :mod:`%s` Module" % module
+ FILEOUT.write("%s\n" % ("=" * len(header),))
+ FILEOUT.write("%s\n" % header)
+ FILEOUT.write("%s\n" % ("=" * len(header),))
+ FILEOUT.write(".. automodule:: %s\n" % module)
+ FILEOUT.write(" :members:\n")
+ FILEOUT.write(" :undoc-members:\n")
+ FILEOUT.write(" :show-inheritance:\n")
+ FILEOUT.write(" :noindex:\n")
+ FILEOUT.close()
+
+ INDEXOUT.close()
+
+write_autodoc_index()
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -57,9 +143,9 @@ copyright = u'2011, OpenStack, LLC'
# built documents.
#
# The short X.Y version.
-version = horizon_version.canonical_version_string()
+version = horizon.version.canonical_version_string()
# The full version, including alpha/beta/rc tags.
-release = horizon_version.canonical_version_string()
+release = horizon.version.canonical_version_string()
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -95,6 +181,9 @@ pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
+primary_domain = 'py'
+nitpicky = False
+
# -- Options for HTML output ---------------------------------------------------
@@ -295,6 +384,7 @@ epub_copyright = u'2011, OpenStack'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
+ 'django': ('http://docs.djangoproject.com/en/dev/_objects/'),
'nova': ('http://nova.openstack.org', None),
'swift': ('http://swift.openstack.org', None),
'keystone': ('http://keystone.openstack.org', None),
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
new file mode 100644
index 00000000..26836ef6
--- /dev/null
+++ b/docs/source/faq.rst
@@ -0,0 +1,37 @@
+==========================
+Frequently Asked Questions
+==========================
+
+What is the relationship between ``Dashboards``, ``Panels``, and navigation?
+
+ The navigational structure is strongly encouraged to flow from
+ ``Dashboard`` objects as top-level navigation items to ``Panel`` objects as
+ sub-navigation items as in the current implementation. Template tags
+ are provided to automatically generate this structure.
+
+ That said, you are not required to use the provided tools and can write
+ templates and URLconfs by hand to create any desired structure.
+
+Does a panel have to be an app in ``INSTALLED_APPS``?
+
+ A panel can live in any Python module. It can be a standalone which ties
+ into an existing dashboard, or it can be contained alongside others within
+ a larger dashboard "app". There is no strict enforcement here. Python
+ is "a language for consenting adults." A module containing a Panel does
+ not need to be added to ``INSTALLED_APPS``, but this is a common and
+ convenient way to load a standalone panel.
+
+Could I hook an external service into a panel using, for example, an iFrame?
+
+ Panels are just entry-points to hook views into the larger dashboard
+ navigational structure and enforce common attributes like RBAC. The
+ view and corresponding templates can contain anything you would like,
+ including iFrames.
+
+What does this mean for visual design?
+
+ The ability to add an arbitrary number of top-level navigational items
+ (``Dashboard`` objects) poses a new design challenge. Horizon's lead
+ designer has taken on the challenge of providing a reference design
+ for Horizon which supports this possibility.
+
diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst
new file mode 100644
index 00000000..cca87400
--- /dev/null
+++ b/docs/source/glossary.rst
@@ -0,0 +1,19 @@
+========
+Glossary
+========
+
+Horizon
+
+ The OpenStack dashboard project. Also the name of the top-level
+ Python object which handles registration for the app.
+
+Dashboard
+
+ A Python class representing a top-level navigation item (e.g. "syspanel")
+ which provides a consistent API for Horizon-compatible applications.
+
+Panel
+
+ A Python class representing a sub-navigation item (e.g. "instances")
+ which contains all the necessary logic (views, forms, tests, etc.) for
+ that interface.
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 00000000..c326d6de
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,101 @@
+..
+ 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.
+
+========================================
+Horizon: The OpenStack Dashboard Project
+========================================
+
+Introduction
+============
+
+Horizon is the canonical implementation of `Openstack's Dashboard
+<https://github.com/openstack/horizon>`_, which provides a web based user
+interface to OpenStack services including Nova, Swift, Keystone, etc.
+
+For a more in-depth look at Horizon and it's architecture, see the
+:doc:`Introduction to Horizon <intro>`.
+
+To learn what you need to know to get going, see the :doc:`quickstart`.
+
+Getting Started With Horizon
+============================
+
+How to use Horizon in your own projects.
+
+.. toctree::
+ :maxdepth: 1
+
+ intro
+ quickstart
+
+
+Developer Reference
+===================
+
+For those wishing to develop Horizon itself, or go in-depth with building
+your own :class:`~horizon.Dashboard` or :class:`~horizon.Panel` classes,
+the following documentation is provided.
+
+Topics
+------
+
+Brief guides to areas of interest and importance when developing Horizon.
+
+.. toctree::
+ :maxdepth: 1
+
+ testing
+
+API Reference
+-------------
+
+In-depth documentation for Horizon and it's APIs.
+
+.. toctree::
+ :maxdepth: 1
+
+ ref/run_tests
+ ref/horizon
+ ref/users
+ ref/forms
+ ref/views
+ ref/middleware
+ ref/context_processors
+ ref/decorators
+ ref/exceptions
+
+Source Code Reference
+---------------------
+
+Auto-generated reference for the complete source code.
+
+.. toctree::
+ :maxdepth: 1
+
+ sourcecode/autoindex
+
+
+Information
+===========
+
+.. toctree::
+ :maxdepth: 1
+
+ faq
+ glossary
+
+* :ref:`genindex`
+* :ref:`modindex`
diff --git a/docs/source/intro.rst b/docs/source/intro.rst
new file mode 100644
index 00000000..83f7819f
--- /dev/null
+++ b/docs/source/intro.rst
@@ -0,0 +1,124 @@
+===================
+Introducing Horizon
+===================
+
+.. contents:: Contents:
+ :local:
+
+Values
+======
+
+ "Think simple" as my old master used to say - meaning reduce
+ the whole of its parts into the simplest terms, getting back
+ to first principles.
+
+ -- Frank Lloyd Wright
+
+Horizon holds several key values at the core of it's design and architecture:
+
+ * Core Support: Out-of-the-box support for all core OpenStack projects.
+ * Extensible: Anyone can add a new component as a "first-class citizen".
+ * Manageable: The core codebase should be simple and easy-to-navigate.
+ * Consistent: Visual and interaction paradigms are maintained throughout.
+ * Stable: A reliable API with an emphasis on backwards-compatibility.
+ * Usable: Providing an *awesome* interface that people *want* to use.
+
+The only way to attain and uphold those ideals is to make it *easy* for
+developers to implement those values.
+
+History
+=======
+
+Horizon started life as a single app to manage OpenStack's compute project.
+As such, all it needed was a set of views, templates, and API calls.
+
+From there it grew to support multiple OpenStack projects and APIs gradually,
+arranged rigidly into "dash" and "syspanel" groupings.
+
+During the "Diablo" release cycle an initial plugin system was added using
+signals to hook in additional URL patterns and add links into the "dash"
+and "syspanel" navigation.
+
+This incremental growth served the goal of "Core Support" phenomenally, but
+left "Extensible" and "Manageable" behind. And while the other key values took
+shape of their own accord, it was time to re-architect for an extensible,
+modular future.
+
+
+The Current Architecture & How It Meets Our Values
+==================================================
+
+At it's core, **Horizon should be a registration pattern for
+applications to hook into**. Here's what that means and how it's
+implemented in terms of our values:
+
+Core Support
+------------
+
+Horizon ships with three central dashboards, a "User Dashboard", a
+"System Dashboard", and a "Settings" dashboard. Between these three they
+cover the core OpenStack applications and deliver on Core Support.
+
+The Horizon application also ships with a set of API abstractions
+for the core OpenStack projects in order to provide a consistent, stable set
+of reusable methods for developers. Using these abstractions, developers
+working on Horizon don't need to be intimately familiar with the APIs of
+each OpenStack project.
+
+Extensible
+----------
+
+A Horizon dashboard application is based around the :class:`~horizon.Dashboard`
+class that provides a consistent API and set of capabilities for both
+core OpenStack dashboard apps shipped with Horizon and equally for third-party
+apps. The :class:`~horizon.Dashboard` class is treated as a top-level
+navigation item.
+
+Should a developer wish to provide functionality within an existing dashboard
+(e.g. adding a monitoring panel to the user dashboard) the simple registration
+pattern makes it possible to write an app which hooks into other dashboards
+just as easily as creating a new dashboard. All you have to do is import the
+dashboard you wish to modify.
+
+Manageable
+----------
+
+Within the application, there is a simple method for registering a
+:class:`~horizon.Panel` (sub-navigation items). Each panel contains the
+necessary logic (views, forms, tests, etc.) for that interface. This granular
+breakdown prevents files (such as ``api.py``) from becoming thousands of
+lines long and makes code easy to find by correlating it directly to the
+navigation.
+
+Consistent
+----------
+
+By providing the necessary core classes to build from, as well as a
+solid set of reusable templates and additional tools (base form classes,
+base widget classes, template tags, and perhaps even class-based views)
+we can maintain consistency across applications.
+
+Stable
+------
+
+By architecting around these core classes and reusable components we
+create an implicit contract that changes to these components will be
+made in the most backwards-compatible ways whenever possible.
+
+Usable
+------
+
+Ultimately that's up to each and every developer that touches the code,
+but if we get all the other goals out of the way then we are free to focus
+on the best possible experience.
+
+.. seealso::
+
+ :doc:`Quickstart <quickstart>`
+ A short guide to getting started with using Horizon.
+
+ :doc:`Frequently Asked Questions <faq>`
+ Common questions and answers.
+
+ :doc:`Glossary <glossary>`
+ Common terms and their definitions.
diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst
new file mode 100644
index 00000000..2e010be9
--- /dev/null
+++ b/docs/source/quickstart.rst
@@ -0,0 +1,146 @@
+==================
+Horizon Quickstart
+==================
+
+Horizon's Structure
+===================
+
+This project is a bit different from other Openstack projects in that it is
+composed of two distinct components:
+
+ * ``horizon``
+ * ``openstack-dashboard``
+
+The ``horizon`` directory holds the generic libraries and components that can
+be used in any Django project. In testing, this component is set up with
+buildout (see :doc:`ref/run_tests`), and any dependencies that need to
+be added to the ``horizon/buildout.cfg`` file.
+
+The ``openstack-dashboard`` directory contains a reference Django project that
+uses ``horizon`` and is built with a virtualenv. If dependencies are added that
+``openstack-dashboard`` requires they should be added to ``openstack-
+dashboard/tools/pip-requires``.
+
+Project
+=======
+
+INSTALLED_APPS
+--------------
+
+At the project level you add Horizon and any desired dashboards to your
+``settings.INSTALLED_APPS``::
+
+ INSTALLED_APPS = (
+ 'django',
+ ...
+ 'horizon',
+ 'horizon.dash',
+ 'horizon.syspanel',
+ )
+
+URLs
+----
+
+Then you add a single line to your project's ``urls.py``::
+
+ url(r'', include(horizon.urls)),
+
+Those urls are automatically constructed based on the registered Horizon apps.
+If a different URL structure is desired it can be constructed by hand.
+
+Templates
+---------
+
+Pre-built template tags generate navigation. In your ``nav.html``
+template you might have the following::
+
+ {% load horizon %}
+
+ <div class='nav'>
+ {% horizon_main_nav %}
+ </div>
+
+And in your ``sidebar.html`` you might have::
+
+ {% load horizon %}
+
+ <div class='sidebar'>
+ {% horizon_dashboard_nav %}
+ </div>
+
+These template tags are aware of the current "active" dashboard and panel
+via template context variables and will render accordingly.
+
+Application
+===========
+
+Structure
+---------
+
+An application would have the following structure (we'll use syspanel as
+an example)::
+
+ syspanel/
+ |---__init__.py
+ |---dashboard.py <-----Registers the app with Horizon and sets dashboard properties
+ |---templates/
+ |---templatetags/
+ |---overview/
+ |---services/
+ |---images/
+ |---__init__.py
+ |---panel.py <-----Registers the panel in the app and defines panel properties
+ |---urls.py
+ |---views.py
+ |---forms.py
+ |---tests.py
+ |---api.py <-------Optional additional API methods for non-core services
+ |---templates/
+ ...
+ ...
+
+Dashboard Classes
+-----------------
+
+Inside of ``dashboard.py`` you would have a class definition and the registration
+process::
+
+ import horizon
+
+
+ class Syspanel(horizon.Dashboard):
+ name = "Syspanel" # Appears in navigation
+ slug = 'syspanel' # Appears in url
+ panels = ('overview', 'services', 'instances', 'flavors', 'images',
+ 'tenants', 'users', 'quotas',)
+ default_panel = 'overview'
+ roles = ('admin',) # Provides RBAC at the dashboard-level
+ ...
+
+
+ horizon.register(Syspanel)
+
+Panel Classes
+-------------
+
+To connect a :class:`~horizon.Panel` with a :class:`~horizon.Dashboard` class
+you register it in a ``panels.py`` file like so::
+
+ import horizon
+
+ from horizon.dashboard.syspanel import dashboard
+
+
+ class Images(horizon.Panel):
+ name = "Images"
+ slug = 'images'
+ roles = ('admin', 'my_other_role',) # Fine-grained RBAC per-panel
+
+
+ # You could also register your panel with another application's dashboard
+ dashboard.Syspanel.register(Images)
+
+By default a :class:`~horizon.Panel` class looks for a ``urls.py`` file in the
+same directory as ``panel.py`` to include in the rollup of url patterns from
+panels to dashboards to Horizon, resulting in a wholly extensible, configurable
+URL structure.
diff --git a/docs/source/ref/context_processors.rst b/docs/source/ref/context_processors.rst
new file mode 100644
index 00000000..b34c0109
--- /dev/null
+++ b/docs/source/ref/context_processors.rst
@@ -0,0 +1,6 @@
+==========================
+Horizon Context Processors
+==========================
+
+.. automodule:: horizon.context_processors
+ :members:
diff --git a/docs/source/ref/decorators.rst b/docs/source/ref/decorators.rst
new file mode 100644
index 00000000..777afbe5
--- /dev/null
+++ b/docs/source/ref/decorators.rst
@@ -0,0 +1,6 @@
+==================
+Horizon Decorators
+==================
+
+.. automodule:: horizon.decorators
+ :members:
diff --git a/docs/source/ref/exceptions.rst b/docs/source/ref/exceptions.rst
new file mode 100644
index 00000000..4151f18f
--- /dev/null
+++ b/docs/source/ref/exceptions.rst
@@ -0,0 +1,6 @@
+==================
+Horizon Exceptions
+==================
+
+.. automodule:: horizon.exceptions
+ :members:
diff --git a/docs/source/ref/forms.rst b/docs/source/ref/forms.rst
new file mode 100644
index 00000000..9b30cb8e
--- /dev/null
+++ b/docs/source/ref/forms.rst
@@ -0,0 +1,17 @@
+=============
+Horizon Forms
+=============
+
+Horizon ships with a number of form classes, some generic and some specific.
+
+Generic Forms
+=============
+
+.. automodule:: horizon.forms
+ :members:
+
+Auth Forms
+==========
+
+.. automodule:: horizon.views.auth_forms
+ :members:
diff --git a/docs/source/ref/horizon.rst b/docs/source/ref/horizon.rst
new file mode 100644
index 00000000..9206e950
--- /dev/null
+++ b/docs/source/ref/horizon.rst
@@ -0,0 +1,42 @@
+======================
+The ``horizon`` Module
+======================
+
+.. module:: horizon
+
+Horizon ships with a single point of contact for hooking into your project if
+you aren't developing your own :class:`~horizon.Dashboard` or
+:class:`~horizon.Panel`::
+
+ import horizon
+
+From there you can access all the key methods you need.
+
+Horizon
+=======
+
+.. attribute:: urls
+
+ The auto-generated URLconf for Horizon. Usage::
+
+ url(r'', include(horizon.urls)),
+
+.. autofunction:: register
+.. autofunction:: unregister
+.. autofunction:: get_absolute_url
+.. autofunction:: get_user_home
+.. autofunction:: get_dashboard
+.. autofunction:: get_default_dashboard
+.. autofunction:: get_dashboards
+
+Dashboard
+=========
+
+.. autoclass:: Dashboard
+ :members:
+
+Panel
+=====
+
+.. autoclass:: Panel
+ :members:
diff --git a/docs/source/ref/middleware.rst b/docs/source/ref/middleware.rst
new file mode 100644
index 00000000..fcca5ff0
--- /dev/null
+++ b/docs/source/ref/middleware.rst
@@ -0,0 +1,6 @@
+==================
+Horizon Middleware
+==================
+
+.. automodule:: horizon.middleware
+ :members:
diff --git a/docs/source/ref/run_tests.rst b/docs/source/ref/run_tests.rst
new file mode 100644
index 00000000..201198ed
--- /dev/null
+++ b/docs/source/ref/run_tests.rst
@@ -0,0 +1,100 @@
+===========================
+The ``run_tests.sh`` Script
+===========================
+
+Horizon ships with a script called ``run_tests.sh`` at the root of the
+repository. This script provides many crucial functions for the project,
+and also makes several otherwise complex tasks trivial for you as a
+developer.
+
+First Run
+=========
+
+If you start with a clean copy of the Horizon repository, the first thing
+you should do is to run ``./run_tests.sh`` from the root of the repository.
+This will do three things for you:
+
+ #. Set up a virtual environment for ``openstack-dashboard`` using
+ ``openstack-dashboard/tools/install_venv.py``.
+ #. Set up an environment for ``horizon`` using
+ ``horizon/bootstrap.py`` and ``horizon/bin/buildout``.
+ #. Run the tests for both ``horizon`` and ``openstack-dashboard`` using
+ their respective environments and verify that evreything is working.
+
+Setting up both environments the first time can take several minutes, but only
+needs to be done once. If dependencies are added in the future, updating the
+environments will be necessary but not necessarily as time consuming.
+
+I just want to run the tests!
+=============================
+
+Running both sets of unit tests quickly and easily is the main goal of this
+script. All you need to do is::
+
+ ./run_tests.sh
+
+Yep, that's it. Everything else the script can do is optional.
+
+Give me metrics!
+================
+
+You can generate various reports and metrics using command line arguments
+to ``run_tests.sh``.
+
+Coverage
+--------
+
+To run coverage reports::
+
+ ./run_tests.sh --coverage
+
+The reports are saved to ``./reports/`` and ``./coverage.xml``.
+
+PEP8
+----
+
+You can check for PEP8 violations as well::
+
+ ./run_tests.sh --pep8
+
+The results are saved to ``./pep8.txt``.
+
+PyLint
+------
+
+For more detailed code analysis you can run::
+
+ ./run_tests.sh --pylint
+
+The output will be saved in ``./pylint.txt``.
+
+Running the development server
+==============================
+
+As an added bonus, you can run Django's development server directly from
+the root of the repository with ``run_tests.sh`` like so::
+
+ ./run_tests.sh --runserver
+
+This is effectively just an alias for::
+
+ ./openstack-dashboard/tools/with_venv.sh ./openstack-dashboard/dashboard/manage.py runserver
+
+Generating the documentation
+============================
+
+You can build Horizon's documentation automatically by running::
+
+ ./run_tests.sh --docs
+
+The output is stored in ``./docs/build/html/``.
+
+Starting clean
+==============
+
+If you ever want to start clean with a new environment for Horizon, you can
+run::
+
+ ./run_tests.sh --force
+
+That will blow away the existing environments and create new ones for you.
diff --git a/docs/source/ref/users.rst b/docs/source/ref/users.rst
new file mode 100644
index 00000000..857358d1
--- /dev/null
+++ b/docs/source/ref/users.rst
@@ -0,0 +1,6 @@
+=================
+Horizon User APIs
+=================
+
+.. automodule:: horizon.users
+ :members:
diff --git a/docs/source/ref/views.rst b/docs/source/ref/views.rst
new file mode 100644
index 00000000..970609ca
--- /dev/null
+++ b/docs/source/ref/views.rst
@@ -0,0 +1,12 @@
+=============
+Horizon Views
+=============
+
+Horizon ships with a number of pre-built views which are used within
+Horizon and can also be reused in your applications.
+
+Auth
+====
+
+.. automodule:: horizon.views.auth
+ :members:
diff --git a/docs/source/testing.rst b/docs/source/testing.rst
new file mode 100644
index 00000000..a968ae50
--- /dev/null
+++ b/docs/source/testing.rst
@@ -0,0 +1,62 @@
+..
+ 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.
+
+===============
+Testing Horizon
+===============
+
+How to run the tests
+====================
+
+Because Horizon is composed of both the ``horizon`` app and the
+``openstack-dashboard`` reference project, there are in fact two sets of unit
+tests. While they can be run individually without problem, there is an easier
+way:
+
+Included at the root of the repository is the ``run_tests.sh`` script
+which invokes both sets of tests, and optionally generates analyses on both
+components in the process. This script is what what Jenkins uses to verify the
+stability of the project, so you should make sure you run it and it passes
+before you submit any pull requests/patches.
+
+To run the tests::
+
+ $ ./run_tests.sh
+
+.. seealso::
+
+ :doc:`ref/run_tests`
+ Full reference for the ``run_tests.sh`` script.
+
+How to write good tests
+=======================
+
+Horizon uses Django's unit test machinery (which extends Python's ``unittest2``
+library) as the core of it's test suite. As such, all tests for the Python code
+should be written as unit tests. No doctests please.
+
+A few pointers for writing good tests:
+
+ * Write tests as you go--If you save them to the end you'll write less of
+ them and they'll often miss large chunks of code.
+ * Keep it as simple as possible--Make sure each test tests one thing
+ and tests it thoroughly.
+ * Think about all the possible inputs your code could have--It's usually
+ the edge cases that end up revealing bugs.
+ * Use ``coverage.py`` to find out what code is *not* being tested.
+
+In general new code without unit tests will not be accepted, and every bugfix
+*must* include a regression test.
diff --git a/django-openstack/LICENSE b/horizon/LICENSE
index 68c771a0..68c771a0 100644
--- a/django-openstack/LICENSE
+++ b/horizon/LICENSE
diff --git a/django-openstack/Makefile b/horizon/Makefile
index 8496df21..d64cd72b 100644
--- a/django-openstack/Makefile
+++ b/horizon/Makefile
@@ -1,7 +1,7 @@
PYTHON=`which python`
DESTDIR=/
-BUILDIR=$(CURDIR)/debian/django-openstack
-PROJECT=django-openstack
+BUILDIR=$(CURDIR)/debian/horizon
+PROJECT=horizon
all:
@echo "make buildout - Run through buildout"
diff --git a/horizon/README b/horizon/README
new file mode 100644
index 00000000..1b6d6fd3
--- /dev/null
+++ b/horizon/README
@@ -0,0 +1,59 @@
+========================================
+Horizon: The OpenStack Dashboard Project
+========================================
+
+The Horizon project is a Django module that is used to provide web based
+interactions with an OpenStack cloud.
+
+There is a reference implementation that uses this module located at:
+
+ http://launchpad.net/horizon
+
+It is highly recommended that you make use of this reference implementation
+so that changes you make can be visualized effectively and are consistent.
+Using this reference implementation as a development environment will greatly
+simplify development of the ``horizon`` module.
+
+Of course, if you are developing your own Django site using Horizon, then
+you can disregard this advice.
+
+
+Getting Started
+===============
+
+Horizon uses Buildout (http://www.buildout.org/) to manage local development.
+To configure your local Buildout environment first install the following
+system-level dependencies:
+
+ * python-dev
+ * git
+ * bzr
+
+Then instantiate buildout with::
+
+ $ python bootstrap.py
+ $ bin/buildout
+
+This will install all the dependencies of Horizon and provide some useful
+scripts in the ``bin/`` directory:
+
+ bin/python provides a python shell for the current buildout.
+ bin/django provides django functions for the current buildout.
+
+
+You should now be able to run unit tests as follows::
+
+ $ bin/django test
+
+or::
+
+ $ bin/test
+
+You can run unit tests with code coverage on Horizon by setting
+``NOSE_WITH_COVERAGE``::
+
+ $ NOSE_WITH_COVERAGE=true bin/test
+
+Get even better coverage info by running coverage directly::
+
+ $ coverage run --branch --source horizon bin/django test horizon && coverage html
diff --git a/django-openstack/bootstrap.py b/horizon/bootstrap.py
index 5f2cb083..5f2cb083 100644
--- a/django-openstack/bootstrap.py
+++ b/horizon/bootstrap.py
diff --git a/django-openstack/buildout.cfg b/horizon/buildout.cfg
index 0858569f..3910799f 100644
--- a/django-openstack/buildout.cfg
+++ b/horizon/buildout.cfg
@@ -26,6 +26,7 @@ webob = 1.0.8
# or can be fetched from pypi
recipe = zc.recipe.egg
eggs =
+ python-dateutil
django-mailer
httplib2
python-cloudfiles
@@ -56,9 +57,9 @@ eggs =
interpreter = python
-[django-openstack]
+[horizon]
recipe = zc.recipe.egg
-eggs = django-openstack
+eggs = horizon
interpreter = python
@@ -69,13 +70,13 @@ interpreter = python
# IE, dependencies fetch from a git repo will not auto-populate
# like the zc.recipe.egg ones will
recipe = djangorecipe
-project = django_openstack
-projectegg = django_openstack
+project = horizon
+projectegg = horizon
settings = tests
-test = django_openstack
+test = horizon
eggs =
${dependencies:eggs}
- ${django-openstack:eggs}
+ ${horizon:eggs}
${glance-dependencies:eggs}
extra-paths =
${buildout:directory}/parts/openstack-compute
diff --git a/horizon/horizon/__init__.py b/horizon/horizon/__init__.py
new file mode 100644
index 00000000..c9838c2f
--- /dev/null
+++ b/horizon/horizon/__init__.py
@@ -0,0 +1,50 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+""" The Horizon OpenStack Dashboard interface.
+
+Contains the core Horizon classes--:class:`~horizon.Dashboard` and
+:class:`horizon.Panel`--the dynamic URLconf for Horizon, and common interface
+methods like :func:`~horizon.register` and :func:`~horizon.unregister`.
+
+"""
+# Because this module is compiled by setup.py before Django may be installed
+# in the environment we try importing Django and issue a warning but move on
+# should that fail.
+django = None
+try:
+ import django
+except ImportError:
+ import warnings
+
+ def simple_warn(message, category, filename, lineno, file=None, line=None):
+ return '%s: %s' % (category.__name__, message)
+
+ msg = ("Could not import Django. This is normal during installation.\n")
+ warnings.formatwarning = simple_warn
+ warnings.warn(msg, Warning)
+
+if django:
+ from horizon.base import Horizon, Dashboard, Panel, Workflow
+
+ register = Horizon.register
+ unregister = Horizon.unregister
+ get_absolute_url = Horizon.get_absolute_url
+ get_user_home = Horizon.get_user_home
+ get_dashboard = Horizon.get_dashboard
+ get_default_dashboard = Horizon.get_default_dashboard
+ get_dashboards = Horizon.get_dashboards
+ urls = Horizon._lazy_urls
diff --git a/horizon/horizon/api/__init__.py b/horizon/horizon/api/__init__.py
new file mode 100644
index 00000000..4d0229ad
--- /dev/null
+++ b/horizon/horizon/api/__init__.py
@@ -0,0 +1,39 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Methods and interface objects used to interact with external APIs.
+
+API method calls return objects that are in many cases objects with
+attributes that are direct maps to the data returned from the API http call.
+Unfortunately, these objects are also often constructed dynamically, making
+it difficult to know what data is available from the API object. Because of
+this, all API calls should wrap their returned object in one defined here,
+using only explicitly defined atributes and/or methods.
+
+In other words, Horizon developers not working on horizon.api
+shouldn't need to understand the finer details of APIs for
+Keystone/Nova/Glance/Swift et. al.
+"""
+from horizon.api.glance import *
+from horizon.api.keystone import *
+from horizon.api.nova import *
+from horizon.api.swift import *
+from horizon.api.quantum import *
diff --git a/horizon/horizon/api/base.py b/horizon/horizon/api/base.py
new file mode 100644
index 00000000..093a214a
--- /dev/null
+++ b/horizon/horizon/api/base.py
@@ -0,0 +1,118 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import functools
+import logging
+
+from django.utils.decorators import available_attrs
+
+from horizon import exceptions
+
+
+__all__ = ('APIResourceWrapper', 'APIDictWrapper',
+ 'get_service_from_catalog', 'url_for',)
+
+
+LOG = logging.getLogger(__name__)
+
+
+class APIResourceWrapper(object):
+ """ Simple wrapper for api objects
+
+ Define _attrs on the child class and pass in the
+ api object as the only argument to the constructor
+ """
+ _attrs = []
+
+ def __init__(self, apiresource):
+ self._apiresource = apiresource
+
+ def __getattr__(self, attr):
+ if attr in self._attrs:
+ # __getattr__ won't find properties
+ return self._apiresource.__getattribute__(attr)
+ else:
+ LOG.debug('Attempted to access unknown attribute "%s" on'
+ ' APIResource object of type "%s" wrapping resource of'
+ ' type "%s"' % (attr, self.__class__,
+ self._apiresource.__class__))
+ raise AttributeError(attr)
+
+
+class APIDictWrapper(object):
+ """ Simple wrapper for api dictionaries
+
+ Some api calls return dictionaries. This class provides identical
+ behavior as APIResourceWrapper, except that it will also behave as a
+ dictionary, in addition to attribute accesses.
+
+ Attribute access is the preferred method of access, to be
+ consistent with api resource objects from openstackx
+ """
+ def __init__(self, apidict):
+ self._apidict = apidict
+
+ def __getattr__(self, attr):
+ if attr in self._attrs:
+ try:
+ return self._apidict[attr]
+ except KeyError, e:
+ raise AttributeError(e)
+
+ else:
+ LOG.debug('Attempted to access unknown item "%s" on'
+ 'APIResource object of type "%s"'
+ % (attr, self.__class__))
+ raise AttributeError(attr)
+
+ def __getitem__(self, item):
+ try:
+ return self.__getattr__(item)
+ except AttributeError, e:
+ # caller is expecting a KeyError
+ raise KeyError(e)
+
+ def get(self, item, default=None):
+ try:
+ return self.__getattr__(item)
+ except AttributeError:
+ return default
+
+
+def get_service_from_catalog(catalog, service_type):
+ for service in catalog:
+ if service['type'] == service_type:
+ return service
+ return None
+
+
+def url_for(request, service_type, admin=False):
+ catalog = request.user.service_catalog
+ service = get_service_from_catalog(catalog, service_type)
+ if service:
+ try:
+ if admin:
+ return service['endpoints'][0]['adminURL']
+ else:
+ return service['endpoints'][0]['internalURL']
+ except (IndexError, KeyError):
+ raise exceptions.ServiceCatalogException(service_type)
+ else:
+ raise exceptions.ServiceCatalogException(service_type)
diff --git a/horizon/horizon/api/deprecated.py b/horizon/horizon/api/deprecated.py
new file mode 100644
index 00000000..58f72ead
--- /dev/null
+++ b/horizon/horizon/api/deprecated.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import functools
+import logging
+
+from django.utils.decorators import available_attrs
+import openstack.compute
+import openstackx.admin
+import openstackx.api.exceptions as openstackx_exceptions
+import openstackx.extras
+
+from horizon.api.base import *
+
+
+LOG = logging.getLogger(__name__)
+
+
+REBOOT_HARD = openstack.compute.servers.REBOOT_HARD
+
+
+def check_openstackx(f):
+ """Decorator that adds extra info to api exceptions
+
+ The OpenStack Dashboard currently depends on openstackx extensions
+ being present in Nova. Error messages depending for views depending
+ on these extensions do not lead to the conclusion that Nova is missing
+ extensions.
+
+ This decorator should be dropped and removed after Keystone and
+ Horizon more gracefully handle extensions and openstackx extensions
+ aren't required by Horizon in Nova.
+ """
+ @functools.wraps(f, assigned=available_attrs(f))
+ def inner(*args, **kwargs):
+ try:
+ return f(*args, **kwargs)
+ except openstackx_exceptions.NotFound, e:
+ e.message = e.details or ''
+ e.message += ' This error may be caused by a misconfigured' \
+ ' Nova url in keystone\'s service catalog, or ' \
+ ' by missing openstackx extensions in Nova. ' \
+ ' See the Horizon README.'
+ raise
+ return inner
+
+
+def compute_api(request):
+ management_url = url_for(request, 'compute')
+ compute = openstack.compute.Compute(
+ auth_token=request.user.token,
+ management_url=management_url)
+ # this below hack is necessary to make the jacobian compute client work
+ # TODO(mgius): It looks like this is unused now?
+ compute.client.auth_token = request.user.token
+ compute.client.management_url = management_url
+ LOG.debug('compute_api connection created using token "%s"'
+ ' and url "%s"' %
+ (request.user.token, management_url))
+ return compute
+
+
+def admin_api(request):
+ management_url = url_for(request, 'compute', True)
+ LOG.debug('admin_api connection created using token "%s"'
+ ' and url "%s"' %
+ (request.user.token, management_url))
+ return openstackx.admin.Admin(auth_token=request.user.token,
+ management_url=management_url)
+
+
+def extras_api(request):
+ management_url = url_for(request, 'compute')
+ LOG.debug('extras_api connection created using token "%s"'
+ ' and url "%s"' %
+ (request.user.token, management_url))
+ return openstackx.extras.Extras(auth_token=request.user.token,
+ management_url=management_url)
diff --git a/horizon/horizon/api/glance.py b/horizon/horizon/api/glance.py
new file mode 100644
index 00000000..24ac7fbd
--- /dev/null
+++ b/horizon/horizon/api/glance.py
@@ -0,0 +1,89 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+import logging
+import urlparse
+
+from glance import client as glance_client
+
+from horizon.api.base import *
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Image(APIDictWrapper):
+ """Simple wrapper around glance image dictionary"""
+ _attrs = ['checksum', 'container_format', 'created_at', 'deleted',
+ 'deleted_at', 'disk_format', 'id', 'is_public', 'location',
+ 'name', 'properties', 'size', 'status', 'updated_at', 'owner']
+
+ def __getattr__(self, attrname):
+ if attrname == "properties":
+ return ImageProperties(super(Image, self).__getattr__(attrname))
+ else:
+ return super(Image, self).__getattr__(attrname)
+
+
+class ImageProperties(APIDictWrapper):
+ """Simple wrapper around glance image properties dictionary"""
+ _attrs = ['architecture', 'image_location', 'image_state', 'kernel_id',
+ 'project_id', 'ramdisk_id']
+
+
+def glance_api(request):
+ o = urlparse.urlparse(url_for(request, 'image'))
+ LOG.debug('glance_api connection created for host "%s:%d"' %
+ (o.hostname, o.port))
+ return glance_client.Client(o.hostname,
+ o.port,
+ auth_tok=request.user.token)
+
+
+def image_create(request, image_meta, image_file):
+ return Image(glance_api(request).add_image(image_meta, image_file))
+
+
+def image_delete(request, image_id):
+ return glance_api(request).delete_image(image_id)
+
+
+def image_get(request, image_id):
+ return Image(glance_api(request).get_image(image_id)[0])
+
+
+def image_list_detailed(request):
+ return [Image(i) for i in glance_api(request).get_images_detailed()]
+
+
+def image_update(request, image_id, image_meta=None):
+ image_meta = image_meta and image_meta or {}
+ return Image(glance_api(request).update_image(image_id,
+ image_meta=image_meta))
+
+
+def snapshot_list_detailed(request):
+ filters = {}
+ filters['property-image_type'] = 'snapshot'
+ filters['is_public'] = 'none'
+ return [Image(i) for i in glance_api(request)
+ .get_images_detailed(filters=filters)]
diff --git a/horizon/horizon/api/keystone.py b/horizon/horizon/api/keystone.py
new file mode 100644
index 00000000..cdc45516
--- /dev/null
+++ b/horizon/horizon/api/keystone.py
@@ -0,0 +1,256 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django.conf import settings
+
+from keystoneclient import exceptions as keystone_exceptions
+from keystoneclient.v2_0 import client as keystone_client
+
+from horizon.api.base import *
+from horizon.api.deprecated import admin_api
+from horizon.api.deprecated import check_openstackx
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Tenant(APIResourceWrapper):
+ """Simple wrapper around keystoneclient.tenants.Tenant"""
+ _attrs = ['id', 'description', 'enabled', 'name']
+
+
+class Token(APIResourceWrapper):
+ """Simple wrapper around keystoneclient.tokens.Tenant"""
+ _attrs = ['id', 'user', 'serviceCatalog', 'tenant']
+
+
+class User(APIResourceWrapper):
+ """Simple wrapper around keystoneclient.users.User"""
+ _attrs = ['email', 'enabled', 'id', 'tenantId', 'name']
+
+
+class Role(APIResourceWrapper):
+ """Wrapper around keystoneclient.roles.role"""
+ _attrs = ['id', 'name', 'description', 'service_id']
+
+
+class Services(APIResourceWrapper):
+ _attrs = ['disabled', 'host', 'id', 'last_update', 'stats', 'type', 'up',
+ 'zone']
+
+
+def keystoneclient(request, username=None, password=None, tenant_id=None,
+ token_id=None, endpoint=None):
+ """Returns a client connected to the Keystone backend.
+
+ Several forms of authentication are supported:
+
+ * Username + password -> Unscoped authentication
+ * Username + password + tenant id -> Scoped authentication
+ * Unscoped token -> Unscoped authentication
+ * Unscoped token + tenant id -> Scoped authentication
+ * Scoped token -> Scoped authentication
+
+ Available services and data from the backend will vary depending on
+ whether the authentication was scoped or unscoped.
+
+ Lazy authentication if an ``endpoint`` parameter is provided.
+
+ The client is cached so that subsequent API calls during the same
+ request/response cycle don't have to be re-authenticated.
+ """
+ # Take care of client connection caching/fetching a new client
+ user = request.user
+ if hasattr(request, '_keystone') and \
+ request._keystone.auth_token == user.token:
+ conn = request._keystone
+ else:
+ conn = keystone_client.Client(username=username or user.username,
+ password=password,
+ project_id=tenant_id or user.tenant_id,
+ token=token_id or user.token,
+ auth_url=settings.OPENSTACK_KEYSTONE_URL,
+ endpoint=endpoint)
+ request._keystone = conn
+
+ # Fetch the correct endpoint for the user type
+ catalog = getattr(conn, 'service_catalog', None)
+ if catalog and "serviceCatalog" in catalog.catalog.keys():
+ if user.is_admin():
+ endpoint = catalog.url_for(service_type='identity',
+ endpoint_type='adminURL')
+ else:
+ endpoint = catalog.url_for(service_type='identity',
+ endpoint_type='publicURL')
+ else:
+ endpoint = settings.OPENSTACK_KEYSTONE_URL
+ conn.management_url = endpoint
+
+ return conn
+
+
+def tenant_create(request, tenant_name, description, enabled):
+ return Tenant(keystoneclient(request).tenants.create(tenant_name,
+ description,
+ enabled))
+
+
+def tenant_get(request, tenant_id):
+ return Tenant(keystoneclient(request).tenants.get(tenant_id))
+
+
+def tenant_delete(request, tenant_id):
+ keystoneclient(request).tenants.delete(tenant_id)
+
+
+def tenant_list(request):
+ return [Tenant(t) for t in keystoneclient(request).tenants.list()]
+
+
+def tenant_update(request, tenant_id, tenant_name, description, enabled):
+ return Tenant(keystoneclient(request).tenants.update(tenant_id,
+ tenant_name,
+ description,
+ enabled))
+
+
+def tenant_delete(request, tenant_id):
+ keystoneclient(request).tenants.delete(tenant_id)
+
+
+def tenant_list_for_token(request, token):
+ c = keystoneclient(request, token_id=token,
+ endpoint=settings.OPENSTACK_KEYSTONE_URL)
+ return [Tenant(t) for t in c.tenants.list()]
+
+
+def token_create(request, tenant, username, password):
+ '''
+ Creates a token using the username and password provided. If tenant
+ is provided it will retrieve a scoped token and the service catalog for
+ the given tenant. Otherwise it will return an unscoped token and without
+ a service catalog.
+ '''
+ c = keystoneclient(request,
+ username=username,
+ password=password,
+ tenant_id=tenant,
+ endpoint=settings.OPENSTACK_KEYSTONE_URL)
+ token = c.tokens.authenticate(username=username,
+ password=password,
+ tenant=tenant)
+ return Token(token)
+
+
+def token_create_scoped(request, tenant, token):
+ '''
+ Creates a scoped token using the tenant id and unscoped token; retrieves
+ the service catalog for the given tenant.
+ '''
+ if hasattr(request, '_keystone'):
+ del request._keystone
+ c = keystoneclient(request, tenant_id=tenant, token_id=token,
+ endpoint=settings.OPENSTACK_KEYSTONE_URL)
+ scoped_token = c.tokens.authenticate(tenant=tenant, token=token)
+ return Token(scoped_token)
+
+
+def user_list(request, tenant_id=None):
+ return [User(u) for u in
+ keystoneclient(request).users.list(tenant_id=tenant_id)]
+
+
+def user_create(request, user_id, email, password, tenant_id, enabled):
+ return User(keystoneclient(request).users.create(
+ user_id, password, email, tenant_id, enabled))
+
+
+def user_delete(request, user_id):
+ keystoneclient(request).users.delete(user_id)
+
+
+def user_get(request, user_id):
+ return User(keystoneclient(request).users.get(user_id))
+
+
+def user_update_email(request, user_id, email):
+ return User(keystoneclient(request).users.update_email(user_id, email))
+
+
+def user_update_enabled(request, user_id, enabled):
+ return User(keystoneclient(request).users.update_enabled(user_id, enabled))
+
+
+def user_update_password(request, user_id, password):
+ return User(keystoneclient(request).users \
+ .update_password(user_id, password))
+
+
+def user_update_tenant(request, user_id, tenant_id):
+ return User(keystoneclient(request).users \
+ .update_tenant(user_id, tenant_id))
+
+
+def _get_role(request, name):
+ roles = keystoneclient(request).roles.list()
+ for role in roles:
+ if role.name.lower() == name.lower():
+ return role
+
+ raise Exception(_('Role does not exist: %s') % name)
+
+
+def _get_roleref(request, user_id, tenant_id, role):
+ rolerefs = keystoneclient(request).roles.get_user_role_refs(user_id)
+ for roleref in rolerefs:
+ if roleref.roleId == role.id and roleref.tenantId == tenant_id:
+ return roleref
+ raise Exception(_('Role "%s" does not exist for that user on this tenant.')
+ % role.name)
+
+
+def role_add_for_tenant_user(request, tenant_id, user_id, role):
+ role = _get_role(request, role)
+ return keystoneclient(request).roles.add_user_to_tenant(tenant_id,
+ user_id,
+ role.id)
+
+
+def role_delete_for_tenant_user(request, tenant_id, user_id, role):
+ role = _get_role(request, role)
+ roleref = _get_roleref(request, user_id, tenant_id, role)
+ return keystoneclient(request).roles.remove_user_from_tenant(tenant_id,
+ user_id,
+ roleref.id)
+
+
+def service_get(request, name):
+ return Services(admin_api(request).services.get(name))
+
+
+@check_openstackx
+def service_list(request):
+ return [Services(s) for s in admin_api(request).services.list()]
+
+
+def service_update(request, name, enabled):
+ return Services(admin_api(request).services.update(name, enabled))
diff --git a/horizon/horizon/api/nova.py b/horizon/horizon/api/nova.py
new file mode 100644
index 00000000..1802d1a4
--- /dev/null
+++ b/horizon/horizon/api/nova.py
@@ -0,0 +1,357 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+import logging
+
+from django.contrib import messages
+from novaclient.v1_1 import client as nova_client
+
+from horizon.api.base import *
+from horizon.api.deprecated import admin_api
+from horizon.api.deprecated import compute_api
+from horizon.api.deprecated import check_openstackx
+from horizon.api.deprecated import extras_api
+from horizon.api.deprecated import REBOOT_HARD
+
+LOG = logging.getLogger(__name__)
+
+
+class Console(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.consoles.Console"""
+ _attrs = ['id', 'output', 'type']
+
+
+class Flavor(APIResourceWrapper):
+ """Simple wrapper around openstackx.admin.flavors.Flavor"""
+ _attrs = ['disk', 'id', 'links', 'name', 'ram', 'vcpus']
+
+
+class FloatingIp(APIResourceWrapper):
+ """Simple wrapper for floating ips"""
+ _attrs = ['ip', 'fixed_ip', 'instance_id', 'id']
+
+
+class KeyPair(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.keypairs.Keypair"""
+ _attrs = ['fingerprint', 'name', 'private_key']
+
+
+class VirtualInterface(APIResourceWrapper):
+ _attrs = ['id', 'mac_address']
+
+
+class Volume(APIResourceWrapper):
+ """Nova Volume representation"""
+ _attrs = ['id', 'status', 'displayName', 'size', 'volumeType', 'createdAt',
+ 'attachments', 'displayDescription']
+
+
+class Server(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.server.Server
+
+ Preserves the request info so image name can later be retrieved
+ """
+ _attrs = ['addresses', 'attrs', 'hostId', 'id', 'image', 'links',
+ 'metadata', 'name', 'private_ip', 'public_ip', 'status', 'uuid',
+ 'image_name', 'VirtualInterfaces']
+
+ def __init__(self, apiresource, request):
+ super(Server, self).__init__(apiresource)
+ self.request = request
+
+ def __getattr__(self, attr):
+ if attr == "attrs":
+ return ServerAttributes(super(Server, self).__getattr__(attr))
+ else:
+ return super(Server, self).__getattr__(attr)
+
+ @property
+ def image_name(self):
+ from glance.common import exception as glance_exceptions
+ from horizon.api import glance
+ try:
+ image = glance.image_get(self.request, self.image['id'])
+ return image.name
+ except glance_exceptions.NotFound:
+ return "(not found)"
+
+ def reboot(self, hardness=REBOOT_HARD):
+ compute_api(self.request).servers.reboot(self.id, hardness)
+
+
+class ServerAttributes(APIDictWrapper):
+ """Simple wrapper around openstackx.extras.server.Server attributes
+
+ Preserves the request info so image name can later be retrieved
+ """
+ _attrs = ['description', 'disk_gb', 'host', 'image_ref', 'kernel_id',
+ 'key_name', 'launched_at', 'mac_address', 'memory_mb', 'name',
+ 'os_type', 'tenant_id', 'ramdisk_id', 'scheduled_at',
+ 'terminated_at', 'user_data', 'user_id', 'vcpus', 'hostname',
+ 'security_groups']
+
+
+class Usage(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.usage.Usage"""
+ _attrs = ['begin', 'instances', 'stop', 'tenant_id',
+ 'total_active_disk_size', 'total_active_instances',
+ 'total_active_ram_size', 'total_active_vcpus', 'total_cpu_usage',
+ 'total_disk_usage', 'total_hours', 'total_ram_usage']
+
+
+class SecurityGroup(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.security_groups.SecurityGroup"""
+ _attrs = ['id', 'name', 'description', 'tenant_id', 'rules']
+
+
+class SecurityGroupRule(APIResourceWrapper):
+ """Simple wrapper around
+ openstackx.extras.security_groups.SecurityGroupRule"""
+ _attrs = ['id', 'parent_group_id', 'group_id', 'ip_protocol',
+ 'from_port', 'to_port', 'groups', 'ip_ranges']
+
+
+class SecurityGroupRule(APIResourceWrapper):
+ """Simple wrapper around openstackx.extras.users.User"""
+ _attrs = ['id', 'name', 'description', 'tenant_id', 'security_group_rules']
+
+
+def novaclient(request):
+ LOG.debug('novaclient connection created using token "%s" and url "%s"' %
+ (request.user.token, url_for(request, 'compute')))
+ c = nova_client.Client(username=request.user.username,
+ api_key=request.user.token,
+ project_id=request.user.tenant_id,
+ auth_url=url_for(request, 'compute'))
+ c.client.auth_token = request.user.token
+ c.client.management_url = url_for(request, 'compute')
+ return c
+
+
+def console_create(request, instance_id, kind='text'):
+ return Console(extras_api(request).consoles.create(instance_id, kind))
+
+
+def flavor_create(request, name, memory, vcpu, disk, flavor_id):
+ # TODO -- convert to novaclient when novaclient adds create support
+ return Flavor(admin_api(request).flavors.create(
+ name, int(memory), int(vcpu), int(disk), flavor_id))
+
+
+def flavor_delete(request, flavor_id, purge=False):
+ # TODO -- convert to novaclient when novaclient adds delete support
+ admin_api(request).flavors.delete(flavor_id, purge)
+
+
+def flavor_get(request, flavor_id):
+ return Flavor(novaclient(request).flavors.get(flavor_id))
+
+
+def flavor_list(request):
+ return [Flavor(f) for f in novaclient(request).flavors.list()]
+
+
+def tenant_floating_ip_list(request):
+ """
+ Fetches a list of all floating ips.
+ """
+ return [FloatingIp(ip) for ip in novaclient(request).floating_ips.list()]
+
+
+def tenant_floating_ip_get(request, floating_ip_id):
+ """
+ Fetches a floating ip.
+ """
+ return novaclient(request).floating_ips.get(floating_ip_id)
+
+
+def tenant_floating_ip_allocate(request):
+ """
+ Allocates a floating ip to tenant.
+ """
+ return novaclient(request).floating_ips.create()
+
+
+def tenant_floating_ip_release(request, floating_ip_id):
+ """
+ Releases floating ip from the pool of a tenant.
+ """
+ return novaclient(request).floating_ips.delete(floating_ip_id)
+
+
+def snapshot_create(request, instance_id, name):
+ return novaclient(request).servers.create_image(instance_id, name)
+
+
+def keypair_create(request, name):
+ return KeyPair(novaclient(request).keypairs.create(name))
+
+
+def keypair_import(request, name, public_key):
+ return KeyPair(novaclient(request).keypairs.create(name, public_key))
+
+
+def keypair_delete(request, keypair_id):
+ novaclient(request).keypairs.delete(keypair_id)
+
+
+def keypair_list(request):
+ return [KeyPair(key) for key in novaclient(request).keypairs.list()]
+
+
+def server_create(request, name, image, flavor,
+ key_name, user_data, security_groups):
+ return Server(novaclient(request).servers.create(
+ name, image, flavor, userdata=user_data,
+ security_groups=security_groups,
+ key_name=key_name), request)
+
+
+def server_delete(request, instance):
+ compute_api(request).servers.delete(instance)
+
+
+def server_get(request, instance_id):
+ return Server(extras_api(request).servers.get(instance_id), request)
+
+
+@check_openstackx
+def server_list(request):
+ return [Server(s, request) for s in extras_api(request).servers.list()]
+
+
+@check_openstackx
+def admin_server_list(request):
+ return [Server(s, request) for s in admin_api(request).servers.list()]
+
+
+def server_reboot(request,
+ instance_id,
+ hardness=REBOOT_HARD):
+ server = server_get(request, instance_id)
+ server.reboot(hardness)
+
+
+def server_update(request, instance_id, name, description):
+ return extras_api(request).servers.update(instance_id,
+ name=name,
+ description=description)
+
+
+def server_add_floating_ip(request, server, address):
+ """
+ Associates floating IP to server's fixed IP.
+ """
+ server = novaclient(request).servers.get(server)
+ fip = novaclient(request).floating_ips.get(address)
+
+ return novaclient(request).servers.add_floating_ip(server, fip)
+
+
+def server_remove_floating_ip(request, server, address):
+ """
+ Removes relationship between floating and server's fixed ip.
+ """
+ fip = novaclient(request).floating_ips.get(address)
+ server = novaclient(request).servers.get(fip.instance_id)
+
+ return novaclient(request).servers.remove_floating_ip(server, fip)
+
+
+def tenant_quota_get(request, tenant):
+ return novaclient(request).quotas.get(tenant)
+
+
+@check_openstackx
+def usage_get(request, tenant_id, start, end):
+ return Usage(extras_api(request).usage.get(tenant_id, start, end))
+
+
+@check_openstackx
+def usage_list(request, start, end):
+ return [Usage(u) for u in extras_api(request).usage.list(start, end)]
+
+
+def security_group_list(request):
+ return [SecurityGroup(g) for g in novaclient(request).\
+ security_groups.list()]
+
+
+def security_group_get(request, security_group_id):
+ return SecurityGroup(novaclient(request).\
+ security_groups.get(security_group_id))
+
+
+def security_group_create(request, name, description):
+ return SecurityGroup(novaclient(request).\
+ security_groups.create(name, description))
+
+
+def security_group_delete(request, security_group_id):
+ novaclient(request).security_groups.delete(security_group_id)
+
+
+def security_group_rule_create(request, parent_group_id, ip_protocol=None,
+ from_port=None, to_port=None, cidr=None,
+ group_id=None):
+ return SecurityGroup(novaclient(request).\
+ security_group_rules.create(parent_group_id,
+ ip_protocol,
+ from_port,
+ to_port,
+ cidr,
+ group_id))
+
+
+def security_group_rule_delete(request, security_group_rule_id):
+ novaclient(request).security_group_rules.delete(security_group_rule_id)
+
+
+def volume_list(request):
+ return [Volume(vol) for vol in novaclient(request).volumes.list()]
+
+
+def volume_get(request, volume_id):
+ return Volume(novaclient(request).volumes.get(volume_id))
+
+
+def volume_instance_list(request, instance_id):
+ return novaclient(request).volumes.get_server_volumes(instance_id)
+
+
+def volume_create(request, size, name, description):
+ return Volume(novaclient(request).volumes.create(
+ size, name, description))
+
+
+def volume_delete(request, volume_id):
+ novaclient(request).volumes.delete(volume_id)
+
+
+def volume_attach(request, volume_id, instance_id, device):
+ novaclient(request).volumes.create_server_volume(
+ instance_id, volume_id, device)
+
+
+def volume_detach(request, instance_id, attachment_id):
+ novaclient(request).volumes.delete_server_volume(
+ instance_id, attachment_id)
diff --git a/horizon/horizon/api/quantum.py b/horizon/horizon/api/quantum.py
new file mode 100644
index 00000000..3d2675c3
--- /dev/null
+++ b/horizon/horizon/api/quantum.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+
+from __future__ import absolute_import
+
+import logging
+
+from django.conf import settings
+from quantum import client as quantum_client
+
+from horizon.api.base import *
+from horizon.api.deprecated import extras_api
+
+
+LOG = logging.getLogger(__name__)
+
+
+def quantum_api(request):
+ if hasattr(request, 'user'):
+ tenant = request.user.tenant_id
+ else:
+ tenant = settings.QUANTUM_TENANT
+
+ return quantum_client.Client(settings.QUANTUM_URL, settings.QUANTUM_PORT,
+ False, tenant, 'json')
+
+
+def quantum_list_networks(request):
+ return quantum_api(request).list_networks()
+
+
+def quantum_network_details(request, network_id):
+ return quantum_api(request).show_network_details(network_id)
+
+
+def quantum_list_ports(request, network_id):
+ return quantum_api(request).list_ports(network_id)
+
+
+def quantum_port_details(request, network_id, port_id):
+ return quantum_api(request).show_port_details(network_id, port_id)
+
+
+def quantum_create_network(request, data):
+ return quantum_api(request).create_network(data)
+
+
+def quantum_delete_network(request, network_id):
+ return quantum_api(request).delete_network(network_id)
+
+
+def quantum_update_network(request, network_id, data):
+ return quantum_api(request).update_network(network_id, data)
+
+
+def quantum_create_port(request, network_id):
+ return quantum_api(request).create_port(network_id)
+
+
+def quantum_delete_port(request, network_id, port_id):
+ return quantum_api(request).delete_port(network_id, port_id)
+
+
+def quantum_attach_port(request, network_id, port_id, data):
+ return quantum_api(request).attach_resource(network_id, port_id, data)
+
+
+def quantum_detach_port(request, network_id, port_id):
+ return quantum_api(request).detach_resource(network_id, port_id)
+
+
+def quantum_set_port_state(request, network_id, port_id, data):
+ return quantum_api(request).set_port_state(network_id, port_id, data)
+
+
+def quantum_port_attachment(request, network_id, port_id):
+ return quantum_api(request).show_port_attachment(network_id, port_id)
+
+
+def get_vif_ids(request):
+ vifs = []
+ attached_vifs = []
+ # Get a list of all networks
+ networks_list = quantum_api(request).list_networks()
+ for network in networks_list['networks']:
+ ports = quantum_api(request).list_ports(network['id'])
+ # Get port attachments
+ for port in ports['ports']:
+ port_attachment = quantum_api(request).show_port_attachment(
+ network['id'],
+ port['id'])
+ if port_attachment['attachment']:
+ attached_vifs.append(
+ port_attachment['attachment']['id'].encode('ascii'))
+ # Get all instances
+ instances = server_list(request)
+ # Get virtual interface ids by instance
+ for instance in instances:
+ id = instance.id
+ instance_vifs = extras_api(request).virtual_interfaces.list(id)
+ for vif in instance_vifs:
+ # Check if this VIF is already connected to any port
+ if str(vif.id) in attached_vifs:
+ vifs.append({
+ 'id': vif.id,
+ 'instance': instance.id,
+ 'instance_name': instance.name,
+ 'available': False})
+ else:
+ vifs.append({
+ 'id': vif.id,
+ 'instance': instance.id,
+ 'instance_name': instance.name,
+ 'available': True})
+ return vifs
diff --git a/horizon/horizon/api/swift.py b/horizon/horizon/api/swift.py
new file mode 100644
index 00000000..55cfebb5
--- /dev/null
+++ b/horizon/horizon/api/swift.py
@@ -0,0 +1,132 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+import cloudfiles
+from django.conf import settings
+
+from horizon.api.base import *
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Container(APIResourceWrapper):
+ """Simple wrapper around cloudfiles.container.Container"""
+ _attrs = ['name']
+
+
+class SwiftObject(APIResourceWrapper):
+ _attrs = ['name']
+
+
+class SwiftAuthentication(object):
+ """Auth container to pass CloudFiles storage URL and token from
+ session.
+ """
+ def __init__(self, storage_url, auth_token):
+ self.storage_url = storage_url
+ self.auth_token = auth_token
+
+ def authenticate(self):
+ return (self.storage_url, '', self.auth_token)
+
+
+def swift_api(request):
+ LOG.debug('object store connection created using token "%s"'
+ ' and url "%s"' %
+ (request.session['token'], url_for(request, 'object-store')))
+ auth = SwiftAuthentication(url_for(request, 'object-store'),
+ request.session['token'])
+ return cloudfiles.get_connection(auth=auth)
+
+
+def swift_container_exists(request, container_name):
+ try:
+ swift_api(request).get_container(container_name)
+ return True
+ except cloudfiles.errors.NoSuchContainer:
+ return False
+
+
+def swift_object_exists(request, container_name, object_name):
+ container = swift_api(request).get_container(container_name)
+
+ try:
+ container.get_object(object_name)
+ return True
+ except cloudfiles.errors.NoSuchObject:
+ return False
+
+
+def swift_get_containers(request, marker=None):
+ return [Container(c) for c in swift_api(request).get_all_containers(
+ limit=getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000),
+ marker=marker)]
+
+
+def swift_create_container(request, name):
+ if swift_container_exists(request, name):
+ raise Exception('Container with name %s already exists.' % (name))
+
+ return Container(swift_api(request).create_container(name))
+
+
+def swift_delete_container(request, name):
+ swift_api(request).delete_container(name)
+
+
+def swift_get_objects(request, container_name, prefix=None, marker=None):
+ container = swift_api(request).get_container(container_name)
+ objects = container.get_objects(prefix=prefix, marker=marker,
+ limit=getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000))
+ return [SwiftObject(o) for o in objects]
+
+
+def swift_copy_object(request, orig_container_name, orig_object_name,
+ new_container_name, new_object_name):
+
+ container = swift_api(request).get_container(orig_container_name)
+
+ if swift_object_exists(request,
+ new_container_name,
+ new_object_name) == True:
+ raise Exception('Object with name %s already exists in container %s'
+ % (new_object_name, new_container_name))
+
+ orig_obj = container.get_object(orig_object_name)
+ return orig_obj.copy_to(new_container_name, new_object_name)
+
+
+def swift_upload_object(request, container_name, object_name, object_data):
+ container = swift_api(request).get_container(container_name)
+ obj = container.create_object(object_name)
+ obj.write(object_data)
+
+
+def swift_delete_object(request, container_name, object_name):
+ container = swift_api(request).get_container(container_name)
+ container.delete_object(object_name)
+
+
+def swift_get_object_data(request, container_name, object_name):
+ container = swift_api(request).get_container(container_name)
+ return container.get_object(object_name).stream()
diff --git a/horizon/horizon/base.py b/horizon/horizon/base.py
new file mode 100644
index 00000000..10ebfd78
--- /dev/null
+++ b/horizon/horizon/base.py
@@ -0,0 +1,594 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Contains the core classes and functionality that makes Horizon what it is.
+This module is considered internal, and should not be relied on directly.
+
+Public APIs are made available through the :mod:`horizon` module and
+the classes contained therein.
+"""
+
+import copy
+import functools
+import inspect
+
+from django.conf import settings
+from django.conf.urls.defaults import patterns, url, include
+from django.core.exceptions import ImproperlyConfigured
+from django.core.urlresolvers import reverse, RegexURLPattern
+from django.utils.functional import SimpleLazyObject
+from django.utils.importlib import import_module
+from django.utils.module_loading import module_has_submodule
+from django.utils.translation import ugettext as _
+
+from horizon.decorators import require_roles, _current_component
+
+
+# Default configuration dictionary. Do not mutate directly. Use copy.copy().
+HORIZON_CONFIG = {
+ # Allow for ordering dashboards; list or tuple if provided.
+ 'dashboards': None,
+ # Name of a default dashboard; defaults to first alphabetically if None
+ 'default_dashboard': None,
+ 'user_home': None,
+}
+
+
+def _decorate_urlconf(urlpatterns, decorator, *args, **kwargs):
+ for pattern in urlpatterns:
+ if getattr(pattern, 'callback', None):
+ pattern._callback = decorator(pattern.callback, *args, **kwargs)
+ if getattr(pattern, 'url_patterns', []):
+ _decorate_urlconf(pattern.url_patterns, decorator, *args, **kwargs)
+
+
+class NotRegistered(Exception):
+ pass
+
+
+class HorizonComponent(object):
+ def __init__(self):
+ super(HorizonComponent, self).__init__()
+ if not self.slug:
+ raise ImproperlyConfigured('Every %s must have a slug.'
+ % self.__class__)
+
+ def __unicode__(self):
+ return getattr(self, 'name', u"Unnamed %s" % self.__class__.__name__)
+
+ def _get_default_urlpatterns(self):
+ package_string = '.'.join(self.__module__.split('.')[:-1])
+ if getattr(self, 'urls', None):
+ try:
+ mod = import_module('.%s' % self.urls, package_string)
+ except ImportError:
+ mod = import_module(self.urls)
+ urlpatterns = mod.urlpatterns
+ else:
+ # Try importing a urls.py from the dashboard package
+ if module_has_submodule(import_module(package_string), 'urls'):
+ urls_mod = import_module('.urls', package_string)
+ urlpatterns = urls_mod.urlpatterns
+ else:
+ urlpatterns = patterns('')
+ return urlpatterns
+
+
+class Registry(object):
+ def __init__(self):
+ self._registry = {}
+ if not getattr(self, '_registerable_class', None):
+ raise ImproperlyConfigured('Subclasses of Registry must set a '
+ '"_registerable_class" property.')
+
+ def _register(self, cls):
+ """Registers the given class.
+
+ If the specified class is already registered then it is ignored.
+ """
+ if not inspect.isclass(cls):
+ raise ValueError('Only classes may be registered.')
+ elif not issubclass(cls, self._registerable_class):
+ raise ValueError('Only %s classes or subclasses may be registered.'
+ % self._registerable_class)
+
+ if cls not in self._registry:
+ cls._registered_with = self
+ self._registry[cls] = cls()
+
+ return self._registry[cls]
+
+ def _unregister(self, cls):
+ """Unregisters the given class.
+
+ If the specified class isn't registered, ``NotRegistered`` will
+ be raised.
+ """
+ if not issubclass(cls, self._registerable_class):
+ raise ValueError('Only %s classes or subclasses may be '
+ 'unregistered.' % self._registerable_class)
+
+ if cls not in self._registry.keys():
+ raise NotRegistered('%s is not registered' % cls)
+
+ del self._registry[cls]
+
+ return True
+
+ def _registered(self, cls):
+ if inspect.isclass(cls) and issubclass(cls, self._registerable_class):
+ cls = self._registry.get(cls, None)
+ if cls:
+ return cls
+ else:
+ # Allow for fetching by slugs as well.
+ for registered in self._registry.values():
+ if registered.slug == cls:
+ return registered
+ raise NotRegistered('%s with slug "%s" is not registered'
+ % (self._registerable_class, cls))
+
+
+class Panel(HorizonComponent):
+ """ A base class for defining Horizon dashboard panels.
+
+ All Horizon dashboard panels should extend from this class. It provides
+ the appropriate hooks for automatically constructing URLconfs, and
+ providing role-based access control.
+
+ .. attribute:: name
+
+ The name of the panel. This will be displayed in the
+ auto-generated navigation and various other places.
+ Default: ``''``.
+
+ .. attribute:: slug
+
+ A unique "short name" for the panel. The slug is used as
+ a component of the URL path for the panel. Default: ``''``.
+
+ .. attribute: roles
+
+ A list of role names, all of which a user must possess in order
+ to access any view associated with this panel. This attribute
+ is combined cumulatively with any roles required on the
+ ``Dashboard`` class with which it is registered.
+
+ .. attribute:: urls
+
+ Path to a URLconf of views for this panel using dotted Python
+ notation. If no value is specified, a file called ``urls.py``
+ living in the same package as the ``panel.py`` file is used.
+ Default: ``None``.
+
+ .. attribute:: nav
+ .. method:: nav(context)
+
+ The ``nav`` attribute can be either boolean value or a callable
+ which accepts a ``RequestContext`` object as a single argument
+ to control whether or not this panel should appear in
+ automatically-generated navigation. Default: ``True``.
+ """
+ name = ''
+ slug = ''
+ urls = None
+ nav = True
+
+ def __repr__(self):
+ return "<Panel: %s>" % self.__unicode__()
+
+ def get_absolute_url(self):
+ """ Returns the default URL for this panel.
+
+ The default URL is defined as the URL pattern with ``name="index"`` in
+ the URLconf for this panel.
+ """
+ return reverse('horizon:%s:%s:index' % (self._registered_with.slug,
+ self.slug,))
+
+ @property
+ def _decorated_urls(self):
+ urlpatterns = self._get_default_urlpatterns()
+
+ # Apply access controls to all views in the patterns
+ roles = getattr(self, 'roles', [])
+ _decorate_urlconf(urlpatterns, require_roles, roles)
+ _decorate_urlconf(urlpatterns, _current_component, panel=self)
+
+ # Return the three arguments to django.conf.urls.defaults.include
+ return urlpatterns, self.slug, self.slug
+
+
+class Dashboard(Registry, HorizonComponent):
+ """ A base class for defining Horizon dashboards.
+
+ All Horizon dashboards should extend from this base class. It provides the
+ appropriate hooks for automatic discovery of :class:`~horizon.Panel`
+ modules, automatically constructing URLconfs, and providing role-based
+ access control.
+
+ .. attribute:: name
+
+ The name of the dashboard. This will be displayed in the
+ auto-generated navigation and various other places.
+ Default: ``''``.
+
+ .. attribute:: slug
+
+ A unique "short name" for the dashboard. The slug is used as
+ a component of the URL path for the dashboard. Default: ``''``.
+
+ .. attribute:: panels
+
+ The ``panels`` attribute can be either a list containing the name
+ of each panel module which should be loaded as part of this
+ dashboard, or a dictionary of tuples which define groups of
+ as in the following example::
+
+ class Syspanel(horizon.Dashboard):
+ panels = {'System Panel': ('overview', 'instances', ...)}
+
+ Automatically generated navigation will use the order of the
+ modules in this attribute. Default: ``[]``.
+
+ Panel modules must be listed in ``panels`` in order to be
+ discovered by the automatic registration mechanism.
+
+ .. attribute:: default_panel
+
+ The name of the panel which should be treated as the default
+ panel for the dashboard, i.e. when you visit the root URL
+ for this dashboard, that's the panel that is displayed.
+ Default: ``None``.
+
+ .. attribute: roles
+
+ A list of role names, all of which a user must possess in order
+ to access any panel registered with this dashboard. This attribute
+ is combined cumulatively with any roles required on individual
+ :class:`~horizon.Panel` classes.
+
+ .. attribute:: urls
+
+ Optional path to a URLconf of additional views for this dashboard
+ which are not connected to specific panels. Default: ``None``.
+
+ .. attribute:: nav
+
+ Optional boolean to control whether or not this dashboard should
+ appear in automatically-generated navigation. Default: ``True``.
+ """
+ _registerable_class = Panel
+ name = ''
+ slug = ''
+ urls = None
+ panels = []
+ default_panel = None
+ nav = True
+
+ def __repr__(self):
+ return "<Dashboard: %s>" % self.__unicode__()
+
+ def get_panel(self, panel):
+ """
+ Returns the specified :class:`~horizon.Panel` instance registered
+ with this dashboard.
+ """
+ return self._registered(panel)
+
+ def get_panels(self):
+ """
+ Returns the :class:`~horizon.Panel` instances registered with this
+ dashboard in order.
+ """
+ registered = copy.copy(self._registry)
+ if type(self.panels) is dict:
+ panels = {}
+ for heading, items in self.panels.iteritems():
+ panels.setdefault(heading, [])
+ for item in items:
+ panel = self._registered(item)
+ panels[heading].append(panel)
+ registered.pop(panel.__class__)
+ if len(registered):
+ panels.setdefault(_("Other"), []).extend(registered.values())
+ else:
+ panels = []
+ for item in self.panels:
+ panel = self._registered(item)
+ panels.append(panel)
+ registered.pop(panel.__class__)
+ panels.extend(registered.values())
+ return panels
+
+ def get_absolute_url(self):
+ """ Returns the default URL for this dashboard.
+
+ The default URL is defined as the URL pattern with ``name="index"``
+ in the URLconf for the :class:`~horizon.Panel` specified by
+ :attr:`~horizon.Dashboard.default_panel`.
+ """
+ return self._registered(self.default_panel).get_absolute_url()
+
+ @property
+ def _decorated_urls(self):
+ urlpatterns = self._get_default_urlpatterns()
+
+ self._autodiscover()
+ default_panel = None
+
+ # Add in each panel's views except for the default view.
+ for panel in self._registry.values():
+ if panel.slug == self.default_panel:
+ default_panel = panel
+ continue
+ urlpatterns += patterns('',
+ url(r'^%s/' % panel.slug, include(panel._decorated_urls)))
+ # Now the default view, which should come last
+ if not default_panel:
+ raise NotRegistered('The default panel "%s" is not registered.'
+ % self.default_panel)
+ urlpatterns += patterns('',
+ url(r'', include(default_panel._decorated_urls)))
+
+ # Apply access controls to all views in the patterns
+ roles = getattr(self, 'roles', [])
+ _decorate_urlconf(urlpatterns, require_roles, roles)
+ _decorate_urlconf(urlpatterns, _current_component, dashboard=self)
+
+ # Return the three arguments to django.conf.urls.defaults.include
+ return urlpatterns, self.slug, self.slug
+
+ def _autodiscover(self):
+ """ Discovers panels to register from the current dashboard module. """
+ package = '.'.join(self.__module__.split('.')[:-1])
+ mod = import_module(package)
+ panels = []
+ if type(self.panels) is dict:
+ [panels.extend(values) for values in self.panels.values()]
+ else:
+ panels = self.panels
+ for panel in panels:
+ try:
+ before_import_registry = copy.copy(self._registry)
+ import_module('.%s.panel' % panel, package)
+ except:
+ self._registry = before_import_registry
+ if module_has_submodule(mod, panel):
+ raise
+
+ @classmethod
+ def register(cls, panel):
+ """ Registers a :class:`~horizon.Panel` with this dashboard. """
+ from horizon import Horizon
+ return Horizon.register_panel(cls, panel)
+
+ @classmethod
+ def unregister(cls, panel):
+ """ Unregisters a :class:`~horizon.Panel` from this dashboard. """
+ from horizon import Horizon
+ return Horizon.unregister_panel(cls, panel)
+
+
+class Workflow(object):
+ def __init__(*args, **kwargs):
+ raise NotImplementedError()
+
+
+class LazyURLPattern(SimpleLazyObject):
+ def __iter__(self):
+ if self._wrapped is None:
+ self._setup()
+ return iter(self._wrapped)
+
+ def __reversed__(self):
+ if self._wrapped is None:
+ self._setup()
+ return reversed(self._wrapped)
+
+
+class Site(Registry, HorizonComponent):
+ """ The core OpenStack Dashboard class. """
+ # Required for registry
+ _registerable_class = Dashboard
+
+ name = "Horizon"
+ namespace = 'horizon'
+ slug = 'horizon'
+ urls = 'horizon.site_urls'
+
+ def __repr__(self):
+ return u"<Site: %s>" % self.__unicode__()
+
+ @property
+ def _conf(self):
+ conf = copy.copy(HORIZON_CONFIG)
+ conf.update(getattr(settings, 'HORIZON_CONFIG', {}))
+ return conf
+
+ @property
+ def dashboards(self):
+ return self._conf['dashboards']
+
+ @property
+ def default_dashboard(self):
+ return self._conf['default_dashboard']
+
+ def register(self, dashboard):
+ """ Registers a :class:`~horizon.Dashboard` with Horizon."""
+ return self._register(dashboard)
+
+ def unregister(self, dashboard):
+ """ Unregisters a :class:`~horizon.Dashboard` from Horizon. """
+ return self._unregister(dashboard)
+
+ def registered(self, dashboard):
+ return self._registered(dashboard)
+
+ def register_panel(self, dashboard, panel):
+ dash_instance = self.registered(dashboard)
+ return dash_instance._register(panel)
+
+ def unregister_panel(self, dashboard, panel):
+ dash_instance = self.registered(dashboard)
+ if not dash_instance:
+ raise NotRegistered("The dashboard %s is not registered."
+ % dashboard)
+ return dash_instance._unregister(panel)
+
+ def get_dashboard(self, dashboard):
+ """ Returns the specified :class:`~horizon.Dashboard` instance. """
+ return self._registered(dashboard)
+
+ def get_dashboards(self):
+ """ Returns an ordered tuple of :class:`~horizon.Dashboard` modules.
+
+ Orders dashboards according to the ``"dashboards"`` key in
+ ``settings.HORIZON_CONFIG`` or else returns all registered dashboards
+ in alphabetical order.
+
+ Any remaining :class:`~horizon.Dashboard` classes registered with
+ Horizon but not listed in ``settings.HORIZON_CONFIG['dashboards']``
+ will be appended to the end of the list alphabetically.
+ """
+ if self.dashboards:
+ registered = copy.copy(self._registry)
+ dashboards = []
+ for item in self.dashboards:
+ dashboard = self._registered(item)
+ dashboards.append(dashboard)
+ registered.pop(dashboard.__class__)
+ if len(registered):
+ extra = registered.values()
+ extra.sort()
+ dashboards.extend(extra)
+ return dashboards
+ else:
+ dashboards = self._registry.values()
+ dashboards.sort()
+ return dashboards
+
+ def get_default_dashboard(self):
+ """ Returns the default :class:`~horizon.Dashboard` instance.
+
+ If ``"default_dashboard"`` is specified in ``settings.HORIZON_CONFIG``
+ then that dashboard will be returned. If not, the first dashboard
+ returned by :func:`~horizon.get_dashboards` will be returned.
+ """
+ if self.default_dashboard:
+ return self._registered(self.default_dashboard)
+ elif len(self._registry):
+ return self.get_dashboards()[0]
+ else:
+ raise NotRegistered("No dashboard modules have been registered.")
+
+ def get_user_home(self, user):
+ """ Returns the default URL for a particular user.
+
+ This method can be used to customize where a user is sent when
+ they log in, etc. By default it returns the value of
+ :meth:`get_absolute_url`.
+
+ An alternative function can be supplied to customize this behavior
+ by specifying a either a URL or a function which returns a URL via
+ the ``"user_home"`` key in ``settings.HORIZON_CONFIG``. Each of these
+ would be valid::
+
+ {"user_home": "/home",} # A URL
+ {"user_home": "my_module.get_user_home",} # Path to a function
+ {"user_home": lambda user: "/" + user.name,} # A function
+
+ This can be useful if the default dashboard may not be accessible
+ to all users.
+ """
+ user_home = self._conf['user_home']
+ if user_home:
+ if callable(user_home):
+ return user_home(user)
+ elif isinstance(user_home, basestring):
+ # Assume we've got a URL if there's a slash in it
+ if user_home.find("/") != -1:
+ return user_home
+ else:
+ mod, func = user_home.rsplit(".", 1)
+ return getattr(import_module(mod), func)(user)
+ # If it's not callable and not a string, it's wrong.
+ raise ValueError('The user_home setting must be either a string '
+ 'or a callable object (e.g. a function).')
+ else:
+ return self.get_absolute_url()
+
+ def get_absolute_url(self):
+ """ Returns the default URL for Horizon's URLconf.
+
+ The default URL is determined by calling
+ :meth:`~horizon.Dashboard.get_absolute_url`
+ on the :class:`~horizon.Dashboard` instance returned by
+ :meth:`~horizon.get_default_dashboard`.
+ """
+ return self.get_default_dashboard().get_absolute_url()
+
+ @property
+ def _lazy_urls(self):
+ """ Lazy loading for URL patterns.
+
+ This method avoids problems associated with attempting to evaluate
+ the the URLconf before the settings module has been loaded.
+ """
+ def url_patterns():
+ return self._urls()[0]
+
+ return LazyURLPattern(url_patterns), self.namespace, self.slug
+
+ def _urls(self):
+ """ Constructs the URLconf for Horizon from registered Dashboards. """
+ urlpatterns = self._get_default_urlpatterns()
+
+ self._autodiscover()
+
+ # Add in each dashboard's views.
+ for dash in self._registry.values():
+ urlpatterns += patterns('',
+ url(r'^%s/' % dash.slug, include(dash._decorated_urls)))
+
+ # Return the three arguments to django.conf.urls.defaults.include
+ return urlpatterns, self.namespace, self.slug
+
+ def _autodiscover(self):
+ """ Discovers modules to register from ``settings.INSTALLED_APPS``.
+
+ This makes sure that the appropriate modules get imported to register
+ themselves with Horizon.
+ """
+ if not getattr(self, '_registerable_class', None):
+ raise ImproperlyConfigured('You must set a '
+ '"_registerable_class" property '
+ 'in order to use autodiscovery.')
+ # Discover both dashboards and panels, in that order
+ for mod_name in ('dashboard', 'panel'):
+ for app in settings.INSTALLED_APPS:
+ mod = import_module(app)
+ try:
+ before_import_registry = copy.copy(self._registry)
+ import_module('%s.%s' % (app, mod_name))
+ except:
+ self._registry = before_import_registry
+ if module_has_submodule(mod, mod_name):
+ raise
+
+# The one true Horizon
+Horizon = Site()
diff --git a/horizon/horizon/context_processors.py b/horizon/horizon/context_processors.py
new file mode 100644
index 00000000..9f0a9878
--- /dev/null
+++ b/horizon/horizon/context_processors.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+"""
+Context processors used by Horizon.
+"""
+
+from django.conf import settings
+from django.contrib import messages
+
+from horizon import api
+
+
+def horizon(request):
+ """ The main Horizon context processor. Required for Horizon to function.
+
+ Adds three variables to the request context:
+
+ ``tenants``
+ A list of the tenants the current uses is authorized to access.
+
+ ``object_store_configured``
+ Boolean. Will be ``True`` if there is a service of type
+ ``object-store`` in the user's ``ServiceCatalog``.
+
+ ``network_configured``
+ Boolean. Will be ``True`` if ``settings.QUANTUM_ENABLED`` is ``True``.
+ """
+ context = {}
+
+ # Auth/Keystone context
+ if request.user.is_authenticated():
+ try:
+ tenants = api.tenant_list_for_token(request, request.user.token)
+ context['tenants'] = tenants
+ except Exception, e:
+ if hasattr(request.user, 'message_set'):
+ messages.error(request, _("Unable to retrieve tenant list from\
+ keystone: %s") % e.message)
+ context['tenants'] = []
+
+ # Object Store/Swift context
+ catalog = getattr(request.user, 'service_catalog', [])
+ object_store = catalog and api.get_service_from_catalog(catalog,
+ 'object-store')
+ context['object_store_configured'] = object_store
+
+ # Quantum context
+ # TODO(gabriel): Convert to service catalog check when Quantum starts
+ # supporting keystone integration.
+ context['network_configured'] = getattr(settings, 'QUANTUM_ENABLED', None)
+
+ return context
diff --git a/django-openstack/django_openstack/auth/__init__.py b/horizon/horizon/dashboards/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/auth/__init__.py
+++ b/horizon/horizon/dashboards/__init__.py
diff --git a/django-openstack/django_openstack/dash/__init__.py b/horizon/horizon/dashboards/nova/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/dash/__init__.py
+++ b/horizon/horizon/dashboards/nova/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/__init__.py b/horizon/horizon/dashboards/nova/containers/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/dash/views/__init__.py
+++ b/horizon/horizon/dashboards/nova/containers/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/objects.py b/horizon/horizon/dashboards/nova/containers/forms.py
index f8d34e55..576f2356 100644
--- a/django-openstack/django_openstack/dash/views/objects.py
+++ b/horizon/horizon/dashboards/nova/containers/forms.py
@@ -18,24 +18,45 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Views for managing Swift containers.
-"""
import logging
-from django import http
-from django import template
-from django.contrib import messages
-from django.contrib.auth.decorators import login_required
+from cloudfiles.errors import ContainerNotEmpty
from django import shortcuts
-from django.shortcuts import render_to_response
-from django.utils.translation import ugettext as _
+from django.contrib import messages
+
+from horizon import api
+from horizon import forms
+
-from django_openstack import api
-from django_openstack import forms
+LOG = logging.getLogger(__name__)
-LOG = logging.getLogger('django_openstack.dash')
+class DeleteContainer(forms.SelfHandlingForm):
+ container_name = forms.CharField(widget=forms.HiddenInput())
+
+ def handle(self, request, data):
+ try:
+ api.swift_delete_container(request, data['container_name'])
+ except ContainerNotEmpty, e:
+ messages.error(request,
+ _('Unable to delete non-empty container: %s') %
+ data['container_name'])
+ LOG.exception('Unable to delete container "%s". Exception: "%s"' %
+ (data['container_name'], str(e)))
+ else:
+ messages.info(request,
+ _('Successfully deleted container: %s') % \
+ data['container_name'])
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class CreateContainer(forms.SelfHandlingForm):
+ name = forms.CharField(max_length="255", label=_("Container Name"))
+
+ def handle(self, request, data):
+ api.swift_create_container(request, data['name'])
+ messages.success(request, _("Container was successfully created."))
+ return shortcuts.redirect("horizon:nova:containers:index")
class FilterObjects(forms.SelfHandlingForm):
@@ -119,77 +140,3 @@ class CopyObject(forms.SelfHandlingForm):
{"container": new_container_name, "obj": new_object_name})
return shortcuts.redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id, container_name):
- marker = request.GET.get('marker', None)
-
- delete_form, handled = DeleteObject.maybe_handle(request)
- if handled:
- return handled
-
- filter_form, objects = FilterObjects.maybe_handle(request)
-
- if objects is None:
- filter_form.fields['container_name'].initial = container_name
- objects = api.swift_get_objects(request, container_name, marker=marker)
-
- delete_form.fields['container_name'].initial = container_name
- return render_to_response(
- 'django_openstack/dash/objects/index.html', {
- 'container_name': container_name,
- 'objects': objects,
- 'delete_form': delete_form,
- 'filter_form': filter_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def upload(request, tenant_id, container_name):
- form, handled = UploadObject.maybe_handle(request)
- if handled:
- return handled
-
- form.fields['container_name'].initial = container_name
- return render_to_response(
- 'django_openstack/dash/objects/upload.html', {
- 'container_name': container_name,
- 'upload_form': form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def download(request, tenant_id, container_name, object_name):
- object_data = api.swift_get_object_data(
- request, container_name, object_name)
-
- response = http.HttpResponse()
- response['Content-Disposition'] = 'attachment; filename=%s' % \
- object_name
- for data in object_data:
- response.write(data)
- return response
-
-
-@login_required
-def copy(request, tenant_id, container_name, object_name):
- containers = \
- [(c.name, c.name) for c in api.swift_get_containers(
- request)]
- form, handled = CopyObject.maybe_handle(request,
- containers=containers)
-
- if handled:
- return handled
-
- form.fields['new_container_name'].initial = container_name
- form.fields['orig_container_name'].initial = container_name
- form.fields['orig_object_name'].initial = object_name
-
- return render_to_response(
- 'django_openstack/dash/objects/copy.html',
- {'container_name': container_name,
- 'object_name': object_name,
- 'copy_form': form},
- context_instance=template.RequestContext(request))
diff --git a/horizon/horizon/dashboards/nova/containers/panel.py b/horizon/horizon/dashboards/nova/containers/panel.py
new file mode 100644
index 00000000..06c95289
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/containers/panel.py
@@ -0,0 +1,35 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.utils.translation import ugettext as _
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Containers(horizon.Panel):
+ name = _("Containers")
+ slug = 'containers'
+
+ def nav(self, context):
+ return context['object_store_configured']
+
+
+dashboard.Nova.register(Containers)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/object_tests.py b/horizon/horizon/dashboards/nova/containers/tests.py
index 0314394e..3be11297 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/object_tests.py
+++ b/horizon/horizon/dashboards/nova/containers/tests.py
@@ -20,14 +20,105 @@
import tempfile
+from cloudfiles.errors import ContainerNotEmpty
from django import http
+from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
-from mox import IsA
+from mox import IgnoreArg, IsA
+from horizon import api
+from horizon import test
-class ObjectViewTests(base.BaseViewTests):
+
+CONTAINER_INDEX_URL = reverse('horizon:nova:containers:index')
+
+
+class ContainerViewTests(test.BaseViewTests):
+ def setUp(self):
+ super(ContainerViewTests, self).setUp()
+ self.container = self.mox.CreateMock(api.Container)
+ self.container.name = 'containerName'
+
+ def test_index(self):
+ self.mox.StubOutWithMock(api, 'swift_get_containers')
+ api.swift_get_containers(
+ IsA(http.HttpRequest), marker=None).AndReturn([self.container])
+
+ self.mox.ReplayAll()
+
+ res = self.client.get(CONTAINER_INDEX_URL)
+
+ self.assertTemplateUsed(res, 'nova/containers/index.html')
+ self.assertIn('containers', res.context)
+ containers = res.context['containers']
+
+ self.assertEqual(len(containers), 1)
+ self.assertEqual(containers[0].name, 'containerName')
+
+ self.mox.VerifyAll()
+
+ def test_delete_container(self):
+ formData = {'container_name': 'containerName',
+ 'method': 'DeleteContainer'}
+
+ self.mox.StubOutWithMock(api, 'swift_delete_container')
+ api.swift_delete_container(IsA(http.HttpRequest),
+ 'containerName')
+
+ self.mox.ReplayAll()
+
+ res = self.client.post(CONTAINER_INDEX_URL, formData)
+
+ self.assertRedirectsNoFollow(res, CONTAINER_INDEX_URL)
+
+ self.mox.VerifyAll()
+
+ def test_delete_container_nonempty(self):
+ formData = {'container_name': 'containerName',
+ 'method': 'DeleteContainer'}
+
+ exception = ContainerNotEmpty('containerNotEmpty')
+
+ self.mox.StubOutWithMock(api, 'swift_delete_container')
+ api.swift_delete_container(
+ IsA(http.HttpRequest),
+ 'containerName').AndRaise(exception)
+
+ self.mox.StubOutWithMock(messages, 'error')
+
+ messages.error(IgnoreArg(), IsA(unicode))
+
+ self.mox.ReplayAll()
+
+ res = self.client.post(CONTAINER_INDEX_URL, formData)
+
+ self.assertRedirectsNoFollow(res, CONTAINER_INDEX_URL)
+
+ self.mox.VerifyAll()
+
+ def test_create_container_get(self):
+ res = self.client.get(reverse('horizon:nova:containers:create'))
+
+ self.assertTemplateUsed(res, 'nova/containers/create.html')
+
+ def test_create_container_post(self):
+ formData = {'name': 'containerName',
+ 'method': 'CreateContainer'}
+
+ self.mox.StubOutWithMock(api, 'swift_create_container')
+ api.swift_create_container(
+ IsA(http.HttpRequest), 'CreateContainer')
+
+ self.mox.StubOutWithMock(messages, 'success')
+ messages.success(IgnoreArg(), IsA(basestring))
+
+ res = self.client.post(reverse('horizon:nova:containers:create'),
+ formData)
+
+ self.assertRedirectsNoFollow(res, CONTAINER_INDEX_URL)
+
+
+class ObjectViewTests(test.BaseViewTests):
CONTAINER_NAME = 'containerName'
def setUp(self):
@@ -44,22 +135,18 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_objects',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/objects/index.html')
+ res = self.client.get(reverse('horizon:nova:containers:object_index',
+ args=[self.CONTAINER_NAME]))
+ self.assertTemplateUsed(res, 'nova/objects/index.html')
self.assertItemsEqual(res.context['objects'], self.swift_objects)
self.mox.VerifyAll()
def test_upload_index(self):
- res = self.client.get(reverse('dash_objects_upload',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]))
+ res = self.client.get(reverse('horizon:nova:containers:object_upload',
+ args=[self.CONTAINER_NAME]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/objects/upload.html')
+ self.assertTemplateUsed(res, 'nova/objects/upload.html')
def test_upload(self):
OBJECT_DATA = 'objectData'
@@ -82,14 +169,13 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_objects_upload',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]),
+ res = self.client.post(reverse('horizon:nova:containers:object_upload',
+ args=[self.CONTAINER_NAME]),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_objects_upload',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:containers:object_upload',
+ args=[self.CONTAINER_NAME]))
self.mox.VerifyAll()
@@ -106,14 +192,13 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_objects',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]),
+ res = self.client.post(reverse('horizon:nova:containers:object_index',
+ args=[self.CONTAINER_NAME]),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_objects',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:containers:object_index',
+ args=[self.CONTAINER_NAME]))
self.mox.VerifyAll()
@@ -128,10 +213,9 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_objects_download',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME,
- OBJECT_NAME]))
+ res = self.client.get(reverse(
+ 'horizon:nova:containers:object_download',
+ args=[self.CONTAINER_NAME, OBJECT_NAME]))
self.assertEqual(res.content, OBJECT_DATA)
self.assertTrue(res.has_header('Content-Disposition'))
@@ -150,13 +234,11 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_object_copy',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME,
+ res = self.client.get(reverse('horizon:nova:containers:object_copy',
+ args=[self.CONTAINER_NAME,
OBJECT_NAME]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/objects/copy.html')
+ self.assertTemplateUsed(res, 'nova/objects/copy.html')
self.mox.VerifyAll()
@@ -188,16 +270,15 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_object_copy',
- args=[self.TEST_TENANT,
- ORIG_CONTAINER_NAME,
+ res = self.client.post(reverse('horizon:nova:containers:object_copy',
+ args=[ORIG_CONTAINER_NAME,
ORIG_OBJECT_NAME]),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_object_copy',
- args=[self.TEST_TENANT,
- ORIG_CONTAINER_NAME,
- ORIG_OBJECT_NAME]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:containers:object_copy',
+ args=[ORIG_CONTAINER_NAME,
+ ORIG_OBJECT_NAME]))
self.mox.VerifyAll()
@@ -212,17 +293,15 @@ class ObjectViewTests(base.BaseViewTests):
self.mox.StubOutWithMock(api, 'swift_get_objects')
api.swift_get_objects(IsA(http.HttpRequest),
unicode(self.CONTAINER_NAME),
- prefix=unicode(PREFIX)
- ).AndReturn(self.swift_objects)
+ prefix=unicode(PREFIX))\
+ .AndReturn(self.swift_objects)
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_objects',
- args=[self.TEST_TENANT,
- self.CONTAINER_NAME]),
+ res = self.client.post(reverse('horizon:nova:containers:object_index',
+ args=[self.CONTAINER_NAME]),
formData)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/objects/index.html')
+ self.assertTemplateUsed(res, 'nova/objects/index.html')
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/containers/urls.py b/horizon/horizon/dashboards/nova/containers/urls.py
new file mode 100644
index 00000000..5ad9a367
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/containers/urls.py
@@ -0,0 +1,36 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+OBJECTS = r'^(?P<container_name>[^/]+)/%s$'
+
+
+# Swift containers and objects.
+urlpatterns = patterns('horizon.dashboards.nova.containers.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'),
+ url(OBJECTS % '', 'object_index', name='object_index'),
+ url(OBJECTS % 'upload', 'object_upload', name='object_upload'),
+ url(OBJECTS % '(?P<object_name>[^/]+)/copy',
+ 'object_copy', name='object_copy'),
+ url(OBJECTS % '(?P<object_name>[^/]+)/download',
+ 'object_download', name='object_download'))
diff --git a/horizon/horizon/dashboards/nova/containers/views.py b/horizon/horizon/dashboards/nova/containers/views.py
new file mode 100644
index 00000000..2f89709e
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/containers/views.py
@@ -0,0 +1,134 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Swift containers.
+"""
+import logging
+
+from django import http
+from django.contrib.auth.decorators import login_required
+from django import shortcuts
+from django.utils.translation import ugettext as _
+
+from horizon import api
+from horizon.dashboards.nova.containers.forms import (DeleteContainer,
+ CreateContainer, FilterObjects, DeleteObject, UploadObject, CopyObject)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ marker = request.GET.get('marker', None)
+
+ delete_form, handled = DeleteContainer.maybe_handle(request)
+ if handled:
+ return handled
+
+ containers = api.swift_get_containers(request, marker=marker)
+
+ return shortcuts.render(request,
+ 'nova/containers/index.html',
+ {'containers': containers,
+ 'delete_form': delete_form})
+
+
+@login_required
+def create(request):
+ form, handled = CreateContainer.maybe_handle(request)
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/containers/create.html',
+ {'create_form': form})
+
+
+@login_required
+def object_index(request, container_name):
+ marker = request.GET.get('marker', None)
+
+ delete_form, handled = DeleteObject.maybe_handle(request)
+ if handled:
+ return handled
+
+ filter_form, objects = FilterObjects.maybe_handle(request)
+
+ if objects is None:
+ filter_form.fields['container_name'].initial = container_name
+ objects = api.swift_get_objects(request, container_name, marker=marker)
+
+ delete_form.fields['container_name'].initial = container_name
+ return shortcuts.render(request,
+ 'nova/objects/index.html',
+ {'container_name': container_name,
+ 'objects': objects,
+ 'delete_form': delete_form,
+ 'filter_form': filter_form})
+
+
+@login_required
+def object_upload(request, container_name):
+ form, handled = UploadObject.maybe_handle(request)
+ if handled:
+ return handled
+
+ form.fields['container_name'].initial = container_name
+ return shortcuts.render(request,
+ 'nova/objects/upload.html',
+ {'container_name': container_name,
+ 'upload_form': form})
+
+
+@login_required
+def object_download(request, container_name, object_name):
+ object_data = api.swift_get_object_data(
+ request, container_name, object_name)
+
+ response = http.HttpResponse()
+ response['Content-Disposition'] = 'attachment; filename=%s' % \
+ object_name
+ for data in object_data:
+ response.write(data)
+ return response
+
+
+@login_required
+def object_copy(request, container_name, object_name):
+ containers = \
+ [(c.name, c.name) for c in api.swift_get_containers(
+ request)]
+ form, handled = CopyObject.maybe_handle(request,
+ containers=containers)
+
+ if handled:
+ return handled
+
+ form.fields['new_container_name'].initial = container_name
+ form.fields['orig_container_name'].initial = container_name
+ form.fields['orig_object_name'].initial = object_name
+
+ return shortcuts.render(request,
+ 'nova/objects/copy.html',
+ {'container_name': container_name,
+ 'object_name': object_name,
+ 'copy_form': form})
diff --git a/horizon/horizon/dashboards/nova/dashboard.py b/horizon/horizon/dashboards/nova/dashboard.py
new file mode 100644
index 00000000..380b2710
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/dashboard.py
@@ -0,0 +1,33 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.utils.translation import ugettext as _
+
+import horizon
+
+
+class Nova(horizon.Dashboard):
+ name = "User Dashboard"
+ slug = "nova"
+ panels = {_("Manage Compute"): ('overview', 'instances', 'images',
+ 'snapshots', 'keypairs', 'volumes',
+ 'floating_ips', 'security_groups',),
+ _("Network"): ('networks',),
+ _("Object Store"): ('containers',)}
+ default_panel = 'overview'
+
+
+horizon.register(Nova)
diff --git a/django-openstack/django_openstack/middleware/__init__.py b/horizon/horizon/dashboards/nova/floating_ips/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/middleware/__init__.py
+++ b/horizon/horizon/dashboards/nova/floating_ips/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/floating_ips.py b/horizon/horizon/dashboards/nova/floating_ips/forms.py
index 6678f8a8..f7100e3b 100644
--- a/django-openstack/django_openstack/dash/views/floating_ips.py
+++ b/horizon/horizon/dashboards/nova/floating_ips/forms.py
@@ -18,23 +18,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Views for managing Nova floating ips.
-"""
import logging
-from django import template
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django import shortcuts
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
from novaclient import exceptions as novaclient_exceptions
+from horizon import api
+from horizon import forms
+
-LOG = logging.getLogger('django_openstack.dash.views.floating_ip')
+LOG = logging.getLogger(__name__)
class ReleaseFloatingIp(forms.SelfHandlingForm):
@@ -81,7 +77,7 @@ class FloatingIpAssociate(forms.SelfHandlingForm):
LOG.exception("ClientException in FloatingIpAssociate")
messages.error(request, _('Error associating Floating IP: %s')
% e.message)
- return shortcuts.redirect('dash_floating_ips', request.user.tenant_id)
+ return shortcuts.redirect('horizon:nova:floating_ips:index')
class FloatingIpDisassociate(forms.SelfHandlingForm):
@@ -102,7 +98,7 @@ class FloatingIpDisassociate(forms.SelfHandlingForm):
LOG.exception("ClientException in FloatingIpAssociate")
messages.error(request, _('Error disassociating Floating IP: %s')
% e.message)
- return shortcuts.redirect('dash_floating_ips', request.user.tenant_id)
+ return shortcuts.redirect('horizon:nova:floating_ips:index')
class FloatingIpAllocate(forms.SelfHandlingForm):
@@ -124,58 +120,4 @@ class FloatingIpAllocate(forms.SelfHandlingForm):
messages.error(request, _('Error allocating Floating IP "%(ip)s"\
to tenant "%(tenant)s": %(msg)s') %
{"ip": fip.ip, "tenant": data['tenant_id'], "msg": e.message})
- return shortcuts.redirect('dash_floating_ips', request.user.tenant_id)
-
-
-@login_required
-def index(request, tenant_id):
- for f in (ReleaseFloatingIp, FloatingIpDisassociate, FloatingIpAllocate):
- _unused, handled = f.maybe_handle(request)
- if handled:
- return handled
- try:
- floating_ips = api.tenant_floating_ip_list(request)
- except novaclient_exceptions.ClientException, e:
- floating_ips = []
- LOG.exception("ClientException in floating ip index")
- messages.error(request,
- _('Error fetching floating ips: %s') % e.message)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/floating_ips/index.html', {
- 'allocate_form': FloatingIpAllocate(
- initial={'tenant_id': request.user.tenant_id}),
- 'disassociate_form': FloatingIpDisassociate(),
- 'floating_ips': floating_ips,
- 'release_form': ReleaseFloatingIp(),
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def associate(request, tenant_id, ip_id):
- instancelist = [(server.id, 'id: %s, name: %s' %
- (server.id, server.name))
- for server in api.server_list(request)]
-
- form, handled = FloatingIpAssociate().maybe_handle(request, initial={
- 'floating_ip_id': ip_id,
- 'floating_ip': api.tenant_floating_ip_get(request, ip_id).ip,
- 'instances': instancelist})
- if handled:
- return handled
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/floating_ips/associate.html', {
- 'associate_form': form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def disassociate(request, tenant_id, ip_id):
- form, handled = FloatingIpDisassociate().maybe_handle(request)
- if handled:
- return handled
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/floating_ips/associate.html', {
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect('horizon:nova:floating_ips:index')
diff --git a/horizon/horizon/dashboards/nova/floating_ips/panel.py b/horizon/horizon/dashboards/nova/floating_ips/panel.py
new file mode 100644
index 00000000..cba90145
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/floating_ips/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class FloatingIPs(horizon.Panel):
+ name = "Floating IPs"
+ slug = 'floating_ips'
+
+
+dashboard.Nova.register(FloatingIPs)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/floating_ip_tests.py b/horizon/horizon/dashboards/nova/floating_ips/tests.py
index 6a7c05f0..3d6925a1 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/floating_ip_tests.py
+++ b/horizon/horizon/dashboards/nova/floating_ips/tests.py
@@ -24,15 +24,18 @@ from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
-from django_openstack import api
-from django_openstack import utils
-from django_openstack.dash.views.floating_ips import FloatingIpAssociate
-from django_openstack.tests.view_tests import base
from mox import IsA, IgnoreArg
from novaclient import exceptions as novaclient_exceptions
+from horizon import api
+from horizon import test
+from horizon.dashboards.nova.floating_ips.forms import FloatingIpAssociate
-class FloatingIpViewTests(base.BaseViewTests):
+
+FLOATING_IPS_INDEX = reverse('horizon:nova:floating_ips:index')
+
+
+class FloatingIpViewTests(test.BaseViewTests):
def setUp(self):
super(FloatingIpViewTests, self).setUp()
@@ -57,10 +60,8 @@ class FloatingIpViewTests(base.BaseViewTests):
AndReturn(self.floating_ips)
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_floating_ips',
- args=[self.TEST_TENANT]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/floating_ips/index.html')
+ res = self.client.get(FLOATING_IPS_INDEX)
+ self.assertTemplateUsed(res, 'nova/floating_ips/index.html')
self.assertItemsEqual(res.context['floating_ips'], self.floating_ips)
self.mox.VerifyAll()
@@ -76,10 +77,9 @@ class FloatingIpViewTests(base.BaseViewTests):
AndReturn(self.floating_ip)
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_floating_ips_associate',
- args=[self.TEST_TENANT, 1]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/floating_ips/associate.html')
+ res = self.client.get(reverse('horizon:nova:floating_ips:associate',
+ args=[1]))
+ self.assertTemplateUsed(res, 'nova/floating_ips/associate.html')
self.mox.VerifyAll()
def test_associate_post(self):
@@ -107,15 +107,14 @@ class FloatingIpViewTests(base.BaseViewTests):
AndReturn(self.floating_ip)
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_floating_ips_associate',
- args=[self.TEST_TENANT, 1]),
- {'instance_id': 1,
- 'floating_ip_id': self.floating_ip.id,
- 'floating_ip': self.floating_ip.ip,
- 'method': 'FloatingIpAssociate'})
+ res = self.client.post(reverse('horizon:nova:floating_ips:associate',
+ args=[1]),
+ {'instance_id': 1,
+ 'floating_ip_id': self.floating_ip.id,
+ 'floating_ip': self.floating_ip.ip,
+ 'method': 'FloatingIpAssociate'})
- self.assertRedirects(res, reverse('dash_floating_ips',
- args=[self.TEST_TENANT]))
+ self.assertRedirects(res, FLOATING_IPS_INDEX)
self.mox.VerifyAll()
def test_associate_post_with_exception(self):
@@ -146,24 +145,22 @@ class FloatingIpViewTests(base.BaseViewTests):
AndReturn(self.floating_ip)
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_floating_ips_associate',
- args=[self.TEST_TENANT, 1]),
- {'instance_id': 1,
- 'floating_ip_id': self.floating_ip.id,
- 'floating_ip': self.floating_ip.ip,
- 'method': 'FloatingIpAssociate'})
+ res = self.client.post(reverse('horizon:nova:floating_ips:associate',
+ args=[1]),
+ {'instance_id': 1,
+ 'floating_ip_id': self.floating_ip.id,
+ 'floating_ip': self.floating_ip.ip,
+ 'method': 'FloatingIpAssociate'})
self.assertRaises(novaclient_exceptions.ClientException)
- self.assertRedirects(res, reverse('dash_floating_ips',
- args=[self.TEST_TENANT]))
+ self.assertRedirects(res, FLOATING_IPS_INDEX)
self.mox.VerifyAll()
def test_disassociate(self):
- res = self.client.get(reverse('dash_floating_ips_disassociate',
- args=[self.TEST_TENANT, 1]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/floating_ips/associate.html')
+ res = self.client.get(reverse('horizon:nova:floating_ips:disassociate',
+ args=[1]))
+ self.assertTemplateUsed(res, 'nova/floating_ips/associate.html')
self.mox.VerifyAll()
def test_disassociate_post(self):
@@ -184,12 +181,11 @@ class FloatingIpViewTests(base.BaseViewTests):
api.tenant_floating_ip_get(IsA(http.HttpRequest), IsA(unicode)).\
AndReturn(self.floating_ip)
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_floating_ips_disassociate',
- args=[self.TEST_TENANT, 1]),
- {'floating_ip_id': self.floating_ip.id,
- 'method': 'FloatingIpDisassociate'})
- self.assertRedirects(res, reverse('dash_floating_ips',
- args=[self.TEST_TENANT]))
+ res = self.client.post(
+ reverse('horizon:nova:floating_ips:disassociate', args=[1]),
+ {'floating_ip_id': self.floating_ip.id,
+ 'method': 'FloatingIpDisassociate'})
+ self.assertRedirects(res, FLOATING_IPS_INDEX)
self.mox.VerifyAll()
def test_disassociate_post_with_exception(self):
@@ -211,11 +207,10 @@ class FloatingIpViewTests(base.BaseViewTests):
api.tenant_floating_ip_get(IsA(http.HttpRequest), IsA(unicode)).\
AndReturn(self.floating_ip)
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_floating_ips_disassociate',
- args=[self.TEST_TENANT, 1]),
- {'floating_ip_id': self.floating_ip.id,
- 'method': 'FloatingIpDisassociate'})
+ res = self.client.post(
+ reverse('horizon:nova:floating_ips:disassociate', args=[1]),
+ {'floating_ip_id': self.floating_ip.id,
+ 'method': 'FloatingIpDisassociate'})
self.assertRaises(novaclient_exceptions.ClientException)
- self.assertRedirects(res, reverse('dash_floating_ips',
- args=[self.TEST_TENANT]))
+ self.assertRedirects(res, FLOATING_IPS_INDEX)
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/floating_ips/urls.py b/horizon/horizon/dashboards/nova/floating_ips/urls.py
new file mode 100644
index 00000000..64abd2d1
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/floating_ips/urls.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.nova.floating_ips.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^(?P<ip_id>[^/]+)/associate/$', 'associate', name='associate'),
+ url(r'^(?P<ip_id>[^/]+)/disassociate/$', 'disassociate',
+ name='disassociate'))
diff --git a/horizon/horizon/dashboards/nova/floating_ips/views.py b/horizon/horizon/dashboards/nova/floating_ips/views.py
new file mode 100644
index 00000000..8e795dec
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/floating_ips/views.py
@@ -0,0 +1,88 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Nova floating IPs.
+"""
+import logging
+
+from django import template
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django import shortcuts
+from django.utils.translation import ugettext as _
+from novaclient import exceptions as novaclient_exceptions
+
+from horizon import api
+from horizon.dashboards.nova.floating_ips.forms import (ReleaseFloatingIp,
+ FloatingIpAssociate, FloatingIpDisassociate, FloatingIpAllocate)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ for f in (ReleaseFloatingIp, FloatingIpDisassociate, FloatingIpAllocate):
+ _unused, handled = f.maybe_handle(request)
+ if handled:
+ return handled
+ try:
+ floating_ips = api.tenant_floating_ip_list(request)
+ except novaclient_exceptions.ClientException, e:
+ floating_ips = []
+ LOG.exception("ClientException in floating ip index")
+ messages.error(request,
+ _('Error fetching floating ips: %s') % e.message)
+ allocate_form = FloatingIpAllocate(initial={
+ 'tenant_id': request.user.tenant_id})
+ return shortcuts.render(request,
+ 'nova/floating_ips/index.html', {
+ 'allocate_form': allocate_form,
+ 'disassociate_form': FloatingIpDisassociate(),
+ 'floating_ips': floating_ips,
+ 'release_form': ReleaseFloatingIp()})
+
+
+@login_required
+def associate(request, ip_id):
+ instancelist = [(server.id, 'id: %s, name: %s' %
+ (server.id, server.name))
+ for server in api.server_list(request)]
+
+ form, handled = FloatingIpAssociate().maybe_handle(request, initial={
+ 'floating_ip_id': ip_id,
+ 'floating_ip': api.tenant_floating_ip_get(request, ip_id).ip,
+ 'instances': instancelist})
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/floating_ips/associate.html', {
+ 'associate_form': form})
+
+
+@login_required
+def disassociate(request, ip_id):
+ form, handled = FloatingIpDisassociate().maybe_handle(request)
+ if handled:
+ return handled
+
+ return shortcuts.render(request, 'nova/floating_ips/associate.html', {})
diff --git a/django-openstack/django_openstack/syspanel/__init__.py b/horizon/horizon/dashboards/nova/images/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/syspanel/__init__.py
+++ b/horizon/horizon/dashboards/nova/images/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/images.py b/horizon/horizon/dashboards/nova/images/forms.py
index 3ff1d61b..806d0621 100644
--- a/django-openstack/django_openstack/dash/views/images.py
+++ b/horizon/horizon/dashboards/nova/images/forms.py
@@ -24,21 +24,17 @@ Views for managing Nova images.
import logging
-from django import template
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect, render_to_response
+from django.shortcuts import redirect
from django.utils.text import normalize_newlines
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
-from openstackx.api import exceptions as api_exceptions
from glance.common import exception as glance_exception
-from novaclient import exceptions as novaclient_exceptions
+from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon import forms
-LOG = logging.getLogger('django_openstack.dash.views.images')
+LOG = logging.getLogger(__name__)
class UpdateImageForm(forms.SelfHandlingForm):
@@ -169,7 +165,7 @@ class LaunchForm(forms.SelfHandlingForm):
msg = _('Instance was successfully launched')
LOG.info(msg)
messages.success(request, msg)
- return redirect('dash_instances', tenant_id)
+ return redirect('horizon:nova:instances:index')
except api_exceptions.ApiException, e:
LOG.exception('ApiException while creating instances of image "%s"'
@@ -202,129 +198,3 @@ class DeleteImage(forms.SelfHandlingForm):
_("Error deleting image: %(image)s: %i(msg)s")
% {"image": image_id, "msg": e.message})
return redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id):
- for f in (DeleteImage, ):
- unused, handled = f.maybe_handle(request)
- if handled:
- return handled
- delete_form = DeleteImage()
-
- all_images = []
- try:
- all_images = api.image_list_detailed(request)
- if not all_images:
- messages.info(request, _("There are currently no images."))
- except glance_exception.ClientConnectionError, e:
- LOG.exception("Error connecting to glance")
- messages.error(request, _("Error connecting to glance: %s") % str(e))
- except glance_exception.Error, e:
- LOG.exception("Error retrieving image list")
- messages.error(request, _("Error retrieving image list: %s") % str(e))
- except api_exceptions.ApiException, e:
- msg = _("Unable to retreive image info from glance: %s") % str(e)
- LOG.exception(msg)
- messages.error(request, msg)
-
- images = [im for im in all_images
- if im['container_format'] not in ['aki', 'ari']]
-
- return render_to_response(
- 'django_openstack/dash/images/index.html', {
- 'delete_form': delete_form,
- 'images': images,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def launch(request, tenant_id, image_id):
-
- def flavorlist():
- try:
- fl = api.flavor_list(request)
-
- # TODO add vcpu count to flavors
- sel = [(f.id, '%s (%svcpu / %sGB Disk / %sMB Ram )' %
- (f.name, f.vcpus, f.disk, f.ram)) for f in fl]
- return sorted(sel)
- except api_exceptions.ApiException:
- LOG.exception('Unable to retrieve list of instance types')
- return [(1, 'm1.tiny')]
-
- def keynamelist():
- try:
- fl = api.keypair_list(request)
- sel = [(f.name, f.name) for f in fl]
- return sel
- except api_exceptions.ApiException:
- LOG.exception('Unable to retrieve list of keypairs')
- return []
-
- def securitygrouplist():
- try:
- fl = api.security_group_list(request)
- sel = [(f.name, f.name) for f in fl]
- return sel
- except novaclient_exceptions.ClientException, e:
- LOG.exception('Unable to retrieve list of security groups')
- return []
-
- # TODO(mgius): Any reason why these can't be after the launchform logic?
- # If The form is valid, we've just wasted these two api calls
- image = api.image_get(request, image_id)
- quotas = api.tenant_quota_get(request, request.user.tenant_id)
- try:
- quotas.ram = int(quotas.ram)
- except Exception, e:
- messages.error(request,
- _('Error parsing quota for %(image)s: %(msg)s') %
- {"image": image_id, "msg": e.message})
- return redirect('dash_instances', tenant_id)
-
- form, handled = LaunchForm.maybe_handle(
- request, initial={'flavorlist': flavorlist(),
- 'keynamelist': keynamelist(),
- 'securitygrouplist': securitygrouplist(),
- 'image_id': image_id,
- 'tenant_id': tenant_id})
- if handled:
- return handled
-
- return render_to_response(
- 'django_openstack/dash/images/launch.html', {
- 'image': image,
- 'form': form,
- 'quotas': quotas,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def update(request, tenant_id, image_id):
- try:
- image = api.image_get(request, image_id)
- except glance_exception.ClientConnectionError, e:
- LOG.exception("Error connecting to glance")
- messages.error(request, _("Error connecting to glance: %s")
- % e.message)
- except glance_exception.Error, e:
- LOG.exception('Error retrieving image with id "%s"' % image_id)
- messages.error(request,
- _("Error retrieving image %(image)s: %(msg)s")
- % {"image": image_id, "msg": e.message})
-
- form, handled = UpdateImageForm().maybe_handle(request, initial={
- 'image_id': image_id,
- 'name': image.get('name', ''),
- 'kernel': image['properties'].get('kernel_id', ''),
- 'ramdisk': image['properties'].get('ramdisk_id', ''),
- 'architecture': image['properties'].get('architecture', ''),
- 'container_format': image.get('container_format', ''),
- 'disk_format': image.get('disk_format', ''), })
- if handled:
- return handled
-
- return render_to_response('django_openstack/dash/images/update.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
diff --git a/django-openstack/django_openstack/syspanel/forms.py b/horizon/horizon/dashboards/nova/images/panel.py
index e8af46ce..12f293c5 100644
--- a/django-openstack/django_openstack/syspanel/forms.py
+++ b/horizon/horizon/dashboards/nova/images/panel.py
@@ -18,12 +18,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django import forms
+import horizon
+from horizon.dashboards.nova import dashboard
-class DisableProject(forms.Form):
- project_name = forms.CharField()
+class Images(horizon.Panel):
+ name = "Images"
+ slug = 'images'
-class DisableIpAddress(forms.Form):
- cidr = forms.CharField()
+dashboard.Nova.register(Images)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/images_tests.py b/horizon/horizon/dashboards/nova/images/tests.py
index 075e0e87..24e2f5bc 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/images_tests.py
+++ b/horizon/horizon/dashboards/nova/images/tests.py
@@ -21,18 +21,22 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from glance.common import exception as glance_exception
from openstackx.api import exceptions as api_exceptions
from mox import IgnoreArg, IsA
+from horizon import api
+from horizon import test
+
+
+IMAGES_INDEX_URL = reverse('horizon:nova:images:index')
+
class FakeQuota:
ram = 100
-class ImageViewTests(base.BaseViewTests):
+class ImageViewTests(test.BaseViewTests):
def setUp(self):
super(ImageViewTests, self).setUp()
image_dict = {'name': 'visibleImage',
@@ -67,10 +71,9 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images', args=[self.TEST_TENANT]))
+ res = self.client.get(IMAGES_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/index.html')
+ self.assertTemplateUsed(res, 'nova/images/index.html')
self.assertIn('images', res.context)
images = res.context['images']
@@ -88,10 +91,9 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images', args=[self.TEST_TENANT]))
+ res = self.client.get(IMAGES_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/index.html')
+ self.assertTemplateUsed(res, 'nova/images/index.html')
self.mox.VerifyAll()
@@ -105,10 +107,10 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images', args=[self.TEST_TENANT]))
+ res = self.client.get(IMAGES_INDEX_URL)
self.assertTemplateUsed(res,
- 'django_openstack/dash/images/index.html')
+ 'nova/images/index.html')
self.mox.VerifyAll()
@@ -122,10 +124,9 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images', args=[self.TEST_TENANT]))
+ res = self.client.get(IMAGES_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/index.html')
+ self.assertTemplateUsed(res, 'nova/images/index.html')
self.mox.VerifyAll()
@@ -152,11 +153,10 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images_launch',
- args=[self.TEST_TENANT, IMAGE_ID]))
+ res = self.client.get(reverse('horizon:nova:images:launch',
+ args=[IMAGE_ID]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/launch.html')
+ self.assertTemplateUsed(res, 'nova/images/launch.html')
image = res.context['image']
self.assertEqual(image.name, self.visibleImage.name)
@@ -226,12 +226,12 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_images_launch',
- args=[self.TEST_TENANT, IMAGE_ID]),
+ res = self.client.post(reverse('horizon:nova:images:launch',
+ args=[IMAGE_ID]),
form_data)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -259,11 +259,10 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images_launch',
- args=[self.TEST_TENANT, IMAGE_ID]))
+ res = self.client.get(reverse('horizon:nova:images:launch',
+ args=[IMAGE_ID]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/launch.html')
+ self.assertTemplateUsed(res, 'nova/images/launch.html')
form = res.context['form']
@@ -296,11 +295,10 @@ class ImageViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_images_launch',
- args=[self.TEST_TENANT, IMAGE_ID]))
+ res = self.client.get(reverse('horizon:nova:images:launch',
+ args=[IMAGE_ID]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/launch.html')
+ self.assertTemplateUsed(res, 'nova/images/launch.html')
form = res.context['form']
@@ -364,11 +362,9 @@ class ImageViewTests(base.BaseViewTests):
messages.error(IsA(http.HttpRequest), IsA(basestring))
self.mox.ReplayAll()
- url = reverse('dash_images_launch',
- args=[self.TEST_TENANT, IMAGE_ID])
+ url = reverse('horizon:nova:images:launch', args=[IMAGE_ID])
res = self.client.post(url, form_data)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/images/launch.html')
+ self.assertTemplateUsed(res, 'nova/images/launch.html')
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/images/urls.py b/horizon/horizon/dashboards/nova/images/urls.py
new file mode 100644
index 00000000..3306293d
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/images/urls.py
@@ -0,0 +1,27 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import *
+
+
+urlpatterns = patterns('horizon.dashboards.nova.images.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^(?P<image_id>[^/]+)/launch/$', 'launch', name='launch'),
+ url(r'^(?P<image_id>[^/]+)/update/$', 'update', name='update'))
diff --git a/horizon/horizon/dashboards/nova/images/views.py b/horizon/horizon/dashboards/nova/images/views.py
new file mode 100644
index 00000000..12e3ef3b
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/images/views.py
@@ -0,0 +1,163 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Nova images.
+"""
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+from glance.common import exception as glance_exception
+from novaclient import exceptions as novaclient_exceptions
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon.dashboards.nova.images.forms import (UpdateImageForm,
+ LaunchForm, DeleteImage)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ for f in (DeleteImage, ):
+ unused, handled = f.maybe_handle(request)
+ if handled:
+ return handled
+ delete_form = DeleteImage()
+
+ all_images = []
+ try:
+ all_images = api.image_list_detailed(request)
+ if not all_images:
+ messages.info(request, _("There are currently no images."))
+ except glance_exception.ClientConnectionError, e:
+ LOG.exception("Error connecting to glance")
+ messages.error(request, _("Error connecting to glance: %s") % str(e))
+ except glance_exception.Error, e:
+ LOG.exception("Error retrieving image list")
+ messages.error(request, _("Error retrieving image list: %s") % str(e))
+ except api_exceptions.ApiException, e:
+ msg = _("Unable to retreive image info from glance: %s") % str(e)
+ LOG.exception(msg)
+ messages.error(request, msg)
+
+ images = [im for im in all_images
+ if im['container_format'] not in ['aki', 'ari']]
+
+ return shortcuts.render(request,
+ 'nova/images/index.html', {
+ 'delete_form': delete_form,
+ 'images': images})
+
+
+@login_required
+def launch(request, image_id):
+
+ def flavorlist():
+ try:
+ fl = api.flavor_list(request)
+
+ # TODO add vcpu count to flavors
+ sel = [(f.id, '%s (%svcpu / %sGB Disk / %sMB Ram )' %
+ (f.name, f.vcpus, f.disk, f.ram)) for f in fl]
+ return sorted(sel)
+ except api_exceptions.ApiException:
+ LOG.exception('Unable to retrieve list of instance types')
+ return [(1, 'm1.tiny')]
+
+ def keynamelist():
+ try:
+ fl = api.keypair_list(request)
+ sel = [(f.name, f.name) for f in fl]
+ return sel
+ except api_exceptions.ApiException:
+ LOG.exception('Unable to retrieve list of keypairs')
+ return []
+
+ def securitygrouplist():
+ try:
+ fl = api.security_group_list(request)
+ sel = [(f.name, f.name) for f in fl]
+ return sel
+ except novaclient_exceptions.ClientException, e:
+ LOG.exception('Unable to retrieve list of security groups')
+ return []
+
+ tenant_id = request.user.tenant_id
+ # TODO(mgius): Any reason why these can't be after the launchform logic?
+ # If The form is valid, we've just wasted these two api calls
+ image = api.image_get(request, image_id)
+ quotas = api.tenant_quota_get(request, request.user.tenant_id)
+ try:
+ quotas.ram = int(quotas.ram)
+ except Exception, e:
+ messages.error(request,
+ _('Error parsing quota for %(image)s: %(msg)s') %
+ {"image": image_id, "msg": e.message})
+ return shortcuts.redirect('horizon:nova:instances:index')
+
+ form, handled = LaunchForm.maybe_handle(
+ request, initial={'flavorlist': flavorlist(),
+ 'keynamelist': keynamelist(),
+ 'securitygrouplist': securitygrouplist(),
+ 'image_id': image_id,
+ 'tenant_id': tenant_id})
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/images/launch.html', {
+ 'image': image,
+ 'form': form,
+ 'quotas': quotas})
+
+
+@login_required
+def update(request, image_id):
+ try:
+ image = api.image_get(request, image_id)
+ except glance_exception.ClientConnectionError, e:
+ LOG.exception("Error connecting to glance")
+ messages.error(request, _("Error connecting to glance: %s")
+ % e.message)
+ except glance_exception.Error, e:
+ LOG.exception('Error retrieving image with id "%s"' % image_id)
+ messages.error(request,
+ _("Error retrieving image %(image)s: %(msg)s")
+ % {"image": image_id, "msg": e.message})
+
+ form, handled = UpdateImageForm().maybe_handle(request, initial={
+ 'image_id': image_id,
+ 'name': image.get('name', ''),
+ 'kernel': image['properties'].get('kernel_id', ''),
+ 'ramdisk': image['properties'].get('ramdisk_id', ''),
+ 'architecture': image['properties'].get('architecture', ''),
+ 'container_format': image.get('container_format', ''),
+ 'disk_format': image.get('disk_format', ''), })
+ if handled:
+ return handled
+
+ return shortcuts.render(request, 'nova/images/update.html', {'form': form})
diff --git a/django-openstack/django_openstack/syspanel/views/__init__.py b/horizon/horizon/dashboards/nova/instances/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/syspanel/views/__init__.py
+++ b/horizon/horizon/dashboards/nova/instances/__init__.py
diff --git a/horizon/horizon/dashboards/nova/instances/forms.py b/horizon/horizon/dashboards/nova/instances/forms.py
new file mode 100644
index 00000000..1296008e
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/instances/forms.py
@@ -0,0 +1,101 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+import openstackx.api.exceptions as api_exceptions
+
+from horizon import api
+from horizon import forms
+
+
+LOG = logging.getLogger(__name__)
+
+
+class TerminateInstance(forms.SelfHandlingForm):
+ instance = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ instance_id = data['instance']
+ instance = api.server_get(request, instance_id)
+
+ try:
+ api.server_delete(request, instance)
+ except api_exceptions.ApiException, e:
+ LOG.exception(_('ApiException while terminating instance "%s"') %
+ instance_id)
+ messages.error(request,
+ _('Unable to terminate %(inst)s: %(message)s') %
+ {"inst": instance_id, "message": e.message})
+ else:
+ msg = _('Instance %s has been terminated.') % instance_id
+ LOG.info(msg)
+ messages.success(request, msg)
+
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class RebootInstance(forms.SelfHandlingForm):
+ instance = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ instance_id = data['instance']
+ try:
+ server = api.server_reboot(request, instance_id)
+ messages.success(request, _("Instance rebooting"))
+ except api_exceptions.ApiException, e:
+ LOG.exception(_('ApiException while rebooting instance "%s"') %
+ instance_id)
+ messages.error(request,
+ _('Unable to reboot instance: %s') % e.message)
+
+ else:
+ msg = _('Instance %s has been rebooted.') % instance_id
+ LOG.info(msg)
+ messages.success(request, msg)
+
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class UpdateInstance(forms.SelfHandlingForm):
+ tenant_id = forms.CharField(widget=forms.HiddenInput())
+ instance = forms.CharField(widget=forms.TextInput(
+ attrs={'readonly': 'readonly'}))
+ name = forms.CharField(required=True)
+ description = forms.CharField(required=False)
+
+ def handle(self, request, data):
+ tenant_id = data['tenant_id']
+ description = data.get('description', '')
+ try:
+ api.server_update(request,
+ data['instance'],
+ data['name'],
+ description)
+ messages.success(request, _("Instance '%s' updated") %
+ data['name'])
+ except api_exceptions.ApiException, e:
+ messages.error(request,
+ _('Unable to update instance: %s') % e.message)
+
+ return shortcuts.redirect('horizon:nova:instances:index')
diff --git a/horizon/horizon/dashboards/nova/instances/panel.py b/horizon/horizon/dashboards/nova/instances/panel.py
new file mode 100644
index 00000000..b4d3b0b8
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/instances/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Instances(horizon.Panel):
+ name = "Instances"
+ slug = 'instances'
+
+
+dashboard.Nova.register(Instances)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/instance_tests.py b/horizon/horizon/dashboards/nova/instances/tests.py
index ed5812f7..e9ec1cec 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/instance_tests.py
+++ b/horizon/horizon/dashboards/nova/instances/tests.py
@@ -23,14 +23,14 @@ import datetime
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack import utils
-from django_openstack.tests.view_tests import base
-from openstackx.api import exceptions as api_exceptions
from mox import IsA, IgnoreArg
+from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon import test
-class InstanceViewTests(base.BaseViewTests):
+
+class InstanceViewTests(test.BaseViewTests):
def setUp(self):
super(InstanceViewTests, self).setUp()
server = self.mox.CreateMock(api.Server)
@@ -45,11 +45,10 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:instances:index'))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/index.html')
+ 'nova/instances/index.html')
self.assertItemsEqual(res.context['instances'], self.servers)
self.mox.VerifyAll()
@@ -61,11 +60,10 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:instances:index'))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/index.html')
+ 'nova/instances/index.html')
self.assertEqual(len(res.context['instances']), 0)
self.mox.VerifyAll()
@@ -84,12 +82,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:instances:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -113,12 +110,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:instances:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -132,12 +128,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:instances:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -157,29 +152,14 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:instances:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
- def override_times(self, time=datetime.datetime.now):
- now = datetime.datetime.utcnow()
- utils.time.override_time = \
- datetime.time(now.hour, now.minute, now.second)
- utils.today.override_time = datetime.date(now.year, now.month, now.day)
- utils.utcnow.override_time = now
-
- return now
-
- def reset_times(self):
- utils.time.override_time = None
- utils.today.override_time = None
- utils.utcnow.override_time = None
-
def test_instance_usage(self):
TEST_RETURN = 'testReturn'
@@ -193,10 +173,10 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_usage', args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:instances:usage'))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/usage.html')
+ 'nova/instances/usage.html')
self.assertEqual(res.context['usage'], TEST_RETURN)
@@ -217,11 +197,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_usage', args=[self.TEST_TENANT]) +
+ res = self.client.get(reverse('horizon:nova:instances:usage') +
"?format=csv")
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/usage.csv')
+ 'nova/instances/usage.csv')
self.assertEqual(res.context['usage'], TEST_RETURN)
@@ -245,10 +225,10 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_usage', args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:instances:usage'))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/usage.html')
+ 'nova/instances/usage.html')
self.assertEqual(res.context['usage'], {})
@@ -269,10 +249,10 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_overview'))
+ res = self.client.get(reverse('horizon:nova:instances:usage'))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/usage.html')
+ 'nova/instances/usage.html')
self.assertEqual(res.context['usage'], TEST_RETURN)
@@ -294,8 +274,8 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_console',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:console',
+ args=[INSTANCE_ID]))
self.assertIsInstance(res, http.HttpResponse)
self.assertContains(res, CONSOLE_OUTPUT)
@@ -318,11 +298,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_console',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:console',
+ args=[INSTANCE_ID]))
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -343,8 +323,8 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_vnc',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:vnc',
+ args=[INSTANCE_ID]))
self.assertRedirectsNoFollow(res,
CONSOLE_OUTPUT + '&title=serverName(1)')
@@ -364,11 +344,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_vnc',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:vnc',
+ args=[INSTANCE_ID]))
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -381,11 +361,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_update',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:update',
+ args=[INSTANCE_ID]))
self.assertTemplateUsed(res,
- 'django_openstack/dash/instances/update.html')
+ 'nova/instances/update.html')
self.mox.VerifyAll()
@@ -399,11 +379,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_instances_update',
- args=[self.TEST_TENANT, INSTANCE_ID]))
+ res = self.client.get(reverse('horizon:nova:instances:update',
+ args=[INSTANCE_ID]))
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -427,13 +407,12 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances_update',
- args=[self.TEST_TENANT,
- INSTANCE_ID]),
+ res = self.client.post(reverse('horizon:nova:instances:update',
+ args=[INSTANCE_ID]),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -459,12 +438,11 @@ class InstanceViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_instances_update',
- args=[self.TEST_TENANT,
- INSTANCE_ID]),
+ res = self.client.post(reverse('horizon:nova:instances:update',
+ args=[INSTANCE_ID]),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/instances/urls.py b/horizon/horizon/dashboards/nova/instances/urls.py
new file mode 100644
index 00000000..82809f24
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/instances/urls.py
@@ -0,0 +1,33 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+INSTANCES = r'^(?P<instance_id>[^/]+)/%s$'
+
+urlpatterns = patterns('horizon.dashboards.nova.instances.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^usage/$', 'usage', name='usage'),
+ url(r'^refresh$', 'refresh', name='refresh'),
+ url(INSTANCES % 'detail', 'detail', name='detail'),
+ url(INSTANCES % 'console', 'console', name='console'),
+ url(INSTANCES % 'vnc', 'vnc', name='vnc'),
+ url(INSTANCES % 'update', 'update', name='update'),
+)
diff --git a/django-openstack/django_openstack/dash/views/instances.py b/horizon/horizon/dashboards/nova/instances/views.py
index 6a726129..75b975e2 100644
--- a/django-openstack/django_openstack/dash/views/instances.py
+++ b/horizon/horizon/dashboards/nova/instances/views.py
@@ -26,93 +26,24 @@ import logging
from django import http
from django import shortcuts
-from django import template
-from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack import utils
-import openstack.compute.servers
import openstackx.api.exceptions as api_exceptions
-import StringIO
-
-LOG = logging.getLogger('django_openstack.dash')
-
-
-class TerminateInstance(forms.SelfHandlingForm):
- instance = forms.CharField(required=True)
-
- def handle(self, request, data):
- instance_id = data['instance']
- instance = api.server_get(request, instance_id)
-
- try:
- api.server_delete(request, instance)
- except api_exceptions.ApiException, e:
- LOG.exception(_('ApiException while terminating instance "%s"') %
- instance_id)
- messages.error(request,
- _('Unable to terminate %(inst)s: %(message)s') %
- {"inst": instance_id, "message": e.message})
- else:
- msg = _('Instance %s has been terminated.') % instance_id
- LOG.info(msg)
- messages.success(request, msg)
-
- return shortcuts.redirect(request.build_absolute_uri())
-
-class RebootInstance(forms.SelfHandlingForm):
- instance = forms.CharField(required=True)
+from horizon import api
+from horizon import forms
+from horizon import test
+from horizon.dashboards.nova.instances.forms import (TerminateInstance,
+ RebootInstance, UpdateInstance)
- def handle(self, request, data):
- instance_id = data['instance']
- try:
- server = api.server_reboot(request, instance_id)
- messages.success(request, _("Instance rebooting"))
- except api_exceptions.ApiException, e:
- LOG.exception(_('ApiException while rebooting instance "%s"') %
- instance_id)
- messages.error(request,
- _('Unable to reboot instance: %s') % e.message)
- else:
- msg = _('Instance %s has been rebooted.') % instance_id
- LOG.info(msg)
- messages.success(request, msg)
-
- return shortcuts.redirect(request.build_absolute_uri())
-
-
-class UpdateInstance(forms.SelfHandlingForm):
- tenant_id = forms.CharField(widget=forms.HiddenInput())
- instance = forms.CharField(widget=forms.TextInput(
- attrs={'readonly': 'readonly'}))
- name = forms.CharField(required=True)
- description = forms.CharField(required=False)
-
- def handle(self, request, data):
- tenant_id = data['tenant_id']
- description = data.get('description', '')
- try:
- api.server_update(request,
- data['instance'],
- data['name'],
- description)
- messages.success(request, _("Instance '%s' updated") %
- data['name'])
- except api_exceptions.ApiException, e:
- messages.error(request,
- _('Unable to update instance: %s') % e.message)
-
- return shortcuts.redirect('dash_instances', tenant_id)
+LOG = logging.getLogger(__name__)
@login_required
-def index(request, tenant_id):
+def index(request):
+ tenant_id = request.user.tenant_id
for f in (TerminateInstance, RebootInstance):
form, handled = f.maybe_handle(request)
if handled:
@@ -130,16 +61,16 @@ def index(request, tenant_id):
terminate_form = TerminateInstance()
reboot_form = RebootInstance()
- return shortcuts.render_to_response(
- 'django_openstack/dash/instances/index.html', {
- 'instances': instances,
- 'terminate_form': terminate_form,
- 'reboot_form': reboot_form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'nova/instances/index.html', {
+ 'instances': instances,
+ 'terminate_form': terminate_form,
+ 'reboot_form': reboot_form})
@login_required
-def refresh(request, tenant_id):
+def refresh(request):
+ tenant_id = request.user.tenant_id
instances = []
try:
instances = api.server_list(request)
@@ -152,20 +83,20 @@ def refresh(request, tenant_id):
terminate_form = TerminateInstance()
reboot_form = RebootInstance()
- return shortcuts.render_to_response(
- 'django_openstack/dash/instances/_list.html', {
- 'instances': instances,
- 'terminate_form': terminate_form,
- 'reboot_form': reboot_form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'nova/instances/_list.html', {
+ 'instances': instances,
+ 'terminate_form': terminate_form,
+ 'reboot_form': reboot_form})
@login_required
def usage(request, tenant_id=None):
- today = utils.today()
+ tenant_id = tenant_id or request.user.tenant_id
+ today = test.today()
date_start = datetime.date(today.year, today.month, 1)
- datetime_start = datetime.datetime.combine(date_start, utils.time())
- datetime_end = utils.utcnow()
+ datetime_start = datetime.datetime.combine(date_start, test.time())
+ datetime_end = test.utcnow()
show_terminated = request.GET.get('show_terminated', False)
@@ -206,27 +137,27 @@ def usage(request, tenant_id=None):
instances += terminated_instances
if request.GET.get('format', 'html') == 'csv':
- template_name = 'django_openstack/dash/instances/usage.csv'
+ template_name = 'nova/instances/usage.csv'
mimetype = "text/csv"
else:
- template_name = 'django_openstack/dash/instances/usage.html'
+ template_name = 'nova/instances/usage.html'
mimetype = "text/html"
- return shortcuts.render_to_response(template_name, {
- 'usage': usage,
- 'ram_unit': ram_unit,
- 'total_ram': total_ram,
- # there are no date selection caps yet so keeping csv_link simple
- 'csv_link': '?format=csv',
- 'show_terminated': show_terminated,
- 'datetime_start': datetime_start,
- 'datetime_end': datetime_end,
- 'instances': instances
- }, context_instance=template.RequestContext(request), mimetype=mimetype)
+ return shortcuts.render(request, template_name, {
+ 'usage': usage,
+ 'ram_unit': ram_unit,
+ 'total_ram': total_ram,
+ 'csv_link': '?format=csv',
+ 'show_terminated': show_terminated,
+ 'datetime_start': datetime_start,
+ 'datetime_end': datetime_end,
+ 'instances': instances},
+ content_type=mimetype)
@login_required
-def console(request, tenant_id, instance_id):
+def console(request, instance_id):
+ tenant_id = request.user.tenant_id
try:
# TODO(jakedahn): clean this up once the api supports tailing.
length = request.GET.get('length', '')
@@ -244,11 +175,12 @@ def console(request, tenant_id, instance_id):
messages.error(request,
_('Unable to get log for instance %(inst)s: %(msg)s') %
{"inst": instance_id, "msg": e.message})
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
@login_required
-def vnc(request, tenant_id, instance_id):
+def vnc(request, instance_id):
+ tenant_id = request.user.tenant_id
try:
console = api.console_create(request, instance_id, 'vnc')
instance = api.server_get(request, instance_id)
@@ -259,11 +191,12 @@ def vnc(request, tenant_id, instance_id):
messages.error(request,
_('Unable to get vnc console for instance %(inst)s: %(message)s') %
{"inst": instance_id, "message": e.message})
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
@login_required
-def update(request, tenant_id, instance_id):
+def update(request, instance_id):
+ tenant_id = request.user.tenant_id
try:
instance = api.server_get(request, instance_id)
except api_exceptions.ApiException, e:
@@ -271,7 +204,7 @@ def update(request, tenant_id, instance_id):
messages.error(request,
_('Unable to get information for instance %(inst)s: %(message)s') %
{"inst": instance_id, "message": e.message})
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
form, handled = UpdateInstance.maybe_handle(request, initial={
'instance': instance_id,
@@ -282,15 +215,15 @@ def update(request, tenant_id, instance_id):
if handled:
return handled
- return shortcuts.render_to_response(
- 'django_openstack/dash/instances/update.html', {
- 'instance': instance,
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'nova/instances/update.html', {
+ 'instance': instance,
+ 'form': form})
@login_required
-def detail(request, tenant_id, instance_id):
+def detail(request, instance_id):
+ tenant_id = request.user.tenant_id
try:
instance = api.server_get(request, instance_id)
volumes = api.volume_instance_list(request, instance_id)
@@ -305,17 +238,16 @@ def detail(request, tenant_id, instance_id):
messages.error(request,
_('Unable to get vnc console for instance %(inst)s: %(msg)s') %
{"inst": instance_id, "msg": e.message})
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
except api_exceptions.ApiException, e:
LOG.exception(_('ApiException while fetching instance info'))
messages.error(request,
_('Unable to get information for instance %(inst)s: %(msg)s') %
{"inst": instance_id, "msg": e.message})
- return shortcuts.redirect('dash_instances', tenant_id)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/instances/detail.html', {
- 'instance': instance,
- 'vnc_url': vnc_url,
- 'volumes': volumes
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect('horizon:nova:instances:index')
+
+ return shortcuts.render(request,
+ 'nova/instances/detail.html', {
+ 'instance': instance,
+ 'vnc_url': vnc_url,
+ 'volumes': volumes})
diff --git a/django-openstack/django_openstack/templatetags/__init__.py b/horizon/horizon/dashboards/nova/keypairs/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/templatetags/__init__.py
+++ b/horizon/horizon/dashboards/nova/keypairs/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/keypairs.py b/horizon/horizon/dashboards/nova/keypairs/forms.py
index ef077f4b..fddc1161 100644
--- a/django-openstack/django_openstack/dash/views/keypairs.py
+++ b/horizon/horizon/dashboards/nova/keypairs/forms.py
@@ -18,25 +18,20 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Views for managing Nova instances.
-"""
import logging
from django import http
-from django import template
+from django import shortcuts
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
from django.core import validators
-from django.shortcuts import redirect, render_to_response
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
from novaclient import exceptions as novaclient_exceptions
+from horizon import api
+from horizon import forms
+
-LOG = logging.getLogger('django_openstack.dash.views.keypairs')
+LOG = logging.getLogger(__name__)
class DeleteKeypair(forms.SelfHandlingForm):
@@ -52,7 +47,7 @@ class DeleteKeypair(forms.SelfHandlingForm):
LOG.exception("ClientException in DeleteKeypair")
messages.error(request,
_('Error deleting keypair: %s') % e.message)
- return redirect(request.build_absolute_uri())
+ return shortcuts.redirect(request.build_absolute_uri())
class CreateKeypair(forms.SelfHandlingForm):
@@ -73,7 +68,7 @@ class CreateKeypair(forms.SelfHandlingForm):
LOG.exception("ClientException in CreateKeyPair")
messages.error(request,
_('Error Creating Keypair: %s') % e.message)
- return redirect(request.build_absolute_uri())
+ return shortcuts.redirect(request.build_absolute_uri())
class ImportKeypair(forms.SelfHandlingForm):
@@ -88,51 +83,9 @@ class ImportKeypair(forms.SelfHandlingForm):
api.keypair_import(request, data['name'], data['public_key'])
messages.success(request, _('Successfully imported public key: %s')
% data['name'])
- return redirect('dash_keypairs', request.user.tenant_id)
+ return shortcuts.redirect('horizon:nova:keypairs:index')
except novaclient_exceptions.ClientException, e:
LOG.exception("ClientException in ImportKeypair")
messages.error(request,
_('Error Importing Keypair: %s') % e.message)
- return redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id):
- delete_form, handled = DeleteKeypair.maybe_handle(request)
-
- if handled:
- return handled
-
- try:
- keypairs = api.keypair_list(request)
- except novaclient_exceptions.ClientException, e:
- keypairs = []
- LOG.exception("ClientException in keypair index")
- messages.error(request, _('Error fetching keypairs: %s') % e.message)
-
- return render_to_response('django_openstack/dash/keypairs/index.html', {
- 'keypairs': keypairs,
- 'delete_form': delete_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def create(request, tenant_id):
- form, handled = CreateKeypair.maybe_handle(request)
- if handled:
- return handled
-
- return render_to_response('django_openstack/dash/keypairs/create.html', {
- 'create_form': form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def import_keypair(request, tenant_id):
- form, handled = ImportKeypair.maybe_handle(request)
- if handled:
- return handled
-
- return render_to_response('django_openstack/dash/keypairs/import.html', {
- 'create_form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/nova/keypairs/panel.py b/horizon/horizon/dashboards/nova/keypairs/panel.py
new file mode 100644
index 00000000..81887738
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/keypairs/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Keypairs(horizon.Panel):
+ name = "Keypairs"
+ slug = 'keypairs'
+
+
+dashboard.Nova.register(Keypairs)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/keypair_tests.py b/horizon/horizon/dashboards/nova/keypairs/tests.py
index 45c090c9..6f50f52d 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/keypair_tests.py
+++ b/horizon/horizon/dashboards/nova/keypairs/tests.py
@@ -21,14 +21,14 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from mox import IsA
-
from novaclient import exceptions as novaclient_exceptions
+from horizon import api
+from horizon import test
+
-class KeyPairViewTests(base.BaseViewTests):
+class KeyPairViewTests(test.BaseViewTests):
def setUp(self):
super(KeyPairViewTests, self).setUp()
keypair = self.mox.CreateMock(api.KeyPair)
@@ -41,11 +41,9 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_keypairs',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:keypairs:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/keypairs/index.html')
+ self.assertTemplateUsed(res, 'nova/keypairs/index.html')
self.assertItemsEqual(res.context['keypairs'], self.keypairs)
self.mox.VerifyAll()
@@ -61,11 +59,9 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_keypairs',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:keypairs:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/keypairs/index.html')
+ self.assertTemplateUsed(res, 'nova/keypairs/index.html')
self.assertEqual(len(res.context['keypairs']), 0)
self.mox.VerifyAll()
@@ -81,12 +77,11 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_keypairs',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:keypairs:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_keypairs',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:keypairs:index'))
self.mox.VerifyAll()
@@ -104,21 +99,18 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_keypairs',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:keypairs:index'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_keypairs',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:keypairs:index'))
self.mox.VerifyAll()
def test_create_keypair_get(self):
- res = self.client.get(reverse('dash_keypairs_create',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:keypairs:create'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/keypairs/create.html')
+ self.assertTemplateUsed(res, 'nova/keypairs/create.html')
def test_create_keypair_post(self):
KEYPAIR_NAME = 'newKeypair'
@@ -138,8 +130,7 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_keypairs_create',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:keypairs:create'),
formData)
self.assertTrue(res.has_header('Content-Disposition'))
@@ -161,11 +152,10 @@ class KeyPairViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_keypairs_create',
- args=[self.TEST_TENANT]),
+ res = self.client.post(reverse('horizon:nova:keypairs:create'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_keypairs_create',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:keypairs:create'))
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/keypairs/urls.py b/horizon/horizon/dashboards/nova/keypairs/urls.py
new file mode 100644
index 00000000..8080debe
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/keypairs/urls.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.nova.keypairs.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'),
+ url(r'^import/$', 'import_keypair', name='import'),
+)
diff --git a/horizon/horizon/dashboards/nova/keypairs/views.py b/horizon/horizon/dashboards/nova/keypairs/views.py
new file mode 100644
index 00000000..b65b64a1
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/keypairs/views.py
@@ -0,0 +1,80 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Nova keypairs.
+"""
+import logging
+
+from django import http
+from django import shortcuts
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+from novaclient import exceptions as novaclient_exceptions
+
+from horizon import api
+from horizon.dashboards.nova.keypairs.forms import (CreateKeypair,
+ DeleteKeypair, ImportKeypair)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ delete_form, handled = DeleteKeypair.maybe_handle(request)
+
+ if handled:
+ return handled
+
+ try:
+ keypairs = api.keypair_list(request)
+ except novaclient_exceptions.ClientException, e:
+ keypairs = []
+ LOG.exception("ClientException in keypair index")
+ messages.error(request, _('Error fetching keypairs: %s') % e.message)
+
+ return shortcuts.render(request,
+ 'nova/keypairs/index.html', {
+ 'keypairs': keypairs,
+ 'delete_form': delete_form})
+
+
+@login_required
+def create(request):
+ form, handled = CreateKeypair.maybe_handle(request)
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/keypairs/create.html', {
+ 'create_form': form})
+
+
+@login_required
+def import_keypair(request):
+ form, handled = ImportKeypair.maybe_handle(request)
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/keypairs/import.html', {
+ 'create_form': form})
diff --git a/django-openstack/django_openstack/models.py b/horizon/horizon/dashboards/nova/models.py
index 300ba4b3..300ba4b3 100644
--- a/django-openstack/django_openstack/models.py
+++ b/horizon/horizon/dashboards/nova/models.py
diff --git a/django-openstack/django_openstack/templatetags/templatetags/__init__.py b/horizon/horizon/dashboards/nova/networks/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/templatetags/templatetags/__init__.py
+++ b/horizon/horizon/dashboards/nova/networks/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/ports.py b/horizon/horizon/dashboards/nova/networks/forms.py
index ad690cfe..2a23a094 100644
--- a/django-openstack/django_openstack/dash/views/ports.py
+++ b/horizon/horizon/dashboards/nova/networks/forms.py
@@ -18,24 +18,81 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Views for managing api.quantum_api(request) network ports.
-"""
import logging
-from django import http
from django import shortcuts
-from django import template
-from django.conf import settings
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
-from django_openstack import forms
-from django_openstack import api
+from horizon import api
+from horizon import forms
-LOG = logging.getLogger('django_openstack.dash.views.ports')
+LOG = logging.getLogger(__name__)
+
+
+class CreateNetwork(forms.SelfHandlingForm):
+ name = forms.CharField(required=True, label=_("Network Name"))
+
+ def handle(self, request, data):
+ network_name = data['name']
+
+ try:
+ LOG.info('Creating network %s ' % network_name)
+ send_data = {'network': {'name': '%s' % network_name}}
+ api.quantum_create_network(request, send_data)
+ except Exception, e:
+ messages.error(request,
+ _('Unable to create network %(network)s: %(msg)s') %
+ {"network": network_name, "msg": e.message})
+ return shortcuts.redirect(request.build_absolute_uri())
+ else:
+ msg = _('Network %s has been created.') % network_name
+ LOG.info(msg)
+ messages.success(request, msg)
+ return shortcuts.redirect('horizon:nova:networks:index')
+
+
+class DeleteNetwork(forms.SelfHandlingForm):
+ network = forms.CharField(widget=forms.HiddenInput())
+
+ def handle(self, request, data):
+ try:
+ LOG.info('Deleting network %s ' % data['network'])
+ api.quantum_delete_network(request, data['network'])
+ except Exception, e:
+ messages.error(request,
+ _('Unable to delete network %(network)s: %(msg)s') %
+ {"network": data['network'], "msg": e.message})
+ else:
+ msg = _('Network %s has been deleted.') % data['network']
+ LOG.info(msg)
+ messages.success(request, msg)
+
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class RenameNetwork(forms.SelfHandlingForm):
+ network = forms.CharField(widget=forms.HiddenInput())
+ new_name = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ try:
+ LOG.info('Renaming network %s to %s' %
+ (data['network'], data['new_name']))
+ send_data = {'network': {'name': '%s' % data['new_name']}}
+ api.quantum_update_network(request, data['network'], send_data)
+ except Exception, e:
+ messages.error(request,
+ _('Unable to rename network %(network)s: %(msg)s') %
+ {"network": data['network'], "msg": e.message})
+ else:
+ msg = _('Network %(net)s has been renamed to %(new_name)s.') % {
+ "net": data['network'], "new_name": data['new_name']}
+ LOG.info(msg)
+ messages.success(request, msg)
+
+ return shortcuts.redirect(request.build_absolute_uri())
class CreatePort(forms.SelfHandlingForm):
@@ -149,60 +206,3 @@ class TogglePort(forms.SelfHandlingForm):
LOG.info(msg)
messages.success(request, msg)
return shortcuts.redirect(request.build_absolute_uri())
-
-
-@login_required
-def create(request, tenant_id, network_id):
- create_form, handled = CreatePort.maybe_handle(request)
-
- if handled:
- return shortcuts.redirect(
- 'dash_networks_detail',
- tenant_id=request.user.tenant_id,
- network_id=network_id
- )
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/ports/create.html', {
- 'network_id': network_id,
- 'create_form': create_form
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def attach(request, tenant_id, network_id, port_id):
- attach_form, handled = AttachPort.maybe_handle(request)
-
- if handled:
- return shortcuts.redirect('dash_networks_detail',
- request.user.tenant_id, network_id)
-
- # Get all avaliable vifs
- vifs = _get_available_vifs(request)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/ports/attach.html', {
- 'network': network_id,
- 'port': port_id,
- 'attach_form': attach_form,
- 'vifs': vifs,
- }, context_instance=template.RequestContext(request))
-
-
-def _get_available_vifs(request):
- """
- Method to get a list of available virtual interfaces
- """
- vif_choices = []
- vifs = api.get_vif_ids(request)
-
- for vif in vifs:
- if vif['available']:
- name = "Instance %s VIF %s" % \
- (str(vif['instance_name']), str(vif['id']))
- vif_choices.append({
- 'name': str(name),
- 'id': str(vif['id'])
- })
-
- return vif_choices
diff --git a/horizon/horizon/dashboards/nova/networks/panel.py b/horizon/horizon/dashboards/nova/networks/panel.py
new file mode 100644
index 00000000..825c720d
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/networks/panel.py
@@ -0,0 +1,33 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Networks(horizon.Panel):
+ name = "Networks"
+ slug = 'networks'
+
+ def nav(self, context):
+ return context.get('network_configured', False)
+
+
+dashboard.Nova.register(Networks)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/network_tests.py b/horizon/horizon/dashboards/nova/networks/tests.py
index ebd17046..aab9ba8e 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/network_tests.py
+++ b/horizon/horizon/dashboards/nova/networks/tests.py
@@ -21,13 +21,14 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
+from horizon import test
from mox import IgnoreArg, IsA
import quantum.client
+from horizon import api
-class NetworkViewTests(base.BaseViewTests):
+
+class NetworkViewTests(test.BaseViewTests):
def setUp(self):
super(NetworkViewTests, self).setUp()
self.network = {}
@@ -40,14 +41,10 @@ class NetworkViewTests(base.BaseViewTests):
self.port_details = {
'port': {
'id': 'p1',
- 'state': 'DOWN'
- }
- }
+ 'state': 'DOWN'}}
self.port_attachment = {
'attachment': {
- 'id': 'vif1'
- }
- }
+ 'id': 'vif1'}}
self.vifs = [{'id': 'vif1'}]
def test_network_index(self):
@@ -69,10 +66,9 @@ class NetworkViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_networks', args=['tenant']))
+ res = self.client.get(reverse('horizon:nova:networks:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/networks/index.html')
+ self.assertTemplateUsed(res, 'nova/networks/index.html')
self.assertIn('networks', res.context)
networks = res.context['networks']
@@ -94,12 +90,11 @@ class NetworkViewTests(base.BaseViewTests):
formData = {'name': 'Test',
'method': 'CreateNetwork'}
- res = self.client.post(reverse('dash_network_create',
- args=[self.request.user.tenant_id]),
+ res = self.client.post(reverse('horizon:nova:networks:create'),
formData)
- self.assertRedirectsNoFollow(res, reverse('dash_networks',
- args=[self.request.user.tenant_id]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:networks:index'))
self.mox.VerifyAll()
def test_network_delete(self):
@@ -127,8 +122,7 @@ class NetworkViewTests(base.BaseViewTests):
formData = {'id': 'n1',
'method': 'DeleteNetwork'}
- res = self.client.post(reverse('dash_networks',
- args=[self.request.user.tenant_id]),
+ res = self.client.post(reverse('horizon:nova:networks:index'),
formData)
def test_network_rename(self):
@@ -157,8 +151,8 @@ class NetworkViewTests(base.BaseViewTests):
formData = {'new_name': 'Test1',
'method': 'RenameNetwork'}
- res = self.client.post(reverse('dash_network_rename',
- args=[self.request.user.tenant_id, "n1"]),
+ res = self.client.post(reverse('horizon:nova:networks:rename',
+ args=["n1"]),
formData)
def test_network_details(self):
@@ -183,11 +177,10 @@ class NetworkViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_networks_detail',
- args=['tenant', 'n1']))
+ res = self.client.get(reverse('horizon:nova:networks:detail',
+ args=['n1']))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/networks/detail.html')
+ self.assertTemplateUsed(res, 'nova/networks/detail.html')
self.assertIn('network', res.context)
network = res.context['network']
@@ -196,3 +189,80 @@ class NetworkViewTests(base.BaseViewTests):
self.assertEqual(network['id'], 'n1')
self.mox.VerifyAll()
+
+
+class PortViewTests(test.BaseViewTests):
+ def setUp(self):
+ super(PortViewTests, self).setUp()
+
+ def test_port_create(self):
+ self.mox.StubOutWithMock(api, "quantum_create_port")
+ api.quantum_create_port(IsA(http.HttpRequest), 'n1').AndReturn(True)
+
+ formData = {'ports_num': 1,
+ 'network': 'n1',
+ 'method': 'CreatePort'}
+
+ self.mox.StubOutWithMock(messages, 'success')
+ messages.success(IgnoreArg(), IsA(basestring))
+
+ res = self.client.post(reverse('horizon:nova:networks:port_create',
+ args=["n1"]),
+ formData)
+
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:networks:detail',
+ args=["n1"]))
+
+ def test_port_delete(self):
+ self.mox.StubOutWithMock(api, "quantum_delete_port")
+ api.quantum_delete_port(IsA(http.HttpRequest),
+ 'n1', 'p1').AndReturn(True)
+
+ formData = {'port': 'p1',
+ 'network': 'n1',
+ 'method': 'DeletePort'}
+
+ self.mox.StubOutWithMock(messages, 'success')
+ messages.success(IgnoreArg(), IsA(basestring))
+
+ res = self.client.post(reverse('horizon:nova:networks:detail',
+ args=["n1"]),
+ formData)
+
+ def test_port_attach(self):
+ self.mox.StubOutWithMock(api, "quantum_attach_port")
+ api.quantum_attach_port(IsA(http.HttpRequest),
+ 'n1', 'p1', dict).AndReturn(True)
+
+ formData = {'port': 'p1',
+ 'network': 'n1',
+ 'vif_id': 'v1',
+ 'method': 'AttachPort'}
+
+ self.mox.StubOutWithMock(messages, 'success')
+ messages.success(IgnoreArg(), IsA(basestring))
+
+ res = self.client.post(reverse('horizon:nova:networks:port_attach',
+ args=["n1", "p1"]),
+ formData)
+
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:networks:detail',
+ args=["n1"]))
+
+ def test_port_detach(self):
+ self.mox.StubOutWithMock(api, "quantum_detach_port")
+ api.quantum_detach_port(IsA(http.HttpRequest),
+ 'n1', 'p1').AndReturn(True)
+
+ formData = {'port': 'p1',
+ 'network': 'n1',
+ 'method': 'DetachPort'}
+
+ self.mox.StubOutWithMock(messages, 'success')
+ messages.success(IgnoreArg(), IsA(basestring))
+
+ res = self.client.post(reverse('horizon:nova:networks:detail',
+ args=["n1"]),
+ formData)
diff --git a/django-openstack/django_openstack/tests/dependency_tests.py b/horizon/horizon/dashboards/nova/networks/urls.py
index 19df189f..fd0c5ae0 100644
--- a/django-openstack/django_openstack/tests/dependency_tests.py
+++ b/horizon/horizon/dashboards/nova/networks/urls.py
@@ -18,22 +18,14 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Tests for dependency packages
-Honestly, this can probably go away once tests that depend on these
-packages become more ingrained in the code.
-"""
+from django.conf.urls.defaults import patterns, url
-from django import test
-from django.core import mail
-from mailer import engine
-from mailer import send_mail
-
-
-class DjangoMailerPresenceTest(test.TestCase):
- def test_mailsent(self):
- send_mail('subject', 'message_body', 'from@test.com', ['to@test.com'])
- engine.send_all()
-
- self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].subject, 'subject')
+urlpatterns = patterns('horizon.dashboards.nova.networks.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'),
+ url(r'^(?P<network_id>[^/]+)/detail/$', 'detail', name='detail'),
+ url(r'^(?P<network_id>[^/]+)/rename/$', 'rename', name='rename'),
+ url(r'^(?P<network_id>[^/]+)/ports/create/$', 'port_create',
+ name='port_create'),
+ url(r'^(?P<network_id>[^/]+)/ports/(?P<port_id>[^/]+)/attach/$',
+ 'port_attach', name='port_attach'))
diff --git a/horizon/horizon/dashboards/nova/networks/views.py b/horizon/horizon/dashboards/nova/networks/views.py
new file mode 100644
index 00000000..69969f65
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/networks/views.py
@@ -0,0 +1,231 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Quantum networks.
+"""
+
+import logging
+import warnings
+
+from django import shortcuts
+from django import template
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+
+from horizon import api
+from horizon.dashboards.nova.networks.forms import (CreateNetwork,
+ DeleteNetwork, RenameNetwork, AttachPort, CreatePort, DeletePort,
+ DetachPort, TogglePort)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ tenant_id = request.user.tenant_id
+ delete_form, delete_handled = DeleteNetwork.maybe_handle(request)
+
+ networks = []
+ instances = []
+
+ try:
+ networks_list = api.quantum_list_networks(request)
+ details = []
+ for network in networks_list['networks']:
+ net_stats = _calc_network_stats(request, network['id'])
+ # Get network details like name and id
+ details = api.quantum_network_details(request, network['id'])
+ networks.append({
+ 'name': details['network']['name'],
+ 'id': network['id'],
+ 'total': net_stats['total'],
+ 'available': net_stats['available'],
+ 'used': net_stats['used'],
+ 'tenant': tenant_id})
+
+ except Exception, e:
+ LOG.exception("Unable to get network list.")
+ messages.error(request,
+ _('Unable to get network list: %s') % e.message)
+
+ return shortcuts.render(request,
+ 'nova/networks/index.html', {
+ 'networks': networks,
+ 'delete_form': delete_form})
+
+
+@login_required
+def create(request):
+ network_form, handled = CreateNetwork.maybe_handle(request)
+ if handled:
+ return shortcuts.redirect('horizon:nova:networks:index')
+
+ return shortcuts.render(request,
+ 'nova/networks/create.html',
+ {'network_form': network_form})
+
+
+@login_required
+def detail(request, network_id):
+ tenant_id = request.user.tenant_id
+ delete_port_form, delete_handled = DeletePort.maybe_handle(request)
+ detach_port_form, detach_handled = DetachPort.maybe_handle(request)
+ toggle_port_form, port_toggle_handled = TogglePort.maybe_handle(request)
+
+ network = {}
+
+ try:
+ network_details = api.quantum_network_details(request, network_id)
+ network['name'] = network_details['network']['name']
+ network['id'] = network_id
+ network['ports'] = _get_port_states(request, network_id)
+ except Exception, e:
+ LOG.exception("Unable to get network details.")
+ messages.error(request,
+ _('Unable to get network details: %s') % e.message)
+
+ return shortcuts.render(request,
+ 'nova/networks/detail.html',
+ {'network': network,
+ 'tenant': tenant_id,
+ 'delete_port_form': delete_port_form,
+ 'detach_port_form': detach_port_form,
+ 'toggle_port_form': toggle_port_form})
+
+
+@login_required
+def rename(request, network_id):
+ rename_form, handled = RenameNetwork.maybe_handle(request)
+ network_details = api.quantum_network_details(request, network_id)
+
+ if handled:
+ return shortcuts.redirect('horizon:nova:networks:index')
+
+ return shortcuts.render(request,
+ 'nova/networks/rename.html', {
+ 'network': network_details,
+ 'rename_form': rename_form})
+
+
+def _get_port_states(request, network_id):
+ """
+ Helper method to find port states for a network
+ """
+ network_ports = []
+ # Get all vifs for comparison with port attachments
+ vifs = api.get_vif_ids(request)
+
+ # Get all ports on this network
+ ports = api.quantum_list_ports(request, network_id)
+ for port in ports['ports']:
+ port_details = api.quantum_port_details(request,
+ network_id, port['id'])
+ # Get port attachments
+ port_attachment = api.quantum_port_attachment(request,
+ network_id, port['id'])
+ # Find instance the attachment belongs to
+ connected_instance = None
+ if port_attachment['attachment']:
+ for vif in vifs:
+ if str(vif['id']) == str(port_attachment['attachment']['id']):
+ connected_instance = vif['instance_name']
+ break
+ network_ports.append({
+ 'id': port_details['port']['id'],
+ 'state': port_details['port']['state'],
+ 'attachment': port_attachment['attachment'],
+ 'instance': connected_instance})
+ return network_ports
+
+
+def _calc_network_stats(request, network_id):
+ """
+ Helper method to calculate statistics for a network
+ """
+ # Get all ports statistics for the network
+ total = 0
+ available = 0
+ used = 0
+ ports = api.quantum_list_ports(request, network_id)
+ for port in ports['ports']:
+ total += 1
+ # Get port attachment
+ port_attachment = api.quantum_port_attachment(request,
+ network_id, port['id'])
+ if port_attachment['attachment']:
+ used += 1
+ else:
+ available += 1
+
+ return {'total': total, 'used': used, 'available': available}
+
+
+@login_required
+def port_create(request, network_id):
+ create_form, handled = CreatePort.maybe_handle(request)
+
+ if handled:
+ return shortcuts.redirect('horizon:nova:networks:detail',
+ network_id=network_id)
+
+ return shortcuts.render(request,
+ 'nova/ports/create.html', {
+ 'network_id': network_id,
+ 'create_form': create_form})
+
+
+@login_required
+def port_attach(request, network_id, port_id):
+ attach_form, handled = AttachPort.maybe_handle(request)
+
+ if handled:
+ return shortcuts.redirect('horizon:nova:networks:detail',
+ network_id=network_id)
+
+ # Get all avaliable vifs
+ vifs = _get_available_vifs(request)
+
+ return shortcuts.render(request,
+ 'nova/ports/attach.html', {
+ 'network': network_id,
+ 'port': port_id,
+ 'attach_form': attach_form,
+ 'vifs': vifs})
+
+
+def _get_available_vifs(request):
+ """
+ Method to get a list of available virtual interfaces
+ """
+ vif_choices = []
+ vifs = api.get_vif_ids(request)
+
+ for vif in vifs:
+ if vif['available']:
+ name = "Instance %s VIF %s" % \
+ (str(vif['instance_name']), str(vif['id']))
+ vif_choices.append({
+ 'name': str(name),
+ 'id': str(vif['id'])})
+
+ return vif_choices
diff --git a/django-openstack/django_openstack/tests/view_tests/__init__.py b/horizon/horizon/dashboards/nova/overview/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/tests/view_tests/__init__.py
+++ b/horizon/horizon/dashboards/nova/overview/__init__.py
diff --git a/horizon/horizon/dashboards/nova/overview/panel.py b/horizon/horizon/dashboards/nova/overview/panel.py
new file mode 100644
index 00000000..fbd5b5d7
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/overview/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Overview(horizon.Panel):
+ name = "Overview"
+ slug = 'overview'
+
+
+dashboard.Nova.register(Overview)
diff --git a/django-openstack/django_openstack/auth/urls.py b/horizon/horizon/dashboards/nova/overview/urls.py
index ba9b04dc..97e1d3da 100644
--- a/django-openstack/django_openstack/auth/urls.py
+++ b/horizon/horizon/dashboards/nova/overview/urls.py
@@ -18,13 +18,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django.conf.urls.defaults import *
-from django.conf import settings
+from django.conf.urls.defaults import *
-urlpatterns = patterns('django_openstack.auth.views',
- url(r'login/$', 'login', name='auth_login'),
- url(r'logout/$', 'logout', name='auth_logout'),
- url(r'switch/(?P<tenant_id>[^/]+)/$', 'switch_tenants',
- name='auth_switch'),
+urlpatterns = patterns('horizon.dashboards.nova',
+ url(r'^$', 'instances.views.usage', name='index'),
)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/__init__.py b/horizon/horizon/dashboards/nova/security_groups/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/__init__.py
+++ b/horizon/horizon/dashboards/nova/security_groups/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/security_groups.py b/horizon/horizon/dashboards/nova/security_groups/forms.py
index 8b88331d..1c27f0cb 100644
--- a/django-openstack/django_openstack/dash/views/security_groups.py
+++ b/horizon/horizon/dashboards/nova/security_groups/forms.py
@@ -18,27 +18,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Views for managing Nova instances.
-"""
import logging
-from django import http
-from django import template
-from django.conf import settings
+from django import shortcuts
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
from django.core import validators
-from django import shortcuts
-from django.shortcuts import redirect, render_to_response
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import forms
from novaclient import exceptions as novaclient_exceptions
+from horizon import api
+from horizon import forms
-LOG = logging.getLogger('django_openstack.dash.views.security_groups')
+
+LOG = logging.getLogger(__name__)
class CreateGroup(forms.SelfHandlingForm):
@@ -55,8 +47,7 @@ class CreateGroup(forms.SelfHandlingForm):
data['description'])
messages.info(request, _('Successfully created security_group: %s')
% data['name'])
- return shortcuts.redirect('dash_security_groups',
- data['tenant_id'])
+ return shortcuts.redirect('horizon:nova:security_groups:index')
except novaclient_exceptions.ClientException, e:
LOG.exception("ClientException in CreateGroup")
messages.error(request, _('Error creating security group: %s') %
@@ -79,7 +70,7 @@ class DeleteGroup(forms.SelfHandlingForm):
LOG.exception("ClientException in DeleteGroup")
messages.error(request, _('Error deleting security group: %s')
% e.message)
- return shortcuts.redirect('dash_security_groups', data['tenant_id'])
+ return shortcuts.redirect('horizon:nova:security_groups:index')
class AddRule(forms.SelfHandlingForm):
@@ -135,69 +126,3 @@ class DeleteRule(forms.SelfHandlingForm):
messages.error(request, _('Error authorizing security group: %s')
% e.message)
return shortcuts.redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id):
- delete_form, handled = DeleteGroup.maybe_handle(request,
- initial={'tenant_id': tenant_id})
-
- if handled:
- return handled
-
- try:
- security_groups = api.security_group_list(request)
- except novaclient_exceptions.ClientException, e:
- security_groups = []
- LOG.exception("ClientException in security_groups index")
- messages.error(request, _('Error fetching security_groups: %s')
- % e.message)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/security_groups/index.html', {
- 'security_groups': security_groups,
- 'delete_form': delete_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def edit_rules(request, tenant_id, security_group_id):
- add_form, handled = AddRule.maybe_handle(request,
- initial={'tenant_id': tenant_id,
- 'security_group_id': security_group_id})
- if handled:
- return handled
-
- delete_form, handled = DeleteRule.maybe_handle(request,
- initial={'tenant_id': tenant_id,
- 'security_group_id': security_group_id})
- if handled:
- return handled
-
- try:
- security_group = api.security_group_get(request, security_group_id)
- except novaclient_exceptions.ClientException, e:
- LOG.exception("ClientException in security_groups rules edit")
- messages.error(request, _('Error getting security_group: %s')
- % e.message)
- return shortcuts.redirect('dash_security_groups', tenant_id)
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/security_groups/edit_rules.html', {
- 'security_group': security_group,
- 'delete_form': delete_form,
- 'form': add_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def create(request, tenant_id):
- form, handled = CreateGroup.maybe_handle(request,
- initial={'tenant_id': tenant_id})
- if handled:
- return handled
-
- return shortcuts.render_to_response(
- 'django_openstack/dash/security_groups/create.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
diff --git a/horizon/horizon/dashboards/nova/security_groups/panel.py b/horizon/horizon/dashboards/nova/security_groups/panel.py
new file mode 100644
index 00000000..344238de
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/security_groups/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class SecurityGroups(horizon.Panel):
+ name = "Security Groups"
+ slug = 'security_groups'
+
+
+dashboard.Nova.register(SecurityGroups)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/security_groups_tests.py b/horizon/horizon/dashboards/nova/security_groups/tests.py
index 7d7bdee2..de061f6f 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/security_groups_tests.py
+++ b/horizon/horizon/dashboards/nova/security_groups/tests.py
@@ -21,15 +21,22 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from glance.common import exception as glance_exception
from openstackx.api import exceptions as api_exceptions
from novaclient import exceptions as novaclient_exceptions
from mox import IgnoreArg, IsA
+from horizon import api
+from horizon import test
-class SecurityGroupsViewTests(base.BaseViewTests):
+SECGROUP_ID = '1'
+SG_INDEX_URL = reverse('horizon:nova:security_groups:index')
+SG_CREATE_URL = reverse('horizon:nova:security_groups:create')
+SG_EDIT_RULE_URL = reverse('horizon:nova:security_groups:edit_rules',
+ args=[SECGROUP_ID])
+
+
+class SecurityGroupsViewTests(test.BaseViewTests):
def setUp(self):
super(SecurityGroupsViewTests, self).setUp()
@@ -44,11 +51,9 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ res = self.client.get(SG_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/security_groups/index.html')
+ self.assertTemplateUsed(res, 'nova/security_groups/index.html')
self.assertItemsEqual(res.context['security_groups'],
self.security_groups)
@@ -65,21 +70,17 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ res = self.client.get(SG_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/security_groups/index.html')
+ self.assertTemplateUsed(res, 'nova/security_groups/index.html')
self.assertEqual(len(res.context['security_groups']), 0)
self.mox.VerifyAll()
def test_create_security_groups_get(self):
- res = self.client.get(reverse('dash_security_groups_create',
- args=[self.TEST_TENANT]))
+ res = self.client.get(SG_CREATE_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/security_groups/create.html')
+ self.assertTemplateUsed(res, 'nova/security_groups/create.html')
def test_create_security_groups_post(self):
SECGROUP_NAME = 'fakegroup'
@@ -100,12 +101,9 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_create',
- args=[self.TEST_TENANT]),
- formData)
+ res = self.client.post(SG_CREATE_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res, SG_INDEX_URL)
self.mox.VerifyAll()
@@ -128,17 +126,13 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_create',
- args=[self.TEST_TENANT]),
- formData)
+ res = self.client.post(SG_CREATE_URL, formData)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/security_groups/create.html')
+ self.assertTemplateUsed(res, 'nova/security_groups/create.html')
self.mox.VerifyAll()
def test_edit_rules_get(self):
- SECGROUP_ID = '1'
self.mox.StubOutWithMock(api, 'security_group_get')
api.security_group_get(IsA(http.HttpRequest), SECGROUP_ID).AndReturn(
@@ -146,19 +140,15 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ res = self.client.get(SG_EDIT_RULE_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/dash/security_groups/edit_rules.html')
+ self.assertTemplateUsed(res, 'nova/security_groups/edit_rules.html')
self.assertItemsEqual(res.context['security_group'].name,
self.security_groups[0].name)
self.mox.VerifyAll()
def test_edit_rules_get_exception(self):
- SECGROUP_ID = '1'
-
exception = novaclient_exceptions.ClientException('ClientException',
message='ClientException')
@@ -168,16 +158,13 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ res = self.client.get(SG_EDIT_RULE_URL)
- self.assertRedirectsNoFollow(res, reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res, SG_INDEX_URL)
self.mox.VerifyAll()
def test_edit_rules_add_rule(self):
- SECGROUP_ID = '1'
RULE_ID = '1'
FROM_PORT = '-1'
TO_PORT = '-1'
@@ -210,13 +197,9 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]),
- formData)
+ res = self.client.post(SG_EDIT_RULE_URL, formData)
- self.assertRedirectsNoFollow(res,
- reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ self.assertRedirectsNoFollow(res, SG_EDIT_RULE_URL)
self.mox.VerifyAll()
@@ -224,7 +207,6 @@ class SecurityGroupsViewTests(base.BaseViewTests):
exception = novaclient_exceptions.ClientException('ClientException',
message='ClientException')
- SECGROUP_ID = '1'
RULE_ID = '1'
FROM_PORT = '-1'
TO_PORT = '-1'
@@ -249,18 +231,13 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]),
- formData)
+ res = self.client.post(SG_EDIT_RULE_URL, formData)
- self.assertRedirectsNoFollow(res,
- reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ self.assertRedirectsNoFollow(res, SG_EDIT_RULE_URL)
self.mox.VerifyAll()
def test_edit_rules_delete_rule(self):
- SECGROUP_ID = '1'
RULE_ID = '1'
formData = {'method': 'DeleteRule',
@@ -276,13 +253,9 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]),
- formData)
+ res = self.client.post(SG_EDIT_RULE_URL, formData)
- self.assertRedirectsNoFollow(res,
- reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ self.assertRedirectsNoFollow(res, SG_EDIT_RULE_URL)
self.mox.VerifyAll()
@@ -290,7 +263,6 @@ class SecurityGroupsViewTests(base.BaseViewTests):
exception = novaclient_exceptions.ClientException('ClientException',
message='ClientException')
- SECGROUP_ID = '1'
RULE_ID = '1'
formData = {'method': 'DeleteRule',
@@ -307,18 +279,13 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]),
- formData)
+ res = self.client.post(SG_EDIT_RULE_URL, formData)
- self.assertRedirectsNoFollow(res,
- reverse('dash_security_groups_edit_rules',
- args=[self.TEST_TENANT, SECGROUP_ID]))
+ self.assertRedirectsNoFollow(res, SG_EDIT_RULE_URL)
self.mox.VerifyAll()
def test_delete_group(self):
- SECGROUP_ID = '1'
formData = {'method': 'DeleteGroup',
'tenant_id': self.TEST_TENANT,
@@ -333,12 +300,9 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups',
- args=[self.TEST_TENANT]),
- formData)
+ res = self.client.post(SG_INDEX_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res, SG_INDEX_URL)
self.mox.VerifyAll()
@@ -346,8 +310,6 @@ class SecurityGroupsViewTests(base.BaseViewTests):
exception = novaclient_exceptions.ClientException('ClientException',
message='ClientException')
- SECGROUP_ID = '1'
-
formData = {'method': 'DeleteGroup',
'tenant_id': self.TEST_TENANT,
'security_group_id': SECGROUP_ID,
@@ -362,11 +324,8 @@ class SecurityGroupsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_security_groups',
- args=[self.TEST_TENANT]),
- formData)
+ res = self.client.post(SG_INDEX_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('dash_security_groups',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res, SG_INDEX_URL)
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/security_groups/urls.py b/horizon/horizon/dashboards/nova/security_groups/urls.py
new file mode 100644
index 00000000..691a7461
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/security_groups/urls.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.nova.security_groups.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'),
+ url(r'^(?P<security_group_id>[^/]+)/edit_rules/$', 'edit_rules',
+ name='edit_rules'))
diff --git a/horizon/horizon/dashboards/nova/security_groups/views.py b/horizon/horizon/dashboards/nova/security_groups/views.py
new file mode 100644
index 00000000..9d6530c4
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/security_groups/views.py
@@ -0,0 +1,103 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Nova instances.
+"""
+import logging
+
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django import shortcuts
+from django.utils.translation import ugettext as _
+from novaclient import exceptions as novaclient_exceptions
+
+from horizon import api
+from horizon.dashboards.nova.security_groups.forms import (CreateGroup,
+ DeleteGroup, AddRule, DeleteRule)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ tenant_id = request.user.tenant_id
+ delete_form, handled = DeleteGroup.maybe_handle(request,
+ initial={'tenant_id': tenant_id})
+
+ if handled:
+ return handled
+
+ try:
+ security_groups = api.security_group_list(request)
+ except novaclient_exceptions.ClientException, e:
+ security_groups = []
+ LOG.exception("ClientException in security_groups index")
+ messages.error(request, _('Error fetching security_groups: %s')
+ % e.message)
+
+ return shortcuts.render(request,
+ 'nova/security_groups/index.html', {
+ 'security_groups': security_groups,
+ 'delete_form': delete_form})
+
+
+@login_required
+def edit_rules(request, security_group_id):
+ tenant_id = request.user.tenant_id
+ add_form, handled = AddRule.maybe_handle(request,
+ initial={'tenant_id': tenant_id,
+ 'security_group_id': security_group_id})
+ if handled:
+ return handled
+
+ delete_form, handled = DeleteRule.maybe_handle(request,
+ initial={'tenant_id': tenant_id,
+ 'security_group_id': security_group_id})
+ if handled:
+ return handled
+
+ try:
+ security_group = api.security_group_get(request, security_group_id)
+ except novaclient_exceptions.ClientException, e:
+ LOG.exception("ClientException in security_groups rules edit")
+ messages.error(request, _('Error getting security_group: %s')
+ % e.message)
+ return shortcuts.redirect('horizon:nova:security_groups:index')
+
+ return shortcuts.render(request,
+ 'nova/security_groups/edit_rules.html', {
+ 'security_group': security_group,
+ 'delete_form': delete_form,
+ 'form': add_form})
+
+
+@login_required
+def create(request):
+ tenant_id = request.user.tenant_id
+ form, handled = CreateGroup.maybe_handle(request,
+ initial={'tenant_id': tenant_id})
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/security_groups/create.html', {
+ 'form': form})
diff --git a/django-openstack/django_openstack/tests/view_tests/syspanel/__init__.py b/horizon/horizon/dashboards/nova/snapshots/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/tests/view_tests/syspanel/__init__.py
+++ b/horizon/horizon/dashboards/nova/snapshots/__init__.py
diff --git a/horizon/horizon/dashboards/nova/snapshots/forms.py b/horizon/horizon/dashboards/nova/snapshots/forms.py
new file mode 100644
index 00000000..3666c399
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/snapshots/forms.py
@@ -0,0 +1,57 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon import forms
+
+
+LOG = logging.getLogger(__name__)
+
+
+class CreateSnapshot(forms.SelfHandlingForm):
+ tenant_id = forms.CharField(widget=forms.HiddenInput())
+ instance_id = forms.CharField(widget=forms.TextInput(
+ attrs={'readonly': 'readonly'}))
+ name = forms.CharField(max_length="20", label=_("Snapshot Name"))
+
+ def handle(self, request, data):
+ try:
+ LOG.info('Creating snapshot "%s"' % data['name'])
+ snapshot = api.snapshot_create(request,
+ data['instance_id'],
+ data['name'])
+ instance = api.server_get(request, data['instance_id'])
+
+ messages.info(request,
+ _('Snapshot "%(name)s" created for instance "%(inst)s"') %
+ {"name": data['name'], "inst": instance.name})
+ return shortcuts.redirect('horizon:nova:snapshots:index')
+ except api_exceptions.ApiException, e:
+ msg = _('Error Creating Snapshot: %s') % e.message
+ LOG.exception(msg)
+ messages.error(request, msg)
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/nova/snapshots/panel.py b/horizon/horizon/dashboards/nova/snapshots/panel.py
new file mode 100644
index 00000000..5b17b193
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/snapshots/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Snapshots(horizon.Panel):
+ name = "Snapshots"
+ slug = 'snapshots'
+
+
+dashboard.Nova.register(Snapshots)
diff --git a/django-openstack/django_openstack/tests/view_tests/dash/snapshots_tests.py b/horizon/horizon/dashboards/nova/snapshots/tests.py
index 7317ef73..c0c70f18 100644
--- a/django-openstack/django_openstack/tests/view_tests/dash/snapshots_tests.py
+++ b/horizon/horizon/dashboards/nova/snapshots/tests.py
@@ -21,14 +21,15 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from glance.common import exception as glance_exception
from openstackx.api import exceptions as api_exceptions
from mox import IgnoreArg, IsA
+from horizon import api
+from horizon import test
-class SnapshotsViewTests(base.BaseViewTests):
+
+class SnapshotsViewTests(test.BaseViewTests):
def setUp(self):
super(SnapshotsViewTests, self).setUp()
image_dict = {'name': 'snapshot',
@@ -54,11 +55,9 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:snapshots:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/snapshots/index.html')
+ self.assertTemplateUsed(res, 'nova/snapshots/index.html')
self.assertIn('images', res.context)
images = res.context['images']
@@ -76,11 +75,9 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:snapshots:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/snapshots/index.html')
+ self.assertTemplateUsed(res, 'nova/snapshots/index.html')
self.mox.VerifyAll()
@@ -94,11 +91,9 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots',
- args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:nova:snapshots:index'))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/snapshots/index.html')
+ self.assertTemplateUsed(res, 'nova/snapshots/index.html')
self.mox.VerifyAll()
@@ -109,12 +104,10 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.good_server.id]))
+ res = self.client.get(reverse('horizon:nova:snapshots:create',
+ args=[self.good_server.id]))
- self.assertTemplateUsed(res,
- 'django_openstack/dash/snapshots/create.html')
+ self.assertTemplateUsed(res, 'nova/snapshots/create.html')
self.mox.VerifyAll()
def test_create_snapshot_get_with_invalid_status(self):
@@ -124,12 +117,11 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.bad_server.id]))
+ res = self.client.get(reverse('horizon:nova:snapshots:create',
+ args=[self.bad_server.id]))
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
def test_create_get_server_exception(self):
@@ -140,12 +132,11 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.good_server.id]))
+ res = self.client.get(reverse('horizon:nova:snapshots:create',
+ args=[self.good_server.id]))
- self.assertRedirectsNoFollow(res, reverse('dash_instances',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:instances:index'))
self.mox.VerifyAll()
@@ -171,13 +162,12 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.good_server.id]),
- formData)
+ res = self.client.post(reverse('horizon:nova:snapshots:create',
+ args=[self.good_server.id]),
+ formData)
- self.assertRedirectsNoFollow(res, reverse('dash_snapshots',
- args=[self.TEST_TENANT]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:snapshots:index'))
self.mox.VerifyAll()
@@ -201,13 +191,12 @@ class SnapshotsViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.good_server.id]),
- formData)
+ res = self.client.post(reverse('horizon:nova:snapshots:create',
+ args=[self.good_server.id]),
+ formData)
- self.assertRedirectsNoFollow(res, reverse('dash_snapshots_create',
- args=[self.TEST_TENANT,
- self.good_server.id]))
+ self.assertRedirectsNoFollow(res,
+ reverse('horizon:nova:snapshots:create',
+ args=[self.good_server.id]))
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/nova/snapshots/urls.py b/horizon/horizon/dashboards/nova/snapshots/urls.py
new file mode 100644
index 00000000..64b43af8
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/snapshots/urls.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.nova.snapshots.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^(?P<instance_id>[^/]+)/create', 'create', name='create'))
diff --git a/django-openstack/django_openstack/dash/views/snapshots.py b/horizon/horizon/dashboards/nova/snapshots/views.py
index 47b5a7b0..5d99484b 100644
--- a/django-openstack/django_openstack/dash/views/snapshots.py
+++ b/horizon/horizon/dashboards/nova/snapshots/views.py
@@ -22,55 +22,28 @@
Views for managing Nova instance snapshots.
"""
-import datetime
import logging
import re
from django import http
+from django import shortcuts
from django import template
-from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect, render_to_response
from django.utils.translation import ugettext as _
-from django import shortcuts
-
-from django_openstack import api
-from django_openstack import forms
-from openstackx.api import exceptions as api_exceptions
from glance.common import exception as glance_exception
+from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon import forms
+from horizon.dashboards.nova.snapshots.forms import CreateSnapshot
-LOG = logging.getLogger('django_openstack.dash.views.snapshots')
-
-
-class CreateSnapshot(forms.SelfHandlingForm):
- tenant_id = forms.CharField(widget=forms.HiddenInput())
- instance_id = forms.CharField(widget=forms.TextInput(
- attrs={'readonly': 'readonly'}))
- name = forms.CharField(max_length="20", label=_("Snapshot Name"))
-
- def handle(self, request, data):
- try:
- LOG.info('Creating snapshot "%s"' % data['name'])
- snapshot = api.snapshot_create(request,
- data['instance_id'],
- data['name'])
- instance = api.server_get(request, data['instance_id'])
- messages.info(request,
- _('Snapshot "%(name)s" created for instance "%(inst)s"') %
- {"name": data['name'], "inst": instance.name})
- return shortcuts.redirect('dash_snapshots', data['tenant_id'])
- except api_exceptions.ApiException, e:
- msg = _('Error Creating Snapshot: %s') % e.message
- LOG.exception(msg)
- messages.error(request, msg)
- return shortcuts.redirect(request.build_absolute_uri())
+LOG = logging.getLogger(__name__)
@login_required
-def index(request, tenant_id):
+def index(request):
images = []
try:
@@ -84,14 +57,14 @@ def index(request, tenant_id):
LOG.exception(msg)
messages.error(request, msg)
- return render_to_response(
- 'django_openstack/dash/snapshots/index.html', {
- 'images': images,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'nova/snapshots/index.html',
+ {'images': images})
@login_required
-def create(request, tenant_id, instance_id):
+def create(request, instance_id):
+ tenant_id = request.user.tenant_id
form, handled = CreateSnapshot.maybe_handle(request,
initial={'tenant_id': tenant_id,
'instance_id': instance_id})
@@ -104,17 +77,16 @@ def create(request, tenant_id, instance_id):
msg = _("Unable to retreive instance: %s") % e
LOG.exception(msg)
messages.error(request, msg)
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
valid_states = ['ACTIVE']
if instance.status not in valid_states:
messages.error(request, _("To snapshot, instance state must be\
one of the following: %s") %
', '.join(valid_states))
- return shortcuts.redirect('dash_instances', tenant_id)
+ return shortcuts.redirect('horizon:nova:instances:index')
- return shortcuts.render_to_response(
- 'django_openstack/dash/snapshots/create.html', {
- 'instance': instance,
- 'create_form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'nova/snapshots/create.html',
+ {'instance': instance,
+ 'create_form': form})
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/base.html b/horizon/horizon/dashboards/nova/templates/nova/base.html
index 430a4d99..2fe83bb6 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/base.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/base.html
@@ -1,18 +1,11 @@
{% extends 'base.html' %}
-{% block topbar %}
- {% with current_topbar="dash" %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
{% block sidebar %}
- {% include 'django_openstack/dash/_sidebar.html' %}
+ {% include 'horizon/common/_sidebar.html' %}
{% endblock %}
{% block main %}
- {% block page_header %}
- {% endblock %}
-
+ {% block page_header %}{% endblock %}
<div class='main_content'>
{% include "_messages.html" %}
{% block dash_main %}{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/containers/_delete.html
index 97ee0609..97ee0609 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/containers/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_form.html b/horizon/horizon/dashboards/nova/templates/nova/containers/_form.html
index 155a20d2..155a20d2 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/containers/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_list.html b/horizon/horizon/dashboards/nova/templates/nova/containers/_list.html
index f15496ea..fe7828f5 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/containers/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/containers/_list.html
@@ -13,9 +13,9 @@
<td>{{ container.name }}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/dash/containers/_delete.html" with form=delete_form %}</li>
- <li><a href="{% url dash_objects request.user.tenant_id container.name %}">{% trans "List Objects" %}</a></li>
- <li><a href="{% url dash_objects_upload request.user.tenant_id container.name %}">{% trans "Upload Object"%}</a></li>
+ <li class="form">{% include "nova/containers/_delete.html" with form=delete_form %}</li>
+ <li><a href="{% url horizon:nova:containers:object_index container.name %}">{% trans "List Objects" %}</a></li>
+ <li><a href="{% url horizon:nova:containers:object_upload container.name %}">{% trans "Upload Object"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/create.html b/horizon/horizon/dashboards/nova/templates/nova/containers/create.html
index f0405480..4d4cde4e 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/containers/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/containers/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Tenant") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Tenant") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/containers/_form.html' with form=create_form %}
+ {% include 'nova/containers/_form.html' with form=create_form %}
</div>
<div class="right">
diff --git a/horizon/horizon/dashboards/nova/templates/nova/containers/index.html b/horizon/horizon/dashboards/nova/templates/nova/containers/index.html
new file mode 100644
index 00000000..156f4817
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/templates/nova/containers/index.html
@@ -0,0 +1,19 @@
+{% extends 'nova/base.html' %}
+{%load i18n%}
+
+{% block sidebar %}
+ {% with current_sidebar="containers" %}
+ {{block.super}}
+ {% endwith %}
+{% endblock %}
+
+{% block page_header %}
+ {% url horizon:nova:images:index as refresh_link %}
+ {# to make searchable false, just remove it from the include statement #}
+ {% include "horizon/common/_page_header.html" with title=_("Containers") refresh_link=refresh_link searchable="true" %}
+{% endblock page_header %}
+
+{% block dash_main %}
+ {% include 'nova/containers/_list.html' %}
+ <a class="action_link large-rounded" href="{% url horizon:nova:containers:create %}">{% trans "Create New Container"%} &gt;&gt;</a>
+{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_allocate.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_allocate.html
index f18b70b3..f18b70b3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_allocate.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_allocate.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_associate.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_associate.html
index 4e8a3ead..4e8a3ead 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_associate.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_associate.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_disassociate.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_disassociate.html
index ca5fae02..ca5fae02 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_disassociate.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_disassociate.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_list.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_list.html
index 156d625e..92d11884 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_list.html
@@ -21,11 +21,11 @@
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/dash/floating_ips/_release.html" with form=release_form %}</li>
+ <li class="form">{% include "nova/floating_ips/_release.html" with form=release_form %}</li>
{% if ip.fixed_ip %}
- <li class="form">{% include "django_openstack/dash/floating_ips/_disassociate.html" with form=disassociate_form %}</li>
+ <li class="form">{% include "nova/floating_ips/_disassociate.html" with form=disassociate_form %}</li>
{% else %}
- <li class="form"><a href="{% url dash_floating_ips_associate request.user.tenant_id ip.id %}">{%trans "Associate to instance"%}</a></li>
+ <li class="form"><a href="{% url horizon:nova:floating_ips:associate ip.id %}">{%trans "Associate to instance"%}</a></li>
{% endif %}
</ul>
</td>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_release.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_release.html
index ae13601d..ae13601d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_release.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/_release.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/associate.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/associate.html
index ff05fa27..5d73f73e 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/associate.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/associate.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,13 +9,13 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Associate Floating IP") %}
+ {% include "horizon/common/_page_header.html" with title=_("Associate Floating IP") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/floating_ips/_associate.html' with form=associate_form %}
+ {% include 'nova/floating_ips/_associate.html' with form=associate_form %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/index.html b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/index.html
index fa224670..013718a0 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/floating_ips/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,19 +8,19 @@
{% endblock %}
{% block page_header %}
- {% url dash_floating_ips request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:floating_ips:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Floating IPs") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Floating IPs") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if floating_ips %}
- {% include 'django_openstack/dash/floating_ips/_list.html' %}
+ {% include 'nova/floating_ips/_list.html' %}
{% else %}
<div class="message_box info">
<h2>{%trans "Info"%}</h2>
<p>{%trans "There are currently no floating ips assigned to your tenant."%}</p>
</div>
{% endif %}
- {% include "django_openstack/dash/floating_ips/_allocate.html" with form=allocate_form %}
+ {% include "nova/floating_ips/_allocate.html" with form=allocate_form %}
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/images/_delete.html
index cc8def96..cc8def96 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/_form.html b/horizon/horizon/dashboards/nova/templates/nova/images/_form.html
index 92dbbade..92dbbade 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/_launch.html b/horizon/horizon/dashboards/nova/templates/nova/images/_launch.html
index d0947c23..20f48c3d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/_launch.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/_launch.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/images/_launch_form.html' %}
+{% extends 'nova/images/_launch_form.html' %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/_launch_form.html b/horizon/horizon/dashboards/nova/templates/nova/images/_launch_form.html
index 8eab67f6..8eab67f6 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/_launch_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/_launch_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/_list.html b/horizon/horizon/dashboards/nova/templates/nova/images/_list.html
index 0a0ad21e..b0f25a8d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/_list.html
@@ -18,10 +18,10 @@
<td id="actions">
<ul>
{% if image.owner == request.user.username %}
- <li class="form">{% include "django_openstack/dash/images/_delete.html" with form=delete_form %}</li>
- <li><a href="{% url dash_images_update request.user.tenant_id image.id %}">{%trans "Edit"%}</a></li>
+ <li class="form">{% include "nova/images/_delete.html" with form=delete_form %}</li>
+ <li><a href="{% url horizon:nova:images:update image.id %}">{%trans "Edit"%}</a></li>
{% endif %}
- <li><a id="launch_{{image.id}}" class="launch" href="{% url dash_images_launch request.user.tenant_id image.id %}">{%trans "Launch"%}</a></li>
+ <li><a id="launch_{{image.id}}" class="launch" href="{% url horizon:nova:images:launch image.id %}">{%trans "Launch"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/index.html b/horizon/horizon/dashboards/nova/templates/nova/images/index.html
index 421d7cf2..78575e90 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
{% with current_sidebar="images" %}
@@ -7,14 +7,14 @@
{% endblock %}
{% block page_header %}
- {% url dash_images request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:images:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Images") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Images") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if images %}
- {% include 'django_openstack/dash/images/_list.html' %}
+ {% include 'nova/images/_list.html' %}
{% else %}
<div class="message_box info">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/launch.html b/horizon/horizon/dashboards/nova/templates/nova/images/launch.html
index 35015950..2e071200 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/launch.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/launch.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,13 +9,13 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Launch Instance") %}
+ {% include "horizon/common/_page_header.html" with title=_("Launch Instance") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/images/_launch.html' %}
+ {% include 'nova/images/_launch.html' %}
</div>
<div class="right">
<h3>{% trans "Description:"%}</h3>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/update.html b/horizon/horizon/dashboards/nova/templates/nova/images/update.html
index 9abf192b..d20491aa 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/images/update.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/images/update.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Update Image") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update Image") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/images/_form.html' %}
+ {% include 'nova/images/_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/_form.html b/horizon/horizon/dashboards/nova/templates/nova/instances/_form.html
index 5e267eff..5e267eff 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/_list.html b/horizon/horizon/dashboards/nova/templates/nova/instances/_list.html
index ab6c0374..52e5180b 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/_list.html
@@ -1,4 +1,4 @@
-<!-- TODO(termie): move most of this to django_openstack -->
+<!-- TODO(termie): move most of this to horizon -->
{% load sizeformat %}
{%load i18n%}
<table id='instances' class="wide">
@@ -17,7 +17,7 @@
<tr class="{% cycle 'odd' 'even' %}">
<td>{{instance.id}}</td>
<td class="name">
- <a href="{% url dash_instances_detail request.user.tenant_name instance.id %}">
+ <a href="{% url horizon:nova:instances:detail instance.id %}">
{{instance.name}}
{% if instance.attrs.key_name %}
<br/>
@@ -61,12 +61,12 @@
<td>{{instance.status|lower|capfirst}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/common/instances/_terminate.html" with form=terminate_form %}</li>
- <li class="form">{% include "django_openstack/common/instances/_reboot.html" with form=reboot_form %}</li>
- <li><a target="_blank" href="{% url dash_instances_console request.user.tenant_id instance.id %}">{% trans "Log"%}</a></li>
- <li><a target="_blank" href="{% url dash_instances_vnc request.user.tenant_id instance.id %}">{% trans "VNC Console"%}</a></li>
- <li><a href="{% url dash_instances_update request.user.tenant_id instance.id %}">{% trans "Edit"%}</a></li>
- <li><a href="{% url dash_snapshots_create request.user.tenant_id instance.id %}">{% trans "Snapshot"%}</a></li>
+ <li class="form">{% include "horizon/common/instances/_terminate.html" with form=terminate_form %}</li>
+ <li class="form">{% include "horizon/common/instances/_reboot.html" with form=reboot_form %}</li>
+ <li><a target="_blank" href="{% url horizon:nova:instances:console instance.id %}">{% trans "Log"%}</a></li>
+ <li><a target="_blank" href="{% url horizon:nova:instances:vnc instance.id %}">{% trans "VNC Console"%}</a></li>
+ <li><a href="{% url horizon:nova:instances:update instance.id %}">{% trans "Edit"%}</a></li>
+ <li><a href="{% url horizon:nova:snapshots:create instance.id %}">{% trans "Snapshot"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/detail.html b/horizon/horizon/dashboards/nova/templates/nova/instances/detail.html
index 414017f8..0e74a7ba 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/detail.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/detail.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{% load i18n %}
{% block sidebar %}
@@ -9,7 +9,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title="Instance Detail: "|add:instance.name %}
+ {% include "horizon/common/_page_header.html" with title="Instance Detail: "|add:instance.name %}
{% endblock page_header %}
{% block dash_main %}
@@ -77,7 +77,7 @@
</div>
<div id="log" class="tab_wrapper">
- <a class="view_full" target="_blank" href="{% url dash_instances_console request.user.tenant_id instance.id %}">{% trans "View Full Log" %}</a>
+ <a class="view_full" target="_blank" href="{% url horizon:nova:instances:console instance.id %}">{% trans "View Full Log" %}</a>
<pre class="logs"></pre>
</div>
@@ -116,7 +116,7 @@
})
function getlog(){
- $.get("{% url dash_instances_console instance.attrs.tenant_id instance.id %}?length=25", function(data){
+ $.get("{% url horizon:nova:instances:console instance.id %}?length=25", function(data){
$("#log .logs").html(data)
})
}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/index.html b/horizon/horizon/dashboards/nova/templates/nova/instances/index.html
index 60a2c7ab..9d49302f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,17 +8,17 @@
{% endblock %}
{% block page_header %}
- {% url dash_instances request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:instances:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Instances") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Instances") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if instances %}
- {% include 'django_openstack/dash/instances/_list.html' %}
+ {% include 'nova/instances/_list.html' %}
{% else %}
<div class="message_box info">
- {% url dash_images request.user.tenant_id as dash_img_url %}
+ {% url horizon:nova:images:index as dash_img_url %}
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no instances. You can launch an instance from the <a href='{{dash_img_url}}'>Images Page.</a>{% endblocktrans %}</p>
</div>
@@ -31,7 +31,7 @@
function loadInstances(){
if ($("#ajax_option_box").is(':checked')) {
$('.refresh').addClass("refreshing");
- $('#instances').load('{% url dash_instances_refresh request.user.tenant_id %}', function(){
+ $('#instances').load('{% url horizon:nova:instances:refresh %}', function(){
$('.refresh').removeClass("refreshing");
});
};
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/update.html b/horizon/horizon/dashboards/nova/templates/nova/instances/update.html
index d497d2be..85a62b64 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/update.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/update.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,14 +9,14 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Update Instance") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update Instance") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/instances/_form.html' with form=form %}
- <h3><a href="{% url dash_instances request.user.tenant_id %}"><< {% trans "Return to Instances List"%}</a></h3>
+ {% include 'nova/instances/_form.html' with form=form %}
+ <h3><a href="{% url horizon:nova:instances:index %}"><< {% trans "Return to Instances List"%}</a></h3>
</div>
<div class="right">
@@ -33,7 +33,7 @@
$("#spinner").hide()
function loadInstances(){
$('#spinner').show();
- $('#instances').load('{% url dash_instances_refresh request.user.tenant_id %}', function(){
+ $('#instances').load('{% url horizon:nova:instances:refresh %}', function(){
$("#spinner").hide()
});
}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.csv b/horizon/horizon/dashboards/nova/templates/nova/instances/usage.csv
index d618b637..d618b637 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.csv
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/usage.csv
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.html b/horizon/horizon/dashboards/nova/templates/nova/instances/usage.html
index b2290440..abc97cbb 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/instances/usage.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{% load parse_date %}
{% load sizeformat %}
{%load i18n%}
@@ -11,7 +11,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Overview") %}
+ {% include "horizon/common/_page_header.html" with title=_("Overview") %}
{% endblock page_header %}
{% block dash_main %}
@@ -47,9 +47,9 @@
<h3>Server Usage Summary
<small>
{% if show_terminated %}
- ( <a href="{% url dash_overview %}">{% trans "Hide Terminated"%}</a> )
+ ( <a href="{% url horizon:nova:instances:usage %}">{% trans "Hide Terminated"%}</a> )
{% else %}
- ( <a href="{% url dash_overview %}?show_terminated=1">{% trans "Show Terminated"%}</a> )
+ ( <a href="{% url horizon:nova:instances:usage %}?show_terminated=1">{% trans "Show Terminated"%}</a> )
{% endif %}
</small>
</h3>
@@ -93,7 +93,7 @@
</table>
{% else %}
<div class="message_box info">
- {% url dash_images request.user.tenant_id as dash_img_url%}
+ {% url horizon:nova:images:index as dash_img_url%}
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no instances.<br/><br/>You can launch an instance from the <a href='{{dash_img_url}}'>Images Page.</a>{% endblocktrans %}</p>
</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_delete.html
index 5e821bdc..5e821bdc 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_form.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_form.html
index 6e32d507..6e32d507 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_list.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_list.html
index d5288245..1b306949 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_list.html
@@ -11,7 +11,7 @@
<td>{{ keypair.fingerprint }}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/dash/keypairs/_delete.html" with form=delete_form %}</li>
+ <li class="form">{% include "nova/keypairs/_delete.html" with form=delete_form %}</li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/create.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/create.html
index f6fb09aa..ea64d36f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -21,15 +21,15 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Keypair") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Keypair") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
<h3>{% trans "Your private key is being downloaded."%}</h3>
- {% include 'django_openstack/dash/keypairs/_form.html' with form=create_form %}
- <h3><a href="{% url dash_keypairs request.user.tenant_id %}"><< {% trans "Return to keypairs list"%}</a></h3>
+ {% include 'nova/keypairs/_form.html' with form=create_form %}
+ <h3><a href="{% url horizon:nova:keypairs:index %}"><< {% trans "Return to keypairs list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/import.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/import.html
index 01544c6d..0df9e20b 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/import.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/import.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -12,14 +12,14 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Keypair") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Keypair") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/keypairs/_form.html' with form=create_form %}
- <h3><a href="{% url dash_keypairs request.user.tenant_id %}">&lt;&lt; {% trans "Return to keypairs list"%}</a></h3>
+ {% include 'nova/keypairs/_form.html' with form=create_form %}
+ <h3><a href="{% url horizon:nova:keypairs:index %}">&lt;&lt; {% trans "Return to keypairs list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/index.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/index.html
index ea95b8ca..8ad9fd70 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/keypairs/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,22 +8,22 @@
{% endblock %}
{% block page_header %}
- {% url dash_keypairs request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:keypairs:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Keypairs") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Keypairs") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if keypairs %}
- {% include 'django_openstack/dash/keypairs/_list.html' %}
- <a id="keypairs_create_link" class="action_link large-rounded" href="{% url dash_keypairs_create request.user.tenant_id %}">{% trans "Add New Keypair"%}</a>
- <a id="keypairs_import_link" class="action_link large-rounded" href="{% url dash_keypairs_import request.user.tenant_id %}">{% trans "Import Keypair"%}</a>
+ {% include 'nova/keypairs/_list.html' %}
+ <a id="keypairs_create_link" class="action_link large-rounded" href="{% url horizon:nova:keypairs:create %}">{% trans "Add New Keypair"%}</a>
+ <a id="keypairs_import_link" class="action_link large-rounded" href="{% url horizon:nova:keypairs:import %}">{% trans "Import Keypair"%}</a>
{% else %}
<div class="message_box info">
<h2>{% trans "Info"%}</h2>
<p>{% trans "There are currently no keypairs."%}</p>
</div>
- <a id="keypairs_create_link" class="action_link large-rounded" href="{% url dash_keypairs_create request.user.tenant_id %}">{% trans "Add New Keypair"%}</a>
- <a id="keypairs_import_link" class="action_link large-rounded" href="{% url dash_keypairs_import request.user.tenant_id %}">{% trans "Import Keypair"%}</a>
+ <a id="keypairs_create_link" class="action_link large-rounded" href="{% url horizon:nova:keypairs:create %}">{% trans "Add New Keypair"%}</a>
+ <a id="keypairs_import_link" class="action_link large-rounded" href="{% url horizon:nova:keypairs:import %}">{% trans "Import Keypair"%}</a>
{% endif %}
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_delete.html
index d009dbb2..d009dbb2 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete_port.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_delete_port.html
index c9e69d09..c9e69d09 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete_port.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_delete_port.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_detach_port.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_detach_port.html
index f1597e52..f1597e52 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_detach_port.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_detach_port.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_detail.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_detail.html
index 7990f4e2..b1bb51f3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_detail.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_detail.html
@@ -31,12 +31,12 @@
<td id="actions">
<ul>
{% if port.attachment %}
- <li class="form">{% include "django_openstack/dash/networks/_detach_port.html" with form=detach_port_form %}</li>
+ <li class="form">{% include "nova/networks/_detach_port.html" with form=detach_port_form %}</li>
{% else %}
- <li><a href='{% url dash_ports_attach request.user.tenant_id network.id port.id %}'>{% trans "Attach"%}</a></li>
+ <li><a href='{% url horizon:nova:networks:port_attach network.id port.id %}'>{% trans "Attach"%}</a></li>
{% endif %}
- <li class="form">{% include "django_openstack/dash/networks/_delete_port.html" with form=delete_port_form %}</li>
- <li class="form">{% include "django_openstack/dash/networks/_toggle_port.html" with form=toggle_port_form %}</li>
+ <li class="form">{% include "nova/networks/_delete_port.html" with form=delete_port_form %}</li>
+ <li class="form">{% include "nova/networks/_toggle_port.html" with form=toggle_port_form %}</li>
</ul>
</td>
<td id="extensions">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_form.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_form.html
index 71e3e760..71e3e760 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_list.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_list.html
index f5823822..2e1ee13e 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_list.html
@@ -11,15 +11,15 @@
<tbody class='main'>
{% for network in networks %}
<tr class="{% cycle 'odd' 'even' %}" id="{{network.id}}">
- <td><a href='{% url dash_networks_detail request.user.tenant_id network.id %}'>{{network.id}}</a></td>
+ <td><a href='{% url horizon:nova:networks:detail network.id %}'>{{network.id}}</a></td>
<td class="name">{{network.name}}</td>
<td>{{network.total}}</td>
<td>{{network.available}}</td>
<td>{{network.used}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/dash/networks/_delete.html" with form=delete_form %}</li>
- <li><a href='{% url dash_network_rename request.user.tenant_id network.id %}'>{% trans "Rename"%}</a></li>
+ <li class="form">{% include "nova/networks/_delete.html" with form=delete_form %}</li>
+ <li><a href='{% url horizon:nova:networks:rename network.id %}'>{% trans "Rename"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_rename.html
index 7a915070..7a915070 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_rename.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename_form.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_rename_form.html
index cc3368ed..cc3368ed 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_rename_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_toggle_port.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_toggle_port.html
index 0be11240..0be11240 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_toggle_port.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/_toggle_port.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/create.html b/horizon/horizon/dashboards/nova/templates/nova/networks/create.html
index 05d4aa48..6ed8d51f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,14 +9,14 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Network") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Network") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/networks/_form.html' with form=network_form %}
- <h3><a href="{% url dash_networks request.user.tenant_id %}"><< {% trans "Return to networks list"%}</a></h3>
+ {% include 'nova/networks/_form.html' with form=network_form %}
+ <h3><a href="{% url horizon:nova:networks:index %}"><< {% trans "Return to networks list"%}</a></h3>
</div>
<div class="right">
diff --git a/horizon/horizon/dashboards/nova/templates/nova/networks/detail.html b/horizon/horizon/dashboards/nova/templates/nova/networks/detail.html
new file mode 100644
index 00000000..09a3b011
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/detail.html
@@ -0,0 +1,31 @@
+{% extends 'nova/base.html' %}
+{%load i18n%}
+
+{% block sidebar %}
+ {% with current_sidebar="networks" %}
+ {{block.super}}
+ {% endwith %}
+{% endblock %}
+
+{% block page_header %}
+ {% url horizon:nova:networks:detail network.id as refresh_link %}
+ {# to make searchable false, just remove it from the include statement #}
+ {% include "horizon/common/_page_header.html" with title=network.name refresh_link=refresh_link searchable="true" %}
+{% endblock page_header %}
+
+{% block breadcrumbs %}
+ <a href="{% url horizon:nova:networks:index %}">Networks</a>&nbsp;&raquo;&nbsp;
+ <a href="{% url horizon:nova:networks:detail network.id %}">{{network.name}}</a>
+{% endblock %}
+
+{% block dash_main %}
+ {% if network.ports %}
+ {% include 'nova/networks/_detail.html' %}
+ <a id="network_create_link" class="action_link large-rounded" href="{% url horizon:nova:networks:port_create network.id %}">{% trans "Create Ports"%}</a>
+ {% else %}
+ <div class="message_box info">
+ <h2>{% trans "Info"%}</h2>
+ <p>{% trans "There are currently no ports in this network."%} <a href="{% url horizon:nova:networks:port_create network.id %}">{% trans "Create Ports"%} &gt;&gt;</a></p>
+ </div>
+ {% endif %}
+{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/index.html b/horizon/horizon/dashboards/nova/templates/nova/networks/index.html
index 16ef1eeb..aac5d671 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,20 +8,20 @@
{% endblock %}
{% block page_header %}
- {% url dash_networks request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:networks:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Networks") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Networks") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if networks %}
- {% include 'django_openstack/dash/networks/_list.html' %}
- {% url dash_network_create request.user.tenant_id as dash_net_url %}
+ {% include 'nova/networks/_list.html' %}
+ {% url horizon:nova:networks:create as dash_net_url %}
<a id="network_create_link" class="action_link large-rounded" href="{{dash_net_url}}">{% trans "Create New Network"%}</a>
{% else %}
<div class="message_box info">
<h2>{% trans "Info"%}</h2>
- <p>{% trans "There are currently no networks."%} <a href='{% url dash_network_create request.user.tenant_id %}'>{% trans "Create A Network"%} &gt;&gt;</a></p>
+ <p>{% trans "There are currently no networks."%} <a href='{% url horizon:nova:networks:create %}'>{% trans "Create A Network"%} &gt;&gt;</a></p>
</div>
{% endif %}
</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/rename.html b/horizon/horizon/dashboards/nova/templates/nova/networks/rename.html
index 1a63096a..2ec732b3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/networks/rename.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/networks/rename.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,7 +9,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Rename Network") %}
+ {% include "horizon/common/_page_header.html" with title=_("Rename Network") %}
{% endblock page_header %}
{% block headerjs %}
@@ -23,8 +23,8 @@
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/networks/_rename_form.html' with form=rename_form %}
- <h3><a href="{% url dash_networks request.user.tenant_id %}"><< {% trans "Return to networks list"%}</a></h3>
+ {% include 'nova/networks/_rename_form.html' with form=rename_form %}
+ <h3><a href="{% url horizon:nova:networks:index %}"><< {% trans "Return to networks list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_copy.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_copy.html
index 4544bce9..4544bce9 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_copy.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_copy.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_delete.html
index 4a0af7bf..4a0af7bf 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_filter.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_filter.html
index 542439ed..542439ed 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_filter.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_filter.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_form.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_form.html
index 0a6de49f..0a6de49f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_list.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_list.html
index a73ea177..e38ae39c 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_list.html
@@ -13,9 +13,9 @@
<td>{{ object.name }}</td>
<td id="actions">
<ul>
- <li><a href="{% url dash_object_copy request.user.tenant_id container_name object.name %}">{% trans "Copy"%}</a></li>
- <li class="form">{% include "django_openstack/dash/objects/_delete.html" with form=delete_form %}</li>
- <li><a href="{% url dash_objects_download request.user.tenant_id container_name object.name %}">{% trans "Download"%}</a>
+ <li><a href="{% url horizon:nova:containers:object_copy container_name object.name %}">{% trans "Copy"%}</a></li>
+ <li class="form">{% include "nova/objects/_delete.html" with form=delete_form %}</li>
+ <li><a href="{% url horizon:nova:containers:object_download container_name object.name %}">{% trans "Download"%}</a>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_paging.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_paging.html
index 99299bdd..99299bdd 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_paging.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/_paging.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/copy.html b/horizon/horizon/dashboards/nova/templates/nova/objects/copy.html
index 38f5e272..fb23f270 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/copy.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/copy.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,7 +8,7 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Copy Object") %}
+ {% include "horizon/common/_page_header.html" with title=_("Copy Object") %}
{% endblock page_header %}
{% block dash_main %}
@@ -17,8 +17,8 @@
<div class="dash_block wide form">
<div class="left">
<h3>Copy Object: '{{object_name}}'</h3>
- {% include 'django_openstack/dash/objects/_copy.html' with form=copy_form greeting="HI" %}
- <h3><a href="{% url dash_objects request.user.tenant_id container_name %}">&lt;&lt; {% trans "Return to objects list"%}</a></h3>
+ {% include 'nova/objects/_copy.html' with form=copy_form greeting="HI" %}
+ <h3><a href="{% url horizon:nova:containers:object_index container_name %}">&lt;&lt; {% trans "Return to objects list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/index.html b/horizon/horizon/dashboards/nova/templates/nova/objects/index.html
index aacefb1e..1ddb2aa8 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -12,9 +12,9 @@
<h2>Objects</h2>
<div class="right">
<div class='search'>
- {% include 'django_openstack/dash/objects/_filter.html' with form=filter_form %}
+ {% include 'nova/objects/_filter.html' with form=filter_form %}
</div>
- <a class="refresh" title="Refresh" href="{% url dash_objects request.user.tenant_id container_name %}">{% trans "Refresh List"%}</a>
+ <a class="refresh" title="Refresh" href="{% url horizon:nova:containers:object_index container_name %}">{% trans "Refresh List"%}</a>
</div>
</div>
{% endblock %}
@@ -23,14 +23,14 @@
<h3 class="container_name"><span>Container:</span> {{ container_name }}</h3>
{% if objects %}
- {% include 'django_openstack/dash/objects/_list.html' %}
+ {% include 'nova/objects/_list.html' %}
{% else %}
<div class="message_box info">
- {% url dash_objects_upload request.user.tenant_id container_name as dash_obj_up_url %}
+ {% url horizon:nova:containers:object_upload container_name as dash_obj_up_url %}
<h2>Info</h2>
<p>{% blocktrans %}There are currently no objects in the container {{container_name}}. You can upload a new object from the <a href='{{dash_obj_up_url}}'>Object Upload Page &gt;&gt;</a>{% endblocktrans %}</p>
</div>
{% endif %}
- <a class="action_link large-rounded" href="{% url dash_objects_upload request.user.tenant_id container_name %}">{% trans "Upload New Object &gt;&gt;"%}</a>
+ <a class="action_link large-rounded" href="{% url horizon:nova:containers:object_upload container_name %}">{% trans "Upload New Object &gt;&gt;"%}</a>
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/upload.html b/horizon/horizon/dashboards/nova/templates/nova/objects/upload.html
index 8bb7b510..7dfa3eb7 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/objects/upload.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/objects/upload.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,7 +8,7 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Upload Objects") %}
+ {% include "horizon/common/_page_header.html" with title=_("Upload Objects") %}
{% endblock page_header %}
{% block dash_main %}
@@ -16,8 +16,8 @@
<div class="dash_block wide form">
<div class="left">
- {% include 'django_openstack/dash/objects/_form.html' with form=upload_form %}
- <h3><a href="{% url dash_objects request.user.tenant_id container_name %}">&lt;&lt; {% trans "Return to objects list"%}</a></h3>
+ {% include 'nova/objects/_form.html' with form=upload_form %}
+ <h3><a href="{% url horizon:nova:containers:object_index container_name %}">&lt;&lt; {% trans "Return to objects list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/_attach.html b/horizon/horizon/dashboards/nova/templates/nova/ports/_attach.html
index 5ff6f73a..5ff6f73a 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/ports/_attach.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/ports/_attach.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/_create.html b/horizon/horizon/dashboards/nova/templates/nova/ports/_create.html
index c8f3fc3d..c8f3fc3d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/ports/_create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/ports/_create.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/attach.html b/horizon/horizon/dashboards/nova/templates/nova/ports/attach.html
index 0155bb3a..e0787111 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/ports/attach.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/ports/attach.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,7 +9,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Attach Port") %}
+ {% include "horizon/common/_page_header.html" with title=_("Attach Port") %}
{% endblock page_header %}
{% block headerjs %}
@@ -34,8 +34,8 @@
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/ports/_attach.html' with form=attach_form %}
- <h3><a href="{% url dash_networks_detail request.user.tenant_id network %}"><< {% trans "Return to network detail"%}</a></h3>
+ {% include 'nova/ports/_attach.html' with form=attach_form %}
+ <h3><a href="{% url horizon:nova:networks:detail network %}"><< {% trans "Return to network detail"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/create.html b/horizon/horizon/dashboards/nova/templates/nova/ports/create.html
index 381fb3d1..629c49a1 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/ports/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/ports/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,14 +9,14 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Network") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Network") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/ports/_create.html' with form=create_form %}
- <h3><a href="{% url dash_networks_detail request.user.tenant_id network_id %}"><< {% trans "Return to network detail"%}</a></h3>
+ {% include 'nova/ports/_create.html' with form=create_form %}
+ <h3><a href="{% url horizon:nova:networks:detail network_id %}"><< {% trans "Return to network detail"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete.html
index 2059d502..2059d502 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete_rule.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete_rule.html
index cba1f9c4..cba1f9c4 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete_rule.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_delete_rule.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_form.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_form.html
index 0a8f7e40..0a8f7e40 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_list.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_list.html
index d8a1da57..7b324f13 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/_list.html
@@ -11,9 +11,9 @@
<td>{{ security_group.description }}</td>
<td id="actions">
<ul>
- <li><a href="{% url dash_security_groups_edit_rules request.user.tenant_id security_group.id %}">{% trans "Edit Rules"%}</a></li>
+ <li><a href="{% url horizon:nova:security_groups:edit_rules security_group.id %}">{% trans "Edit Rules"%}</a></li>
{% if security_group.name != 'default' %}
- <li class="form">{% include "django_openstack/dash/security_groups/_delete.html" with form=delete_form %}</li>
+ <li class="form">{% include "nova/security_groups/_delete.html" with form=delete_form %}</li>
{% endif %}
</ul>
</td>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/create.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/create.html
index 6e9d591f..9c0bc53c 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Security Group") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Security Group") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/security_groups/_form.html' %}
+ {% include 'nova/security_groups/_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/edit_rules.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/edit_rules.html
index 39986042..f2179103 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/edit_rules.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/edit_rules.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,7 +8,7 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Edit Security Group Rules") %}
+ {% include "horizon/common/_page_header.html" with title=_("Edit Security Group Rules") %}
{% endblock page_header %}
{% block dash_main %}
@@ -31,7 +31,7 @@
<td>{{rule.ip_range.cidr}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/dash/security_groups/_delete_rule.html" with form=delete_form %}</li>
+ <li class="form">{% include "nova/security_groups/_delete_rule.html" with form=delete_form %}</li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/index.html b/horizon/horizon/dashboards/nova/templates/nova/security_groups/index.html
index 48e9fa49..b266ebb7 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/security_groups/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/security_groups/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,19 +8,19 @@
{% endblock %}
{% block page_header %}
- {% url dash_security_groups request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:security_groups:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Security Groups") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Security Groups") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if security_groups %}
- {% include 'django_openstack/dash/security_groups/_list.html' %}
- {% url dash_security_groups_create request.user.tenant_id as create_sec_url %}
+ {% include 'nova/security_groups/_list.html' %}
+ {% url horizon:nova:security_groups:create as create_sec_url %}
<a id="security_groups_create_link" class="action_link large-rounded" href="{{create_sec_url}}">{% trans "Create Security Group"%}</a>
{% else %}
<div class="message_box info">
- {% url dash_security_groups_create request.user.tenant_id as dash_sec_url %}
+ {% url horizon:nova:security_groups:create as dash_sec_url %}
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no security groups. <a href='{{dash_sec_url}}'>Create A Security Group &gt;&gt;</a>{% endblocktrans %}</p>
</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/settings.html b/horizon/horizon/dashboards/nova/templates/nova/settings.html
index 658e2f50..e7708774 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/settings.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/settings.html
@@ -9,15 +9,15 @@
{% block sidebar %}
- {% include 'django_openstack/dash/_sidebar.html' %}
+ {% include 'nova/_sidebar.html' %}
{% endblock %}
{% block main %}
{% block page_header %}
- {% url dash_instances request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:instances:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Dashboard Settings") %}
+ {% include "horizon/common/_page_header.html" with title=_("Dashboard Settings") %}
{% endblock page_header %}
{% include "_messages.html" %}
<div class='main_content'>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/_form.html b/horizon/horizon/dashboards/nova/templates/nova/snapshots/_form.html
index fea72672..fea72672 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/snapshots/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/create.html b/horizon/horizon/dashboards/nova/templates/nova/snapshots/create.html
index 2f059ab9..f9fcabf1 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/snapshots/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -16,15 +16,15 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create a Snapshot") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create a Snapshot") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
<h3>{% trans "Choose a name for your snapshot."%}</h3>
- {% include 'django_openstack/dash/snapshots/_form.html' with form=create_form %}
- <h3><a href="{% url dash_snapshots request.user.tenant_id %}"><< {% trans "Return to snapshots list"%}</a></h3>
+ {% include 'nova/snapshots/_form.html' with form=create_form %}
+ <h3><a href="{% url horizon:nova:snapshots:index %}"><< {% trans "Return to snapshots list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/index.html b/horizon/horizon/dashboards/nova/templates/nova/snapshots/index.html
index 437a504e..b4e84123 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/snapshots/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,17 +8,17 @@
{% endblock %}
{% block page_header %}
- {% url dash_snapshots request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:snapshots:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Snapshots") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Snapshots") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if images %}
- {% include 'django_openstack/dash/images/_list.html' %}
+ {% include 'nova/images/_list.html' %}
{% else %}
<div class="message_box info">
- {% url dash_instances request.user.tenant_id as inst_url %}
+ {% url horizon:nova:instances:index as inst_url %}
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no snapshots. You can create snapshots from running instances. <a href='{{inst_url}}'>View Running Instances &gt;&gt;</a>{% endblocktrans %}</p>
</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_attach_form.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/_attach_form.html
index 6ad7d603..6ad7d603 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_attach_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/_attach_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/_delete.html
index 77310986..77310986 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_delete.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_detach_form.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/_detach_form.html
index 0f383a87..0f383a87 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_detach_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/_detach_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_form.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/_form.html
index 758fb185..758fb185 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_form.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_list.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/_list.html
index 18910ff7..15935231 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/_list.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/_list.html
@@ -14,7 +14,7 @@
<tr class="{% cycle 'odd' 'even' %}">
<td>{{ volume.id }}</td>
<td>
- <a href="{% url dash_volumes_detail request.user.tenant_name volume.id %}">
+ <a href="{% url horizon:nova:volumes:detail volume.id %}">
{{ volume.displayName }}
</a>
</td>
@@ -24,7 +24,7 @@
<td>
{% for attachment in volume.attachments %}
{% if attachment %}
- <a href="{% url dash_instances_detail request.user.tenant_name attachment.serverId %}">
+ <a href="{% url horizon:nova:volumes:detail attachment.serverId %}">
<!-- TODO (tres): Show instance name -->
Instance {{ attachment.serverId }}
<small>({{ attachment.device }})</small>
@@ -39,16 +39,16 @@
{% if volume.status == "in-use" %}
{% for attachment in volume.attachments %}
<li class="form">
- {% include "django_openstack/dash/volumes/_detach_form.html" with form=detach_form %}
+ {% include "nova/volumes/_detach_form.html" with form=detach_form %}
</li>
{% endfor %}
{% endif %}
{% if volume.status == "available" %}
<li>
- <a href="{% url dash_volumes_attach request.user.tenant_id volume.id %}">{% trans "Attach" %}</a>
+ <a href="{% url horizon:nova:volumes:attach volume.id %}">{% trans "Attach" %}</a>
</li>
<li class="form">
- {% include "django_openstack/dash/volumes/_delete.html" with form=delete_form %}
+ {% include "nova/volumes/_delete.html" with form=delete_form %}
</li>
{% endif %}
</ul>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/attach.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/attach.html
index ec0456f7..c762b52d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/attach.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/attach.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{% load i18n %}
{% block sidebar %}
@@ -8,14 +8,14 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Attach a Volume") %}
+ {% include "horizon/common/_page_header.html" with title=_("Attach a Volume") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/volumes/_attach_form.html' with form=attach_form %}
- <h3><a href="{% url dash_volumes request.user.tenant_id %}">&lt;&lt; {% trans "Return to volumes list" %}</a></h3>
+ {% include 'nova/volumes/_attach_form.html' with form=attach_form %}
+ <h3><a href="{% url horizon:nova:volumes:index %}">&lt;&lt; {% trans "Return to volumes list" %}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/create.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/create.html
index 9f57c8b6..4297d5d5 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/create.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -16,14 +16,14 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create a Volume") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create a Volume") %}
{% endblock page_header %}
{% block dash_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/dash/volumes/_form.html' with form=create_form %}
- <h3><a href="{% url dash_volumes request.user.tenant_id %}">&lt;&lt; {% trans "Return to volumes list"%}</a></h3>
+ {% include 'nova/volumes/_form.html' with form=create_form %}
+ <h3><a href="{% url horizon:nova:volumes:index %}">&lt;&lt; {% trans "Return to volumes list"%}</a></h3>
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/detail.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/detail.html
index edd67348..55541636 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/detail.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/detail.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{% load i18n %}
{% load parse_date %}
@@ -10,7 +10,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title="Volume Detail: "|add:volume.displayName %}
+ {% include "horizon/common/_page_header.html" with title="Volume Detail: "|add:volume.displayName %}
{% endblock page_header %}
{% block dash_main %}
@@ -34,7 +34,7 @@
<li>
<span>{% trans "Attached To:" %}</span>
{% if instance %}
- <a href="{% url dash_instances_detail request.user.tenant_name attachment.serverId %}">
+ <a href="{% url horizon:nova:volumes:detail attachment.serverId %}">
{% trans "Instance" %} {{ instance.id }}
({{ instance.name }})
</a>
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/index.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/index.html
index e6fbf983..7029e51f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/index.html
+++ b/horizon/horizon/dashboards/nova/templates/nova/volumes/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/dash/base.html' %}
+{% extends 'nova/base.html' %}
{% load i18n %}
{% block sidebar %}
@@ -8,19 +8,19 @@
{% endblock %}
{% block page_header %}
- {% url dash_volumes request.user.tenant_id as refresh_link %}
+ {% url horizon:nova:volumes:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Volumes") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Volumes") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block dash_main %}
{% if volumes %}
- {% include 'django_openstack/dash/volumes/_list.html' %}
+ {% include 'nova/volumes/_list.html' %}
{% else %}
<div class="message_box info">
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no volumes.{% endblocktrans %}</p>
</div>
{% endif %}
- <a id="volume_create_link" class="action_link large-rounded" href="{% url dash_volumes_create request.user.tenant_id %}">{% trans "Create New Volume" %}</a>
+ <a id="volume_create_link" class="action_link large-rounded" href="{% url horizon:nova:volumes:create %}">{% trans "Create New Volume" %}</a>
{% endblock %}
diff --git a/django-openstack/django_openstack/tests/templates/base-sidebar.html b/horizon/horizon/dashboards/nova/volumes/__init__.py
index e69de29b..e69de29b 100644
--- a/django-openstack/django_openstack/tests/templates/base-sidebar.html
+++ b/horizon/horizon/dashboards/nova/volumes/__init__.py
diff --git a/django-openstack/django_openstack/dash/views/volumes.py b/horizon/horizon/dashboards/nova/volumes/forms.py
index 69b225b3..b67d2d92 100644
--- a/django-openstack/django_openstack/dash/views/volumes.py
+++ b/horizon/horizon/dashboards/nova/volumes/forms.py
@@ -9,18 +9,16 @@ Views for managing Nova volumes.
import logging
-from django import template
+from django import shortcuts
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect, render_to_response
from django.utils.translation import ugettext as _
-from django_openstack import api
-from django_openstack import forms
+from horizon import api
+from horizon import forms
from novaclient import exceptions as novaclient_exceptions
-LOG = logging.getLogger('django_openstack.dash.views.volumes')
+LOG = logging.getLogger(__name__)
class CreateForm(forms.SelfHandlingForm):
@@ -40,7 +38,7 @@ class CreateForm(forms.SelfHandlingForm):
LOG.exception("ClientException in CreateVolume")
messages.error(request,
_('Error Creating Volume: %s') % e.message)
- return redirect(request.build_absolute_uri())
+ return shortcuts.redirect(request.build_absolute_uri())
class DeleteForm(forms.SelfHandlingForm):
@@ -57,7 +55,7 @@ class DeleteForm(forms.SelfHandlingForm):
LOG.exception("ClientException in DeleteVolume")
messages.error(request,
_('Error deleting volume: %s') % e.message)
- return redirect(request.build_absolute_uri())
+ return shortcuts.redirect(request.build_absolute_uri())
class AttachForm(forms.SelfHandlingForm):
@@ -85,7 +83,7 @@ class AttachForm(forms.SelfHandlingForm):
LOG.exception("ClientException in AttachVolume")
messages.error(request,
_('Error attaching volume: %s') % e.message)
- return redirect(request.build_absolute_uri())
+ return shortcuts.redirect(request.build_absolute_uri())
class DetachForm(forms.SelfHandlingForm):
@@ -105,78 +103,4 @@ class DetachForm(forms.SelfHandlingForm):
LOG.exception("ClientException in DetachVolume")
messages.error(request,
_('Error detaching volume: %s') % e.message)
- return redirect(request.build_absolute_uri())
-
-
-@login_required
-def index(request, tenant_id):
- delete_form, handled = DeleteForm.maybe_handle(request)
- detach_form, handled = DetachForm.maybe_handle(request)
-
- if handled:
- return handled
-
- try:
- volumes = api.volume_list(request)
- except novaclient_exceptions.ClientException, e:
- volumes = []
- LOG.exception("ClientException in volume index")
- messages.error(request, _('Error fetching volumes: %s') % e.message)
-
- return render_to_response('django_openstack/dash/volumes/index.html', {
- 'volumes': volumes, 'delete_form': delete_form,
- 'detach_form': detach_form
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def detail(request, tenant_id, volume_id):
- try:
- volume = api.volume_get(request, volume_id)
- attachment = volume.attachments[0]
- if attachment:
- instance = api.server_get(
- request, volume.attachments[0]['serverId'])
- else:
- instance = None
- except novaclient_exceptions.ClientException, e:
- LOG.exception("ClientException in volume get")
- messages.error(request, _('Error fetching volume: %s') % e.message)
- return redirect('dash_volumes', tenant_id)
-
- return render_to_response('django_openstack/dash/volumes/detail.html', {
- 'volume': volume,
- 'attachment': attachment,
- 'instance': instance
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def create(request, tenant_id):
- create_form, handled = CreateForm.maybe_handle(request)
-
- if handled:
- return handled
-
- return render_to_response('django_openstack/dash/volumes/create.html', {
- 'create_form': create_form
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-def attach(request, tenant_id, volume_id):
-
- def instances():
- insts = api.server_list(request)
- return [(inst.id, '%s (Instance %s)' % (inst.name, inst.id))
- for inst in insts]
-
- attach_form, handled = AttachForm.maybe_handle(
- request, initial={'instance_list': instances()})
-
- if handled:
- return handled
-
- return render_to_response('django_openstack/dash/volumes/attach.html', {
- 'attach_form': attach_form, 'volume_id': volume_id
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/nova/volumes/panel.py b/horizon/horizon/dashboards/nova/volumes/panel.py
new file mode 100644
index 00000000..f5692e7b
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/volumes/panel.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.nova import dashboard
+
+
+class Volumes(horizon.Panel):
+ name = "Volumes"
+ slug = 'volumes'
+
+
+dashboard.Nova.register(Volumes)
diff --git a/horizon/horizon/dashboards/nova/volumes/tests.py b/horizon/horizon/dashboards/nova/volumes/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/volumes/tests.py
diff --git a/horizon/horizon/dashboards/nova/volumes/urls.py b/horizon/horizon/dashboards/nova/volumes/urls.py
new file mode 100644
index 00000000..1e5ec42d
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/volumes/urls.py
@@ -0,0 +1,25 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.nova.volumes.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'),
+ url(r'^(?P<volume_id>[^/]+)/attach/$', 'attach', name='attach'),
+ url(r'^(?P<volume_id>[^/]+)/detail/$', 'detail', name='detail'),
+)
diff --git a/horizon/horizon/dashboards/nova/volumes/views.py b/horizon/horizon/dashboards/nova/volumes/views.py
new file mode 100644
index 00000000..72da94d8
--- /dev/null
+++ b/horizon/horizon/dashboards/nova/volumes/views.py
@@ -0,0 +1,110 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Views for managing Nova volumes.
+"""
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+from novaclient import exceptions as novaclient_exceptions
+
+from horizon import api
+from horizon.dashboards.nova.volumes.forms import (CreateForm,
+ DeleteForm, AttachForm, DetachForm)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ delete_form, handled = DeleteForm.maybe_handle(request)
+ detach_form, handled = DetachForm.maybe_handle(request)
+
+ if handled:
+ return handled
+
+ try:
+ volumes = api.volume_list(request)
+ except novaclient_exceptions.ClientException, e:
+ volumes = []
+ LOG.exception("ClientException in volume index")
+ messages.error(request, _('Error fetching volumes: %s') % e.message)
+
+ return shortcuts.render(request,
+ 'nova/volumes/index.html', {
+ 'volumes': volumes,
+ 'delete_form': delete_form,
+ 'detach_form': detach_form})
+
+
+@login_required
+def detail(request, volume_id):
+ try:
+ volume = api.volume_get(request, volume_id)
+ attachment = volume.attachments[0]
+ if attachment:
+ instance = api.server_get(
+ request, volume.attachments[0]['serverId'])
+ else:
+ instance = None
+ except novaclient_exceptions.ClientException, e:
+ LOG.exception("ClientException in volume get")
+ messages.error(request, _('Error fetching volume: %s') % e.message)
+ return shortcuts.redirect('horizon:nova:volumes:index')
+
+ return shortcuts.render(request,
+ 'nova/volumes/detail.html', {
+ 'volume': volume,
+ 'attachment': attachment,
+ 'instance': instance})
+
+
+@login_required
+def create(request):
+ create_form, handled = CreateForm.maybe_handle(request)
+
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/volumes/create.html', {
+ 'create_form': create_form})
+
+
+@login_required
+def attach(request, volume_id):
+
+ def instances():
+ insts = api.server_list(request)
+ return [(inst.id, '%s (Instance %s)' % (inst.name, inst.id))
+ for inst in insts]
+
+ attach_form, handled = AttachForm.maybe_handle(
+ request, initial={'instance_list': instances()})
+
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'nova/volumes/attach.html', {
+ 'attach_form': attach_form,
+ 'volume_id': volume_id})
diff --git a/horizon/horizon/dashboards/settings/__init__.py b/horizon/horizon/dashboards/settings/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/__init__.py
diff --git a/horizon/horizon/dashboards/settings/dashboard.py b/horizon/horizon/dashboards/settings/dashboard.py
new file mode 100644
index 00000000..9cc88c45
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/dashboard.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.utils.translation import ugettext as _
+
+import horizon
+
+
+class Settings(horizon.Dashboard):
+ name = "Settings"
+ slug = "settings"
+ panels = ('user',)
+ default_panel = 'user'
+ nav = False
+
+
+horizon.register(Settings)
diff --git a/horizon/horizon/dashboards/settings/models.py b/horizon/horizon/dashboards/settings/models.py
new file mode 100644
index 00000000..300ba4b3
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/models.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
+"""
diff --git a/horizon/horizon/dashboards/settings/templates/settings/base.html b/horizon/horizon/dashboards/settings/templates/settings/base.html
new file mode 100644
index 00000000..739b94c1
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/templates/settings/base.html
@@ -0,0 +1,13 @@
+{% extends 'base.html' %}
+
+{% block sidebar %}
+ {% include 'horizon/common/_sidebar.html' %}
+{% endblock %}
+
+{% block main %}
+ {% block page_header %}{% endblock %}
+ <div class="main_content">
+ {% include "_messages.html" %}
+ {% block settings_main %}{% endblock %}
+ </div>
+{% endblock %}
diff --git a/horizon/horizon/dashboards/settings/templates/settings/user/settings.html b/horizon/horizon/dashboards/settings/templates/settings/user/settings.html
new file mode 100644
index 00000000..4e7fc531
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/templates/settings/user/settings.html
@@ -0,0 +1,32 @@
+{% extends 'settings/base.html' %}
+{% load i18n %}
+
+{% block page_header %}
+ {% url horizon:nova:instances:index as refresh_link %}
+ {% include "horizon/common/_page_header.html" with title=_("Dashboard Settings") %}
+{% endblock page_header %}
+
+{% block settings_main %}
+
+ <div class="dash_block">
+ <div class="left">
+ <h3>{% trans "Dashboard User Interface Language"%}</h3>
+ <form action="/i18n/setlang/" method="post"> {% csrf_token %}
+ <p><select name="language">
+ {% get_language_info_list for LANGUAGES as languages %}
+ {% for language in languages %}
+ {% if language.code == LANGUAGE_CODE %}
+ <option selected value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
+ {%else%}
+ <option value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
+ {%endif%}
+ {% endfor %}
+ </select></p>
+ <input type="submit" value="{% trans "Select Language"%}" class="large-rounded" />
+ </form>
+ </div>
+
+ <div class="right">&nbsp;</div>
+ <div class="clear">&nbsp;</div>
+ </div>
+{% endblock %}
diff --git a/horizon/horizon/dashboards/settings/user/__init__.py b/horizon/horizon/dashboards/settings/user/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/user/__init__.py
diff --git a/horizon/horizon/dashboards/settings/user/panel.py b/horizon/horizon/dashboards/settings/user/panel.py
new file mode 100644
index 00000000..5f11a897
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/user/panel.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.settings import dashboard
+
+
+class UserPanel(horizon.Panel):
+ name = "User Settings"
+ slug = 'user'
+
+
+dashboard.Settings.register(UserPanel)
diff --git a/horizon/horizon/dashboards/settings/user/urls.py b/horizon/horizon/dashboards/settings/user/urls.py
new file mode 100644
index 00000000..7bfddcf5
--- /dev/null
+++ b/horizon/horizon/dashboards/settings/user/urls.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+from django.views.generic import TemplateView
+
+
+urlpatterns = patterns('',
+ url(r'^$', TemplateView.as_view(
+ template_name='settings/user/settings.html'),
+ name='index'))
diff --git a/horizon/horizon/dashboards/syspanel/__init__.py b/horizon/horizon/dashboards/syspanel/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/dashboard.py b/horizon/horizon/dashboards/syspanel/dashboard.py
new file mode 100644
index 00000000..ce4e4e01
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/dashboard.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.utils.translation import ugettext as _
+
+import horizon
+
+
+class Syspanel(horizon.Dashboard):
+ name = "System Dashboard" # Appears in navigation
+ slug = "syspanel"
+ panels = {_("System Panel"): ('overview', 'instances', 'services',
+ 'flavors', 'images', 'tenants', 'users',
+ 'quotas',)}
+ default_panel = 'overview'
+ roles = ('admin',)
+
+
+horizon.register(Syspanel)
diff --git a/horizon/horizon/dashboards/syspanel/flavors/__init__.py b/horizon/horizon/dashboards/syspanel/flavors/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/flavors/__init__.py
diff --git a/django-openstack/django_openstack/syspanel/views/flavors.py b/horizon/horizon/dashboards/syspanel/flavors/forms.py
index e15f9561..c79fcdbe 100644
--- a/django-openstack/django_openstack/syspanel/views/flavors.py
+++ b/horizon/horizon/dashboards/syspanel/flavors/forms.py
@@ -20,24 +20,16 @@
import logging
-from operator import itemgetter
-
-from django import template
-from django import http
-from django.conf import settings
+from django import shortcuts
from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect
-from django.shortcuts import render_to_response
from django.utils.translation import ugettext as _
-
from openstackx.api import exceptions as api_exceptions
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.decorators import enforce_admin_access
+from horizon import api
+from horizon import forms
+
-LOG = logging.getLogger('django_openstack.syspanel.views.flavors')
+LOG = logging.getLogger(__name__)
class CreateFlavor(forms.SelfHandlingForm):
@@ -57,7 +49,7 @@ class CreateFlavor(forms.SelfHandlingForm):
msg = _('%s was successfully added to flavors.') % data['name']
LOG.info(msg)
messages.success(request, msg)
- return redirect('syspanel_flavors')
+ return shortcuts.redirect('horizon:syspanel:flavors:index')
class DeleteFlavor(forms.SelfHandlingForm):
@@ -74,49 +66,4 @@ class DeleteFlavor(forms.SelfHandlingForm):
except api_exceptions.ApiException, e:
messages.error(request, _('Unable to delete flavor: %s') %
e.message)
- return redirect(request.build_absolute_uri())
-
-
-@login_required
-@enforce_admin_access
-def index(request):
- for f in (DeleteFlavor,):
- form, handled = f.maybe_handle(request)
- if handled:
- return handled
-
- delete_form = DeleteFlavor()
-
- flavors = []
- try:
- flavors = api.flavor_list(request)
- except api_exceptions.ApiException, e:
- LOG.exception('ApiException while fetching usage info')
- messages.error(request, _('Unable to get usage info: %s') % e.message)
-
- flavors.sort(key=lambda x: x.id, reverse=True)
- return render_to_response(
- 'django_openstack/syspanel/flavors/index.html', {
- 'delete_form': delete_form,
- 'flavors': flavors,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-@enforce_admin_access
-def create(request):
- form, handled = CreateFlavor.maybe_handle(request)
- if handled:
- return handled
-
- global_summary = api.GlobalSummary(request)
- global_summary.service()
- global_summary.avail()
- global_summary.human_readable('disk_size')
- global_summary.human_readable('ram_size')
-
- return render_to_response(
- 'django_openstack/syspanel/flavors/create.html', {
- 'global_summary': global_summary.summary,
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/syspanel/flavors/panel.py b/horizon/horizon/dashboards/syspanel/flavors/panel.py
new file mode 100644
index 00000000..7a765a27
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/flavors/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Flavors(horizon.Panel):
+ name = "Flavors"
+ slug = 'flavors'
+
+
+dashboard.Syspanel.register(Flavors)
diff --git a/horizon/horizon/dashboards/syspanel/flavors/tests.py b/horizon/horizon/dashboards/syspanel/flavors/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/flavors/tests.py
diff --git a/horizon/horizon/dashboards/syspanel/flavors/urls.py b/horizon/horizon/dashboards/syspanel/flavors/urls.py
new file mode 100644
index 00000000..e38603d7
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/flavors/urls.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.syspanel.flavors.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create/$', 'create', name='create'))
diff --git a/horizon/horizon/dashboards/syspanel/flavors/views.py b/horizon/horizon/dashboards/syspanel/flavors/views.py
new file mode 100644
index 00000000..7be1c1ed
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/flavors/views.py
@@ -0,0 +1,77 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon import forms
+from horizon.dashboards.syspanel.flavors.forms import (CreateFlavor,
+ DeleteFlavor)
+from horizon.dashboards.syspanel.instances import views as instance_views
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ for f in (DeleteFlavor,):
+ form, handled = f.maybe_handle(request)
+ if handled:
+ return handled
+
+ delete_form = DeleteFlavor()
+
+ flavors = []
+ try:
+ flavors = api.flavor_list(request)
+ except api_exceptions.ApiException, e:
+ LOG.exception('ApiException while fetching usage info')
+ messages.error(request, _('Unable to get usage info: %s') % e.message)
+
+ flavors.sort(key=lambda x: x.id, reverse=True)
+ return shortcuts.render(request,
+ 'syspanel/flavors/index.html', {
+ 'delete_form': delete_form,
+ 'flavors': flavors})
+
+
+@login_required
+def create(request):
+ form, handled = CreateFlavor.maybe_handle(request)
+ if handled:
+ return handled
+
+ global_summary = instance_views.GlobalSummary(request)
+ global_summary.service()
+ global_summary.avail()
+ global_summary.human_readable('disk_size')
+ global_summary.human_readable('ram_size')
+
+ return shortcuts.render(request,
+ 'syspanel/flavors/create.html', {
+ 'global_summary': global_summary.summary,
+ 'form': form})
diff --git a/horizon/horizon/dashboards/syspanel/images/__init__.py b/horizon/horizon/dashboards/syspanel/images/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/images/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/images/forms.py b/horizon/horizon/dashboards/syspanel/images/forms.py
new file mode 100644
index 00000000..766bd474
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/images/forms.py
@@ -0,0 +1,83 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+
+from glance.common import exception as glance_exception
+
+from horizon import api
+from horizon import forms
+
+
+LOG = logging.getLogger(__name__)
+
+
+class DeleteImage(forms.SelfHandlingForm):
+ image_id = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ image_id = data['image_id']
+ try:
+ api.image_delete(request, image_id)
+ except glance_exception.ClientConnectionError, e:
+ LOG.exception("Error connecting to glance")
+ messages.error(request,
+ _("Error connecting to glance: %s") % e.message)
+ except glance_exception.Error, e:
+ LOG.exception('Error deleting image with id "%s"' % image_id)
+ messages.error(request, _("Error deleting image: %s") % e.message)
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class ToggleImage(forms.SelfHandlingForm):
+ image_id = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ image_id = data['image_id']
+ try:
+ api.image_update(request, image_id,
+ image_meta={'is_public': False})
+ except glance_exception.ClientConnectionError, e:
+ LOG.exception("Error connecting to glance")
+ messages.error(request,
+ _("Error connecting to glance: %s") % e.message)
+ except glance_exception.Error, e:
+ LOG.exception('Error updating image with id "%s"' % image_id)
+ messages.error(request, _("Error updating image: %s") % e.message)
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class UpdateImageForm(forms.Form):
+ name = forms.CharField(max_length="25", label=_("Name"))
+ kernel = forms.CharField(max_length="25", label=_("Kernel ID"),
+ required=False)
+ ramdisk = forms.CharField(max_length="25", label=_("Ramdisk ID"),
+ required=False)
+ architecture = forms.CharField(label=_("Architecture"), required=False)
+ #project_id = forms.CharField(label=_("Project ID"))
+ container_format = forms.CharField(label=_("Container Format"),
+ required=False)
+ disk_format = forms.CharField(label=_("Disk Format"))
+ #is_public = forms.BooleanField(label=_("Publicly Available"),
+ # required=False)
diff --git a/horizon/horizon/dashboards/syspanel/images/panel.py b/horizon/horizon/dashboards/syspanel/images/panel.py
new file mode 100644
index 00000000..77e7bbb0
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/images/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Images(horizon.Panel):
+ name = "Images"
+ slug = 'images'
+
+
+dashboard.Syspanel.register(Images)
diff --git a/horizon/horizon/dashboards/syspanel/images/tests.py b/horizon/horizon/dashboards/syspanel/images/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/images/tests.py
diff --git a/horizon/horizon/dashboards/syspanel/images/urls.py b/horizon/horizon/dashboards/syspanel/images/urls.py
new file mode 100644
index 00000000..5df3696a
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/images/urls.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.syspanel.images.views',
+ url(r'^images/$', 'index', name='index'),
+ url(r'^(?P<image_id>[^/]+)/update/$', 'update', name='update'))
diff --git a/django-openstack/django_openstack/syspanel/views/images.py b/horizon/horizon/dashboards/syspanel/images/views.py
index 887581a4..4a998a5f 100644
--- a/django-openstack/django_openstack/syspanel/views/images.py
+++ b/horizon/horizon/dashboards/syspanel/images/views.py
@@ -20,74 +20,21 @@
import logging
-from django import template
+from django import shortcuts
from django.contrib import messages
-from django.shortcuts import redirect
-from django.shortcuts import render_to_response
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
-
from glance.common import exception as glance_exception
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.decorators import enforce_admin_access
-
-LOG = logging.getLogger('django_openstack.sysadmin.views.images')
-
+from horizon import api
+from horizon.dashboards.syspanel.images.forms import (DeleteImage,
+ ToggleImage, UpdateImageForm)
-class DeleteImage(forms.SelfHandlingForm):
- image_id = forms.CharField(required=True)
- def handle(self, request, data):
- image_id = data['image_id']
- try:
- api.image_delete(request, image_id)
- except glance_exception.ClientConnectionError, e:
- LOG.exception("Error connecting to glance")
- messages.error(request,
- _("Error connecting to glance: %s") % e.message)
- except glance_exception.Error, e:
- LOG.exception('Error deleting image with id "%s"' % image_id)
- messages.error(request, _("Error deleting image: %s") % e.message)
- return redirect(request.build_absolute_uri())
-
-
-class ToggleImage(forms.SelfHandlingForm):
- image_id = forms.CharField(required=True)
-
- def handle(self, request, data):
- image_id = data['image_id']
- try:
- api.image_update(request, image_id,
- image_meta={'is_public': False})
- except glance_exception.ClientConnectionError, e:
- LOG.exception("Error connecting to glance")
- messages.error(request,
- _("Error connecting to glance: %s") % e.message)
- except glance_exception.Error, e:
- LOG.exception('Error updating image with id "%s"' % image_id)
- messages.error(request, _("Error updating image: %s") % e.message)
- return redirect(request.build_absolute_uri())
-
-
-class UpdateImageForm(forms.Form):
- name = forms.CharField(max_length="25", label=_("Name"))
- kernel = forms.CharField(max_length="25", label=_("Kernel ID"),
- required=False)
- ramdisk = forms.CharField(max_length="25", label=_("Ramdisk ID"),
- required=False)
- architecture = forms.CharField(label=_("Architecture"), required=False)
- #project_id = forms.CharField(label=_("Project ID"))
- container_format = forms.CharField(label=_("Container Format"),
- required=False)
- disk_format = forms.CharField(label=_("Disk Format"))
- #is_public = forms.BooleanField(label=_("Publicly Available"),
- # required=False)
+LOG = logging.getLogger(__name__)
@login_required
-@enforce_admin_access
def index(request):
for f in (DeleteImage, ToggleImage):
form, handled = f.maybe_handle(request)
@@ -113,15 +60,14 @@ def index(request):
messages.error(request,
_("Error retrieving image list: %s") % e.message)
- return render_to_response('django_openstack/syspanel/images/index.html', {
- 'delete_form': delete_form,
- 'toggle_form': toggle_form,
- 'images': images,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/images/index.html', {
+ 'delete_form': delete_form,
+ 'toggle_form': toggle_form,
+ 'images': images})
@login_required
-@enforce_admin_access
def update(request, image_id):
try:
image = api.image_get(request, image_id)
@@ -170,17 +116,16 @@ def update(request, image_id):
LOG.exception('Unspecified Exception in image update')
messages.error(request,
_("Image could not be updated, please try again."))
- return redirect('syspanel_images_update', image_id)
+ return shortcuts.redirect('syspanel_images_update', image_id)
else:
LOG.exception('Image "%s" failed to update' % image['name'])
messages.error(request,
_("Image could not be uploaded, please try agian."))
form = UpdateImageForm(request.POST)
- return render_to_response('django_openstack/syspanel/images/'
- 'update.html', {
- 'image': image,
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/images/update.html', {
+ 'image': image,
+ 'form': form})
else:
form = UpdateImageForm(initial={
'name': image.get('name', ''),
@@ -195,15 +140,13 @@ def update(request, image_id):
'disk_format': image.get('disk_format', ''),
})
- return render_to_response('django_openstack/syspanel/images/'
- 'update.html', {
- 'image': image,
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/images/update.html', {
+ 'image': image,
+ 'form': form})
@login_required
-@enforce_admin_access
def upload(request):
if request.method == "POST":
form = UploadImageForm(request.POST)
@@ -237,15 +180,13 @@ def upload(request):
messages.error(request,
_("Image could not be uploaded, please try agian."))
form = UploadImageForm(request.POST)
- return render_to_response('django_nova_syspanel/images/'
- 'upload.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'django_nova_syspanel/images/upload.html',
+ {'form': form})
- return redirect('syspanel_images')
+ return shortcuts.redirect('syspanel_images')
else:
form = UploadImageForm()
- return render_to_response('django_nova_syspanel/images/'
- 'upload.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'django_nova_syspanel/images/upload.html',
+ {'form': form})
diff --git a/horizon/horizon/dashboards/syspanel/instances/__init__.py b/horizon/horizon/dashboards/syspanel/instances/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/instances/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/instances/panel.py b/horizon/horizon/dashboards/syspanel/instances/panel.py
new file mode 100644
index 00000000..56b52590
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/instances/panel.py
@@ -0,0 +1,31 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Instances(horizon.Panel):
+ name = "Instances"
+ slug = 'instances'
+ roles = ('admin',)
+
+
+dashboard.Syspanel.register(Instances)
diff --git a/horizon/horizon/dashboards/syspanel/instances/tests.py b/horizon/horizon/dashboards/syspanel/instances/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/instances/tests.py
diff --git a/django-openstack/django_openstack/tests/testurls.py b/horizon/horizon/dashboards/syspanel/instances/urls.py
index 4dc34d9f..369a3eb5 100644
--- a/django-openstack/django_openstack/tests/testurls.py
+++ b/horizon/horizon/dashboards/syspanel/instances/urls.py
@@ -18,23 +18,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-URL patterns for testing django-openstack views.
-"""
-
from django.conf.urls.defaults import *
-
-from django_openstack import urls as django_openstack_urls
+from django.conf import settings
-urlpatterns = patterns('',
- url(r'^$', 'django_openstack.tests.views.fakeView', name='splash'),
- url(r'^dash/$', 'django_openstack.dash.views.instances.usage',
- name='dash_overview'),
- url(r'^syspanel/$', 'django_openstack.syspanel.views.instances.usage',
- name='syspanel_overview')
-)
+INSTANCES = r'^(?P<instance_id>[^/]+)/%s$'
-# NOTE(termie): just append them since we want the routes at the root
-urlpatterns += django_openstack_urls.urlpatterns
+urlpatterns = patterns('horizon.dashboards.syspanel.instances.views',
+ url(r'^usage/(?P<tenant_id>[^/]+)$', 'tenant_usage', name='tenant_usage'),
+ url(r'^$', 'index', name='index'),
+ url(r'^refresh$', 'refresh', name='refresh'),
+ url(INSTANCES % 'detail', 'detail', name='detail'),
+ # NOTE(termie): currently just using the 'dash' versions
+ #url(INSTANCES % 'console', 'console', name='instances_console'),
+ #url(INSTANCES % 'vnc', 'vnc', name='syspanel_instances_vnc'),
+)
diff --git a/django-openstack/django_openstack/syspanel/views/instances.py b/horizon/horizon/dashboards/syspanel/instances/views.py
index b150efa4..81634b6b 100644
--- a/django-openstack/django_openstack/syspanel/views/instances.py
+++ b/horizon/horizon/dashboards/syspanel/instances/views.py
@@ -18,30 +18,112 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
+import logging
+
from django import template
from django import http
from django.conf import settings
+from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, redirect
from django.utils.translation import ugettext as _
-import datetime
-import logging
-
-from django.contrib import messages
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.dash.views import instances as dash_instances
-from django_openstack.decorators import enforce_admin_access
-
+from horizon import api
+from horizon import forms
+from horizon.dashboards.nova.instances import views as dash_instances
from openstackx.api import exceptions as api_exceptions
TerminateInstance = dash_instances.TerminateInstance
RebootInstance = dash_instances.RebootInstance
-LOG = logging.getLogger('django_openstack.syspanel.views.instances')
+
+LOG = logging.getLogger(__name__)
+
+
+class GlobalSummary(object):
+ node_resources = ['vcpus', 'disk_size', 'ram_size']
+ unit_mem_size = {'disk_size': ['GiB', 'TiB'], 'ram_size': ['MiB', 'GiB']}
+ node_resource_info = ['', 'active_', 'avail_']
+
+ def __init__(self, request):
+ self.summary = {}
+ for rsrc in GlobalSummary.node_resources:
+ for info in GlobalSummary.node_resource_info:
+ self.summary['total_' + info + rsrc] = 0
+ self.request = request
+ self.service_list = []
+ self.usage_list = []
+
+ def service(self):
+ try:
+ self.service_list = api.service_list(self.request)
+ except api_exceptions.ApiException, e:
+ self.service_list = []
+ LOG.exception('ApiException fetching service list '
+ 'in instance usage')
+ messages.error(self.request,
+ _('Unable to get service info: %s') % e.message)
+ return
+
+ for service in self.service_list:
+ if service.type == 'nova-compute':
+ self.summary['total_vcpus'] += min(service.stats['max_vcpus'],
+ service.stats.get('vcpus', 0))
+ self.summary['total_disk_size'] += min(
+ service.stats['max_gigabytes'],
+ service.stats.get('local_gb', 0))
+ self.summary['total_ram_size'] += min(
+ service.stats['max_ram'],
+ service.stats['memory_mb']) if 'max_ram' \
+ in service.stats \
+ else service.stats.get('memory_mb', 0)
+
+ def usage(self, datetime_start, datetime_end):
+ try:
+ self.usage_list = api.usage_list(self.request, datetime_start,
+ datetime_end)
+ except api_exceptions.ApiException, e:
+ self.usage_list = []
+ LOG.exception('ApiException fetching usage list in instance usage'
+ ' on date range "%s to %s"' % (datetime_start,
+ datetime_end))
+ messages.error(self.request,
+ _('Unable to get usage info: %s') % e.message)
+ return
+
+ for usage in self.usage_list:
+ # FIXME: api needs a simpler dict interface (with iteration)
+ # - anthony
+ # NOTE(mgius): Changed this on the api end. Not too much
+ # neater, but at least its not going into private member
+ # data of an external class anymore
+ # usage = usage._info
+ for k in usage._attrs:
+ v = usage.__getattr__(k)
+ if type(v) in [float, int]:
+ if not k in self.summary:
+ self.summary[k] = 0
+ self.summary[k] += v
+
+ def human_readable(self, rsrc):
+ if self.summary['total_' + rsrc] > 1023:
+ self.summary['unit_' + rsrc] = GlobalSummary.unit_mem_size[rsrc][1]
+ mult = 1024.0
+ else:
+ self.summary['unit_' + rsrc] = GlobalSummary.unit_mem_size[rsrc][0]
+ mult = 1.0
+
+ for kind in GlobalSummary.node_resource_info:
+ self.summary['total_' + kind + rsrc + '_hr'] = \
+ self.summary['total_' + kind + rsrc] / mult
+
+ def avail(self):
+ for rsrc in GlobalSummary.node_resources:
+ self.summary['total_avail_' + rsrc] = \
+ self.summary['total_' + rsrc] - \
+ self.summary['total_active_' + rsrc]
def _next_month(date_start):
@@ -81,13 +163,11 @@ def _csv_usage_link(date_start):
date_start.year)
-@login_required
-@enforce_admin_access
def usage(request):
(date_start, date_end, datetime_start, datetime_end) = \
_get_start_and_end_date(request)
- global_summary = api.GlobalSummary(request)
+ global_summary = GlobalSummary(request)
if date_start > _current_month():
messages.error(request, _('No data for the selected period'))
date_end = date_start
@@ -104,10 +184,10 @@ def usage(request):
global_summary.human_readable('ram_size')
if request.GET.get('format', 'html') == 'csv':
- template_name = 'django_openstack/syspanel/instances/usage.csv'
+ template_name = 'syspanel/instances/usage.csv'
mimetype = "text/csv"
else:
- template_name = 'django_openstack/syspanel/instances/usage.html'
+ template_name = 'syspanel/instances/usage.html'
mimetype = "text/html"
return render_to_response(
@@ -118,13 +198,12 @@ def usage(request):
'usage_list': global_summary.usage_list,
'csv_link': _csv_usage_link(date_start),
'global_summary': global_summary.summary,
- 'external_links': settings.EXTERNAL_MONITORING,
+ 'external_links': getattr(settings, 'EXTERNAL_MONITORING', []),
}, context_instance=template.RequestContext(request), mimetype=mimetype)
-@login_required
-@enforce_admin_access
-def tenant_usage(request, tenant_id):
+def tenant_usage(request):
+ tenant_id = request.user.tenant
(date_start, date_end, datetime_start, datetime_end) = \
_get_start_and_end_date(request)
if date_start > _current_month():
@@ -159,10 +238,10 @@ def tenant_usage(request, tenant_id):
running_instances.append(i)
if request.GET.get('format', 'html') == 'csv':
- template_name = 'django_openstack/syspanel/instances/tenant_usage.csv'
+ template_name = 'syspanel/instances/tenant_usage.csv'
mimetype = "text/csv"
else:
- template_name = 'django_openstack/syspanel/instances/tenant_usage.html'
+ template_name = 'syspanel/instances/tenant_usage.html'
mimetype = "text/html"
return render_to_response(template_name, {
@@ -176,8 +255,6 @@ def tenant_usage(request, tenant_id):
}, context_instance=template.RequestContext(request), mimetype=mimetype)
-@login_required
-@enforce_admin_access
def index(request):
for f in (TerminateInstance, RebootInstance):
form, handled = f.maybe_handle(request)
@@ -198,15 +275,13 @@ def index(request):
reboot_form = RebootInstance()
return render_to_response(
- 'django_openstack/syspanel/instances/index.html', {
+ 'syspanel/instances/index.html', {
'instances': instances,
'terminate_form': terminate_form,
'reboot_form': reboot_form,
}, context_instance=template.RequestContext(request))
-@login_required
-@enforce_admin_access
def refresh(request):
for f in (TerminateInstance, RebootInstance):
form, handled = f.maybe_handle(request)
@@ -226,14 +301,13 @@ def refresh(request):
reboot_form = RebootInstance()
return render_to_response(
- 'django_openstack/syspanel/instances/_list.html', {
+ 'syspanel/instances/_list.html', {
'instances': instances,
'terminate_form': terminate_form,
'reboot_form': reboot_form,
}, context_instance=template.RequestContext(request))
-@login_required
def detail(request, instance_id):
try:
instance = api.server_get(request, instance_id)
@@ -248,16 +322,16 @@ def detail(request, instance_id):
messages.error(request,
_('Unable to get vnc console for instance %(inst)s: %(message)s') %
{"inst": instance_id, "message": e.message})
- return redirect('dash_instances', tenant_id)
+ return redirect('horizon:syspanel:instances:index', tenant_id)
except api_exceptions.ApiException, e:
LOG.exception('ApiException while fetching instance info')
messages.error(request,
_('Unable to get information for instance %(inst)s: %(message)s') %
{"inst": instance_id, "message": e.message})
- return redirect('dash_instances', tenant_id)
+ return redirect('horizon:syspanel:instances:index', tenant_id)
return render_to_response(
- 'django_openstack/syspanel/instances/detail.html', {
+ 'syspanel/instances/detail.html', {
'instance': instance,
'vnc_url': vnc_url,
}, context_instance=template.RequestContext(request))
diff --git a/horizon/horizon/dashboards/syspanel/models.py b/horizon/horizon/dashboards/syspanel/models.py
new file mode 100644
index 00000000..300ba4b3
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/models.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
+"""
diff --git a/horizon/horizon/dashboards/syspanel/overview/__init__.py b/horizon/horizon/dashboards/syspanel/overview/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/overview/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/overview/panel.py b/horizon/horizon/dashboards/syspanel/overview/panel.py
new file mode 100644
index 00000000..5ca5d23d
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/overview/panel.py
@@ -0,0 +1,31 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Overview(horizon.Panel):
+ name = "Overview"
+ slug = 'overview'
+ roles = ('admin',)
+
+
+dashboard.Syspanel.register(Overview)
diff --git a/horizon/horizon/dashboards/syspanel/overview/urls.py b/horizon/horizon/dashboards/syspanel/overview/urls.py
new file mode 100644
index 00000000..614f58be
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/overview/urls.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('horizon.dashboards.syspanel',
+ url(r'^$', 'instances.views.usage', name='index'),
+)
diff --git a/horizon/horizon/dashboards/syspanel/quotas/__init__.py b/horizon/horizon/dashboards/syspanel/quotas/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/quotas/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/quotas/panel.py b/horizon/horizon/dashboards/syspanel/quotas/panel.py
new file mode 100644
index 00000000..ede0efb4
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/quotas/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Quotas(horizon.Panel):
+ name = "Quotas"
+ slug = 'quotas'
+
+
+dashboard.Syspanel.register(Quotas)
diff --git a/horizon/horizon/dashboards/syspanel/quotas/tests.py b/horizon/horizon/dashboards/syspanel/quotas/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/quotas/tests.py
diff --git a/horizon/horizon/dashboards/syspanel/quotas/urls.py b/horizon/horizon/dashboards/syspanel/quotas/urls.py
new file mode 100644
index 00000000..6f7436a8
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/quotas/urls.py
@@ -0,0 +1,25 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.syspanel.quotas.views',
+ url(r'^$', 'index', name='index'))
diff --git a/django-openstack/django_openstack/syspanel/views/quotas.py b/horizon/horizon/dashboards/syspanel/quotas/views.py
index 816c1c8f..73a1d4ee 100644
--- a/django-openstack/django_openstack/syspanel/views/quotas.py
+++ b/horizon/horizon/dashboards/syspanel/quotas/views.py
@@ -18,31 +18,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-from operator import itemgetter
-
-from django import template
-from django import http
-from django.conf import settings
-from django.contrib import messages
+from django import shortcuts
from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect
-from django.shortcuts import render_to_response
from openstackx.api import exceptions as api_exceptions
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.decorators import enforce_admin_access
+from horizon import api
@login_required
-@enforce_admin_access
def index(request):
quotas = api.admin_api(request).quota_sets.get(True)._info
quotas['ram'] = int(quotas['ram']) / 100
quotas.pop('id')
- return render_to_response(
- 'django_openstack/syspanel/quotas/index.html', {
- 'quotas': quotas,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/quotas/index.html', {
+ 'quotas': quotas})
diff --git a/horizon/horizon/dashboards/syspanel/services/__init__.py b/horizon/horizon/dashboards/syspanel/services/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/services/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/services/forms.py b/horizon/horizon/dashboards/syspanel/services/forms.py
new file mode 100644
index 00000000..81f1f673
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/services/forms.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon import forms
+
+
+LOG = logging.getLogger(__name__)
+
+
+class ToggleService(forms.SelfHandlingForm):
+ service = forms.CharField(required=False)
+ name = forms.CharField(required=False)
+
+ def handle(self, request, data):
+ try:
+ service = api.service_get(request, data['service'])
+ api.service_update(request,
+ data['service'],
+ not service.disabled)
+ if service.disabled:
+ messages.info(request, _("Service '%s' has been enabled")
+ % data['name'])
+ else:
+ messages.info(request, _("Service '%s' has been disabled")
+ % data['name'])
+ except api_exceptions.ApiException, e:
+ LOG.exception('ApiException while toggling service %s' %
+ data['service'])
+ messages.error(request,
+ _("Unable to update service '%(name)s': %(msg)s")
+ % {"name": data['name'], "msg": e.message})
+
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/syspanel/services/panel.py b/horizon/horizon/dashboards/syspanel/services/panel.py
new file mode 100644
index 00000000..7a17f8de
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/services/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Services(horizon.Panel):
+ name = "Services"
+ slug = 'services'
+
+
+dashboard.Syspanel.register(Services)
diff --git a/horizon/horizon/dashboards/syspanel/services/tests.py b/horizon/horizon/dashboards/syspanel/services/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/services/tests.py
diff --git a/horizon/horizon/dashboards/syspanel/services/urls.py b/horizon/horizon/dashboards/syspanel/services/urls.py
new file mode 100644
index 00000000..e7757de0
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/services/urls.py
@@ -0,0 +1,25 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.syspanel.services.views',
+ url(r'^$', 'index', name='index'))
diff --git a/django-openstack/django_openstack/syspanel/views/services.py b/horizon/horizon/dashboards/syspanel/services/views.py
index c1c76a69..73d29ee0 100644
--- a/django-openstack/django_openstack/syspanel/views/services.py
+++ b/horizon/horizon/dashboards/syspanel/services/views.py
@@ -18,61 +18,25 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django import template
-from django import http
-from django.conf import settings
-from django.contrib.auth.decorators import login_required
-from django.shortcuts import render_to_response
-from django.shortcuts import redirect
-from django.utils.translation import ugettext as _
-
-import datetime
-import json
import logging
import os
import subprocess
-import sys
import urlparse
+from django import shortcuts
from django.contrib import messages
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.dash.views import instances as dash_instances
-from django_openstack.decorators import enforce_admin_access
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
from openstackx.api import exceptions as api_exceptions
-LOG = logging.getLogger('django_openstack.syspanel.views.services')
-
+from horizon import api
+from horizon.dashboards.syspanel.services.forms import ToggleService
-class ToggleService(forms.SelfHandlingForm):
- service = forms.CharField(required=False)
- name = forms.CharField(required=False)
-
- def handle(self, request, data):
- try:
- service = api.service_get(request, data['service'])
- api.service_update(request,
- data['service'],
- not service.disabled)
- if service.disabled:
- messages.info(request, _("Service '%s' has been enabled")
- % data['name'])
- else:
- messages.info(request, _("Service '%s' has been disabled")
- % data['name'])
- except api_exceptions.ApiException, e:
- LOG.exception('ApiException while toggling service %s' %
- data['service'])
- messages.error(request,
- _("Unable to update service '%(name)s': %(msg)s")
- % {"name": data['name'], "msg": e.message})
- return redirect(request.build_absolute_uri())
+LOG = logging.getLogger(__name__)
@login_required
-@enforce_admin_access
def index(request):
for f in (ToggleService,):
form, handled = f.maybe_handle(request)
@@ -110,9 +74,8 @@ def index(request):
other_services = sorted(other_services, key=lambda svc: (svc['type'] +
svc['host']))
- return render_to_response(
- 'django_openstack/syspanel/services/index.html', {
- 'services': services,
- 'service_toggle_enabled_form': ToggleService,
- 'other_services': other_services,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/services/index.html', {
+ 'services': services,
+ 'service_toggle_enabled_form': ToggleService,
+ 'other_services': other_services})
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/base.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/base.html
index 9f5d3055..1add065c 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/base.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/base.html
@@ -1,18 +1,11 @@
{% extends 'base.html' %}
-{% block topbar %}
- {% with current_topbar="syspanel" %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
{% block sidebar %}
- {% include 'django_openstack/syspanel/_sidebar.html' %}
+ {% include 'horizon/common/_sidebar.html' %}
{% endblock %}
{% block main %}
- {% block page_header %}
- {% endblock %}
-
+ {% block page_header %}{% endblock %}
<div class="main_content">
{% include "_messages.html" %}
{% block syspanel_main %}{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_create.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_create.html
index 04f8cad9..a5bc2dd3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_create.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/flavors/_form.html' %}
+{% extends 'syspanel/flavors/_form.html' %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_delete.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_delete.html
index 9d00e04e..9d00e04e 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_delete.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_form.html
index 2ec0f4cd..2ec0f4cd 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_list.html
index 05a5ddc8..e2fe3df2 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_list.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_list.html
@@ -17,7 +17,7 @@
<td>{{flavor.disk}}GB</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/flavors/_delete.html" with form=delete_form %}</li>
+ <li class="form">{% include "syspanel/flavors/_delete.html" with form=delete_form %}</li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/create.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/create.html
index 5802dda0..c80ae350 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/create.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,7 +8,7 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Flavor") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Flavor") %}
{% endblock page_header %}
{% block syspanel_main %}
@@ -30,7 +30,7 @@
</ul>
</div>
<div class="left">
- {% include "django_openstack/syspanel/flavors/_create.html" %}
+ {% include "syspanel/flavors/_create.html" %}
</div>
<div class="right">
<h3>{% trans "Description"%}:</h3>
diff --git a/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/index.html
new file mode 100644
index 00000000..d1eabacf
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/index.html
@@ -0,0 +1,19 @@
+{% extends 'syspanel/base.html' %}
+{%load i18n%}
+
+{% block sidebar %}
+ {% with current_sidebar="flavors" %}
+ {{block.super}}
+ {% endwith %}
+{% endblock %}
+
+{% block page_header %}
+ {% url horizon:syspanel:flavors:index as refresh_link %}
+ {# to make searchable false, just remove it from the include statement #}
+ {% include "horizon/common/_page_header.html" with title=_("Flavors") refresh_link=refresh_link searchable="true" %}
+{% endblock page_header %}
+
+{% block syspanel_main %}
+ {% include "syspanel/flavors/_list.html" %}
+ <a id="flavor_create_link" class="action_link large-rounded" href="{% url horizon:syspanel:flavors:create %}">{% trans "Create New Flavor"%}</a>
+{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_delete.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_delete.html
index 3ec7a2e5..3ec7a2e5 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_delete.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_form.html
index c2c5e7dd..c2c5e7dd 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_list.html
index adc85e5b..c3ada501 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_list.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_list.html
@@ -22,10 +22,10 @@
<td>{{image.status|capfirst}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/images/_delete.html" with form=delete_form %}</li>
- {# <li class="form">{% include "django_openstack/syspanel/images/_toggle.html" with form=toggle_form %}</li> #}
+ <li class="form">{% include "syspanel/images/_delete.html" with form=delete_form %}</li>
+ {# <li class="form">{% include "syspanel/images/_toggle.html" with form=toggle_form %}</li> #}
- <li><a href="{% url syspanel_images_update image.id %}">{% trans "Edit"%}</a></li>
+ <li><a href="{% url horizon:syspanel:images:update image.id %}">{% trans "Edit"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_toggle.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_toggle.html
index 9aee6370..9aee6370 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_toggle.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_toggle.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/index.html
index 9c0092cd..a0e29433 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,11 +8,11 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_images as refresh_link %}
+ {% url horizon:syspanel:images:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Images") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Images") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
- {% include "django_openstack/syspanel/images/_list.html" %}
+ {% include "syspanel/images/_list.html" %}
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/update.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/update.html
index 805c4c3c..a9ff84ee 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/update.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/update.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Update Image") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update Image") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/images/_form.html' %}
+ {% include 'syspanel/images/_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/_list.html
index 9c20dba6..71a13041 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/_list.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/_list.html
@@ -1,5 +1,5 @@
{% load parse_date %}
-{%load i18n%}
+{% load i18n %}
<table id="instances" class="wide">
<tr>
<th>{% trans "Name"%}</th>
@@ -14,7 +14,7 @@
</tr>
{% for instance in instances %}
<tr id="{{instance.id}}" class="{% cycle "odd" "even" %}">
- <td><a href="{% url syspanel_instances_detail instance.id %}">{{instance.name}} <small>(id: {{instance.id}})</small></a></td>
+ <td><a href="{% url horizon:syspanel:instances:detail instance.id %}">{{instance.name}} <small>(id: {{instance.id}})</small></a></td>
<td>{{instance.attrs.tenant_id}}</td>
<td>{{instance.attrs.user_id}}</td>
<td class="name">{{instance.attrs.host}}</td>
@@ -43,10 +43,10 @@
<td>{{instance.status|lower|capfirst}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/common/instances/_terminate.html" with form=terminate_form %}</li>
- <li class="form">{% include "django_openstack/common/instances/_reboot.html" with form=reboot_form %}</li>
- <li><a target="_blank" href="{% url dash_instances_console request.user.tenant_id instance.id %}">{% trans "Console Log"%}</a></li>
- <li><a target="_blank" href="{% url dash_instances_vnc request.user.tenant_id instance.id %}">{% trans "VNC Console"%}</a></li>
+ <li class="form">{% include "horizon/common/instances/_terminate.html" with form=terminate_form %}</li>
+ <li class="form">{% include "horizon/common/instances/_reboot.html" with form=reboot_form %}</li>
+ <li><a target="_blank" href="{% url horizon:nova:instances:console instance.id %}">{% trans "Console Log"%}</a></li>
+ <li><a target="_blank" href="{% url horizon:nova:instances:vnc instance.id %}">{% trans "VNC Console"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/detail.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/detail.html
index 89d4723a..def6e8ab 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/detail.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/detail.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{% block sidebar %}
{% with current_sidebar="instances" %}
@@ -8,7 +8,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title="Instance Detail: "|add:instance.name %}
+ {% include "horizon/common/_page_header.html" with title="Instance Detail: "|add:instance.name %}
{% endblock page_header %}
{% block syspanel_main %}
@@ -57,14 +57,14 @@
</div>
<div id="log" class="tab_wrapper">
- <a class="view_full" target="_blank" href="{% url dash_instances_console request.user.tenant_id instance.id %}">View Full Log</a>
+ <a class="view_full" target="_blank" href="{% url horizon:nova:instances:console instance.id %}">View Full Log</a>
<pre class="logs"></pre>
</div>
<div id="vnc" class="tab_wrapper">
<iframe src="{{vnc_url}}" width="720" height="420"></iframe>
</div>
-
+
</div>
{% endblock %}
@@ -96,7 +96,7 @@
})
function getlog(){
- $.get("{% url dash_instances_console instance.attrs.tenant_id instance.id %}?length=25", function(data){
+ $.get("{% url horizon:nova:instances:console instance.id %}?length=25", function(data){
$("#log .logs").html(data)
})
}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/index.html
index 228ff2dd..3f956cc9 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,17 +8,17 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_instances as refresh_link %}
+ {% url horizon:syspanel:instances:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Instances") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Instances") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
{% if instances %}
- {% include 'django_openstack/syspanel/instances/_list.html' %}
+ {% include 'syspanel/instances/_list.html' %}
{% else %}
<div class="message_box info">
- {% url dash_images request.user.tenant_id as dash_image_url%}
+ {% url horizon:nova:images:index as dash_image_url%}
<h2>{% trans "Info"%}</h2>
<p>{% blocktrans %}There are currently no instances. You can launch an instance from the <a href='{{dash_image_url}}'>Images Page.</a>{% endblocktrans %}</p>
</div>
@@ -31,7 +31,7 @@
function loadInstances(){
if ($("#ajax_option_box").is(':checked')) {
$('.refresh').addClass("refreshing");
- $('#instances').load('{% url syspanel_instances_refresh %}', function(){
+ $('#instances').load('{% url horizon:syspanel:instances:refresh %}', function(){
$('.refresh').removeClass("refreshing");
});
};
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.csv b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.csv
index d618b637..d618b637 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.csv
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.csv
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.html
index 934830d7..15a5cc73 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{% load parse_date %}
{% load sizeformat %}
{%load i18n%}
@@ -11,7 +11,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("System Panel Overview") %}
+ {% include "horizon/common/_page_header.html" with title=_("System Panel Overview") %}
{% endblock page_header %}
{% block syspanel_main %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.csv b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.csv
index 79acd2c7..79acd2c7 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.csv
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.csv
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.html
index 905d19d7..de58d8a4 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{% load sizeformat %}
{%load i18n%}
@@ -13,7 +13,7 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("System Panel Overview") %}
+ {% include "horizon/common/_page_header.html" with title=_("System Panel Overview") %}
{% endblock page_header %}
{% block syspanel_main %}
@@ -83,7 +83,7 @@
</tr>
{% for usage in usage_list %}
<tr>
- <td><a href="{% url syspanel_tenant_usage usage.tenant_id %}">{{usage.tenant_id}}</a></td>
+ <td><a href="{% url horizon:syspanel:instances:tenant_usage usage.tenant_id %}">{{usage.tenant_id}}</a></td>
<td>{{usage.total_active_instances}}</td>
<td>{{usage.total_active_vcpus}}</td>
<td>{{usage.total_active_disk_size|diskgbformat}}</td>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/quotas/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/quotas/index.html
index 8e471285..ccc90c88 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/quotas/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/quotas/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,9 +8,9 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_quotas as refresh_link %}
+ {% url horizon:syspanel:quotas:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Default Quotas") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Default Quotas") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/_list.html
index a158c8e8..9bda1f4c 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/_list.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/_list.html
@@ -45,7 +45,7 @@
<td>{{service.up}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/services/_toggle.html" with form=service_toggle_enabled_form %}</li>
+ <li class="form">{% include "syspanel/services/_toggle.html" with form=service_toggle_enabled_form %}</li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/_toggle.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/_toggle.html
index 43c5bfb3..43c5bfb3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/_toggle.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/_toggle.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/index.html
index 551e9018..b5145c71 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,12 +8,12 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_services as refresh_link %}
+ {% url horizon:syspanel:services:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Services") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Services") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
- {% include "django_openstack/syspanel/services/_list.html" %}
+ {% include "syspanel/services/_list.html" %}
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_add_user.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_add_user.html
index a326e825..a326e825 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_add_user.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_add_user.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_create_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_create_form.html
index 20c58988..6bdae710 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_create_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_create_form.html
@@ -1,4 +1,4 @@
-{% extends "django_openstack/syspanel/tenants/_form.html" %}
+{% extends "syspanel/tenants/_form.html" %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_delete.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_delete.html
index e933f95b..e933f95b 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_delete.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_form.html
index 69276c0f..69276c0f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_list.html
index dbd44e80..ac6410c4 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_list.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_list.html
@@ -15,10 +15,10 @@
<td>{{tenant.enabled}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/tenants/_delete.html" with form=tenant_delete_form %}</li>
- <li><a href="{% url syspanel_tenant_update tenant.id %}">{% trans "Edit"%}</a></li>
- <li><a href="{% url syspanel_tenant_users tenant.id %}">{% trans "View Members"%}</a></li>
- <li><a href="{% url syspanel_tenant_quotas tenant.id %}">{% trans "Modify Quotas"%}</a></li>
+ <li class="form">{% include "syspanel/tenants/_delete.html" with form=tenant_delete_form %}</li>
+ <li><a href="{% url horizon:syspanel:tenants:update tenant.id %}">{% trans "Edit"%}</a></li>
+ <li><a href="{% url horizon:syspanel:tenants:users tenant.id %}">{% trans "View Members"%}</a></li>
+ <li><a href="{% url horizon:syspanel:tenants:quotas tenant.id %}">{% trans "Modify Quotas"%}</a></li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_quotas_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_quotas_form.html
index a2168618..a2168618 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_quotas_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_quotas_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_remove_user.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_remove_user.html
index 828c48c7..828c48c7 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_remove_user.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_remove_user.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_form.html
index 5c17a8c2..5748ec0f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_form.html
@@ -1,4 +1,4 @@
-{% extends "django_openstack/syspanel/tenants/_form.html" %}
+{% extends "syspanel/tenants/_form.html" %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_quotas_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html
index cfa0e601..5875f6ad 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_quotas_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html
@@ -1,4 +1,4 @@
-{% extends "django_openstack/syspanel/tenants/_quotas_form.html" %}
+{% extends "syspanel/tenants/_quotas_form.html" %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/create.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/create.html
index d681c8be..0a621d69 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/create.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Create Tenant") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create Tenant") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/tenants/_create_form.html' %}
+ {% include 'syspanel/tenants/_create_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/index.html
index a6d76c07..251759ec 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,14 +8,14 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_tenants as refresh_link %}
+ {% url horizon:syspanel:tenants:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Tenants") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Tenants") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
- {% include "django_openstack/syspanel/tenants/_list.html" %}
- <a id="tenant_create_link" class="action_link large-rounded" href="{% url syspanel_tenants_create %}">{% trans "Create New Tenant"%}</a>
+ {% include "syspanel/tenants/_list.html" %}
+ <a id="tenant_create_link" class="action_link large-rounded" href="{% url horizon:syspanel:tenants:create %}">{% trans "Create New Tenant"%}</a>
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/quotas.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/quotas.html
index 63b865fe..75e762cc 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/quotas.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/quotas.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,18 +8,18 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Update Tenant Quotas") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update Tenant Quotas") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/tenants/_update_quotas_form.html' with form=form %}
+ {% include 'syspanel/tenants/_update_quotas_form.html' with form=form %}
</div>
<div class="right">
<h3>{% trans "Description"%}:</h3>
- <p>{% trans "From here you can edit quotas (max limits) for the tenant {{tenant_id}}."%}</p>
+ <p>{% trans "From here you can edit quotas (max limits) for the tenant "%}{{ tenant_id }}.</p>
</div>
<div class="clear">&nbsp;</div>
</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/update.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/update.html
index 18da7c39..6602bac0 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/update.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/update.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,13 +8,13 @@
{% endblock %}
{% block page_header %}
- {% include "django_openstack/common/_page_header.html" with title=_("Update Tenant") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update Tenant") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/tenants/_update_form.html' %}
+ {% include 'syspanel/tenants/_update_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/users.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/users.html
index 5f7da9c2..6ca867e0 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/users.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/users.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -32,7 +32,7 @@
<td>{{user.email}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/tenants/_remove_user.html" with form=remove_user_form %}</li>
+ <li class="form">{% include "syspanel/tenants/_remove_user.html" with form=remove_user_form %}</li>
</ul>
</td>
</tr>
@@ -60,7 +60,7 @@
<td>{{user.name}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/tenants/_add_user.html" with form=add_user_form %}</li>
+ <li class="form">{% include "syspanel/tenants/_add_user.html" with form=add_user_form %}</li>
</ul>
</td>
</tr>
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_create_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_create_form.html
index 20221f23..c55fd77d 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_create_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_create_form.html
@@ -1,4 +1,4 @@
-{% extends "django_openstack/syspanel/users/_form.html" %}
+{% extends "syspanel/users/_form.html" %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_delete.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_delete.html
index 408f27e2..408f27e2 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_delete.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_delete.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_enable_disable.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_enable_disable.html
index 69f3ac5f..69f3ac5f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_enable_disable.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_enable_disable.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_form.html
index 3caecdb6..3caecdb6 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_form.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_toggle_enabled.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html
index 7436648e..7436648e 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_toggle_enabled.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_update_form.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_update_form.html
index 32117fb3..02b77f75 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/_update_form.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/_update_form.html
@@ -1,4 +1,4 @@
-{% extends "django_openstack/syspanel/users/_form.html" %}
+{% extends "syspanel/users/_form.html" %}
{%load i18n%}
{% block submit %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/create.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/create.html
index c54d26cb..f22120d3 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/create.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/create.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,13 +9,13 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Create User") %}
+ {% include "horizon/common/_page_header.html" with title=_("Create User") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/users/_create_form.html' %}
+ {% include 'syspanel/users/_create_form.html' %}
</div>
<div class="right">
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/index.html
index 4783b70b..0890295f 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/index.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/index.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -8,9 +8,9 @@
{% endblock %}
{% block page_header %}
- {% url syspanel_users as refresh_link %}
+ {% url horizon:syspanel:users:index as refresh_link %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Users") refresh_link=refresh_link searchable="true" %}
+ {% include "horizon/common/_page_header.html" with title=_("Users") refresh_link=refresh_link searchable="true" %}
{% endblock page_header %}
{% block syspanel_main %}
@@ -31,15 +31,15 @@
<td>{{user.tenantId}}</td>
<td id="actions">
<ul>
- <li class="form">{% include "django_openstack/syspanel/users/_enable_disable.html" with form=user_enable_disable_form %}</li>
- <li class="form">{% include "django_openstack/syspanel/users/_delete.html" with form=user_delete_form %}</li>
- <li><a href="{% url syspanel_users_update user.id %}">{% trans "Edit"%}</a></li>
+ <li class="form">{% include "syspanel/users/_enable_disable.html" with form=user_enable_disable_form %}</li>
+ <li class="form">{% include "syspanel/users/_delete.html" with form=user_delete_form %}</li>
+ <li><a href="{% url horizon:syspanel:users:update user.id %}">{% trans "Edit"%}</a></li>
</ul>
</td>
</tr>
{% endfor %}
</table>
- <a id="user_create_link" class="action_link large-rounded" href="{% url syspanel_users_create %}">{% trans "Create New User"%}</a>
+ <a id="user_create_link" class="action_link large-rounded" href="{% url horizon:syspanel:users:create %}">{% trans "Create New User"%}</a>
</div>
{% endblock %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/update.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/update.html
index 301446c5..6d9839fb 100644
--- a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/update.html
+++ b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/update.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/syspanel/base.html' %}
+{% extends 'syspanel/base.html' %}
{%load i18n%}
{% block sidebar %}
@@ -9,13 +9,13 @@
{% block page_header %}
{# to make searchable false, just remove it from the include statement #}
- {% include "django_openstack/common/_page_header.html" with title=_("Update User") %}
+ {% include "horizon/common/_page_header.html" with title=_("Update User") %}
{% endblock page_header %}
{% block syspanel_main %}
<div class="dash_block">
<div class="left">
- {% include 'django_openstack/syspanel/users/_update_form.html' %}
+ {% include 'syspanel/users/_update_form.html' %}
</div>
<div class="right">
diff --git a/horizon/horizon/dashboards/syspanel/tenants/__init__.py b/horizon/horizon/dashboards/syspanel/tenants/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/tenants/__init__.py
diff --git a/django-openstack/django_openstack/syspanel/views/tenants.py b/horizon/horizon/dashboards/syspanel/tenants/forms.py
index 2b7ee3ab..e84b63da 100644
--- a/django-openstack/django_openstack/syspanel/views/tenants.py
+++ b/horizon/horizon/dashboards/syspanel/tenants/forms.py
@@ -18,28 +18,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django import template
-from django import http
-from django.conf import settings
-from django.contrib.auth.decorators import login_required
-from django.shortcuts import render_to_response
-from django.shortcuts import redirect
-from django.utils.translation import ugettext as _
-
-import datetime
-import json
import logging
+from django import shortcuts
+from django.conf import settings
from django.contrib import messages
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.dash.views import instances as dash_instances
-from django_openstack.decorators import enforce_admin_access
+from django.utils.translation import ugettext as _
from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon import forms
-LOG = logging.getLogger('django_openstack.syspanel.views.tenants')
+
+LOG = logging.getLogger(__name__)
class AddUser(forms.SelfHandlingForm):
@@ -59,7 +50,8 @@ class AddUser(forms.SelfHandlingForm):
except api_exceptions.ApiException, e:
messages.error(request, _('Unable to create user association: %s')
% (e.message))
- return redirect('syspanel_tenant_users', tenant_id=data['tenant'])
+ return shortcuts.redirect('horizon:syspanel:tenants:users',
+ tenant_id=data['tenant'])
class RemoveUser(forms.SelfHandlingForm):
@@ -79,7 +71,8 @@ class RemoveUser(forms.SelfHandlingForm):
except api_exceptions.ApiException, e:
messages.error(request, _('Unable to create tenant: %s') %
(e.message))
- return redirect('syspanel_tenant_users', tenant_id=data['tenant'])
+ return shortcuts.redirect('horizon:syspanel:tenants:users',
+ tenant_id=data['tenant'])
class CreateTenant(forms.SelfHandlingForm):
@@ -105,7 +98,7 @@ class CreateTenant(forms.SelfHandlingForm):
(data['name'], data['description'], data['enabled']))
messages.error(request, _('Unable to create tenant: %s') %
(e.message))
- return redirect('syspanel_tenants')
+ return shortcuts.redirect('horizon:syspanel:tenants:index')
class UpdateTenant(forms.SelfHandlingForm):
@@ -135,7 +128,7 @@ class UpdateTenant(forms.SelfHandlingForm):
data['description'], data['enabled']))
messages.error(request,
_('Unable to update tenant: %s') % e.message)
- return redirect('syspanel_tenants')
+ return shortcuts.redirect('horizon:syspanel:tenants:index')
class UpdateQuotas(forms.SelfHandlingForm):
@@ -171,7 +164,7 @@ class UpdateQuotas(forms.SelfHandlingForm):
except api_exceptions.ApiException, e:
messages.error(request,
_('Unable to update quotas: %s') % e.message)
- return redirect('syspanel_tenants')
+ return shortcuts.redirect('horizon:syspanel:tenants:index')
class DeleteTenant(forms.SelfHandlingForm):
@@ -187,122 +180,4 @@ class DeleteTenant(forms.SelfHandlingForm):
LOG.exception("Error deleting tenant")
messages.error(request,
_("Error deleting tenant: %s") % e.message)
- return redirect(request.build_absolute_uri())
-
-
-@login_required
-@enforce_admin_access
-def index(request):
- form, handled = DeleteTenant.maybe_handle(request)
- if handled:
- return handled
-
- tenant_delete_form = DeleteTenant()
-
- tenants = []
- try:
- tenants = api.tenant_list(request)
- except api_exceptions.ApiException, e:
- LOG.exception('ApiException while getting tenant list')
- messages.error(request, _('Unable to get tenant info: %s') % e.message)
- tenants.sort(key=lambda x: x.id, reverse=True)
- return render_to_response(
- 'django_openstack/syspanel/tenants/index.html', {
- 'tenants': tenants,
- 'tenant_delete_form': tenant_delete_form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-@enforce_admin_access
-def create(request):
- form, handled = CreateTenant.maybe_handle(request)
- if handled:
- return handled
-
- return render_to_response(
- 'django_openstack/syspanel/tenants/create.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-@enforce_admin_access
-def update(request, tenant_id):
- form, handled = UpdateTenant.maybe_handle(request)
- if handled:
- return handled
-
- if request.method == 'GET':
- try:
- tenant = api.tenant_get(request, tenant_id)
- form = UpdateTenant(initial={'id': tenant.id,
- 'name': tenant.name,
- 'description': tenant.description,
- 'enabled': tenant.enabled})
- except api_exceptions.ApiException, e:
- LOG.exception('Error fetching tenant with id "%s"' % tenant_id)
- messages.error(request,
- _('Unable to update tenant: %s') % e.message)
- return redirect('syspanel_tenants')
-
- return render_to_response(
- 'django_openstack/syspanel/tenants/update.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-@enforce_admin_access
-def users(request, tenant_id):
- for f in (AddUser, RemoveUser,):
- form, handled = f.maybe_handle(request)
- if handled:
- return handled
-
- add_user_form = AddUser()
- remove_user_form = RemoveUser()
-
- users = api.user_list(request, tenant_id)
- all_users = api.user_list(request)
- user_ids = [u.id for u in users]
- new_users = [u for u in all_users if not u.id in user_ids]
- return render_to_response(
- 'django_openstack/syspanel/tenants/users.html', {
- 'add_user_form': add_user_form,
- 'remove_user_form': remove_user_form,
- 'tenant_id': tenant_id,
- 'users': users,
- 'new_users': new_users,
- }, context_instance=template.RequestContext(request))
-
-
-@login_required
-@enforce_admin_access
-def quotas(request, tenant_id):
- for f in (UpdateQuotas,):
- form, handled = f.maybe_handle(request)
- if handled:
- return handled
-
- quotas = api.admin_api(request).quota_sets.get(tenant_id)
- quota_set = {
- 'tenant_id': quotas.id,
- 'metadata_items': quotas.metadata_items,
- 'injected_file_content_bytes': quotas.injected_file_content_bytes,
- 'volumes': quotas.volumes,
- 'gigabytes': quotas.gigabytes,
- 'ram': int(quotas.ram),
- 'floating_ips': quotas.floating_ips,
- 'instances': quotas.instances,
- 'injected_files': quotas.injected_files,
- 'cores': quotas.cores,
- }
- form = UpdateQuotas(initial=quota_set)
-
- return render_to_response(
- 'django_openstack/syspanel/tenants/quotas.html', {
- 'form': form,
- 'tenant_id': tenant_id,
- 'quotas': quotas,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/syspanel/tenants/panel.py b/horizon/horizon/dashboards/syspanel/tenants/panel.py
new file mode 100644
index 00000000..692a93ee
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/tenants/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Tenants(horizon.Panel):
+ name = "Tenants"
+ slug = 'tenants'
+
+
+dashboard.Syspanel.register(Tenants)
diff --git a/horizon/horizon/dashboards/syspanel/tenants/tests.py b/horizon/horizon/dashboards/syspanel/tenants/tests.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/tenants/tests.py
diff --git a/horizon/horizon/dashboards/syspanel/tenants/urls.py b/horizon/horizon/dashboards/syspanel/tenants/urls.py
new file mode 100644
index 00000000..1e43b874
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/tenants/urls.py
@@ -0,0 +1,29 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('horizon.dashboards.syspanel.tenants.views',
+ url(r'^$', 'index', name='index'),
+ url(r'^create$', 'create', name='create'),
+ url(r'^(?P<tenant_id>[^/]+)/update/$', 'update', name='update'),
+ url(r'^(?P<tenant_id>[^/]+)/users/$', 'users', name='users'),
+ url(r'^(?P<tenant_id>[^/]+)/quotas/$', 'quotas', name='quotas'))
diff --git a/horizon/horizon/dashboards/syspanel/tenants/views.py b/horizon/horizon/dashboards/syspanel/tenants/views.py
new file mode 100644
index 00000000..d6cc2735
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/tenants/views.py
@@ -0,0 +1,143 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.conf import settings
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon.dashboards.syspanel.tenants.forms import (AddUser, RemoveUser,
+ CreateTenant, UpdateTenant, UpdateQuotas, DeleteTenant)
+
+
+LOG = logging.getLogger(__name__)
+
+
+@login_required
+def index(request):
+ form, handled = DeleteTenant.maybe_handle(request)
+ if handled:
+ return handled
+
+ tenant_delete_form = DeleteTenant()
+
+ tenants = []
+ try:
+ tenants = api.tenant_list(request)
+ except api_exceptions.ApiException, e:
+ LOG.exception('ApiException while getting tenant list')
+ messages.error(request, _('Unable to get tenant info: %s') % e.message)
+ tenants.sort(key=lambda x: x.id, reverse=True)
+ return shortcuts.render(request,
+ 'syspanel/tenants/index.html', {
+ 'tenants': tenants,
+ 'tenant_delete_form': tenant_delete_form})
+
+
+@login_required
+def create(request):
+ form, handled = CreateTenant.maybe_handle(request)
+ if handled:
+ return handled
+
+ return shortcuts.render(request,
+ 'syspanel/tenants/create.html', {
+ 'form': form})
+
+
+@login_required
+def update(request, tenant_id):
+ form, handled = UpdateTenant.maybe_handle(request)
+ if handled:
+ return handled
+
+ if request.method == 'GET':
+ try:
+ tenant = api.tenant_get(request, tenant_id)
+ form = UpdateTenant(initial={'id': tenant.id,
+ 'name': tenant.name,
+ 'description': tenant.description,
+ 'enabled': tenant.enabled})
+ except api_exceptions.ApiException, e:
+ LOG.exception('Error fetching tenant with id "%s"' % tenant_id)
+ messages.error(request,
+ _('Unable to update tenant: %s') % e.message)
+ return shortcuts.redirect('horizon:syspanel:tenants:index')
+
+ return shortcuts.render(request,
+ 'syspanel/tenants/update.html', {
+ 'form': form})
+
+
+@login_required
+def users(request, tenant_id):
+ for f in (AddUser, RemoveUser,):
+ form, handled = f.maybe_handle(request)
+ if handled:
+ return handled
+
+ add_user_form = AddUser()
+ remove_user_form = RemoveUser()
+
+ users = api.user_list(request, tenant_id)
+ all_users = api.user_list(request)
+ user_ids = [u.id for u in users]
+ new_users = [u for u in all_users if not u.id in user_ids]
+ return shortcuts.render(request,
+ 'syspanel/tenants/users.html', {
+ 'add_user_form': add_user_form,
+ 'remove_user_form': remove_user_form,
+ 'tenant_id': tenant_id,
+ 'users': users,
+ 'new_users': new_users})
+
+
+@login_required
+def quotas(request, tenant_id):
+ for f in (UpdateQuotas,):
+ form, handled = f.maybe_handle(request)
+ if handled:
+ return handled
+
+ quotas = api.admin_api(request).quota_sets.get(tenant_id)
+ quota_set = {
+ 'tenant_id': quotas.id,
+ 'metadata_items': quotas.metadata_items,
+ 'injected_file_content_bytes': quotas.injected_file_content_bytes,
+ 'volumes': quotas.volumes,
+ 'gigabytes': quotas.gigabytes,
+ 'ram': int(quotas.ram),
+ 'floating_ips': quotas.floating_ips,
+ 'instances': quotas.instances,
+ 'injected_files': quotas.injected_files,
+ 'cores': quotas.cores,
+ }
+ form = UpdateQuotas(initial=quota_set)
+
+ return shortcuts.render(request,
+ 'syspanel/tenants/quotas.html', {
+ 'form': form,
+ 'tenant_id': tenant_id,
+ 'quotas': quotas})
diff --git a/horizon/horizon/dashboards/syspanel/users/__init__.py b/horizon/horizon/dashboards/syspanel/users/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/users/__init__.py
diff --git a/horizon/horizon/dashboards/syspanel/users/forms.py b/horizon/horizon/dashboards/syspanel/users/forms.py
new file mode 100644
index 00000000..4033c37e
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/users/forms.py
@@ -0,0 +1,102 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon import forms
+
+
+LOG = logging.getLogger(__name__)
+
+
+class UserForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ tenant_list = kwargs.pop('tenant_list', None)
+ super(UserForm, self).__init__(*args, **kwargs)
+ self.fields['tenant_id'].choices = [[tenant.id, tenant.name]
+ for tenant in tenant_list]
+
+ name = forms.CharField(label=_("Name"))
+ email = forms.CharField(label=_("Email"))
+ password = forms.CharField(label=_("Password"),
+ widget=forms.PasswordInput(render_value=False),
+ required=False)
+ tenant_id = forms.ChoiceField(label=_("Primary Tenant"))
+
+
+class UserUpdateForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ tenant_list = kwargs.pop('tenant_list', None)
+ super(UserUpdateForm, self).__init__(*args, **kwargs)
+ self.fields['tenant_id'].choices = [[tenant.id, tenant.name]
+ for tenant in tenant_list]
+
+ id = forms.CharField(label=_("ID"),
+ widget=forms.TextInput(attrs={'readonly': 'readonly'}))
+ # FIXME: keystone doesn't return the username from a get API call.
+ #name = forms.CharField(label=_("Name"))
+ email = forms.CharField(label=_("Email"))
+ password = forms.CharField(label=_("Password"),
+ widget=forms.PasswordInput(render_value=False),
+ required=False)
+ tenant_id = forms.ChoiceField(label=_("Primary Tenant"))
+
+
+class UserDeleteForm(forms.SelfHandlingForm):
+ user = forms.CharField(required=True)
+
+ def handle(self, request, data):
+ user_id = data['user']
+ LOG.info('Deleting user with id "%s"' % user_id)
+ api.user_delete(request, user_id)
+ messages.info(request, _('%(user)s was successfully deleted.')
+ % {"user": user_id})
+ return shortcuts.redirect(request.build_absolute_uri())
+
+
+class UserEnableDisableForm(forms.SelfHandlingForm):
+ id = forms.CharField(label=_("ID (username)"), widget=forms.HiddenInput())
+ enabled = forms.ChoiceField(label=_("enabled"), widget=forms.HiddenInput(),
+ choices=[[c, c]
+ for c in ("disable", "enable")])
+
+ def handle(self, request, data):
+ user_id = data['id']
+ enabled = data['enabled'] == "enable"
+
+ try:
+ api.user_update_enabled(request, user_id, enabled)
+ messages.info(request,
+ _("User %(user)s %(state)s") %
+ {"user": user_id,
+ "state": "enabled" if enabled else "disabled"})
+ except api_exceptions.ApiException:
+ messages.error(request,
+ _("Unable to %(state)s user %(user)s") %
+ {"state": "enable" if enabled else "disable",
+ "user": user_id})
+
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/horizon/horizon/dashboards/syspanel/users/panel.py b/horizon/horizon/dashboards/syspanel/users/panel.py
new file mode 100644
index 00000000..7a7380e3
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/users/panel.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import horizon
+from horizon.dashboards.syspanel import dashboard
+
+
+class Users(horizon.Panel):
+ name = "Users"
+ slug = 'users'
+
+
+dashboard.Syspanel.register(Users)
diff --git a/django-openstack/django_openstack/tests/view_tests/syspanel/users_tests.py b/horizon/horizon/dashboards/syspanel/users/tests.py
index 9c08d12d..7b5273e0 100644
--- a/django-openstack/django_openstack/tests/view_tests/syspanel/users_tests.py
+++ b/horizon/horizon/dashboards/syspanel/users/tests.py
@@ -19,19 +19,24 @@
# under the License.
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from mox import IgnoreArg
from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon import test
-class UsersViewTests(base.BaseViewTests):
+
+USERS_INDEX_URL = reverse('horizon:syspanel:users:index')
+
+
+class UsersViewTests(test.BaseAdminViewTests):
def setUp(self):
super(UsersViewTests, self).setUp()
self.user = self.mox.CreateMock(api.User)
self.user.enabled = True
self.user.id = self.TEST_USER
+ self.user.roles = self.TEST_ROLES
self.user.tenantId = self.TEST_TENANT
self.users = [self.user]
@@ -42,10 +47,9 @@ class UsersViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.get(reverse('syspanel_users'))
+ res = self.client.get(USERS_INDEX_URL)
- self.assertTemplateUsed(res,
- 'django_openstack/syspanel/users/index.html')
+ self.assertTemplateUsed(res, 'syspanel/users/index.html')
self.assertItemsEqual(res.context['users'], self.users)
self.mox.VerifyAll()
@@ -62,9 +66,9 @@ class UsersViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('syspanel_users'), formData)
+ res = self.client.post(USERS_INDEX_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('syspanel_users'))
+ self.assertRedirectsNoFollow(res, USERS_INDEX_URL)
self.mox.VerifyAll()
@@ -80,9 +84,9 @@ class UsersViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('syspanel_users'), formData)
+ res = self.client.post(USERS_INDEX_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('syspanel_users'))
+ self.assertRedirectsNoFollow(res, USERS_INDEX_URL)
self.mox.VerifyAll()
@@ -100,8 +104,8 @@ class UsersViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('syspanel_users'), formData)
+ res = self.client.post(USERS_INDEX_URL, formData)
- self.assertRedirectsNoFollow(res, reverse('syspanel_users'))
+ self.assertRedirectsNoFollow(res, USERS_INDEX_URL)
self.mox.VerifyAll()
diff --git a/horizon/horizon/dashboards/syspanel/users/urls.py b/horizon/horizon/dashboards/syspanel/users/urls.py
new file mode 100644
index 00000000..2be685f9
--- /dev/null
+++ b/horizon/horizon/dashboards/syspanel/users/urls.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url
+
+urlpatterns = patterns('horizon.dashboards.syspanel.users.views',
+ url(r'^users/$', 'index', name='index'),
+ url(r'^(?P<user_id>[^/]+)/update/$', 'update', name='update'),
+ url(r'^users/create/$', 'create', name='create'))
diff --git a/django-openstack/django_openstack/syspanel/views/users.py b/horizon/horizon/dashboards/syspanel/users/views.py
index 647e3c36..9a1dfdad 100644
--- a/django-openstack/django_openstack/syspanel/views/users.py
+++ b/horizon/horizon/dashboards/syspanel/users/views.py
@@ -18,103 +18,24 @@
# License for the specific language governing permissions and limitations
# under the License.
+import logging
+
from django import shortcuts
-from django import template
-from django import http
from django.conf import settings
+from django.contrib import messages
from django.contrib.auth.decorators import login_required
-from django.shortcuts import render_to_response
-from django.shortcuts import redirect
from django.utils.translation import ugettext as _
-
-import datetime
-import json
-import logging
-
-from django.contrib import messages
-
-from django_openstack import api
-from django_openstack import forms
-from django_openstack.dash.views import instances as dash_instances
-from django_openstack.decorators import enforce_admin_access
from openstackx.api import exceptions as api_exceptions
+from horizon import api
+from horizon.dashboards.syspanel.users.forms import (UserForm, UserUpdateForm,
+ UserDeleteForm, UserEnableDisableForm)
-LOG = logging.getLogger('django_openstack.syspanel.views.users')
-
-
-class UserForm(forms.Form):
- def __init__(self, *args, **kwargs):
- tenant_list = kwargs.pop('tenant_list', None)
- super(UserForm, self).__init__(*args, **kwargs)
- self.fields['tenant_id'].choices = [[tenant.id, tenant.name]
- for tenant in tenant_list]
-
- name = forms.CharField(label=_("Name"))
- email = forms.CharField(label=_("Email"))
- password = forms.CharField(label=_("Password"),
- widget=forms.PasswordInput(render_value=False),
- required=False)
- tenant_id = forms.ChoiceField(label=_("Primary Tenant"))
-
-
-class UserUpdateForm(forms.Form):
- def __init__(self, *args, **kwargs):
- tenant_list = kwargs.pop('tenant_list', None)
- super(UserUpdateForm, self).__init__(*args, **kwargs)
- self.fields['tenant_id'].choices = [[tenant.id, tenant.name]
- for tenant in tenant_list]
-
- id = forms.CharField(label=_("ID"),
- widget=forms.TextInput(attrs={'readonly': 'readonly'}))
- # FIXME: keystone doesn't return the username from a get API call.
- #name = forms.CharField(label=_("Name"))
- email = forms.CharField(label=_("Email"))
- password = forms.CharField(label=_("Password"),
- widget=forms.PasswordInput(render_value=False),
- required=False)
- tenant_id = forms.ChoiceField(label=_("Primary Tenant"))
-
-
-class UserDeleteForm(forms.SelfHandlingForm):
- user = forms.CharField(required=True)
-
- def handle(self, request, data):
- user_id = data['user']
- LOG.info('Deleting user with id "%s"' % user_id)
- api.user_delete(request, user_id)
- messages.info(request, _('%(user)s was successfully deleted.')
- % {"user": user_id})
- return redirect(request.build_absolute_uri())
-
-
-class UserEnableDisableForm(forms.SelfHandlingForm):
- id = forms.CharField(label=_("ID (username)"), widget=forms.HiddenInput())
- enabled = forms.ChoiceField(label=_("enabled"), widget=forms.HiddenInput(),
- choices=[[c, c]
- for c in ("disable", "enable")])
-
- def handle(self, request, data):
- user_id = data['id']
- enabled = data['enabled'] == "enable"
-
- try:
- api.user_update_enabled(request, user_id, enabled)
- messages.info(request,
- _("User %(user)s %(state)s") %
- {"user": user_id,
- "state": "enabled" if enabled else "disabled"})
- except api_exceptions.ApiException:
- messages.error(request,
- _("Unable to %(state)s user %(user)s") %
- {"state": "enable" if enabled else "disable",
- "user": user_id})
- return redirect(request.build_absolute_uri())
+LOG = logging.getLogger(__name__)
@login_required
-@enforce_admin_access
def index(request):
for f in (UserDeleteForm, UserEnableDisableForm):
form, handled = f.maybe_handle(request)
@@ -129,18 +50,16 @@ def index(request):
e.message)
user_delete_form = UserDeleteForm()
- user_enable_disable_form = UserEnableDisableForm()
+ toggle_form = UserEnableDisableForm()
- return shortcuts.render_to_response(
- 'django_openstack/syspanel/users/index.html', {
- 'users': users,
- 'user_delete_form': user_delete_form,
- 'user_enable_disable_form': user_enable_disable_form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/users/index.html', {
+ 'users': users,
+ 'user_delete_form': user_delete_form,
+ 'user_enable_disable_form': toggle_form})
@login_required
-@enforce_admin_access
def update(request, user_id):
if request.method == "POST":
tenants = api.tenant_list(request)
@@ -160,17 +79,16 @@ def update(request, user_id):
messages.success(request,
_('Updated %(attrib)s for %(user)s.') %
{"attrib": ', '.join(updated), "user": user_id})
- return redirect('syspanel_users')
+ return shortcuts.redirect('horizon:syspanel:users:index')
else:
# TODO add better error management
messages.error(request,
_('Unable to update user, please try again.'))
- return render_to_response(
- 'django_openstack/syspanel/users/update.html', {
- 'form': form,
- 'user_id': user_id,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/users/update.html', {
+ 'form': form,
+ 'user_id': user_id})
else:
user = api.user_get(request, user_id)
@@ -181,22 +99,20 @@ def update(request, user_id):
'tenantId',
None),
'email': getattr(user, 'email', '')})
- return render_to_response(
- 'django_openstack/syspanel/users/update.html', {
- 'form': form,
- 'user_id': user_id,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/users/update.html', {
+ 'form': form,
+ 'user_id': user_id})
@login_required
-@enforce_admin_access
def create(request):
try:
tenants = api.tenant_list(request)
except api_exceptions.ApiException, e:
messages.error(request, _('Unable to retrieve tenant list: %s') %
e.message)
- return redirect('syspanel_users')
+ return shortcuts.redirect('horizon:syspanel:users:index')
if request.method == "POST":
form = UserForm(request.POST, tenant_list=tenants)
@@ -225,7 +141,7 @@ def create(request):
_('Error assigning role to user: %s')
% e.message)
- return redirect('syspanel_users')
+ return shortcuts.redirect('horizon:syspanel:users:index')
except Exception, e:
LOG.exception('Exception while creating user\n'
@@ -234,16 +150,14 @@ def create(request):
messages.error(request,
_('Error creating user: %s')
% e.message)
- return redirect('syspanel_users')
+ return shortcuts.redirect('horizon:syspanel:users:index')
else:
- return render_to_response(
- 'django_openstack/syspanel/users/create.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/users/create.html', {
+ 'form': form})
else:
form = UserForm(tenant_list=tenants)
- return render_to_response(
- 'django_openstack/syspanel/users/create.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'syspanel/users/create.html', {
+ 'form': form})
diff --git a/horizon/horizon/decorators.py b/horizon/horizon/decorators.py
new file mode 100644
index 00000000..c5dc7bf2
--- /dev/null
+++ b/horizon/horizon/decorators.py
@@ -0,0 +1,86 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 CRS4
+#
+# 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.
+
+"""
+General-purpose decorators for use with Horizon.
+"""
+import functools
+import logging
+
+from django import http
+from django.utils.decorators import available_attrs
+
+from horizon.exceptions import NotAuthorized
+
+
+def _current_component(view_func, dashboard=None, panel=None):
+ """ Sets the currently-active dashboard and/or panel on the request. """
+ @functools.wraps(view_func, assigned=available_attrs(view_func))
+ def dec(request, *args, **kwargs):
+ if dashboard:
+ request.horizon['dashboard'] = dashboard
+ if panel:
+ request.horizon['panel'] = panel
+ return view_func(request, *args, **kwargs)
+ return dec
+
+
+def require_roles(view_func, required):
+ """ Enforces role-based access controls.
+
+ :param list required: A tuple of role names, all of which the request user
+ must possess in order access the decorated view.
+
+ Example usage::
+
+ from horizon.decorators import require_roles
+
+
+ @require_roles(['admin', 'member'])
+ def my_view(request):
+ ...
+
+ Raises a :exc:`~horizon.exceptions.NotAuthorized` exception if the
+ requirements are not met.
+ """
+ # We only need to check each role once for a view, so we'll use a set
+ current_roles = getattr(view_func, '_required_roles', set([]))
+ view_func._required_roles = current_roles | set(required)
+
+ @functools.wraps(view_func, assigned=available_attrs(view_func))
+ def dec(request, *args, **kwargs):
+ if request.user.is_authenticated():
+ roles = set([role['name'].lower() for role in request.user.roles])
+ # set operator <= tests that all members of set 1 are in set 2
+ if view_func._required_roles <= set(roles):
+ return view_func(request, *args, **kwargs)
+ raise NotAuthorized("You are not authorized to access %s"
+ % request.path)
+
+ # If we don't have any roles, just return the original view.
+ if required:
+ return dec
+ else:
+ return view_func
+
+
+def enforce_admin_access(view_func):
+ """ Marks a view as requiring the ``"admin"`` role for access. """
+ return require_roles(view_func, ('admin',))
diff --git a/horizon/horizon/exceptions.py b/horizon/horizon/exceptions.py
new file mode 100644
index 00000000..a2c621f2
--- /dev/null
+++ b/horizon/horizon/exceptions.py
@@ -0,0 +1,40 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+""" Exceptions raised by the Horizon code. """
+
+
+class NotAuthorized(Exception):
+ """
+ Raised whenever a user attempts to access a resource which they do not
+ have role-based access to (such as when failing the
+ :func:`~horizon.decorators.require_roles` decorator).
+
+ The included :class:`~horizon.middleware.HorizonMiddleware` catches
+ ``NotAuthorized`` and handles it gracefully by displaying an error
+ message and redirecting the user to a login page.
+ """
+ pass
+
+
+class ServiceCatalogException(Exception):
+ """
+ Raised when a requested service is not available in the ``ServiceCatalog``
+ returned by Keystone.
+ """
+ def __init__(self, service_name):
+ message = 'Invalid service catalog service: %s' % service_name
+ super(ServiceCatalogException, self).__init__(message)
diff --git a/django-openstack/django_openstack/forms.py b/horizon/horizon/forms.py
index 201add43..dda6eafd 100644
--- a/django-openstack/django_openstack/forms.py
+++ b/horizon/horizon/forms.py
@@ -25,14 +25,16 @@ import re
from django import utils
from django.conf import settings
from django.contrib import messages
+from django.forms import *
from django.forms import widgets
from django.utils import dates
from django.utils import safestring
from django.utils import formats
-from django.forms import *
+from horizon import exceptions
+
-LOG = logging.getLogger('django_openstack.forms')
+LOG = logging.getLogger(__name__)
RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
@@ -150,6 +152,21 @@ class SelectDateWidget(widgets.Widget):
class SelfHandlingForm(Form):
+ """
+ A base :class:`Form <django:django.forms.Form>` class which includes
+ processing logic in its subclasses and handling errors raised during
+ form processing.
+
+ .. attribute:: method
+
+ A :class:`CharField <django:django.forms.CharField>` instance
+ rendered with a
+ :class:`CharField <django:django.forms.widgets.HiddenInput>`
+ widget which is automatically set to the value of the class name.
+
+ This is used to determine whether this form should handle the
+ input it is given or not.
+ """
method = CharField(required=True, widget=HiddenInput)
def __init__(self, *args, **kwargs):
@@ -160,6 +177,15 @@ class SelfHandlingForm(Form):
@classmethod
def maybe_handle(cls, request, *args, **kwargs):
+ """
+ If the form is valid, :meth:`.maybe_handle` calls a
+ ``handle(request, data)`` method on its subclass to
+ determine what action to take.
+
+ Any exceptions raised during processing are captured and
+ converted to messages.
+ """
+
if cls.__name__ != request.POST.get('method'):
return cls(*args, **kwargs), None
@@ -176,12 +202,19 @@ class SelfHandlingForm(Form):
return form, form.handle(request, data)
except Exception as e:
- LOG.exception('Nonspecific error while handling form')
- messages.error(request, _('Unexpected error: %s') % e.message)
+ LOG.exception('Error while handling form "%s".' % cls.__name__)
+ if issubclass(e.__class__, exceptions.NotAuthorized):
+ # Let the middleware handle it as intended.
+ raise
+ messages.error(request, _('%s') % e.message)
return form, None
class DateForm(Form):
+ """
+ A :class:`Form <django:django.forms.Form>` subclass that includes a field
+ called ``date`` which uses :class:`.SelectDateWidget`.
+ """
date = DateField(widget=SelectDateWidget(
years=range(datetime.date.today().year, 2009, -1),
skip_day_field=True))
diff --git a/django-openstack/django_openstack/locale/es/LC_MESSAGES/django.mo b/horizon/horizon/locale/es/LC_MESSAGES/django.mo
index 62e92be1..426ef534 100644
--- a/django-openstack/django_openstack/locale/es/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/es/LC_MESSAGES/django.mo
Binary files differ
diff --git a/horizon/horizon/locale/es/LC_MESSAGES/django.po b/horizon/horizon/locale/es/LC_MESSAGES/django.po
new file mode 100644
index 00000000..17ea2c1e
--- /dev/null
+++ b/horizon/horizon/locale/es/LC_MESSAGES/django.po
@@ -0,0 +1,1971 @@
+# Translations of Dashboard for OpenStack User Interface.
+# Copyright 2011 Midokura KK
+# This file is distributed under the same license as the Dashboard for OpenStack.
+# FIRST AUTHOR Jeffrey Wilcox, 2011.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: openstack-dashboard\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-11-01 23:08-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: context_processors.py:35
+#, python-format
+msgid ""
+"Unable to retrieve tenant list from "
+"keystone: %s"
+msgstr ""
+
+#: forms.py:180
+#, python-format
+msgid "Unexpected error: %s"
+msgstr ""
+
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
+msgstr ""
+
+#: api/keystone.py:199
+#, python-format
+msgid "Role does not exist: %s"
+msgstr ""
+
+#: api/keystone.py:207
+#, python-format
+msgid "Role \"%s\" does not exist for that user on this tenant."
+msgstr ""
+
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+msgid "Network"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:22
+#, python-format
+msgid "Unable to delete non-empty container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:28
+#, python-format
+msgid "Successfully deleted container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:34
+msgid "Container Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:38
+msgid "Container was successfully created."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, python-format
+msgid "Successfully deleted object: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+msgid "Object was successfully uploaded."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
+#, python-format
+msgid "Successfully released Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:47
+#, python-format
+msgid "Error releasing Floating IP from tenant: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
+msgid "Instance"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:72
+#, python-format
+msgid ""
+"Successfully associated Floating IP: "
+"%(ip)s with Instance: %(inst)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:78
+#, python-format
+msgid "Error associating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:95
+#, python-format
+msgid "Successfully disassociated Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:99
+#, python-format
+msgid "Error disassociating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:114
+#, python-format
+msgid ""
+"Successfully allocated Floating IP \"%(ip)s\" "
+"to tenant \"%(tenant)s\""
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:120
+#, python-format
+msgid ""
+"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
+"\": %(msg)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/views.py:53
+#, python-format
+msgid "Error fetching floating ips: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
+msgid "Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
+msgid "Kernel ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
+msgid "Ramdisk ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
+msgid "Architecture"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
+msgid "Container Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
+msgid "Disk Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
+#, python-format
+msgid "Unable to retreive image info from glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:57
+#, python-format
+msgid "Error updating image with id: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
+msgid "Error connecting to glance"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
+msgid "Image was successfully updated."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:97
+msgid "Unspecified Exception in image update"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:101
+msgid ""
+"Unable to update image. You are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:107
+msgid "Server Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:111
+msgid "User Data"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
+msgid "Flavor"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:126
+msgid "Key Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
+msgid "Security Groups"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:165
+msgid "Instance was successfully launched"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:174
+#, python-format
+msgid "Unable to launch instance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:188
+msgid ""
+"Unable to delete image, you are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
+#, python-format
+msgid "Error connecting to glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:198
+msgid "Error deleting image: %(image)s: %i(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
+msgid "There are currently no images."
+msgstr ""
+
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
+#, python-format
+msgid "Error retrieving image list: %s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:118
+#, python-format
+msgid "Error parsing quota for %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
+#, python-format
+msgid "Error retrieving image %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:25
+#, python-format
+msgid "ApiException while terminating instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:28
+#, python-format
+msgid "Unable to terminate %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:31
+#, python-format
+msgid "Instance %s has been terminated."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:45
+msgid "Instance rebooting"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:47
+#, python-format
+msgid "ApiException while rebooting instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:50
+#, python-format
+msgid "Unable to reboot instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:53
+#, python-format
+msgid "Instance %s has been rebooted."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:75
+#, python-format
+msgid "Instance '%s' updated"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:79
+#, python-format
+msgid "Unable to update instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:55
+msgid "Exception in instance index"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
+#, python-format
+msgid "Unable to get instance list: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:110
+msgid "ApiException in instance usage"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, python-format
+msgid "Unable to get usage info: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:174
+msgid "ApiException while fetching instance console"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:176
+#, python-format
+msgid "Unable to get log for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:190
+msgid "ApiException while fetching instance vnc connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
+msgid "ApiException while fetching instance info"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:235
+msgid ""
+"ApiException while fetching instance vnc "
+"connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:238
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:244
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:24
+#, python-format
+msgid "Successfully deleted keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:29
+#, python-format
+msgid "Error deleting keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
+msgid "Keypair Name"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:50
+#, python-format
+msgid "Error Creating Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:58
+msgid "Public Key"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:64
+#, python-format
+msgid "Successfully imported public key: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:70
+#, python-format
+msgid "Error Importing Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/views.py:53
+#, python-format
+msgid "Error fetching keypairs: %s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:15
+msgid "Network Name"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:26
+#, python-format
+msgid "Unable to create network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:30
+#, python-format
+msgid "Network %s has been created."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:45
+#, python-format
+msgid "Unable to delete network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:48
+#, python-format
+msgid "Network %s has been deleted."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:67
+#, python-format
+msgid "Unable to rename network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:70
+#, python-format
+msgid "Network %(net)s has been renamed to %(new_name)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:80
+msgid "Number of Ports"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:90
+#, python-format
+msgid "Unable to create ports on network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:93
+#, python-format
+msgid "%(num_ports)s ports created on network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:112
+#, python-format
+msgid "Unable to delete port %(port)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:115
+#, python-format
+msgid "Port %(port)s deleted from network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:126
+msgid "Select VIF to connect"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:137
+#, python-format
+msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:142
+#, python-format
+msgid "Port %(port)s connected to VIF %(vif)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:159
+#, python-format
+msgid "Unable to detach port %(port)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:162
+#, python-format
+msgid "Port %s detached."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:181
+#, python-format
+msgid "Unable to set port state to %(state)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:184
+#, python-format
+msgid "Port %(port)s state set to %(state)s."
+msgstr ""
+
+#: dashboards/dash/networks/views.py:68
+#, python-format
+msgid "Unable to get network list: %s"
+msgstr ""
+
+#: dashboards/dash/networks/views.py:104
+#, python-format
+msgid "Unable to get network details: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:48
+#, python-format
+msgid "Successfully created security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:53
+#, python-format
+msgid "Error creating security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:67
+#, python-format
+msgid "Successfully deleted security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:71
+#, python-format
+msgid "Error deleting security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:100
+#, python-format
+msgid "Successfully added rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:104
+#, python-format
+msgid "Error adding rule security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:122
+#, python-format
+msgid "Successfully deleted rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:126
+#, python-format
+msgid "Error authorizing security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:54
+#, python-format
+msgid "Error fetching security_groups: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:82
+#, python-format
+msgid "Error getting security_group: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:19
+msgid "Snapshot Name"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:30
+#, python-format
+msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:34
+#, python-format
+msgid "Error Creating Snapshot: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:76
+#, python-format
+msgid "Unable to retreive instance: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:83
+#, python-format
+msgid ""
+"To snapshot, instance state must be one of "
+"the following: %s"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
+msgid "Dashboard Settings"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
+msgid "Dashboard User Interface Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
+msgid "Select Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
+msgid "Delete"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_form.html:10
+msgid "Create Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
+msgid "Actions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:17
+msgid "List Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
+msgid "Upload Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
+msgid "Create Tenant"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:22
+msgid ""
+"A container is a storage compartment for your data and provides a way for "
+"you to organize your data. You can think of a container as a folder in "
+"Windows® or a directory in UNIX®. The primary difference between a container "
+"and these other file system concepts is that containers cannot be nested. "
+"You can, however, create an unlimited number of containers within your "
+"account. Data must be stored in a container so you must have at least one "
+"container defined in your account prior to uploading data."
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/index.html:18
+msgid "Create New Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
+msgid "Allocate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
+msgid "Associate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
+msgid "Disassociate"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
+msgid "Instance ID:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
+msgid "Fixed IP:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
+msgid "Associate to instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
+msgid "Release"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
+msgid "Associate Floating IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
+msgid "Description:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
+msgid "Associate a floating ip with an instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
+msgid "Info"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
+msgid "There are currently no floating ips assigned to your tenant."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
+msgid "Update Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
+msgid "Launch Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
+msgid "Created"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
+msgid "Updated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
+msgid "Status"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
+msgid "Edit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:24
+msgid "Launch"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:22
+msgid ""
+"Specify the details for launching an instance. Also please make note of the "
+"table below; all tenants have quotas which define the limit of resources you "
+"are allowed to provision."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
+msgid "Quota Name"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
+msgid "Limit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:29
+msgid "RAM (MB)"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
+msgid "From here you can modify different properties of an image."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
+msgid "Update Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:8
+msgid "Groups"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
+msgid "Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
+msgid "Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
+msgid "IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
+msgid "State"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:66
+msgid "Log"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
+msgid "VNC Console"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:69
+msgid "Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:19
+msgid "Return to Instances List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:24
+msgid "Update the name and description of your instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
+msgid "Download CSV"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:50
+msgid "Hide Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:52
+msgid "Show Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
+msgid "User"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
+msgid "Ram Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
+msgid "Disk Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
+msgid "Uptime"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:89
+msgid "No active instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:98
+#, python-format
+msgid ""
+"There are currently no instances.<br/><br/>You can launch an instance from "
+"the <a href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
+msgid "Add Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
+msgid "Fingerprint"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
+msgid "Create Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:30
+msgid "Your private key is being downloaded."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
+msgid "Return to keypairs list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
+msgid ""
+"Keypairs are ssh credentials which are injected into images when they are "
+"launched. Creating a new key pair registers the public key and downloads the "
+"private key (a .pem file)."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
+msgid "Protect and use the key as you would any normal ssh private key."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
+msgid "Add New Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
+msgid "Import Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:24
+msgid "There are currently no keypairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
+msgid "Detach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:6
+msgid "Attachment"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:8
+msgid "Extensions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:20
+msgid "VIF Id"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:36
+msgid "Attach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
+msgid "Create Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:6
+msgid "Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:7
+msgid "Available"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:8
+msgid "Used"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:9
+msgid "Action"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
+msgid "Rename"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
+msgid "Rename Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
+msgid "Port UP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
+msgid "Port DOWN"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
+msgid "Return to networks list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:24
+msgid "Networks provide layer 2 connectivity to your instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "Create Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "There are currently no ports in this network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
+msgid "Create New Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "There are currently no networks."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "Create A Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/rename.html:32
+msgid "Enter a new name for your network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
+msgid "Copy Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_filter.html:7
+msgid "Filter"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:16
+msgid "Copy"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:18
+msgid "Download"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
+msgid "Return to objects list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:26
+msgid ""
+"You may make a new copy of an existing object to store in this or another "
+"container."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
+#, python-format
+msgid ""
+"There are currently no objects in the container %(container_name)s. You can "
+"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
+"Page &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:34
+msgid "Upload New Object &gt;&gt;"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:11
+msgid "Upload Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:25
+msgid ""
+"An object is the basic storage entity and any optional metadata that "
+"represents the files you store in the OpenStack Object Storage system. When "
+"you upload data to OpenStack Object Storage, the data is stored as-is (no "
+"compression or encryption) and consists of a location (container), the "
+"object's name, and any metadata consisting of key/value pairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:12
+msgid "Attach Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
+msgid "Return to network detail"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:42
+msgid ""
+"<p>Select an interface from the list on the left to attach it to this port.</"
+"p>\n"
+" <p>Only interfaces that are not connected to any existing port are "
+"shown</p>\n"
+" <p>If you want to reconnect a connected interface, please detach it "
+"first</p>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/create.html:24
+msgid ""
+"You can plug virtual interfaces from your instances to ports created in the "
+"network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
+msgid "Create Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
+msgid "Edit Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/create.html:22
+msgid "From here you can create a new security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
+msgid "Edit Security Group Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
+msgid "Rules for Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
+msgid "IP Protocol"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
+msgid "From Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
+msgid "To Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
+msgid "CIDR"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
+msgid "No rules for this security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
+msgid "Add a rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
+msgid "Add Rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/index.html:25
+#, python-format
+msgid ""
+"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
+"Security Group &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
+msgid "Create Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:19
+msgid "Create a Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:25
+msgid "Choose a name for your snapshot."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:27
+msgid "Return to snapshots list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:32
+msgid "Snapshots preserve the disk state of a running instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
+#, python-format
+msgid ""
+"There are currently no snapshots. You can create snapshots from running "
+"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/syspanel/dashboard.py:25
+msgid "System Panel"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, python-format
+msgid "%s was successfully added to flavors."
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, python-format
+msgid "Unable to delete flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, python-format
+msgid "Error updating image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+msgid "Image was successfully uploaded."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, python-format
+msgid "Unable to get service info: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, python-format
+msgid "Service '%s' has been enabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:49
+#, python-format
+msgid "Service '%s' has been disabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:55
+#, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
+msgid "Create Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
+msgid "Id"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
+msgid "Memory"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
+msgid "Disk"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
+msgid "From here you can define the sizing of a new flavor."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
+msgid "Create New Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
+msgid "Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
+msgid "Location"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
+msgid "Project ID"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
+msgid "Toggle Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
+msgid "Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
+msgid "Host"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
+msgid "Console Log"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_image_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
+msgid "System Panel Overview"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
+msgid "Active Instances"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
+msgid "This month's VCPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
+msgid "This month's GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
+msgid "Tenant Usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
+msgid "Monitoring"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
+msgid "Select a month to query its usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
+msgid "Server Usage Summary"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
+msgid "RAM"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
+msgid "VCPU CPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
+msgid "Disk GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
+msgid "Default Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
+msgid "Service"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
+msgid "System Stats"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
+msgid "Up"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
+msgid "Hypervisor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
+msgid "Allocable Cores"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
+msgid "Allocable Storage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
+msgid "System Ram"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
+msgid "Enable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
+msgid "Disable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
+msgid "Add"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
+msgid "Options"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
+msgid "View Members"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
+msgid "Modify Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
+msgid "Remove"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
+msgid "Update Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
+msgid "Update Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
+msgid "From here you can create a new tenant (aka project) to organize users."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
+msgid "Create New Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
+msgid "Update Tenant Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
+msgid "From here you can edit a tenant."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
+msgid "Users for Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
+msgid "here are currently no users for this tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
+msgid "Add new users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
+msgid "Create User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
+msgid "Update User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
+msgid ""
+"From here you can create a new user and assign them to a tenant (aka "
+"project)."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
+msgid "Default Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
+msgid "Create New User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
+msgid ""
+"From here you can edit users by changing their usernames, emails, passwords, "
+"and tenants."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:48
+#, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, python-format
+msgid "Unable to create user association: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, python-format
+msgid "Unable to create tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, python-format
+msgid "%s was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, python-format
+msgid "%s was successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, python-format
+msgid "Unable to update tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, python-format
+msgid "Unable to update quotas: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, python-format
+msgid "Error deleting tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/views.py:51
+#, python-format
+msgid "Unable to get tenant info: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, python-format
+msgid "%(user)s was successfully deleted."
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:49
+#, python-format
+msgid "Unable to list users: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+msgid "Unable to update user, please try again."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:113
+#, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:131
+#, python-format
+msgid "User \"%s\" was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, python-format
+msgid "Error creating user: %s"
+msgstr ""
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:50
+#, python-format
+msgid "%(size)d"
+msgid_plural "%(size)d"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:53
+#, python-format
+msgid "%s KB"
+msgstr ""
+
+#: templatetags/sizeformat.py:56
+#, python-format
+msgid "%s MB"
+msgstr ""
+
+#: templatetags/sizeformat.py:59
+#, python-format
+msgid "%s GB"
+msgstr ""
+
+#: templatetags/sizeformat.py:62
+#, python-format
+msgid "%s TB"
+msgstr ""
+
+#: templatetags/sizeformat.py:64
+#, python-format
+msgid "%s PB"
+msgstr ""
+
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, python-format
+msgid "Error authenticating: %s"
+msgstr ""
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
diff --git a/django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.mo b/horizon/horizon/locale/fr/LC_MESSAGES/django.mo
index f444aa74..b469bff6 100644
--- a/django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/fr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/horizon/horizon/locale/fr/LC_MESSAGES/django.po b/horizon/horizon/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 00000000..94a9530a
--- /dev/null
+++ b/horizon/horizon/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,1971 @@
+# Translations of Dashboard for OpenStack User Interface.
+# Copyright 2011 Midokura KK
+# This file is distributed under the same license as the Dashboard for OpenStack.
+# FIRST AUTHOR Jeffrey Wilcox, 2011.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: openstack-dashboard\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-11-01 23:07-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n>1;\n"
+
+#: context_processors.py:35
+#, python-format
+msgid ""
+"Unable to retrieve tenant list from "
+"keystone: %s"
+msgstr ""
+
+#: forms.py:180
+#, python-format
+msgid "Unexpected error: %s"
+msgstr ""
+
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
+msgstr ""
+
+#: api/keystone.py:199
+#, python-format
+msgid "Role does not exist: %s"
+msgstr ""
+
+#: api/keystone.py:207
+#, python-format
+msgid "Role \"%s\" does not exist for that user on this tenant."
+msgstr ""
+
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+msgid "Network"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:22
+#, python-format
+msgid "Unable to delete non-empty container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:28
+#, python-format
+msgid "Successfully deleted container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:34
+msgid "Container Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:38
+msgid "Container was successfully created."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, python-format
+msgid "Successfully deleted object: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+msgid "Object was successfully uploaded."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
+#, python-format
+msgid "Successfully released Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:47
+#, python-format
+msgid "Error releasing Floating IP from tenant: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
+msgid "Instance"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:72
+#, python-format
+msgid ""
+"Successfully associated Floating IP: "
+"%(ip)s with Instance: %(inst)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:78
+#, python-format
+msgid "Error associating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:95
+#, python-format
+msgid "Successfully disassociated Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:99
+#, python-format
+msgid "Error disassociating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:114
+#, python-format
+msgid ""
+"Successfully allocated Floating IP \"%(ip)s\" "
+"to tenant \"%(tenant)s\""
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:120
+#, python-format
+msgid ""
+"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
+"\": %(msg)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/views.py:53
+#, python-format
+msgid "Error fetching floating ips: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
+msgid "Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
+msgid "Kernel ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
+msgid "Ramdisk ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
+msgid "Architecture"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
+msgid "Container Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
+msgid "Disk Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
+#, python-format
+msgid "Unable to retreive image info from glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:57
+#, python-format
+msgid "Error updating image with id: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
+msgid "Error connecting to glance"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
+msgid "Image was successfully updated."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:97
+msgid "Unspecified Exception in image update"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:101
+msgid ""
+"Unable to update image. You are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:107
+msgid "Server Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:111
+msgid "User Data"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
+msgid "Flavor"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:126
+msgid "Key Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
+msgid "Security Groups"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:165
+msgid "Instance was successfully launched"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:174
+#, python-format
+msgid "Unable to launch instance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:188
+msgid ""
+"Unable to delete image, you are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
+#, python-format
+msgid "Error connecting to glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:198
+msgid "Error deleting image: %(image)s: %i(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
+msgid "There are currently no images."
+msgstr ""
+
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
+#, python-format
+msgid "Error retrieving image list: %s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:118
+#, python-format
+msgid "Error parsing quota for %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
+#, python-format
+msgid "Error retrieving image %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:25
+#, python-format
+msgid "ApiException while terminating instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:28
+#, python-format
+msgid "Unable to terminate %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:31
+#, python-format
+msgid "Instance %s has been terminated."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:45
+msgid "Instance rebooting"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:47
+#, python-format
+msgid "ApiException while rebooting instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:50
+#, python-format
+msgid "Unable to reboot instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:53
+#, python-format
+msgid "Instance %s has been rebooted."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:75
+#, python-format
+msgid "Instance '%s' updated"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:79
+#, python-format
+msgid "Unable to update instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:55
+msgid "Exception in instance index"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
+#, python-format
+msgid "Unable to get instance list: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:110
+msgid "ApiException in instance usage"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, python-format
+msgid "Unable to get usage info: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:174
+msgid "ApiException while fetching instance console"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:176
+#, python-format
+msgid "Unable to get log for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:190
+msgid "ApiException while fetching instance vnc connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
+msgid "ApiException while fetching instance info"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:235
+msgid ""
+"ApiException while fetching instance vnc "
+"connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:238
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:244
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:24
+#, python-format
+msgid "Successfully deleted keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:29
+#, python-format
+msgid "Error deleting keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
+msgid "Keypair Name"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:50
+#, python-format
+msgid "Error Creating Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:58
+msgid "Public Key"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:64
+#, python-format
+msgid "Successfully imported public key: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:70
+#, python-format
+msgid "Error Importing Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/views.py:53
+#, python-format
+msgid "Error fetching keypairs: %s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:15
+msgid "Network Name"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:26
+#, python-format
+msgid "Unable to create network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:30
+#, python-format
+msgid "Network %s has been created."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:45
+#, python-format
+msgid "Unable to delete network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:48
+#, python-format
+msgid "Network %s has been deleted."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:67
+#, python-format
+msgid "Unable to rename network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:70
+#, python-format
+msgid "Network %(net)s has been renamed to %(new_name)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:80
+msgid "Number of Ports"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:90
+#, python-format
+msgid "Unable to create ports on network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:93
+#, python-format
+msgid "%(num_ports)s ports created on network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:112
+#, python-format
+msgid "Unable to delete port %(port)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:115
+#, python-format
+msgid "Port %(port)s deleted from network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:126
+msgid "Select VIF to connect"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:137
+#, python-format
+msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:142
+#, python-format
+msgid "Port %(port)s connected to VIF %(vif)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:159
+#, python-format
+msgid "Unable to detach port %(port)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:162
+#, python-format
+msgid "Port %s detached."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:181
+#, python-format
+msgid "Unable to set port state to %(state)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:184
+#, python-format
+msgid "Port %(port)s state set to %(state)s."
+msgstr ""
+
+#: dashboards/dash/networks/views.py:68
+#, python-format
+msgid "Unable to get network list: %s"
+msgstr ""
+
+#: dashboards/dash/networks/views.py:104
+#, python-format
+msgid "Unable to get network details: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:48
+#, python-format
+msgid "Successfully created security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:53
+#, python-format
+msgid "Error creating security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:67
+#, python-format
+msgid "Successfully deleted security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:71
+#, python-format
+msgid "Error deleting security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:100
+#, python-format
+msgid "Successfully added rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:104
+#, python-format
+msgid "Error adding rule security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:122
+#, python-format
+msgid "Successfully deleted rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:126
+#, python-format
+msgid "Error authorizing security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:54
+#, python-format
+msgid "Error fetching security_groups: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:82
+#, python-format
+msgid "Error getting security_group: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:19
+msgid "Snapshot Name"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:30
+#, python-format
+msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:34
+#, python-format
+msgid "Error Creating Snapshot: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:76
+#, python-format
+msgid "Unable to retreive instance: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:83
+#, python-format
+msgid ""
+"To snapshot, instance state must be one of "
+"the following: %s"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
+msgid "Dashboard Settings"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
+msgid "Dashboard User Interface Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
+msgid "Select Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
+msgid "Delete"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_form.html:10
+msgid "Create Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
+msgid "Actions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:17
+msgid "List Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
+msgid "Upload Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
+msgid "Create Tenant"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:22
+msgid ""
+"A container is a storage compartment for your data and provides a way for "
+"you to organize your data. You can think of a container as a folder in "
+"Windows® or a directory in UNIX®. The primary difference between a container "
+"and these other file system concepts is that containers cannot be nested. "
+"You can, however, create an unlimited number of containers within your "
+"account. Data must be stored in a container so you must have at least one "
+"container defined in your account prior to uploading data."
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/index.html:18
+msgid "Create New Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
+msgid "Allocate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
+msgid "Associate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
+msgid "Disassociate"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
+msgid "Instance ID:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
+msgid "Fixed IP:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
+msgid "Associate to instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
+msgid "Release"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
+msgid "Associate Floating IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
+msgid "Description:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
+msgid "Associate a floating ip with an instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
+msgid "Info"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
+msgid "There are currently no floating ips assigned to your tenant."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
+msgid "Update Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
+msgid "Launch Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
+msgid "Created"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
+msgid "Updated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
+msgid "Status"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
+msgid "Edit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:24
+msgid "Launch"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:22
+msgid ""
+"Specify the details for launching an instance. Also please make note of the "
+"table below; all tenants have quotas which define the limit of resources you "
+"are allowed to provision."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
+msgid "Quota Name"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
+msgid "Limit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:29
+msgid "RAM (MB)"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
+msgid "From here you can modify different properties of an image."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
+msgid "Update Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:8
+msgid "Groups"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
+msgid "Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
+msgid "Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
+msgid "IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
+msgid "State"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:66
+msgid "Log"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
+msgid "VNC Console"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:69
+msgid "Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:19
+msgid "Return to Instances List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:24
+msgid "Update the name and description of your instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
+msgid "Download CSV"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:50
+msgid "Hide Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:52
+msgid "Show Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
+msgid "User"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
+msgid "Ram Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
+msgid "Disk Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
+msgid "Uptime"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:89
+msgid "No active instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:98
+#, python-format
+msgid ""
+"There are currently no instances.<br/><br/>You can launch an instance from "
+"the <a href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
+msgid "Add Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
+msgid "Fingerprint"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
+msgid "Create Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:30
+msgid "Your private key is being downloaded."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
+msgid "Return to keypairs list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
+msgid ""
+"Keypairs are ssh credentials which are injected into images when they are "
+"launched. Creating a new key pair registers the public key and downloads the "
+"private key (a .pem file)."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
+msgid "Protect and use the key as you would any normal ssh private key."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
+msgid "Add New Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
+msgid "Import Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:24
+msgid "There are currently no keypairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
+msgid "Detach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:6
+msgid "Attachment"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:8
+msgid "Extensions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:20
+msgid "VIF Id"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:36
+msgid "Attach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
+msgid "Create Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:6
+msgid "Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:7
+msgid "Available"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:8
+msgid "Used"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:9
+msgid "Action"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
+msgid "Rename"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
+msgid "Rename Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
+msgid "Port UP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
+msgid "Port DOWN"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
+msgid "Return to networks list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:24
+msgid "Networks provide layer 2 connectivity to your instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "Create Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "There are currently no ports in this network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
+msgid "Create New Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "There are currently no networks."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "Create A Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/rename.html:32
+msgid "Enter a new name for your network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
+msgid "Copy Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_filter.html:7
+msgid "Filter"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:16
+msgid "Copy"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:18
+msgid "Download"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
+msgid "Return to objects list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:26
+msgid ""
+"You may make a new copy of an existing object to store in this or another "
+"container."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
+#, python-format
+msgid ""
+"There are currently no objects in the container %(container_name)s. You can "
+"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
+"Page &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:34
+msgid "Upload New Object &gt;&gt;"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:11
+msgid "Upload Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:25
+msgid ""
+"An object is the basic storage entity and any optional metadata that "
+"represents the files you store in the OpenStack Object Storage system. When "
+"you upload data to OpenStack Object Storage, the data is stored as-is (no "
+"compression or encryption) and consists of a location (container), the "
+"object's name, and any metadata consisting of key/value pairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:12
+msgid "Attach Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
+msgid "Return to network detail"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:42
+msgid ""
+"<p>Select an interface from the list on the left to attach it to this port.</"
+"p>\n"
+" <p>Only interfaces that are not connected to any existing port are "
+"shown</p>\n"
+" <p>If you want to reconnect a connected interface, please detach it "
+"first</p>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/create.html:24
+msgid ""
+"You can plug virtual interfaces from your instances to ports created in the "
+"network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
+msgid "Create Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
+msgid "Edit Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/create.html:22
+msgid "From here you can create a new security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
+msgid "Edit Security Group Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
+msgid "Rules for Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
+msgid "IP Protocol"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
+msgid "From Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
+msgid "To Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
+msgid "CIDR"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
+msgid "No rules for this security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
+msgid "Add a rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
+msgid "Add Rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/index.html:25
+#, python-format
+msgid ""
+"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
+"Security Group &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
+msgid "Create Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:19
+msgid "Create a Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:25
+msgid "Choose a name for your snapshot."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:27
+msgid "Return to snapshots list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:32
+msgid "Snapshots preserve the disk state of a running instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
+#, python-format
+msgid ""
+"There are currently no snapshots. You can create snapshots from running "
+"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/syspanel/dashboard.py:25
+msgid "System Panel"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, python-format
+msgid "%s was successfully added to flavors."
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, python-format
+msgid "Unable to delete flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, python-format
+msgid "Error updating image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+msgid "Image was successfully uploaded."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, python-format
+msgid "Unable to get service info: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, python-format
+msgid "Service '%s' has been enabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:49
+#, python-format
+msgid "Service '%s' has been disabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:55
+#, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
+msgid "Create Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
+msgid "Id"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
+msgid "Memory"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
+msgid "Disk"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
+msgid "From here you can define the sizing of a new flavor."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
+msgid "Create New Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
+msgid "Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
+msgid "Location"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
+msgid "Project ID"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
+msgid "Toggle Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
+msgid "Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
+msgid "Host"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
+msgid "Console Log"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_image_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
+msgid "System Panel Overview"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
+msgid "Active Instances"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
+msgid "This month's VCPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
+msgid "This month's GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
+msgid "Tenant Usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
+msgid "Monitoring"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
+msgid "Select a month to query its usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
+msgid "Server Usage Summary"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
+msgid "RAM"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
+msgid "VCPU CPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
+msgid "Disk GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
+msgid "Default Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
+msgid "Service"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
+msgid "System Stats"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
+msgid "Up"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
+msgid "Hypervisor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
+msgid "Allocable Cores"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
+msgid "Allocable Storage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
+msgid "System Ram"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
+msgid "Enable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
+msgid "Disable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
+msgid "Add"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
+msgid "Options"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
+msgid "View Members"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
+msgid "Modify Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
+msgid "Remove"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
+msgid "Update Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
+msgid "Update Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
+msgid "From here you can create a new tenant (aka project) to organize users."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
+msgid "Create New Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
+msgid "Update Tenant Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
+msgid "From here you can edit a tenant."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
+msgid "Users for Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
+msgid "here are currently no users for this tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
+msgid "Add new users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
+msgid "Create User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
+msgid "Update User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
+msgid ""
+"From here you can create a new user and assign them to a tenant (aka "
+"project)."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
+msgid "Default Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
+msgid "Create New User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
+msgid ""
+"From here you can edit users by changing their usernames, emails, passwords, "
+"and tenants."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:48
+#, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, python-format
+msgid "Unable to create user association: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, python-format
+msgid "Unable to create tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, python-format
+msgid "%s was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, python-format
+msgid "%s was successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, python-format
+msgid "Unable to update tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, python-format
+msgid "Unable to update quotas: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, python-format
+msgid "Error deleting tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/views.py:51
+#, python-format
+msgid "Unable to get tenant info: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, python-format
+msgid "%(user)s was successfully deleted."
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:49
+#, python-format
+msgid "Unable to list users: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+msgid "Unable to update user, please try again."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:113
+#, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:131
+#, python-format
+msgid "User \"%s\" was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, python-format
+msgid "Error creating user: %s"
+msgstr ""
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:50
+#, python-format
+msgid "%(size)d"
+msgid_plural "%(size)d"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:53
+#, python-format
+msgid "%s KB"
+msgstr ""
+
+#: templatetags/sizeformat.py:56
+#, python-format
+msgid "%s MB"
+msgstr ""
+
+#: templatetags/sizeformat.py:59
+#, python-format
+msgid "%s GB"
+msgstr ""
+
+#: templatetags/sizeformat.py:62
+#, python-format
+msgid "%s TB"
+msgstr ""
+
+#: templatetags/sizeformat.py:64
+#, python-format
+msgid "%s PB"
+msgstr ""
+
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, python-format
+msgid "Error authenticating: %s"
+msgstr ""
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
diff --git a/horizon/horizon/locale/ja/LC_MESSAGES/django.mo b/horizon/horizon/locale/ja/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..59ebb941
--- /dev/null
+++ b/horizon/horizon/locale/ja/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.po b/horizon/horizon/locale/ja/LC_MESSAGES/django.po
index 0a3b25d4..29d273b3 100644
--- a/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.po
+++ b/horizon/horizon/locale/ja/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: openstack-dashboard\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
+"POT-Creation-Date: 2011-11-01 23:08-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Takeshi Nakajima <tnakaji@midokura.jp>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,18 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: api.py:1002 syspanel/views/services.py:88
-#, fuzzy, python-format
-msgid "Unable to get service info: %s"
-msgstr "セキュリティグループ%sを作成できません。"
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, fuzzy, python-format
-msgid "Unable to get usage info: %s"
-msgstr "イメージ%sを公開できません。"
-
-#: context_processors.py:34
+#: context_processors.py:35
#, python-format
msgid ""
"Unable to retrieve tenant list from "
@@ -41,1063 +30,713 @@ msgstr ""
msgid "Unexpected error: %s"
msgstr ""
-#: auth/views.py:38
-msgid "User Name"
-msgstr "ユーザ名"
-
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr "パスワード"
-
-#: auth/views.py:83
-#, python-format
-msgid "No tenants present for user: %(user)s"
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
msgstr ""
-#: auth/views.py:105
+#: api/keystone.py:199
#, fuzzy, python-format
-msgid "Error authenticating: %s"
-msgstr "ユーザが認証されておりません。"
+msgid "Role does not exist: %s"
+msgstr "プロジェクト%sは存在しません。"
-#: auth/views.py:110
+#: api/keystone.py:207
#, python-format
-msgid "Error authenticating with keystone: %s"
+msgid "Role \"%s\" does not exist for that user on this tenant."
msgstr ""
-#: dash/views/containers.py:49
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+#, fuzzy
+msgid "Network"
+msgstr "ネットワーク"
+
+#: dashboards/dash/dashboard.py:29
+#, fuzzy
+msgid "Object Store"
+msgstr "ユーザ名"
+
+#: dashboards/dash/containers/forms.py:22
#, fuzzy, python-format
msgid "Unable to delete non-empty container: %s"
msgstr "キー%sを削除できません。"
-#: dash/views/containers.py:55
+#: dashboards/dash/containers/forms.py:28
#, fuzzy, python-format
msgid "Successfully deleted container: %s"
msgstr "プロジェクト%(proj)sを正常に修正しました。"
-#: dash/views/containers.py:61
+#: dashboards/dash/containers/forms.py:34
#, fuzzy
msgid "Container Name"
msgstr "ユーザ名"
-#: dash/views/containers.py:65
+#: dashboards/dash/containers/forms.py:38
#, fuzzy
msgid "Container was successfully created."
msgstr "ボリューム %(id)s %(name)s は正常に作成されました。"
-#: dash/views/floating_ips.py:47
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, fuzzy, python-format
+msgid "Successfully deleted object: %s"
+msgstr "プロジェクト%(proj)sを正常に修正しました。"
+
+#: dashboards/dash/containers/forms.py:77
+#, fuzzy
+msgid "Object Name"
+msgstr "ユーザ名"
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+#, fuzzy
+msgid "Object was successfully uploaded."
+msgstr "セキュリティグループ%sが正常に削除されました。"
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
#, python-format
msgid "Successfully released Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:51
+#: dashboards/dash/floating_ips/forms.py:47
#, python-format
msgid "Error releasing Floating IP from tenant: %s"
msgstr ""
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
#, fuzzy
msgid "Instance"
msgstr "インスタンス"
-#: dash/views/floating_ips.py:76
+#: dashboards/dash/floating_ips/forms.py:72
#, python-format
msgid ""
"Successfully associated Floating IP: "
"%(ip)s with Instance: %(inst)s"
msgstr ""
-#: dash/views/floating_ips.py:82
+#: dashboards/dash/floating_ips/forms.py:78
#, fuzzy, python-format
msgid "Error associating Floating IP: %s"
msgstr "イメージ%sを更新できません。"
-#: dash/views/floating_ips.py:99
+#: dashboards/dash/floating_ips/forms.py:95
#, python-format
msgid "Successfully disassociated Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:103
+#: dashboards/dash/floating_ips/forms.py:99
#, python-format
msgid "Error disassociating Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:118
+#: dashboards/dash/floating_ips/forms.py:114
#, python-format
msgid ""
"Successfully allocated Floating IP \"%(ip)s\" "
"to tenant \"%(tenant)s\""
msgstr ""
-#: dash/views/floating_ips.py:124
+#: dashboards/dash/floating_ips/forms.py:120
#, python-format
msgid ""
"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
"\": %(msg)s"
msgstr ""
-#: dash/views/floating_ips.py:142
+#: dashboards/dash/floating_ips/views.py:53
#, python-format
msgid "Error fetching floating ips: %s"
msgstr ""
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
msgid "Name"
msgstr "名前"
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
msgid "Kernel ID"
msgstr ""
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
msgid "Ramdisk ID"
msgstr ""
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
msgid "Architecture"
msgstr ""
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
msgid "Container Format"
msgstr ""
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
msgid "Disk Format"
msgstr ""
-#: dash/views/images.py:59 dash/views/images.py:233
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
#, fuzzy, python-format
msgid "Unable to retreive image info from glance: %s"
msgstr "イメージ%sの登録削除ができませんでした。"
-#: dash/views/images.py:61
+#: dashboards/dash/images/forms.py:57
#, python-format
msgid "Error updating image with id: %s"
msgstr ""
-#: dash/views/images.py:66 dash/views/images.py:95
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
msgid "Error connecting to glance"
msgstr ""
-#: dash/views/images.py:92 syspanel/views/images.py:159
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
#, fuzzy
msgid "Image was successfully updated."
msgstr "イメージ%sが正常に登録削除されました。"
-#: dash/views/images.py:101
+#: dashboards/dash/images/forms.py:97
msgid "Unspecified Exception in image update"
msgstr ""
-#: dash/views/images.py:105
+#: dashboards/dash/images/forms.py:101
msgid ""
"Unable to update image. You are not "
"its owner."
msgstr ""
-#: dash/views/images.py:111
+#: dashboards/dash/images/forms.py:107
#, fuzzy
msgid "Server Name"
msgstr "ユーザ名"
-#: dash/views/images.py:115
+#: dashboards/dash/images/forms.py:111
#, fuzzy
msgid "User Data"
msgstr "ユーザ名"
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
msgid "Flavor"
msgstr ""
-#: dash/views/images.py:130
+#: dashboards/dash/images/forms.py:126
#, fuzzy
msgid "Key Name"
msgstr "ユーザ名"
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
msgid "Security Groups"
msgstr "セキュリティグループ"
-#: dash/views/images.py:169
+#: dashboards/dash/images/forms.py:165
#, fuzzy
msgid "Instance was successfully launched"
msgstr "イメージ%sが正常に登録削除されました。"
-#: dash/views/images.py:178
+#: dashboards/dash/images/forms.py:174
#, fuzzy, python-format
msgid "Unable to launch instance: %s"
msgstr "イメージ%sを更新できません。"
-#: dash/views/images.py:192
+#: dashboards/dash/images/forms.py:188
msgid ""
"Unable to delete image, you are not "
"its owner."
msgstr ""
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
#, python-format
msgid "Error connecting to glance: %s"
msgstr ""
-#: dash/views/images.py:202
+#: dashboards/dash/images/forms.py:198
#, fuzzy
msgid "Error deleting image: %(image)s: %i(msg)s"
msgstr "イメージ%sを更新できません。"
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
#, fuzzy
msgid "There are currently no images."
msgstr "キーペアが存在しません。"
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
#, python-format
msgid "Error retrieving image list: %s"
msgstr ""
-#: dash/views/images.py:290
+#: dashboards/dash/images/views.py:118
#, fuzzy, python-format
msgid "Error parsing quota for %(image)s: %(msg)s"
msgstr "イメージ%sを更新できません。"
-#: dash/views/images.py:323 syspanel/views/images.py:134
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
#, python-format
msgid "Error retrieving image %(image)s: %(msg)s"
msgstr ""
-#: dash/views/instances.py:55
+#: dashboards/dash/instances/forms.py:25
#, python-format
msgid "ApiException while terminating instance \"%s\""
msgstr ""
-#: dash/views/instances.py:58
+#: dashboards/dash/instances/forms.py:28
#, python-format
msgid "Unable to terminate %(inst)s: %(message)s"
msgstr "(%(inst)s: %(message)sを停止する事ができません。"
-#: dash/views/instances.py:61
+#: dashboards/dash/instances/forms.py:31
#, python-format
msgid "Instance %s has been terminated."
msgstr "インスタンス%sは停止されました。"
-#: dash/views/instances.py:75
+#: dashboards/dash/instances/forms.py:45
#, fuzzy
msgid "Instance rebooting"
msgstr "インスタンス%(inst)sが更新されました。"
-#: dash/views/instances.py:77
+#: dashboards/dash/instances/forms.py:47
#, fuzzy, python-format
msgid "ApiException while rebooting instance \"%s\""
msgstr "%sをリボーク(無効化)できません。"
-#: dash/views/instances.py:80
+#: dashboards/dash/instances/forms.py:50
#, fuzzy, python-format
msgid "Unable to reboot instance: %s"
msgstr "%sをリボーク(無効化)できません。"
-#: dash/views/instances.py:83
+#: dashboards/dash/instances/forms.py:53
#, fuzzy, python-format
msgid "Instance %s has been rebooted."
msgstr "インスタンス%(inst)sが更新されました。"
-#: dash/views/instances.py:105
+#: dashboards/dash/instances/forms.py:75
#, fuzzy, python-format
msgid "Instance '%s' updated"
msgstr "インスタンス%sが開始しました。"
-#: dash/views/instances.py:109
+#: dashboards/dash/instances/forms.py:79
#, fuzzy, python-format
msgid "Unable to update instance: %s"
msgstr "イメージ%sを更新できません。"
-#: dash/views/instances.py:124
+#: dashboards/dash/instances/views.py:55
msgid "Exception in instance index"
msgstr ""
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
#, fuzzy, python-format
msgid "Unable to get instance list: %s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/instances.py:178
+#: dashboards/dash/instances/views.py:110
msgid "ApiException in instance usage"
msgstr ""
-#: dash/views/instances.py:241
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, fuzzy, python-format
+msgid "Unable to get usage info: %s"
+msgstr "イメージ%sを公開できません。"
+
+#: dashboards/dash/instances/views.py:174
msgid "ApiException while fetching instance console"
msgstr ""
-#: dash/views/instances.py:243
+#: dashboards/dash/instances/views.py:176
#, fuzzy, python-format
msgid "Unable to get log for instance %(inst)s: %(msg)s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/instances.py:256
+#: dashboards/dash/instances/views.py:190
msgid "ApiException while fetching instance vnc connection"
msgstr ""
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
#, fuzzy, python-format
msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/instances.py:268 dash/views/instances.py:307
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
msgid "ApiException while fetching instance info"
msgstr ""
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
#, fuzzy, python-format
msgid "Unable to get information for instance %(inst)s: %(message)s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/instances.py:300
+#: dashboards/dash/instances/views.py:235
msgid ""
"ApiException while fetching instance vnc "
"connection"
msgstr ""
-#: dash/views/instances.py:303
+#: dashboards/dash/instances/views.py:238
#, fuzzy, python-format
msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/instances.py:309
+#: dashboards/dash/instances/views.py:244
#, fuzzy, python-format
msgid "Unable to get information for instance %(inst)s: %(msg)s"
msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: dash/views/keypairs.py:49
+#: dashboards/dash/keypairs/forms.py:24
#, fuzzy, python-format
msgid "Successfully deleted keypair: %s"
msgstr "プロジェクト%(proj)sを正常に修正しました。"
-#: dash/views/keypairs.py:54
+#: dashboards/dash/keypairs/forms.py:29
#, fuzzy, python-format
msgid "Error deleting keypair: %s"
msgstr "キー%sを削除できません。"
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
#, fuzzy
msgid "Keypair Name"
msgstr "キーペア"
-#: dash/views/keypairs.py:75
+#: dashboards/dash/keypairs/forms.py:50
#, python-format
msgid "Error Creating Keypair: %s"
msgstr ""
-#: dash/views/keypairs.py:83
+#: dashboards/dash/keypairs/forms.py:58
#, fuzzy
msgid "Public Key"
msgstr "公開する"
-#: dash/views/keypairs.py:89
+#: dashboards/dash/keypairs/forms.py:64
#, python-format
msgid "Successfully imported public key: %s"
msgstr ""
-#: dash/views/keypairs.py:95
+#: dashboards/dash/keypairs/forms.py:70
#, python-format
msgid "Error Importing Keypair: %s"
msgstr ""
-#: dash/views/keypairs.py:111
+#: dashboards/dash/keypairs/views.py:53
#, python-format
msgid "Error fetching keypairs: %s"
msgstr ""
-#: dash/views/networks.py:49
+#: dashboards/dash/networks/forms.py:15
#, fuzzy
msgid "Network Name"
msgstr "ネットワーク"
-#: dash/views/networks.py:60
+#: dashboards/dash/networks/forms.py:26
#, fuzzy, python-format
msgid "Unable to create network %(network)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/networks.py:64
+#: dashboards/dash/networks/forms.py:30
#, fuzzy, python-format
msgid "Network %s has been created."
msgstr "イメージ%sが更新されました。"
-#: dash/views/networks.py:80
+#: dashboards/dash/networks/forms.py:45
#, fuzzy, python-format
msgid "Unable to delete network %(network)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/networks.py:83
+#: dashboards/dash/networks/forms.py:48
#, fuzzy, python-format
msgid "Network %s has been deleted."
msgstr "イメージ%sが更新されました。"
-#: dash/views/networks.py:102
+#: dashboards/dash/networks/forms.py:67
#, fuzzy, python-format
msgid "Unable to rename network %(network)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/networks.py:105
+#: dashboards/dash/networks/forms.py:70
#, python-format
msgid "Network %(net)s has been renamed to %(new_name)s."
msgstr ""
-#: dash/views/networks.py:138
-#, fuzzy, python-format
-msgid "Unable to get network list: %s"
-msgstr "%sをリボーク(無効化)できません。"
-
-#: dash/views/networks.py:174
-#, fuzzy, python-format
-msgid "Unable to get network details: %s"
-msgstr "%sをリボーク(無効化)できません。"
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, fuzzy, python-format
-msgid "Successfully deleted object: %s"
-msgstr "プロジェクト%(proj)sを正常に修正しました。"
-
-#: dash/views/objects.py:76
-#, fuzzy
-msgid "Object Name"
-msgstr "ユーザ名"
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-#, fuzzy
-msgid "Object was successfully uploaded."
-msgstr "セキュリティグループ%sが正常に削除されました。"
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
+#: dashboards/dash/networks/forms.py:80
msgid "Number of Ports"
msgstr ""
-#: dash/views/ports.py:53
+#: dashboards/dash/networks/forms.py:90
#, fuzzy, python-format
msgid "Unable to create ports on network %(network)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/ports.py:56
+#: dashboards/dash/networks/forms.py:93
#, python-format
msgid "%(num_ports)s ports created on network %(network)s."
msgstr ""
-#: dash/views/ports.py:75
+#: dashboards/dash/networks/forms.py:112
#, fuzzy, python-format
msgid "Unable to delete port %(port)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/ports.py:78
+#: dashboards/dash/networks/forms.py:115
#, python-format
msgid "Port %(port)s deleted from network %(network)s."
msgstr ""
-#: dash/views/ports.py:89
+#: dashboards/dash/networks/forms.py:126
msgid "Select VIF to connect"
msgstr ""
-#: dash/views/ports.py:100
+#: dashboards/dash/networks/forms.py:137
#, fuzzy, python-format
msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/ports.py:103
+#: dashboards/dash/networks/forms.py:142
#, python-format
msgid "Port %(port)s connected to VIF %(vif)s."
msgstr ""
-#: dash/views/ports.py:120
+#: dashboards/dash/networks/forms.py:159
#, fuzzy, python-format
msgid "Unable to detach port %(port)s: %(message)s"
msgstr "(%(inst)s: %(msg)sを停止する事ができません。"
-#: dash/views/ports.py:123
+#: dashboards/dash/networks/forms.py:162
#, python-format
msgid "Port %s detached."
msgstr ""
-#: dash/views/ports.py:142
+#: dashboards/dash/networks/forms.py:181
#, fuzzy, python-format
msgid "Unable to set port state to %(state)s: %(message)s"
msgstr "(%(inst)s: %(message)sを停止する事ができません。"
-#: dash/views/ports.py:145
+#: dashboards/dash/networks/forms.py:184
#, python-format
msgid "Port %(port)s state set to %(state)s."
msgstr ""
-#: dash/views/security_groups.py:56
+#: dashboards/dash/networks/views.py:68
+#, fuzzy, python-format
+msgid "Unable to get network list: %s"
+msgstr "%sをリボーク(無効化)できません。"
+
+#: dashboards/dash/networks/views.py:104
+#, fuzzy, python-format
+msgid "Unable to get network details: %s"
+msgstr "%sをリボーク(無効化)できません。"
+
+#: dashboards/dash/security_groups/forms.py:48
#, fuzzy, python-format
msgid "Successfully created security_group: %s"
msgstr "セキュリティグループ%sを作成できません。"
-#: dash/views/security_groups.py:62
+#: dashboards/dash/security_groups/forms.py:53
#, fuzzy, python-format
msgid "Error creating security group: %s"
msgstr "セキュリティグループ%sを作成できません。"
-#: dash/views/security_groups.py:76
+#: dashboards/dash/security_groups/forms.py:67
#, fuzzy, python-format
msgid "Successfully deleted security_group: %s"
msgstr "セキュリティグループ%sを削除できません"
-#: dash/views/security_groups.py:80
+#: dashboards/dash/security_groups/forms.py:71
#, fuzzy, python-format
msgid "Error deleting security group: %s"
msgstr "セキュリティグループ%sを削除できません"
-#: dash/views/security_groups.py:109
+#: dashboards/dash/security_groups/forms.py:100
#, fuzzy, python-format
msgid "Successfully added rule: %s"
msgstr "プロジェクト%(proj)sを正常に修正しました。"
-#: dash/views/security_groups.py:113
+#: dashboards/dash/security_groups/forms.py:104
#, fuzzy, python-format
msgid "Error adding rule security group: %s"
msgstr "セキュリティグループ%sを削除できません"
-#: dash/views/security_groups.py:131
+#: dashboards/dash/security_groups/forms.py:122
#, fuzzy, python-format
msgid "Successfully deleted rule: %s"
msgstr "プロジェクト%(proj)sを正常に修正しました。"
-#: dash/views/security_groups.py:135
+#: dashboards/dash/security_groups/forms.py:126
#, fuzzy, python-format
msgid "Error authorizing security group: %s"
msgstr "セキュリティグループ%sを作成できません。"
-#: dash/views/security_groups.py:153
+#: dashboards/dash/security_groups/views.py:54
#, fuzzy, python-format
msgid "Error fetching security_groups: %s"
msgstr "セキュリティグループ%sを作成できません。"
-#: dash/views/security_groups.py:181
+#: dashboards/dash/security_groups/views.py:82
#, fuzzy, python-format
msgid "Error getting security_group: %s"
msgstr "セキュリティグループ%sを作成できません。"
-#: dash/views/snapshots.py:51
+#: dashboards/dash/snapshots/forms.py:19
#, fuzzy
msgid "Snapshot Name"
msgstr "スナップショット"
-#: dash/views/snapshots.py:62
+#: dashboards/dash/snapshots/forms.py:30
#, python-format
msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
msgstr ""
-#: dash/views/snapshots.py:66
+#: dashboards/dash/snapshots/forms.py:34
#, fuzzy, python-format
msgid "Error Creating Snapshot: %s"
msgstr "ユーザ%sを作成中..."
-#: dash/views/snapshots.py:104
+#: dashboards/dash/snapshots/views.py:76
#, fuzzy, python-format
msgid "Unable to retreive instance: %s"
msgstr "%sをリボーク(無効化)できません。"
-#: dash/views/snapshots.py:111
+#: dashboards/dash/snapshots/views.py:83
#, python-format
msgid ""
"To snapshot, instance state must be one of "
"the following: %s"
msgstr ""
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-#, fuzzy
-msgid "Flavor ID"
-msgstr "インスタンスタイプ"
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, fuzzy, python-format
-msgid "%s was successfully added to flavors."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, fuzzy, python-format
-msgid "Unable to delete flavor: %s"
-msgstr "ボリューム%sを削除できません。"
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, fuzzy, python-format
-msgid "Error updating image: %s"
-msgstr "イメージ%sを更新できません。"
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-#, fuzzy
-msgid "Image was successfully uploaded."
-msgstr "イメージ%sが正常に登録削除されました。"
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, fuzzy, python-format
-msgid "Service '%s' has been enabled"
-msgstr "イメージ%sが更新されました。"
-
-#: syspanel/views/services.py:62
-#, fuzzy, python-format
-msgid "Service '%s' has been disabled"
-msgstr "イメージ%sが更新されました。"
-
-#: syspanel/views/services.py:68
-#, fuzzy, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-
-#: syspanel/views/tenants.py:57
-#, fuzzy, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/tenants.py:60
-#, fuzzy, python-format
-msgid "Unable to create user association: %s"
-msgstr "セキュリティグループ%sを作成できません。"
-
-#: syspanel/views/tenants.py:77
-#, fuzzy, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, fuzzy, python-format
-msgid "Unable to create tenant: %s"
-msgstr "キー%sを作成できません。"
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr "説明"
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, fuzzy, python-format
-msgid "%s was successfully created."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, fuzzy, python-format
-msgid "%s was successfully updated."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, fuzzy, python-format
-msgid "Unable to update tenant: %s"
-msgstr "イメージ%sを更新できません。"
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr "インスタンス"
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr "ボリューム"
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, fuzzy, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr "セキュリティグループ%sが正常に削除されました。"
-
-#: syspanel/views/tenants.py:173
-#, fuzzy, python-format
-msgid "Unable to update quotas: %s"
-msgstr "イメージ%sを更新できません。"
-
-#: syspanel/views/tenants.py:183
-#, fuzzy, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr "プロジェクト%(proj)sを正常に修正しました。"
-
-#: syspanel/views/tenants.py:188
-#, fuzzy, python-format
-msgid "Error deleting tenant: %s"
-msgstr "キー%sを削除できません。"
-
-#: syspanel/views/tenants.py:206
-#, fuzzy, python-format
-msgid "Unable to get tenant info: %s"
-msgstr "キー%sを作成できません。"
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-#, fuzzy
-msgid "Primary Tenant"
-msgstr "テナント"
-
-#: syspanel/views/users.py:86
-#, fuzzy, python-format
-msgid "%(user)s was successfully deleted."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, fuzzy, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr "キー%sを削除できません。"
-
-#: syspanel/views/users.py:128
-#, fuzzy, python-format
-msgid "Unable to list users: %s"
-msgstr "キー%sを削除できません。"
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-#, fuzzy
-msgid "Unable to update user, please try again."
-msgstr "イメージ%sを更新できません。"
-
-#: syspanel/views/users.py:194
-#, fuzzy, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr "キー%sを作成できません。"
-
-#: syspanel/views/users.py:212
-#, fuzzy, python-format
-msgid "User \"%s\" was successfully created."
-msgstr "キー%sは正常に削除されました。"
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, fuzzy, python-format
-msgid "Error creating user: %s"
-msgstr "ユーザ%sを作成中..."
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr "検索"
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr "リストを再読み込みする"
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr "削除"
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr "概要"
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr "イメージ"
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr "スナップショット"
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr "キーペア"
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr "ネットワーク"
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
msgid "Dashboard Settings"
msgstr "ダッシュボードの設定"
-#: templates/django_openstack/dash/settings.html:26
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
msgid "Dashboard User Interface Language"
msgstr ""
-#: templates/django_openstack/dash/settings.html:38
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
msgid "Select Language"
msgstr "言語を選択"
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
msgid "Delete"
msgstr "削除"
-#: templates/django_openstack/dash/containers/_form.html:10
+#: dashboards/dash/templates/dash/containers/_form.html:10
msgid "Create Container"
msgstr ""
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
msgid "Actions"
msgstr "アクション"
-#: templates/django_openstack/dash/containers/_list.html:17
+#: dashboards/dash/templates/dash/containers/_list.html:17
msgid "List Objects"
msgstr ""
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
msgid "Upload Object"
msgstr ""
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
msgid "Create Tenant"
msgstr ""
-#: templates/django_openstack/dash/containers/create.html:22
+#: dashboards/dash/templates/dash/containers/create.html:22
msgid ""
"A container is a storage compartment for your data and provides a way for "
"you to organize your data. You can think of a container as a folder in "
@@ -1108,275 +747,354 @@ msgid ""
"container defined in your account prior to uploading data."
msgstr ""
-#: templates/django_openstack/dash/containers/index.html:18
+#: dashboards/dash/templates/dash/containers/index.html:18
#, fuzzy
msgid "Create New Container"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
msgid "Allocate IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
msgid "Associate IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
msgid "Disassociate"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_list.html:14
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
msgid "Instance ID:"
msgstr "インスタンスID:"
-#: templates/django_openstack/dash/floating_ips/_list.html:15
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
msgid "Fixed IP:"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_list.html:28
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
#, fuzzy
msgid "Associate to instance"
msgstr "インスタンスを更新"
-#: templates/django_openstack/dash/floating_ips/_release.html:8
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
msgid "Release"
msgstr "リリース"
-#: templates/django_openstack/dash/floating_ips/associate.html:12
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
msgid "Associate Floating IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
msgid "Description:"
msgstr "説明:"
-#: templates/django_openstack/dash/floating_ips/associate.html:23
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
msgid "Associate a floating ip with an instance."
msgstr ""
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
msgid "Info"
msgstr "情報"
-#: templates/django_openstack/dash/floating_ips/index.html:22
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
msgid "There are currently no floating ips assigned to your tenant."
msgstr ""
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
msgid "Update Image"
msgstr "イメージを更新"
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
msgid "Launch Instance"
msgstr "イメージを起動します。"
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
msgid "Created"
msgstr "作成"
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
msgid "Updated"
msgstr "イメージを更新"
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
msgid "Status"
msgstr "ステータス"
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
msgid "Edit"
msgstr "編集"
-#: templates/django_openstack/dash/images/_list.html:24
+#: dashboards/dash/templates/dash/images/_list.html:24
#, fuzzy
msgid "Launch"
msgstr "イメージを起動します。"
-#: templates/django_openstack/dash/images/launch.html:22
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr "イメージ"
+
+#: dashboards/dash/templates/dash/images/launch.html:22
msgid ""
"Specify the details for launching an instance. Also please make note of the "
"table below; all tenants have quotas which define the limit of resources you "
"are allowed to provision."
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
msgid "Quota Name"
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
msgid "Limit"
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:29
+#: dashboards/dash/templates/dash/images/launch.html:29
msgid "RAM (MB)"
msgstr ""
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr "インスタンス"
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr "ボリューム"
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
#, fuzzy
msgid "From here you can modify different properties of an image."
msgstr "ここより、ユーザとその資格を管理できます。"
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
msgid "Update Instance"
msgstr "インスタンスを更新"
-#: templates/django_openstack/dash/instances/_list.html:8
+#: dashboards/dash/templates/dash/instances/_list.html:8
msgid "Groups"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
#, fuzzy
msgid "Image"
msgstr "イメージ"
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
msgid "Size"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
msgid "IPs"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
msgid "State"
msgstr "状態"
-#: templates/django_openstack/dash/instances/_list.html:66
+#: dashboards/dash/templates/dash/instances/_list.html:66
msgid "Log"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
msgid "VNC Console"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:69
+#: dashboards/dash/templates/dash/instances/_list.html:69
msgid "Snapshot"
msgstr "スナップショット"
-#: templates/django_openstack/dash/instances/index.html:23
+#: dashboards/dash/templates/dash/instances/index.html:23
#, python-format
msgid ""
"There are currently no instances. You can launch an instance from the <a "
"href='%(dash_img_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/dash/instances/update.html:19
+#: dashboards/dash/templates/dash/instances/update.html:19
msgid "Return to Instances List"
msgstr ""
-#: templates/django_openstack/dash/instances/update.html:24
+#: dashboards/dash/templates/dash/instances/update.html:24
msgid "Update the name and description of your instance"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr "概要"
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
msgid "Download CSV"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:50
+#: dashboards/dash/templates/dash/instances/usage.html:50
msgid "Hide Terminated"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:52
+#: dashboards/dash/templates/dash/instances/usage.html:52
msgid "Show Terminated"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
msgid "User"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
msgid "Ram Size"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
msgid "Disk Size"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
msgid "Uptime"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:89
+#: dashboards/dash/templates/dash/instances/usage.html:89
#, fuzzy
msgid "No active instances."
msgstr "インスタンスを表示する"
-#: templates/django_openstack/dash/instances/usage.html:98
+#: dashboards/dash/templates/dash/instances/usage.html:98
#, python-format
msgid ""
"There are currently no instances.<br/><br/>You can launch an instance from "
"the <a href='%(dash_img_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/dash/keypairs/_form.html:10
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
msgid "Add Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/_list.html:5
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
msgid "Fingerprint"
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
msgid "Create Keypair"
msgstr "キーペアを作成"
-#: templates/django_openstack/dash/keypairs/create.html:30
+#: dashboards/dash/templates/dash/keypairs/create.html:30
msgid "Your private key is being downloaded."
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
msgid "Return to keypairs list"
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr "説明"
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
#, fuzzy
msgid ""
"Keypairs are ssh credentials which are injected into images when they are "
@@ -1387,158 +1105,171 @@ msgstr ""
"キーペアを作成するとき、公開キーを登録し、秘密キー(pemファイル)をダウンロード"
"します。<em>これは、通常の秘密キーの様に保護した上でご使用ください。</em>"
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
msgid "Protect and use the key as you would any normal ssh private key."
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr "キーペア"
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
msgid "Add New Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
msgid "Import Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:24
+#: dashboards/dash/templates/dash/keypairs/index.html:24
#, fuzzy
msgid "There are currently no keypairs."
msgstr "キーペアが存在しません。"
-#: templates/django_openstack/dash/networks/_detach_port.html:9
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
msgid "Detach"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:6
#, fuzzy
msgid "Attachment"
msgstr "ボリュームを付与する。"
-#: templates/django_openstack/dash/networks/_detail.html:8
+#: dashboards/dash/templates/dash/networks/_detail.html:8
msgid "Extensions"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:20
+#: dashboards/dash/templates/dash/networks/_detail.html:20
msgid "VIF Id"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:36
+#: dashboards/dash/templates/dash/networks/_detail.html:36
#, fuzzy
msgid "Attach"
msgstr "ボリュームを付与する。"
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
#, fuzzy
msgid "Create Network"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/dash/networks/_list.html:6
+#: dashboards/dash/templates/dash/networks/_list.html:6
msgid "Ports"
msgstr ""
-#: templates/django_openstack/dash/networks/_list.html:7
+#: dashboards/dash/templates/dash/networks/_list.html:7
msgid "Available"
msgstr ""
-#: templates/django_openstack/dash/networks/_list.html:8
+#: dashboards/dash/templates/dash/networks/_list.html:8
msgid "Used"
msgstr ""
-#: templates/django_openstack/dash/networks/_list.html:9
+#: dashboards/dash/templates/dash/networks/_list.html:9
#, fuzzy
msgid "Action"
msgstr "ロケーション"
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
msgid "Rename"
msgstr ""
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
msgid "Rename Network"
msgstr ""
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
msgid "Port UP"
msgstr ""
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
msgid "Port DOWN"
msgstr ""
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
msgid "Return to networks list"
msgstr ""
-#: templates/django_openstack/dash/networks/create.html:24
+#: dashboards/dash/templates/dash/networks/create.html:24
msgid "Networks provide layer 2 connectivity to your instances."
msgstr ""
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
msgid "Create Ports"
msgstr ""
-#: templates/django_openstack/dash/networks/detail.html:28
+#: dashboards/dash/templates/dash/networks/detail.html:28
#, fuzzy
msgid "There are currently no ports in this network."
msgstr "ユーザがいない現在、このプロジェクトに関連付けられている。"
-#: templates/django_openstack/dash/networks/index.html:20
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr "ネットワーク"
+
+#: dashboards/dash/templates/dash/networks/index.html:20
#, fuzzy
msgid "Create New Network"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/dash/networks/index.html:24
+#: dashboards/dash/templates/dash/networks/index.html:24
msgid "There are currently no networks."
msgstr ""
-#: templates/django_openstack/dash/networks/index.html:24
+#: dashboards/dash/templates/dash/networks/index.html:24
#, fuzzy
msgid "Create A Network"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/dash/networks/rename.html:32
+#: dashboards/dash/templates/dash/networks/rename.html:32
msgid "Enter a new name for your network."
msgstr ""
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
msgid "Copy Object"
msgstr ""
-#: templates/django_openstack/dash/objects/_filter.html:7
+#: dashboards/dash/templates/dash/objects/_filter.html:7
msgid "Filter"
msgstr ""
-#: templates/django_openstack/dash/objects/_list.html:16
+#: dashboards/dash/templates/dash/objects/_list.html:16
msgid "Copy"
msgstr ""
-#: templates/django_openstack/dash/objects/_list.html:18
+#: dashboards/dash/templates/dash/objects/_list.html:18
msgid "Download"
msgstr ""
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
msgid "Return to objects list"
msgstr ""
-#: templates/django_openstack/dash/objects/copy.html:26
+#: dashboards/dash/templates/dash/objects/copy.html:26
msgid ""
"You may make a new copy of an existing object to store in this or another "
"container."
msgstr ""
-#: templates/django_openstack/dash/objects/index.html:31
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
#, python-format
msgid ""
"There are currently no objects in the container %(container_name)s. You can "
@@ -1546,15 +1277,15 @@ msgid ""
"Page &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/dash/objects/index.html:34
+#: dashboards/dash/templates/dash/objects/index.html:34
msgid "Upload New Object &gt;&gt;"
msgstr ""
-#: templates/django_openstack/dash/objects/upload.html:11
+#: dashboards/dash/templates/dash/objects/upload.html:11
msgid "Upload Objects"
msgstr ""
-#: templates/django_openstack/dash/objects/upload.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:25
msgid ""
"An object is the basic storage entity and any optional metadata that "
"represents the files you store in the OpenStack Object Storage system. When "
@@ -1563,17 +1294,17 @@ msgid ""
"object's name, and any metadata consisting of key/value pairs."
msgstr ""
-#: templates/django_openstack/dash/ports/attach.html:12
+#: dashboards/dash/templates/dash/ports/attach.html:12
#, fuzzy
msgid "Attach Port"
msgstr "ボリュームを付与する。"
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
msgid "Return to network detail"
msgstr ""
-#: templates/django_openstack/dash/ports/attach.html:42
+#: dashboards/dash/templates/dash/ports/attach.html:42
msgid ""
"<p>Select an interface from the list on the left to attach it to this port.</"
"p>\n"
@@ -1583,427 +1314,725 @@ msgid ""
"first</p>"
msgstr ""
-#: templates/django_openstack/dash/ports/create.html:24
+#: dashboards/dash/templates/dash/ports/create.html:24
msgid ""
"You can plug virtual interfaces from your instances to ports created in the "
"network"
msgstr ""
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
#, fuzzy
msgid "Create Security Group"
msgstr "セキュリティグループ"
-#: templates/django_openstack/dash/security_groups/_list.html:14
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
#, fuzzy
msgid "Edit Rules"
msgstr "ユーザ資格の編集"
-#: templates/django_openstack/dash/security_groups/create.html:22
+#: dashboards/dash/templates/dash/security_groups/create.html:22
#, fuzzy
msgid "From here you can create a new security group"
msgstr "ここで、複数のユーザ資格を編集できます。"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
#, fuzzy
msgid "Edit Security Group Rules"
msgstr "セキュリティグループ"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
#, fuzzy
msgid "Rules for Security Group"
msgstr "セキュリティグループ"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
msgid "IP Protocol"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
msgid "From Port"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
msgid "To Port"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
msgid "CIDR"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
#, fuzzy
msgid "No rules for this security group"
msgstr "セキュリティグループ%sを作成できません。"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
msgid "Add a rule"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
msgid "Add Rule"
msgstr ""
-#: templates/django_openstack/dash/security_groups/index.html:25
+#: dashboards/dash/templates/dash/security_groups/index.html:25
#, python-format
msgid ""
"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
"Security Group &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/dash/snapshots/_form.html:11
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
msgid "Create Snapshot"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:19
+#: dashboards/dash/templates/dash/snapshots/create.html:19
msgid "Create a Snapshot"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:25
+#: dashboards/dash/templates/dash/snapshots/create.html:25
msgid "Choose a name for your snapshot."
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:27
+#: dashboards/dash/templates/dash/snapshots/create.html:27
msgid "Return to snapshots list"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:32
+#: dashboards/dash/templates/dash/snapshots/create.html:32
msgid "Snapshots preserve the disk state of a running instance."
msgstr ""
-#: templates/django_openstack/dash/snapshots/index.html:23
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr "スナップショット"
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
#, python-format
msgid ""
"There are currently no snapshots. You can create snapshots from running "
"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:5
+#: dashboards/syspanel/dashboard.py:25
msgid "System Panel"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
-msgstr "サービス"
-
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
+#: dashboards/syspanel/flavors/forms.py:36
+#, fuzzy
+msgid "Flavor ID"
msgstr "インスタンスタイプ"
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
-msgstr "テナント"
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
-msgstr "ユーザー"
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, fuzzy, python-format
+msgid "%s was successfully added to flavors."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, fuzzy, python-format
+msgid "Unable to delete flavor: %s"
+msgstr "ボリューム%sを削除できません。"
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, fuzzy, python-format
+msgid "Error updating image: %s"
+msgstr "イメージ%sを更新できません。"
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+#, fuzzy
+msgid "Image was successfully uploaded."
+msgstr "イメージ%sが正常に登録削除されました。"
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, fuzzy, python-format
+msgid "Unable to get service info: %s"
+msgstr "セキュリティグループ%sを作成できません。"
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, fuzzy, python-format
+msgid "Service '%s' has been enabled"
+msgstr "イメージ%sが更新されました。"
+
+#: dashboards/syspanel/services/forms.py:49
+#, fuzzy, python-format
+msgid "Service '%s' has been disabled"
+msgstr "イメージ%sが更新されました。"
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
-msgstr "クォータ"
+#: dashboards/syspanel/services/forms.py:55
+#, fuzzy, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr "インスタンス%(inst)s: %(msg)sを更新する事ができません。"
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
msgid "Create Flavor"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
msgid "Id"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:7
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
msgid "Memory"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
msgid "Disk"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/create.html:37
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
#, fuzzy
msgid "From here you can define the sizing of a new flavor."
msgstr "ここより、ユーザとその資格を管理できます。"
-#: templates/django_openstack/syspanel/flavors/index.html:18
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr "インスタンスタイプ"
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
#, fuzzy
msgid "Create New Flavor"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/syspanel/images/_list.html:9
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
#, fuzzy
msgid "Public"
msgstr "公開する"
-#: templates/django_openstack/syspanel/images/_list.html:35
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
msgid "Location"
msgstr "ロケーション"
-#: templates/django_openstack/syspanel/images/_list.html:40
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
msgid "Project ID"
msgstr ""
-#: templates/django_openstack/syspanel/images/_toggle.html:8
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
#, fuzzy
msgid "Toggle Public"
msgstr "公開する"
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
msgid "Tenant"
msgstr "テナント"
-#: templates/django_openstack/syspanel/instances/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
msgid "Host"
msgstr ""
-#: templates/django_openstack/syspanel/instances/_list.html:48
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
msgid "Console Log"
msgstr ""
-#: templates/django_openstack/syspanel/instances/index.html:23
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
#, python-format
msgid ""
"There are currently no instances. You can launch an instance from the <a "
"href='%(dash_image_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
msgid "System Panel Overview"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
#, fuzzy
msgid "Active Instances"
msgstr "インスタンスを表示する"
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
msgid "This month's VCPU-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
msgid "This month's GB-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
msgid "Tenant Usage"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:23
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
msgid "Monitoring"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:34
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
msgid "Select a month to query its usage"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:71
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
msgid "Server Usage Summary"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:80
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
msgid "RAM"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:81
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
msgid "VCPU CPU-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:82
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
msgid "Disk GB-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/quotas/index.html:13
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
msgid "Default Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:5
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
msgid "Service"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:6
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
msgid "System Stats"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:8
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
msgid "Up"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:22
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
msgid "Hypervisor"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:25
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
msgid "Allocable Cores"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:30
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
msgid "Allocable Storage"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:35
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
msgid "System Ram"
msgstr ""
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
msgid "Enable"
msgstr ""
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
msgid "Disable"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr "サービス"
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
msgid "Add"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
msgid "Options"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_list.html:20
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
#, fuzzy
msgid "View Members"
msgstr "イメージの表示"
-#: templates/django_openstack/syspanel/tenants/_list.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
msgid "Modify Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
#, fuzzy
msgid "Remove"
msgstr "イメージを削除する"
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
#, fuzzy
msgid "Update Tenant"
msgstr "インスタンスを更新"
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
#, fuzzy
msgid "Update Quotas"
msgstr "インスタンスを更新"
-#: templates/django_openstack/syspanel/tenants/create.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
msgid "From here you can create a new tenant (aka project) to organize users."
msgstr ""
-#: templates/django_openstack/syspanel/tenants/index.html:18
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr "テナント"
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
#, fuzzy
msgid "Create New Tenant"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
msgid "Update Tenant Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+#, fuzzy
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr "ここで、複数のユーザ資格を編集できます。"
-#: templates/django_openstack/syspanel/tenants/update.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
#, fuzzy
msgid "From here you can edit a tenant."
msgstr "ここで、複数のユーザ資格を編集できます。"
-#: templates/django_openstack/syspanel/tenants/users.html:12
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
msgid "Users for Tenant"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/users.html:45
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
msgid "here are currently no users for this tenant"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/users.html:49
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
msgid "Add new users"
msgstr ""
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
msgid "Create User"
msgstr ""
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
#, fuzzy
msgid "Update User"
msgstr "イメージを更新"
-#: templates/django_openstack/syspanel/users/create.html:23
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
msgid ""
"From here you can create a new user and assign them to a tenant (aka "
"project)."
msgstr ""
-#: templates/django_openstack/syspanel/users/index.html:23
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr "ユーザー"
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
msgid "Default Tenant"
msgstr ""
-#: templates/django_openstack/syspanel/users/index.html:42
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
#, fuzzy
msgid "Create New User"
msgstr "新規ボリュームを作成する。"
-#: templates/django_openstack/syspanel/users/update.html:23
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
msgid ""
"From here you can edit users by changing their usernames, emails, passwords, "
"and tenants."
msgstr ""
-#: templatetags/templatetags/sizeformat.py:46
+#: dashboards/syspanel/tenants/forms.py:48
+#, fuzzy, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, fuzzy, python-format
+msgid "Unable to create user association: %s"
+msgstr "セキュリティグループ%sを作成できません。"
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, fuzzy, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, fuzzy, python-format
+msgid "Unable to create tenant: %s"
+msgstr "キー%sを作成できません。"
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, fuzzy, python-format
+msgid "%s was successfully created."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, fuzzy, python-format
+msgid "%s was successfully updated."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, fuzzy, python-format
+msgid "Unable to update tenant: %s"
+msgstr "イメージ%sを更新できません。"
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, fuzzy, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr "セキュリティグループ%sが正常に削除されました。"
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, fuzzy, python-format
+msgid "Unable to update quotas: %s"
+msgstr "イメージ%sを更新できません。"
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, fuzzy, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr "プロジェクト%(proj)sを正常に修正しました。"
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, fuzzy, python-format
+msgid "Error deleting tenant: %s"
+msgstr "キー%sを削除できません。"
+
+#: dashboards/syspanel/tenants/views.py:51
+#, fuzzy, python-format
+msgid "Unable to get tenant info: %s"
+msgstr "キー%sを作成できません。"
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr "パスワード"
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+#, fuzzy
+msgid "Primary Tenant"
+msgstr "テナント"
+
+#: dashboards/syspanel/users/forms.py:75
+#, fuzzy, python-format
+msgid "%(user)s was successfully deleted."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, fuzzy, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr "キー%sを削除できません。"
+
+#: dashboards/syspanel/users/views.py:49
+#, fuzzy, python-format
+msgid "Unable to list users: %s"
+msgstr "キー%sを削除できません。"
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+#, fuzzy
+msgid "Unable to update user, please try again."
+msgstr "イメージ%sを更新できません。"
+
+#: dashboards/syspanel/users/views.py:113
+#, fuzzy, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr "キー%sを作成できません。"
+
+#: dashboards/syspanel/users/views.py:131
+#, fuzzy, python-format
+msgid "User \"%s\" was successfully created."
+msgstr "キー%sは正常に削除されました。"
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, fuzzy, python-format
+msgid "Error creating user: %s"
+msgstr "ユーザ%sを作成中..."
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr "検索"
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr "リストを再読み込みする"
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr "削除"
+
+#: templatetags/sizeformat.py:46
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] ""
-#: templatetags/templatetags/sizeformat.py:50
+#: templatetags/sizeformat.py:50
#, python-format
msgid "%(size)d"
msgid_plural "%(size)d"
msgstr[0] ""
-#: templatetags/templatetags/sizeformat.py:53
+#: templatetags/sizeformat.py:53
#, python-format
msgid "%s KB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:56
+#: templatetags/sizeformat.py:56
#, python-format
msgid "%s MB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:59
+#: templatetags/sizeformat.py:59
#, python-format
msgid "%s GB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:62
+#: templatetags/sizeformat.py:62
#, python-format
msgid "%s TB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:64
+#: templatetags/sizeformat.py:64
#, python-format
msgid "%s PB"
msgstr ""
+#: views/auth.py:56
+msgid "User Name"
+msgstr "ユーザ名"
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, fuzzy, python-format
+msgid "Error authenticating: %s"
+msgstr "ユーザが認証されておりません。"
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
+
+#~ msgid "Quotas"
+#~ msgstr "クォータ"
+
#~ msgid "Creates nova users for all users in the django auth database."
#~ msgstr ""
#~ "Djangoの認証データベース内のすべてのユーザーに対してnovaユーザーを作成しま"
@@ -2015,9 +2044,6 @@ msgstr ""
#~ msgid "A security group named %s already exists."
#~ msgstr "%sというセキュリティグループは既に存在します。"
-#~ msgid "Project %s does not exist."
-#~ msgstr "プロジェクト%sは存在しません。"
-
#~ msgid "Successfully started VPN for project %(proj)s."
#~ msgstr "正常にVPNプロジェクト%(proj)sを開始しました。"
diff --git a/django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.mo b/horizon/horizon/locale/pl/LC_MESSAGES/django.mo
index 1a8cc2af..94b835fd 100644
--- a/django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/pl/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.po b/horizon/horizon/locale/pl/LC_MESSAGES/django.po
index df2d1ade..809f6293 100644
--- a/django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.po
+++ b/horizon/horizon/locale/pl/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: openstack-dashboard\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-27 14:03+0900\n"
+"POT-Creation-Date: 2011-11-01 23:08-0700\n"
"PO-Revision-Date: 2011-09-24 14:41+0100\n"
"Last-Translator: Tomasz 'Zen' Napierala <tomasz@napierala.org>\n"
"Language-Team: Polish OpenStack translations team <tomasz+openstack-"
@@ -20,18 +20,7 @@ msgstr ""
"X-Poedit-Country: POLAND\n"
"X-Poedit-SourceCharset: utf-8\n"
-#: api.py:1002 syspanel/views/services.py:88
-#, fuzzy, python-format
-msgid "Unable to get service info: %s"
-msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-
-#: api.py:1028 dash/views/instances.py:180 syspanel/views/flavors.py:95
-#: syspanel/views/instances.py:146
-#, fuzzy, python-format
-msgid "Unable to get usage info: %s"
-msgstr "Nie można ustawić widoczności obrazu na publiczną: %s"
-
-#: context_processors.py:34
+#: context_processors.py:35
#, python-format
msgid ""
"Unable to retrieve tenant list from "
@@ -43,1054 +32,705 @@ msgstr ""
msgid "Unexpected error: %s"
msgstr ""
-#: auth/views.py:38
-msgid "User Name"
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
msgstr ""
-#: auth/views.py:39 syspanel/views/users.py:55 syspanel/views/users.py:73
-msgid "Password"
-msgstr ""
+#: api/keystone.py:199
+#, fuzzy, python-format
+msgid "Role does not exist: %s"
+msgstr "Projekt %s nie istnieje."
-#: auth/views.py:83
+#: api/keystone.py:207
#, python-format
-msgid "No tenants present for user: %(user)s"
+msgid "Role \"%s\" does not exist for that user on this tenant."
msgstr ""
-#: auth/views.py:105
-#, fuzzy, python-format
-msgid "Error authenticating: %s"
-msgstr "Użytkownik nie jest uwierzytelniony"
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
-#: auth/views.py:110
-#, python-format
-msgid "Error authenticating with keystone: %s"
+#: dashboards/dash/dashboard.py:28
+#, fuzzy
+msgid "Network"
+msgstr "Utwórz nowy wolumen."
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
msgstr ""
-#: dash/views/containers.py:49
+#: dashboards/dash/containers/forms.py:22
#, fuzzy, python-format
msgid "Unable to delete non-empty container: %s"
msgstr "Nie można usunąć klucza: %s"
-#: dash/views/containers.py:55
+#: dashboards/dash/containers/forms.py:28
#, fuzzy, python-format
msgid "Successfully deleted container: %s"
msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-#: dash/views/containers.py:61
+#: dashboards/dash/containers/forms.py:34
msgid "Container Name"
msgstr ""
-#: dash/views/containers.py:65
+#: dashboards/dash/containers/forms.py:38
#, fuzzy
msgid "Container was successfully created."
msgstr "Wolumen %(id)s %(name)s został pomyślnie utworzony."
-#: dash/views/floating_ips.py:47
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, fuzzy, python-format
+msgid "Successfully deleted object: %s"
+msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+#, fuzzy
+msgid "Object was successfully uploaded."
+msgstr "Grupa bezpieczeństwa %s została pomyślnie usunięta."
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
#, python-format
msgid "Successfully released Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:51
+#: dashboards/dash/floating_ips/forms.py:47
#, python-format
msgid "Error releasing Floating IP from tenant: %s"
msgstr ""
-#: dash/views/floating_ips.py:67
-#: templates/django_openstack/dash/networks/_detail.html:19
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
#, fuzzy
msgid "Instance"
msgstr "Instancje"
-#: dash/views/floating_ips.py:76
+#: dashboards/dash/floating_ips/forms.py:72
#, python-format
msgid ""
"Successfully associated Floating IP: "
"%(ip)s with Instance: %(inst)s"
msgstr ""
-#: dash/views/floating_ips.py:82
+#: dashboards/dash/floating_ips/forms.py:78
#, fuzzy, python-format
msgid "Error associating Floating IP: %s"
msgstr "Nie można zaktualizować obrazu: %s"
-#: dash/views/floating_ips.py:99
+#: dashboards/dash/floating_ips/forms.py:95
#, python-format
msgid "Successfully disassociated Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:103
+#: dashboards/dash/floating_ips/forms.py:99
#, python-format
msgid "Error disassociating Floating IP: %s"
msgstr ""
-#: dash/views/floating_ips.py:118
+#: dashboards/dash/floating_ips/forms.py:114
#, python-format
msgid ""
"Successfully allocated Floating IP \"%(ip)s\" "
"to tenant \"%(tenant)s\""
msgstr ""
-#: dash/views/floating_ips.py:124
+#: dashboards/dash/floating_ips/forms.py:120
#, python-format
msgid ""
"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
"\": %(msg)s"
msgstr ""
-#: dash/views/floating_ips.py:142
+#: dashboards/dash/floating_ips/views.py:53
#, python-format
msgid "Error fetching floating ips: %s"
msgstr ""
-#: dash/views/images.py:46 syspanel/views/flavors.py:45
-#: syspanel/views/images.py:75 syspanel/views/tenants.py:86
-#: syspanel/views/tenants.py:114 syspanel/views/users.py:53
-#: templates/django_openstack/dash/containers/_list.html:6
-#: templates/django_openstack/dash/images/_list.html:6
-#: templates/django_openstack/dash/instances/_list.html:7
-#: templates/django_openstack/dash/instances/usage.html:61
-#: templates/django_openstack/dash/keypairs/_list.html:4
-#: templates/django_openstack/dash/networks/_list.html:5
-#: templates/django_openstack/dash/objects/_list.html:6
-#: templates/django_openstack/dash/security_groups/_list.html:4
-#: templates/django_openstack/syspanel/flavors/_list.html:5
-#: templates/django_openstack/syspanel/images/_list.html:7
-#: templates/django_openstack/syspanel/instances/_list.html:5
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:67
-#: templates/django_openstack/syspanel/tenants/_list.html:5
-#: templates/django_openstack/syspanel/tenants/users.html:23
-#: templates/django_openstack/syspanel/tenants/users.html:53
-#: templates/django_openstack/syspanel/users/index.html:21
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
msgid "Name"
msgstr ""
-#: dash/views/images.py:47 syspanel/views/images.py:76
-#: templates/django_openstack/syspanel/images/_list.html:37
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
msgid "Kernel ID"
msgstr ""
-#: dash/views/images.py:49 syspanel/views/images.py:78
-#: templates/django_openstack/syspanel/images/_list.html:38
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
msgid "Ramdisk ID"
msgstr ""
-#: dash/views/images.py:51 syspanel/views/images.py:80
-#: templates/django_openstack/syspanel/images/_list.html:39
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
msgid "Architecture"
msgstr ""
-#: dash/views/images.py:52 syspanel/views/images.py:82
-#: templates/django_openstack/syspanel/images/_list.html:41
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
msgid "Container Format"
msgstr ""
-#: dash/views/images.py:54 syspanel/views/images.py:84
-#: templates/django_openstack/syspanel/images/_list.html:42
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
msgid "Disk Format"
msgstr ""
-#: dash/views/images.py:59 dash/views/images.py:233
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
#, fuzzy, python-format
msgid "Unable to retreive image info from glance: %s"
msgstr "Nie można wyrejestrować obrazu: %s"
-#: dash/views/images.py:61
+#: dashboards/dash/images/forms.py:57
#, python-format
msgid "Error updating image with id: %s"
msgstr ""
-#: dash/views/images.py:66 dash/views/images.py:95
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
msgid "Error connecting to glance"
msgstr ""
-#: dash/views/images.py:92 syspanel/views/images.py:159
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
#, fuzzy
msgid "Image was successfully updated."
msgstr "Obraz %s został pomyślnie wyrejestrowany."
-#: dash/views/images.py:101
+#: dashboards/dash/images/forms.py:97
msgid "Unspecified Exception in image update"
msgstr ""
-#: dash/views/images.py:105
+#: dashboards/dash/images/forms.py:101
msgid ""
"Unable to update image. You are not "
"its owner."
msgstr ""
-#: dash/views/images.py:111
+#: dashboards/dash/images/forms.py:107
msgid "Server Name"
msgstr ""
-#: dash/views/images.py:115
+#: dashboards/dash/images/forms.py:111
msgid "User Data"
msgstr ""
-#: dash/views/images.py:125
-#: templates/django_openstack/dash/instances/usage.html:66
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:72
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
msgid "Flavor"
msgstr ""
-#: dash/views/images.py:130
+#: dashboards/dash/images/forms.py:126
msgid "Key Name"
msgstr ""
-#: dash/views/images.py:138 templates/django_openstack/dash/_sidebar.html:13
-#: templates/django_openstack/dash/security_groups/index.html:13
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
msgid "Security Groups"
msgstr "Grupy bezpieczeństwa"
-#: dash/views/images.py:169
+#: dashboards/dash/images/forms.py:165
#, fuzzy
msgid "Instance was successfully launched"
msgstr "Obraz %s został pomyślnie wyrejestrowany."
-#: dash/views/images.py:178
+#: dashboards/dash/images/forms.py:174
#, fuzzy, python-format
msgid "Unable to launch instance: %s"
msgstr "Nie można zaktualizować obrazu: %s"
-#: dash/views/images.py:192
+#: dashboards/dash/images/forms.py:188
msgid ""
"Unable to delete image, you are not "
"its owner."
msgstr ""
-#: dash/views/images.py:197 dash/views/images.py:228 dash/views/images.py:318
-#: dash/views/snapshots.py:79 syspanel/views/images.py:49
-#: syspanel/views/images.py:67 syspanel/views/images.py:109
-#: syspanel/views/images.py:130 syspanel/views/images.py:163
-#: syspanel/views/images.py:227
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
#, python-format
msgid "Error connecting to glance: %s"
msgstr ""
-#: dash/views/images.py:202
+#: dashboards/dash/images/forms.py:198
#, fuzzy
msgid "Error deleting image: %(image)s: %i(msg)s"
msgstr "Nie można zaktualizować obrazu: %s"
-#: dash/views/images.py:219
-#, python-format
-msgid ""
-"Unable to retrienve tenant info from "
-"keystone: %s"
-msgstr ""
-
-#: dash/views/images.py:225 syspanel/views/images.py:105
-#: templates/django_openstack/dash/images/index.html:22
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
#, fuzzy
msgid "There are currently no images."
msgstr "Brak istniejących par kluczy."
-#: dash/views/images.py:231 dash/views/snapshots.py:83
-#: syspanel/views/images.py:113
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
#, python-format
msgid "Error retrieving image list: %s"
msgstr ""
-#: dash/views/images.py:290
+#: dashboards/dash/images/views.py:118
#, fuzzy, python-format
msgid "Error parsing quota for %(image)s: %(msg)s"
msgstr "Nie można zaktualizować obrazu: %s"
-#: dash/views/images.py:323 syspanel/views/images.py:134
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
#, python-format
msgid "Error retrieving image %(image)s: %(msg)s"
msgstr ""
-#: dash/views/instances.py:55
+#: dashboards/dash/instances/forms.py:25
#, python-format
msgid "ApiException while terminating instance \"%s\""
msgstr ""
-#: dash/views/instances.py:58
+#: dashboards/dash/instances/forms.py:28
#, fuzzy, python-format
msgid "Unable to terminate %(inst)s: %(message)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/instances.py:61
+#: dashboards/dash/instances/forms.py:31
#, fuzzy, python-format
msgid "Instance %s has been terminated."
msgstr "Instancja %(inst)s została zakończona."
-#: dash/views/instances.py:75
+#: dashboards/dash/instances/forms.py:45
#, fuzzy
msgid "Instance rebooting"
msgstr "Instancja %(inst)s została zaktualizowana."
-#: dash/views/instances.py:77
+#: dashboards/dash/instances/forms.py:47
#, fuzzy, python-format
msgid "ApiException while rebooting instance \"%s\""
msgstr "Nie można cofnąć: %s"
-#: dash/views/instances.py:80
+#: dashboards/dash/instances/forms.py:50
#, fuzzy, python-format
msgid "Unable to reboot instance: %s"
msgstr "Nie można cofnąć: %s"
-#: dash/views/instances.py:83
+#: dashboards/dash/instances/forms.py:53
#, fuzzy, python-format
msgid "Instance %s has been rebooted."
msgstr "Instancja %(inst)s została zaktualizowana."
-#: dash/views/instances.py:105
+#: dashboards/dash/instances/forms.py:75
#, fuzzy, python-format
msgid "Instance '%s' updated"
msgstr "Instancja %s uruchomiona."
-#: dash/views/instances.py:109
+#: dashboards/dash/instances/forms.py:79
#, fuzzy, python-format
msgid "Unable to update instance: %s"
msgstr "Nie można zaktualizować obrazu: %s"
-#: dash/views/instances.py:124
+#: dashboards/dash/instances/views.py:55
msgid "Exception in instance index"
msgstr ""
-#: dash/views/instances.py:125 dash/views/instances.py:147
-#: syspanel/views/instances.py:193 syspanel/views/instances.py:221
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
#, fuzzy, python-format
msgid "Unable to get instance list: %s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/instances.py:178
+#: dashboards/dash/instances/views.py:110
msgid "ApiException in instance usage"
msgstr ""
-#: dash/views/instances.py:241
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, fuzzy, python-format
+msgid "Unable to get usage info: %s"
+msgstr "Nie można ustawić widoczności obrazu na publiczną: %s"
+
+#: dashboards/dash/instances/views.py:174
msgid "ApiException while fetching instance console"
msgstr ""
-#: dash/views/instances.py:243
+#: dashboards/dash/instances/views.py:176
#, fuzzy, python-format
msgid "Unable to get log for instance %(inst)s: %(msg)s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/instances.py:256
+#: dashboards/dash/instances/views.py:190
msgid "ApiException while fetching instance vnc connection"
msgstr ""
-#: dash/views/instances.py:258 syspanel/views/instances.py:249
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
#, fuzzy, python-format
msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/instances.py:268 dash/views/instances.py:307
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
msgid "ApiException while fetching instance info"
msgstr ""
-#: dash/views/instances.py:270 syspanel/views/instances.py:255
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
#, fuzzy, python-format
msgid "Unable to get information for instance %(inst)s: %(message)s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/instances.py:300
+#: dashboards/dash/instances/views.py:235
msgid ""
"ApiException while fetching instance vnc "
"connection"
msgstr ""
-#: dash/views/instances.py:303
+#: dashboards/dash/instances/views.py:238
#, fuzzy, python-format
msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/instances.py:309
+#: dashboards/dash/instances/views.py:244
#, fuzzy, python-format
msgid "Unable to get information for instance %(inst)s: %(msg)s"
msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-#: dash/views/keypairs.py:49
+#: dashboards/dash/keypairs/forms.py:24
#, fuzzy, python-format
msgid "Successfully deleted keypair: %s"
msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-#: dash/views/keypairs.py:54
+#: dashboards/dash/keypairs/forms.py:29
#, fuzzy, python-format
msgid "Error deleting keypair: %s"
msgstr "Nie można usunąć klucza: %s"
-#: dash/views/keypairs.py:60 dash/views/keypairs.py:81
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
msgid "Keypair Name"
msgstr ""
-#: dash/views/keypairs.py:75
+#: dashboards/dash/keypairs/forms.py:50
#, python-format
msgid "Error Creating Keypair: %s"
msgstr ""
-#: dash/views/keypairs.py:83
+#: dashboards/dash/keypairs/forms.py:58
#, fuzzy
msgid "Public Key"
msgstr "Uczyń publicznym"
-#: dash/views/keypairs.py:89
+#: dashboards/dash/keypairs/forms.py:64
#, python-format
msgid "Successfully imported public key: %s"
msgstr ""
-#: dash/views/keypairs.py:95
+#: dashboards/dash/keypairs/forms.py:70
#, python-format
msgid "Error Importing Keypair: %s"
msgstr ""
-#: dash/views/keypairs.py:111
+#: dashboards/dash/keypairs/views.py:53
#, python-format
msgid "Error fetching keypairs: %s"
msgstr ""
-#: dash/views/networks.py:49
+#: dashboards/dash/networks/forms.py:15
msgid "Network Name"
msgstr ""
-#: dash/views/networks.py:60
+#: dashboards/dash/networks/forms.py:26
#, fuzzy, python-format
msgid "Unable to create network %(network)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/networks.py:64
+#: dashboards/dash/networks/forms.py:30
#, fuzzy, python-format
msgid "Network %s has been created."
msgstr "Obraz %s został zaktualizowany."
-#: dash/views/networks.py:80
+#: dashboards/dash/networks/forms.py:45
#, fuzzy, python-format
msgid "Unable to delete network %(network)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/networks.py:83
+#: dashboards/dash/networks/forms.py:48
#, fuzzy, python-format
msgid "Network %s has been deleted."
msgstr "Obraz %s został zaktualizowany."
-#: dash/views/networks.py:102
+#: dashboards/dash/networks/forms.py:67
#, fuzzy, python-format
msgid "Unable to rename network %(network)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/networks.py:105
+#: dashboards/dash/networks/forms.py:70
#, python-format
msgid "Network %(net)s has been renamed to %(new_name)s."
msgstr ""
-#: dash/views/networks.py:138
-#, fuzzy, python-format
-msgid "Unable to get network list: %s"
-msgstr "Nie można cofnąć: %s"
-
-#: dash/views/networks.py:174
-#, fuzzy, python-format
-msgid "Unable to get network details: %s"
-msgstr "Nie można cofnąć: %s"
-
-#: dash/views/objects.py:54
-#, python-format
-msgid "There are no objects matching that prefix in %s"
-msgstr ""
-
-#: dash/views/objects.py:70
-#, fuzzy, python-format
-msgid "Successfully deleted object: %s"
-msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-
-#: dash/views/objects.py:76
-msgid "Object Name"
-msgstr ""
-
-#: dash/views/objects.py:77
-msgid "File"
-msgstr ""
-
-#: dash/views/objects.py:87
-#, fuzzy
-msgid "Object was successfully uploaded."
-msgstr "Grupa bezpieczeństwa %s została pomyślnie usunięta."
-
-#: dash/views/objects.py:93
-msgid "Container to store object in"
-msgstr ""
-
-#: dash/views/objects.py:96
-msgid "New object name"
-msgstr ""
-
-#: dash/views/objects.py:118
-#, python-format
-msgid "Object was successfully copied to %(container)s\\%(obj)s"
-msgstr ""
-
-#: dash/views/ports.py:43
+#: dashboards/dash/networks/forms.py:80
msgid "Number of Ports"
msgstr ""
-#: dash/views/ports.py:53
+#: dashboards/dash/networks/forms.py:90
#, fuzzy, python-format
msgid "Unable to create ports on network %(network)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/ports.py:56
+#: dashboards/dash/networks/forms.py:93
#, python-format
msgid "%(num_ports)s ports created on network %(network)s."
msgstr ""
-#: dash/views/ports.py:75
+#: dashboards/dash/networks/forms.py:112
#, fuzzy, python-format
msgid "Unable to delete port %(port)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/ports.py:78
+#: dashboards/dash/networks/forms.py:115
#, python-format
msgid "Port %(port)s deleted from network %(network)s."
msgstr ""
-#: dash/views/ports.py:89
+#: dashboards/dash/networks/forms.py:126
msgid "Select VIF to connect"
msgstr ""
-#: dash/views/ports.py:100
+#: dashboards/dash/networks/forms.py:137
#, fuzzy, python-format
msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/ports.py:103
+#: dashboards/dash/networks/forms.py:142
#, python-format
msgid "Port %(port)s connected to VIF %(vif)s."
msgstr ""
-#: dash/views/ports.py:120
+#: dashboards/dash/networks/forms.py:159
#, fuzzy, python-format
msgid "Unable to detach port %(port)s: %(message)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/ports.py:123
+#: dashboards/dash/networks/forms.py:162
#, python-format
msgid "Port %s detached."
msgstr ""
-#: dash/views/ports.py:142
+#: dashboards/dash/networks/forms.py:181
#, fuzzy, python-format
msgid "Unable to set port state to %(state)s: %(message)s"
msgstr "Nie można zakończyć %(inst)s: %(msg)s"
-#: dash/views/ports.py:145
+#: dashboards/dash/networks/forms.py:184
#, python-format
msgid "Port %(port)s state set to %(state)s."
msgstr ""
-#: dash/views/security_groups.py:56
+#: dashboards/dash/networks/views.py:68
+#, fuzzy, python-format
+msgid "Unable to get network list: %s"
+msgstr "Nie można cofnąć: %s"
+
+#: dashboards/dash/networks/views.py:104
+#, fuzzy, python-format
+msgid "Unable to get network details: %s"
+msgstr "Nie można cofnąć: %s"
+
+#: dashboards/dash/security_groups/forms.py:48
#, fuzzy, python-format
msgid "Successfully created security_group: %s"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:62
+#: dashboards/dash/security_groups/forms.py:53
#, fuzzy, python-format
msgid "Error creating security group: %s"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:76
+#: dashboards/dash/security_groups/forms.py:67
#, fuzzy, python-format
msgid "Successfully deleted security_group: %s"
msgstr "Nie można usunąć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:80
+#: dashboards/dash/security_groups/forms.py:71
#, fuzzy, python-format
msgid "Error deleting security group: %s"
msgstr "Nie można usunąć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:109
+#: dashboards/dash/security_groups/forms.py:100
#, fuzzy, python-format
msgid "Successfully added rule: %s"
msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-#: dash/views/security_groups.py:113
+#: dashboards/dash/security_groups/forms.py:104
#, fuzzy, python-format
msgid "Error adding rule security group: %s"
msgstr "Nie można usunąć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:131
+#: dashboards/dash/security_groups/forms.py:122
#, fuzzy, python-format
msgid "Successfully deleted rule: %s"
msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-#: dash/views/security_groups.py:135
+#: dashboards/dash/security_groups/forms.py:126
#, fuzzy, python-format
msgid "Error authorizing security group: %s"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:153
+#: dashboards/dash/security_groups/views.py:54
#, fuzzy, python-format
msgid "Error fetching security_groups: %s"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: dash/views/security_groups.py:181
+#: dashboards/dash/security_groups/views.py:82
#, fuzzy, python-format
msgid "Error getting security_group: %s"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: dash/views/snapshots.py:51
+#: dashboards/dash/snapshots/forms.py:19
msgid "Snapshot Name"
msgstr ""
-#: dash/views/snapshots.py:62
+#: dashboards/dash/snapshots/forms.py:30
#, python-format
msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
msgstr ""
-#: dash/views/snapshots.py:66
+#: dashboards/dash/snapshots/forms.py:34
#, fuzzy, python-format
msgid "Error Creating Snapshot: %s"
msgstr "tworzenie użytkownika %s..."
-#: dash/views/snapshots.py:104
+#: dashboards/dash/snapshots/views.py:76
#, fuzzy, python-format
msgid "Unable to retreive instance: %s"
msgstr "Nie można cofnąć: %s"
-#: dash/views/snapshots.py:111
+#: dashboards/dash/snapshots/views.py:83
#, python-format
msgid ""
"To snapshot, instance state must be one of "
"the following: %s"
msgstr ""
-#: middleware/keystone.py:77
-msgid "Your token has expired. Please log in again"
-msgstr ""
-
-#: syspanel/views/flavors.py:44
-msgid "Flavor ID"
-msgstr ""
-
-#: syspanel/views/flavors.py:46 syspanel/views/tenants.py:148
-#: templates/django_openstack/dash/instances/usage.html:63
-#: templates/django_openstack/syspanel/flavors/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:69
-#: templates/django_openstack/syspanel/instances/usage.html:78
-msgid "VCPUs"
-msgstr ""
-
-#: syspanel/views/flavors.py:47
-msgid "Memory MB"
-msgstr ""
-
-#: syspanel/views/flavors.py:48
-msgid "Disk GB"
-msgstr ""
-
-#: syspanel/views/flavors.py:57
-#, fuzzy, python-format
-msgid "%s was successfully added to flavors."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/flavors.py:72
-#, python-format
-msgid "Successfully deleted flavor: %s"
-msgstr ""
-
-#: syspanel/views/flavors.py:75
-#, fuzzy, python-format
-msgid "Unable to delete flavor: %s"
-msgstr "Nie można usunąć wolumenu: %s"
-
-#: syspanel/views/images.py:52
-#, python-format
-msgid "Error deleting image: %s"
-msgstr ""
-
-#: syspanel/views/images.py:70 syspanel/views/images.py:167
-#, fuzzy, python-format
-msgid "Error updating image: %s"
-msgstr "Nie można zaktualizować obrazu: %s"
-
-#: syspanel/views/images.py:171
-msgid "Image could not be updated, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:176 syspanel/views/images.py:235
-msgid "Image could not be uploaded, please try agian."
-msgstr ""
-
-#: syspanel/views/images.py:215
-#, fuzzy
-msgid "Image was successfully uploaded."
-msgstr "Obraz %s został pomyślnie wyrejestrowany."
-
-#: syspanel/views/images.py:219
-msgid "Image could not be uploaded, please try again."
-msgstr ""
-
-#: syspanel/views/images.py:231
-#, python-format
-msgid "Error adding image: %s"
-msgstr ""
-
-#: syspanel/views/instances.py:92 syspanel/views/instances.py:131
-msgid "No data for the selected period"
-msgstr ""
-
-#: syspanel/views/services.py:59
-#, fuzzy, python-format
-msgid "Service '%s' has been enabled"
-msgstr "Obraz %s został zaktualizowany."
-
-#: syspanel/views/services.py:62
-#, fuzzy, python-format
-msgid "Service '%s' has been disabled"
-msgstr "Obraz %s został zaktualizowany."
-
-#: syspanel/views/services.py:68
-#, fuzzy, python-format
-msgid "Unable to update service '%(name)s': %(msg)s"
-msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
-
-#: syspanel/views/tenants.py:57
-#, fuzzy, python-format
-msgid "%(user)s was successfully added to %(tenant)s."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/tenants.py:60
-#, fuzzy, python-format
-msgid "Unable to create user association: %s"
-msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-
-#: syspanel/views/tenants.py:77
-#, fuzzy, python-format
-msgid "%(user)s was successfully removed from %(tenant)s."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/tenants.py:80 syspanel/views/tenants.py:106
-#, fuzzy, python-format
-msgid "Unable to create tenant: %s"
-msgstr "Nie można utworzyć klucza: %s"
-
-#: syspanel/views/tenants.py:88 syspanel/views/tenants.py:117
-#: templates/django_openstack/dash/keypairs/create.html:36
-#: templates/django_openstack/dash/keypairs/import.html:26
-#: templates/django_openstack/dash/networks/create.html:23
-#: templates/django_openstack/dash/objects/copy.html:25
-#: templates/django_openstack/dash/objects/upload.html:24
-#: templates/django_openstack/dash/ports/create.html:23
-#: templates/django_openstack/dash/security_groups/_list.html:5
-#: templates/django_openstack/dash/security_groups/create.html:21
-#: templates/django_openstack/dash/snapshots/create.html:31
-#: templates/django_openstack/syspanel/flavors/create.html:36
-#: templates/django_openstack/syspanel/images/update.html:21
-#: templates/django_openstack/syspanel/tenants/_list.html:6
-#: templates/django_openstack/syspanel/tenants/create.html:21
-#: templates/django_openstack/syspanel/tenants/quotas.html:21
-#: templates/django_openstack/syspanel/tenants/update.html:21
-#: templates/django_openstack/syspanel/users/create.html:22
-#: templates/django_openstack/syspanel/users/update.html:22
-msgid "Description"
-msgstr ""
-
-#: syspanel/views/tenants.py:89 syspanel/views/tenants.py:118
-#: templates/django_openstack/syspanel/services/_list.html:7
-#: templates/django_openstack/syspanel/tenants/_list.html:7
-msgid "Enabled"
-msgstr ""
-
-#: syspanel/views/tenants.py:100
-#, fuzzy, python-format
-msgid "%s was successfully created."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/tenants.py:112 syspanel/views/users.py:68
-#: templates/django_openstack/dash/images/_list.html:5
-#: templates/django_openstack/dash/instances/_list.html:6
-#: templates/django_openstack/dash/instances/usage.html:60
-#: templates/django_openstack/dash/networks/_detail.html:4
-#: templates/django_openstack/dash/networks/_list.html:4
-#: templates/django_openstack/syspanel/images/_list.html:6
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:66
-#: templates/django_openstack/syspanel/tenants/users.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:52
-#: templates/django_openstack/syspanel/users/index.html:20
-msgid "ID"
-msgstr ""
-
-#: syspanel/views/tenants.py:129
-#, fuzzy, python-format
-msgid "%s was successfully updated."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/tenants.py:137 syspanel/views/tenants.py:245
-#, fuzzy, python-format
-msgid "Unable to update tenant: %s"
-msgstr "Nie można zaktualizować obrazu: %s"
-
-#: syspanel/views/tenants.py:142
-msgid "ID (name)"
-msgstr ""
-
-#: syspanel/views/tenants.py:144
-msgid "Metadata Items"
-msgstr ""
-
-#: syspanel/views/tenants.py:145
-msgid "Injected Files"
-msgstr ""
-
-#: syspanel/views/tenants.py:146
-msgid "Injected File Content Bytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:149
-#: templates/django_openstack/dash/_sidebar.html:8
-#: templates/django_openstack/dash/images/launch.html:37
-#: templates/django_openstack/dash/instances/index.html:13
-#: templates/django_openstack/syspanel/_sidebar.html:9
-#: templates/django_openstack/syspanel/instances/index.html:13
-#: templates/django_openstack/syspanel/instances/usage.html:77
-msgid "Instances"
-msgstr "Instancje"
-
-#: syspanel/views/tenants.py:150
-#: templates/django_openstack/dash/images/launch.html:41
-msgid "Volumes"
-msgstr "Wolumeny"
-
-#: syspanel/views/tenants.py:151
-#: templates/django_openstack/dash/images/launch.html:45
-msgid "Gigabytes"
-msgstr ""
-
-#: syspanel/views/tenants.py:152
-msgid "RAM (in MB)"
-msgstr ""
-
-#: syspanel/views/tenants.py:153
-#: templates/django_openstack/dash/_sidebar.html:12
-#: templates/django_openstack/dash/floating_ips/index.html:13
-#: templates/django_openstack/dash/images/launch.html:33
-msgid "Floating IPs"
-msgstr ""
-
-#: syspanel/views/tenants.py:169
-#, fuzzy, python-format
-msgid "Quotas for %s were successfully updated."
-msgstr "Grupa bezpieczeństwa %s została pomyślnie usunięta."
-
-#: syspanel/views/tenants.py:173
-#, fuzzy, python-format
-msgid "Unable to update quotas: %s"
-msgstr "Nie można zaktualizować obrazu: %s"
-
-#: syspanel/views/tenants.py:183
-#, fuzzy, python-format
-msgid "Successfully deleted tenant %(tenant)s."
-msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
-
-#: syspanel/views/tenants.py:188
-#, fuzzy, python-format
-msgid "Error deleting tenant: %s"
-msgstr "Nie można usunąć klucza: %s"
-
-#: syspanel/views/tenants.py:206
-#, fuzzy, python-format
-msgid "Unable to get tenant info: %s"
-msgstr "Nie można utworzyć klucza: %s"
-
-#: syspanel/views/users.py:54 syspanel/views/users.py:72
-#: templates/django_openstack/syspanel/tenants/users.html:24
-#: templates/django_openstack/syspanel/users/index.html:22
-msgid "Email"
-msgstr ""
-
-#: syspanel/views/users.py:58 syspanel/views/users.py:76
-msgid "Primary Tenant"
-msgstr ""
-
-#: syspanel/views/users.py:86
-#, fuzzy, python-format
-msgid "%(user)s was successfully deleted."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/users.py:92
-msgid "ID (username)"
-msgstr ""
-
-#: syspanel/views/users.py:93
-msgid "enabled"
-msgstr ""
-
-#: syspanel/views/users.py:104
-#, python-format
-msgid "User %(user)s %(state)s"
-msgstr ""
-
-#: syspanel/views/users.py:109
-#, fuzzy, python-format
-msgid "Unable to %(state)s user %(user)s"
-msgstr "Nie można usunąć klucza: %s"
-
-#: syspanel/views/users.py:128
-#, fuzzy, python-format
-msgid "Unable to list users: %s"
-msgstr "Nie można usunąć klucza: %s"
-
-#: syspanel/views/users.py:160
-#, python-format
-msgid "Updated %(attrib)s for %(user)s."
-msgstr ""
-
-#: syspanel/views/users.py:166
-#, fuzzy
-msgid "Unable to update user, please try again."
-msgstr "Nie można zaktualizować obrazu: %s"
-
-#: syspanel/views/users.py:194
-#, fuzzy, python-format
-msgid "Unable to retrieve tenant list: %s"
-msgstr "Nie można utworzyć klucza: %s"
-
-#: syspanel/views/users.py:212
-#, fuzzy, python-format
-msgid "User \"%s\" was successfully created."
-msgstr "Klucz %s został pomyślnie usunięty."
-
-#: syspanel/views/users.py:222
-#, python-format
-msgid "Error assigning role to user: %s"
-msgstr ""
-
-#: syspanel/views/users.py:232
-#, fuzzy, python-format
-msgid "Error creating user: %s"
-msgstr "tworzenie użytkownika %s..."
-
-#: templates/django_openstack/auth/_login.html:14
-#: templates/django_openstack/auth/_switch.html:14
-msgid "Login"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:12
-msgid "Search"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-msgid "Refresh"
-msgstr ""
-
-#: templates/django_openstack/common/_page_header.html:17
-#: templates/django_openstack/dash/objects/index.html:17
-msgid "Refresh List"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_reboot.html:8
-msgid "Reboot"
-msgstr ""
-
-#: templates/django_openstack/common/instances/_terminate.html:8
-msgid "Terminate"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:5
-msgid "Manage Compute"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:7
-#: templates/django_openstack/dash/instances/usage.html:14
-#: templates/django_openstack/syspanel/_sidebar.html:7
-msgid "Overview"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:9
-#: templates/django_openstack/dash/images/index.html:12
-#: templates/django_openstack/syspanel/_sidebar.html:11
-#: templates/django_openstack/syspanel/images/index.html:13
-msgid "Images"
-msgstr "Obrazy"
-
-#: templates/django_openstack/dash/_sidebar.html:10
-#: templates/django_openstack/dash/snapshots/index.html:13
-msgid "Snapshots"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:11
-#: templates/django_openstack/dash/keypairs/index.html:13
-msgid "Keypairs"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:15
-#: templates/django_openstack/dash/networks/index.html:13
-msgid "Networks"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:19
-msgid "Manage Object Store"
-msgstr ""
-
-#: templates/django_openstack/dash/_sidebar.html:21
-#: templates/django_openstack/dash/containers/index.html:13
-msgid "Containers"
-msgstr ""
-
-#: templates/django_openstack/dash/settings.html:20
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
msgid "Dashboard Settings"
msgstr ""
-#: templates/django_openstack/dash/settings.html:26
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
msgid "Dashboard User Interface Language"
msgstr ""
-#: templates/django_openstack/dash/settings.html:38
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
msgid "Select Language"
msgstr ""
-#: templates/django_openstack/dash/containers/_delete.html:8
-#: templates/django_openstack/dash/images/_delete.html:8
-#: templates/django_openstack/dash/keypairs/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete.html:8
-#: templates/django_openstack/dash/networks/_delete_port.html:9
-#: templates/django_openstack/dash/objects/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete.html:8
-#: templates/django_openstack/dash/security_groups/_delete_rule.html:8
-#: templates/django_openstack/syspanel/flavors/_delete.html:8
-#: templates/django_openstack/syspanel/images/_delete.html:8
-#: templates/django_openstack/syspanel/tenants/_delete.html:8
-#: templates/django_openstack/syspanel/users/_delete.html:8
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
msgid "Delete"
msgstr "Usuń"
-#: templates/django_openstack/dash/containers/_form.html:10
+#: dashboards/dash/templates/dash/containers/_form.html:10
msgid "Create Container"
msgstr ""
-#: templates/django_openstack/dash/containers/_list.html:7
-#: templates/django_openstack/dash/instances/_list.html:13
-#: templates/django_openstack/dash/keypairs/_list.html:6
-#: templates/django_openstack/dash/networks/_detail.html:7
-#: templates/django_openstack/dash/objects/_list.html:7
-#: templates/django_openstack/dash/security_groups/_list.html:6
-#: templates/django_openstack/dash/security_groups/edit_rules.html:24
-#: templates/django_openstack/syspanel/flavors/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:13
-#: templates/django_openstack/syspanel/services/_list.html:9
-#: templates/django_openstack/syspanel/tenants/users.html:25
-#: templates/django_openstack/syspanel/tenants/users.html:54
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
#, fuzzy
msgid "Actions"
msgstr "Położenie"
-#: templates/django_openstack/dash/containers/_list.html:17
+#: dashboards/dash/templates/dash/containers/_list.html:17
msgid "List Objects"
msgstr ""
-#: templates/django_openstack/dash/containers/_list.html:18
-#: templates/django_openstack/dash/objects/_form.html:10
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
msgid "Upload Object"
msgstr ""
-#: templates/django_openstack/dash/containers/create.html:11
-#: templates/django_openstack/syspanel/tenants/_create_form.html:5
-#: templates/django_openstack/syspanel/tenants/create.html:11
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
msgid "Create Tenant"
msgstr ""
-#: templates/django_openstack/dash/containers/create.html:22
+#: dashboards/dash/templates/dash/containers/create.html:22
msgid ""
"A container is a storage compartment for your data and provides a way for "
"you to organize your data. You can think of a container as a folder in "
@@ -1101,277 +741,356 @@ msgid ""
"container defined in your account prior to uploading data."
msgstr ""
-#: templates/django_openstack/dash/containers/index.html:18
+#: dashboards/dash/templates/dash/containers/index.html:18
#, fuzzy
msgid "Create New Container"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/dash/floating_ips/_allocate.html:7
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
msgid "Allocate IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_associate.html:14
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
msgid "Associate IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_disassociate.html:8
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
msgid "Disassociate"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_list.html:14
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
msgid "Instance ID:"
msgstr "ID instancji:"
-#: templates/django_openstack/dash/floating_ips/_list.html:15
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
msgid "Fixed IP:"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/_list.html:28
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
#, fuzzy
msgid "Associate to instance"
msgstr "Aktualizuj instncję"
-#: templates/django_openstack/dash/floating_ips/_release.html:8
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
msgid "Release"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/associate.html:12
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
msgid "Associate Floating IP"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/associate.html:22
-#: templates/django_openstack/dash/images/launch.html:21
-#: templates/django_openstack/dash/images/update.html:21
-#: templates/django_openstack/dash/instances/update.html:23
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
msgid "Description:"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/associate.html:23
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
msgid "Associate a floating ip with an instance."
msgstr ""
-#: templates/django_openstack/dash/floating_ips/index.html:21
-#: templates/django_openstack/dash/images/index.html:21
-#: templates/django_openstack/dash/instances/index.html:22
-#: templates/django_openstack/dash/instances/usage.html:97
-#: templates/django_openstack/dash/keypairs/index.html:23
-#: templates/django_openstack/dash/networks/detail.html:27
-#: templates/django_openstack/dash/networks/index.html:23
-#: templates/django_openstack/dash/security_groups/index.html:24
-#: templates/django_openstack/dash/snapshots/index.html:22
-#: templates/django_openstack/syspanel/instances/index.html:22
-#: templates/django_openstack/syspanel/tenants/users.html:44
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
msgid "Info"
msgstr ""
-#: templates/django_openstack/dash/floating_ips/index.html:22
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
msgid "There are currently no floating ips assigned to your tenant."
msgstr ""
-#: templates/django_openstack/dash/images/_form.html:10
-#: templates/django_openstack/dash/images/update.html:11
-#: templates/django_openstack/syspanel/images/_form.html:10
-#: templates/django_openstack/syspanel/images/update.html:11
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
msgid "Update Image"
msgstr "Aktualizuj obraz"
-#: templates/django_openstack/dash/images/_launch.html:5
-#: templates/django_openstack/dash/images/_launch_form.html:14
-#: templates/django_openstack/dash/images/launch.html:12
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
#, fuzzy
msgid "Launch Instance"
msgstr "Uruchom obraz"
-#: templates/django_openstack/dash/images/_list.html:7
-#: templates/django_openstack/syspanel/images/_list.html:10
-#: templates/django_openstack/syspanel/instances/_list.html:9
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
msgid "Created"
msgstr ""
-#: templates/django_openstack/dash/images/_list.html:8
-#: templates/django_openstack/syspanel/images/_list.html:11
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
#, fuzzy
msgid "Updated"
msgstr "Aktualizuj obraz"
-#: templates/django_openstack/dash/images/_list.html:9
-#: templates/django_openstack/dash/instances/usage.html:68
-#: templates/django_openstack/syspanel/images/_list.html:12
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:74
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
msgid "Status"
msgstr ""
-#: templates/django_openstack/dash/images/_list.html:22
-#: templates/django_openstack/dash/instances/_list.html:68
-#: templates/django_openstack/syspanel/images/_list.html:28
-#: templates/django_openstack/syspanel/tenants/_list.html:19
-#: templates/django_openstack/syspanel/users/index.html:36
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
msgid "Edit"
msgstr ""
-#: templates/django_openstack/dash/images/_list.html:24
+#: dashboards/dash/templates/dash/images/_list.html:24
#, fuzzy
msgid "Launch"
msgstr "Uruchom obraz"
-#: templates/django_openstack/dash/images/launch.html:22
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr "Obrazy"
+
+#: dashboards/dash/templates/dash/images/launch.html:22
msgid ""
"Specify the details for launching an instance. Also please make note of the "
"table below; all tenants have quotas which define the limit of resources you "
"are allowed to provision."
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:25
-#: templates/django_openstack/syspanel/quotas/index.html:19
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
msgid "Quota Name"
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:26
-#: templates/django_openstack/syspanel/quotas/index.html:20
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
msgid "Limit"
msgstr ""
-#: templates/django_openstack/dash/images/launch.html:29
+#: dashboards/dash/templates/dash/images/launch.html:29
msgid "RAM (MB)"
msgstr ""
-#: templates/django_openstack/dash/images/update.html:22
-#: templates/django_openstack/syspanel/images/update.html:22
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr "Instancje"
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr "Wolumeny"
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
#, fuzzy
msgid "From here you can modify different properties of an image."
msgstr "Tutaj można zarządzać użytkownikami i rolami."
-#: templates/django_openstack/dash/instances/_form.html:10
-#: templates/django_openstack/dash/instances/update.html:12
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
msgid "Update Instance"
msgstr "Aktualizuj instncję"
-#: templates/django_openstack/dash/instances/_list.html:8
+#: dashboards/dash/templates/dash/instances/_list.html:8
msgid "Groups"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:9
-#: templates/django_openstack/syspanel/instances/_list.html:10
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
#, fuzzy
msgid "Image"
msgstr "Obrazy"
-#: templates/django_openstack/dash/instances/_list.html:10
-#: templates/django_openstack/syspanel/images/_list.html:8
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
msgid "Size"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:11
-#: templates/django_openstack/syspanel/instances/_list.html:11
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
msgid "IPs"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:12
-#: templates/django_openstack/dash/networks/_detail.html:5
-#: templates/django_openstack/syspanel/images/_list.html:36
-#: templates/django_openstack/syspanel/instances/_list.html:12
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
msgid "State"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:66
+#: dashboards/dash/templates/dash/instances/_list.html:66
msgid "Log"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:67
-#: templates/django_openstack/syspanel/instances/_list.html:49
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
msgid "VNC Console"
msgstr ""
-#: templates/django_openstack/dash/instances/_list.html:69
+#: dashboards/dash/templates/dash/instances/_list.html:69
msgid "Snapshot"
msgstr ""
-#: templates/django_openstack/dash/instances/index.html:23
+#: dashboards/dash/templates/dash/instances/index.html:23
#, python-format
msgid ""
"There are currently no instances. You can launch an instance from the <a "
"href='%(dash_img_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/dash/instances/update.html:19
+#: dashboards/dash/templates/dash/instances/update.html:19
msgid "Return to Instances List"
msgstr ""
-#: templates/django_openstack/dash/instances/update.html:24
+#: dashboards/dash/templates/dash/instances/update.html:24
msgid "Update the name and description of your instance"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:46
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:60
-#: templates/django_openstack/syspanel/instances/usage.html:70
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
msgid "Download CSV"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:50
+#: dashboards/dash/templates/dash/instances/usage.html:50
msgid "Hide Terminated"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:52
+#: dashboards/dash/templates/dash/instances/usage.html:52
msgid "Show Terminated"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:62
-#: templates/django_openstack/syspanel/instances/_list.html:7
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:68
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
msgid "User"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:64
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:70
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
msgid "Ram Size"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:65
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:71
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
msgid "Disk Size"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:67
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:73
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
msgid "Uptime"
msgstr ""
-#: templates/django_openstack/dash/instances/usage.html:89
+#: dashboards/dash/templates/dash/instances/usage.html:89
#, fuzzy
msgid "No active instances."
msgstr "Zobacz instancje"
-#: templates/django_openstack/dash/instances/usage.html:98
+#: dashboards/dash/templates/dash/instances/usage.html:98
#, python-format
msgid ""
"There are currently no instances.<br/><br/>You can launch an instance from "
"the <a href='%(dash_img_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/dash/keypairs/_form.html:10
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
msgid "Add Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/_list.html:5
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
msgid "Fingerprint"
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:24
-#: templates/django_openstack/dash/keypairs/import.html:15
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
msgid "Create Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:30
+#: dashboards/dash/templates/dash/keypairs/create.html:30
msgid "Your private key is being downloaded."
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:32
-#: templates/django_openstack/dash/keypairs/import.html:22
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
msgid "Return to keypairs list"
msgstr ""
-#: templates/django_openstack/dash/keypairs/create.html:37
-#: templates/django_openstack/dash/keypairs/import.html:27
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
#, fuzzy
msgid ""
"Keypairs are ssh credentials which are injected into images when they are "
@@ -1383,159 +1102,172 @@ msgstr ""
"publiczny umożliwia pobranie klucza prywatnego (pliku pem). <em>Należy "
"chronić i używać ten klucza tak jak normalnego klucza prywantego.</em>"
-#: templates/django_openstack/dash/keypairs/create.html:38
-#: templates/django_openstack/dash/keypairs/import.html:28
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
msgid "Protect and use the key as you would any normal ssh private key."
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:19
-#: templates/django_openstack/dash/keypairs/index.html:26
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
msgid "Add New Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:20
-#: templates/django_openstack/dash/keypairs/index.html:27
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
msgid "Import Keypair"
msgstr ""
-#: templates/django_openstack/dash/keypairs/index.html:24
+#: dashboards/dash/templates/dash/keypairs/index.html:24
#, fuzzy
msgid "There are currently no keypairs."
msgstr "Brak istniejących par kluczy."
-#: templates/django_openstack/dash/networks/_detach_port.html:9
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
msgid "Detach"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:6
#, fuzzy
msgid "Attachment"
msgstr "Dołącz wolumen"
-#: templates/django_openstack/dash/networks/_detail.html:8
+#: dashboards/dash/templates/dash/networks/_detail.html:8
msgid "Extensions"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:20
+#: dashboards/dash/templates/dash/networks/_detail.html:20
msgid "VIF Id"
msgstr ""
-#: templates/django_openstack/dash/networks/_detail.html:36
+#: dashboards/dash/templates/dash/networks/_detail.html:36
#, fuzzy
msgid "Attach"
msgstr "Dołącz wolumen"
-#: templates/django_openstack/dash/networks/_form.html:10
-#: templates/django_openstack/dash/networks/create.html:12
-#: templates/django_openstack/dash/ports/create.html:12
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
#, fuzzy
msgid "Create Network"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/dash/networks/_list.html:6
+#: dashboards/dash/templates/dash/networks/_list.html:6
msgid "Ports"
msgstr ""
-#: templates/django_openstack/dash/networks/_list.html:7
+#: dashboards/dash/templates/dash/networks/_list.html:7
#, fuzzy
msgid "Available"
msgstr "brak dostępnych"
-#: templates/django_openstack/dash/networks/_list.html:8
+#: dashboards/dash/templates/dash/networks/_list.html:8
msgid "Used"
msgstr ""
-#: templates/django_openstack/dash/networks/_list.html:9
+#: dashboards/dash/templates/dash/networks/_list.html:9
#, fuzzy
msgid "Action"
msgstr "Położenie"
-#: templates/django_openstack/dash/networks/_list.html:22
-#: templates/django_openstack/dash/networks/_rename.html:11
-#: templates/django_openstack/dash/networks/_rename.html:15
-#: templates/django_openstack/dash/networks/rename.html:31
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
msgid "Rename"
msgstr ""
-#: templates/django_openstack/dash/networks/_rename_form.html:11
-#: templates/django_openstack/dash/networks/rename.html:12
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
msgid "Rename Network"
msgstr ""
-#: templates/django_openstack/dash/networks/_toggle_port.html:11
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
msgid "Port UP"
msgstr ""
-#: templates/django_openstack/dash/networks/_toggle_port.html:14
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
msgid "Port DOWN"
msgstr ""
-#: templates/django_openstack/dash/networks/create.html:19
-#: templates/django_openstack/dash/networks/rename.html:27
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
msgid "Return to networks list"
msgstr ""
-#: templates/django_openstack/dash/networks/create.html:24
+#: dashboards/dash/templates/dash/networks/create.html:24
msgid "Networks provide layer 2 connectivity to your instances."
msgstr ""
-#: templates/django_openstack/dash/networks/detail.html:24
-#: templates/django_openstack/dash/networks/detail.html:28
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
msgid "Create Ports"
msgstr ""
-#: templates/django_openstack/dash/networks/detail.html:28
+#: dashboards/dash/templates/dash/networks/detail.html:28
#, fuzzy
msgid "There are currently no ports in this network."
msgstr "Brak użytkowników aktualnie powiązanych z projektem."
-#: templates/django_openstack/dash/networks/index.html:20
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
#, fuzzy
msgid "Create New Network"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/dash/networks/index.html:24
+#: dashboards/dash/templates/dash/networks/index.html:24
msgid "There are currently no networks."
msgstr ""
-#: templates/django_openstack/dash/networks/index.html:24
+#: dashboards/dash/templates/dash/networks/index.html:24
#, fuzzy
msgid "Create A Network"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/dash/networks/rename.html:32
+#: dashboards/dash/templates/dash/networks/rename.html:32
msgid "Enter a new name for your network."
msgstr ""
-#: templates/django_openstack/dash/objects/_copy.html:10
-#: templates/django_openstack/dash/objects/copy.html:11
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
msgid "Copy Object"
msgstr ""
-#: templates/django_openstack/dash/objects/_filter.html:7
+#: dashboards/dash/templates/dash/objects/_filter.html:7
msgid "Filter"
msgstr ""
-#: templates/django_openstack/dash/objects/_list.html:16
+#: dashboards/dash/templates/dash/objects/_list.html:16
msgid "Copy"
msgstr ""
-#: templates/django_openstack/dash/objects/_list.html:18
+#: dashboards/dash/templates/dash/objects/_list.html:18
msgid "Download"
msgstr ""
-#: templates/django_openstack/dash/objects/copy.html:21
-#: templates/django_openstack/dash/objects/upload.html:20
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
msgid "Return to objects list"
msgstr ""
-#: templates/django_openstack/dash/objects/copy.html:26
+#: dashboards/dash/templates/dash/objects/copy.html:26
msgid ""
"You may make a new copy of an existing object to store in this or another "
"container."
msgstr ""
-#: templates/django_openstack/dash/objects/index.html:31
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
#, python-format
msgid ""
"There are currently no objects in the container %(container_name)s. You can "
@@ -1543,15 +1275,15 @@ msgid ""
"Page &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/dash/objects/index.html:34
+#: dashboards/dash/templates/dash/objects/index.html:34
msgid "Upload New Object &gt;&gt;"
msgstr ""
-#: templates/django_openstack/dash/objects/upload.html:11
+#: dashboards/dash/templates/dash/objects/upload.html:11
msgid "Upload Objects"
msgstr ""
-#: templates/django_openstack/dash/objects/upload.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:25
msgid ""
"An object is the basic storage entity and any optional metadata that "
"represents the files you store in the OpenStack Object Storage system. When "
@@ -1560,17 +1292,17 @@ msgid ""
"object's name, and any metadata consisting of key/value pairs."
msgstr ""
-#: templates/django_openstack/dash/ports/attach.html:12
+#: dashboards/dash/templates/dash/ports/attach.html:12
#, fuzzy
msgid "Attach Port"
msgstr "Dołącz wolumen"
-#: templates/django_openstack/dash/ports/attach.html:38
-#: templates/django_openstack/dash/ports/create.html:19
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
msgid "Return to network detail"
msgstr ""
-#: templates/django_openstack/dash/ports/attach.html:42
+#: dashboards/dash/templates/dash/ports/attach.html:42
msgid ""
"<p>Select an interface from the list on the left to attach it to this port.</"
"p>\n"
@@ -1580,429 +1312,722 @@ msgid ""
"first</p>"
msgstr ""
-#: templates/django_openstack/dash/ports/create.html:24
+#: dashboards/dash/templates/dash/ports/create.html:24
msgid ""
"You can plug virtual interfaces from your instances to ports created in the "
"network"
msgstr ""
-#: templates/django_openstack/dash/security_groups/_form.html:11
-#: templates/django_openstack/dash/security_groups/create.html:11
-#: templates/django_openstack/dash/security_groups/index.html:20
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
#, fuzzy
msgid "Create Security Group"
msgstr "Grupy bezpieczeństwa"
-#: templates/django_openstack/dash/security_groups/_list.html:14
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
#, fuzzy
msgid "Edit Rules"
msgstr "Edytuj role użytkowników"
-#: templates/django_openstack/dash/security_groups/create.html:22
+#: dashboards/dash/templates/dash/security_groups/create.html:22
#, fuzzy
msgid "From here you can create a new security group"
msgstr "Tutaj można edytować wiele ról użytkowników."
-#: templates/django_openstack/dash/security_groups/edit_rules.html:11
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
#, fuzzy
msgid "Edit Security Group Rules"
msgstr "Grupy bezpieczeństwa"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:17
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
#, fuzzy
msgid "Rules for Security Group"
msgstr "Grupy bezpieczeństwa"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:20
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
msgid "IP Protocol"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:21
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
msgid "From Port"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:22
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
msgid "To Port"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:23
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
msgid "CIDR"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:41
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
#, fuzzy
msgid "No rules for this security group"
msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
-#: templates/django_openstack/dash/security_groups/edit_rules.html:49
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
msgid "Add a rule"
msgstr ""
-#: templates/django_openstack/dash/security_groups/edit_rules.html:60
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
msgid "Add Rule"
msgstr ""
-#: templates/django_openstack/dash/security_groups/index.html:25
+#: dashboards/dash/templates/dash/security_groups/index.html:25
#, python-format
msgid ""
"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
"Security Group &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/dash/snapshots/_form.html:11
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
msgid "Create Snapshot"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:19
+#: dashboards/dash/templates/dash/snapshots/create.html:19
msgid "Create a Snapshot"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:25
+#: dashboards/dash/templates/dash/snapshots/create.html:25
msgid "Choose a name for your snapshot."
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:27
+#: dashboards/dash/templates/dash/snapshots/create.html:27
msgid "Return to snapshots list"
msgstr ""
-#: templates/django_openstack/dash/snapshots/create.html:32
+#: dashboards/dash/templates/dash/snapshots/create.html:32
msgid "Snapshots preserve the disk state of a running instance."
msgstr ""
-#: templates/django_openstack/dash/snapshots/index.html:23
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
#, python-format
msgid ""
"There are currently no snapshots. You can create snapshots from running "
"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:5
+#: dashboards/syspanel/dashboard.py:25
msgid "System Panel"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:8
-#: templates/django_openstack/syspanel/services/index.html:13
-msgid "Services"
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:10
-#: templates/django_openstack/syspanel/flavors/index.html:13
-msgid "Flavors"
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:12
-#: templates/django_openstack/syspanel/tenants/index.html:13
-msgid "Tenants"
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:13
-#: templates/django_openstack/syspanel/users/index.html:13
-msgid "Users"
+#: dashboards/syspanel/flavors/forms.py:49
+#, fuzzy, python-format
+msgid "%s was successfully added to flavors."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, fuzzy, python-format
+msgid "Unable to delete flavor: %s"
+msgstr "Nie można usunąć wolumenu: %s"
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, fuzzy, python-format
+msgid "Error updating image: %s"
+msgstr "Nie można zaktualizować obrazu: %s"
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+#, fuzzy
+msgid "Image was successfully uploaded."
+msgstr "Obraz %s został pomyślnie wyrejestrowany."
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
msgstr ""
-#: templates/django_openstack/syspanel/_sidebar.html:14
-msgid "Quotas"
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, fuzzy, python-format
+msgid "Unable to get service info: %s"
+msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_create.html:5
-#: templates/django_openstack/syspanel/flavors/_form.html:14
-#: templates/django_openstack/syspanel/flavors/create.html:11
+#: dashboards/syspanel/services/forms.py:46
+#, fuzzy, python-format
+msgid "Service '%s' has been enabled"
+msgstr "Obraz %s został zaktualizowany."
+
+#: dashboards/syspanel/services/forms.py:49
+#, fuzzy, python-format
+msgid "Service '%s' has been disabled"
+msgstr "Obraz %s został zaktualizowany."
+
+#: dashboards/syspanel/services/forms.py:55
+#, fuzzy, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr "Nie można zaktualizować instancji %(inst)s: %(msg)s"
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
msgid "Create Flavor"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:4
-#: templates/django_openstack/syspanel/tenants/_list.html:4
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
msgid "Id"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:7
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
msgid "Memory"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/_list.html:8
-#: templates/django_openstack/syspanel/instances/usage.html:79
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
msgid "Disk"
msgstr ""
-#: templates/django_openstack/syspanel/flavors/create.html:37
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
#, fuzzy
msgid "From here you can define the sizing of a new flavor."
msgstr "Tutaj można zarządzać użytkownikami i rolami."
-#: templates/django_openstack/syspanel/flavors/index.html:18
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
#, fuzzy
msgid "Create New Flavor"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/syspanel/images/_list.html:9
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
#, fuzzy
msgid "Public"
msgstr "Uczyń publicznym"
-#: templates/django_openstack/syspanel/images/_list.html:35
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
msgid "Location"
msgstr "Położenie"
-#: templates/django_openstack/syspanel/images/_list.html:40
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
msgid "Project ID"
msgstr ""
-#: templates/django_openstack/syspanel/images/_toggle.html:8
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
#, fuzzy
msgid "Toggle Public"
msgstr "Uczyń publicznym"
-#: templates/django_openstack/syspanel/instances/_list.html:6
-#: templates/django_openstack/syspanel/instances/usage.html:76
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
msgid "Tenant"
msgstr ""
-#: templates/django_openstack/syspanel/instances/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
msgid "Host"
msgstr ""
-#: templates/django_openstack/syspanel/instances/_list.html:48
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
msgid "Console Log"
msgstr ""
-#: templates/django_openstack/syspanel/instances/index.html:23
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
#, python-format
msgid ""
"There are currently no instances. You can launch an instance from the <a "
"href='%(dash_image_url)s'>Images Page.</a>"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:14
-#: templates/django_openstack/syspanel/instances/usage.html:16
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
msgid "System Panel Overview"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:52
-#: templates/django_openstack/syspanel/instances/usage.html:61
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
#, fuzzy
msgid "Active Instances"
msgstr "Zobacz instancje"
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:53
-#: templates/django_openstack/syspanel/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
msgid "This month's VCPU-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:54
-#: templates/django_openstack/syspanel/instances/usage.html:63
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
msgid "This month's GB-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/tenant_usage.html:61
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
msgid "Tenant Usage"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:23
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
msgid "Monitoring"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:34
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
msgid "Select a month to query its usage"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:71
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
msgid "Server Usage Summary"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:80
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
msgid "RAM"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:81
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
msgid "VCPU CPU-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/instances/usage.html:82
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
msgid "Disk GB-Hours"
msgstr ""
-#: templates/django_openstack/syspanel/quotas/index.html:13
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
msgid "Default Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:5
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
msgid "Service"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:6
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
msgid "System Stats"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:8
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
msgid "Up"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:22
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
msgid "Hypervisor"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:25
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
msgid "Allocable Cores"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:30
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
msgid "Allocable Storage"
msgstr ""
-#: templates/django_openstack/syspanel/services/_list.html:35
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
msgid "System Ram"
msgstr ""
-#: templates/django_openstack/syspanel/services/_toggle.html:10
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:18
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
msgid "Enable"
msgstr ""
-#: templates/django_openstack/syspanel/services/_toggle.html:20
-#: templates/django_openstack/syspanel/users/_toggle_enabled.html:9
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
msgid "Disable"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_add_user.html:9
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
msgid "Add"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_list.html:8
-#: templates/django_openstack/syspanel/users/index.html:24
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
msgid "Options"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_list.html:20
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
#, fuzzy
msgid "View Members"
msgstr "Zobacz obrazy"
-#: templates/django_openstack/syspanel/tenants/_list.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
msgid "Modify Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/_remove_user.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
#, fuzzy
msgid "Remove"
msgstr "Usuń obraz"
-#: templates/django_openstack/syspanel/tenants/_update_form.html:5
-#: templates/django_openstack/syspanel/tenants/update.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
#, fuzzy
msgid "Update Tenant"
msgstr "Aktualizuj instncję"
-#: templates/django_openstack/syspanel/tenants/_update_quotas_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
#, fuzzy
msgid "Update Quotas"
msgstr "Aktualizuj instncję"
-#: templates/django_openstack/syspanel/tenants/create.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
msgid "From here you can create a new tenant (aka project) to organize users."
msgstr ""
-#: templates/django_openstack/syspanel/tenants/index.html:18
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
#, fuzzy
msgid "Create New Tenant"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/syspanel/tenants/quotas.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
msgid "Update Tenant Quotas"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/quotas.html:22
-msgid ""
-"From here you can edit quotas (max limits) for the tenant {{tenant_id}}."
-msgstr ""
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+#, fuzzy
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr "Tutaj można edytować wiele ról użytkowników."
-#: templates/django_openstack/syspanel/tenants/update.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
#, fuzzy
msgid "From here you can edit a tenant."
msgstr "Tutaj można edytować wiele ról użytkowników."
-#: templates/django_openstack/syspanel/tenants/users.html:12
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
msgid "Users for Tenant"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/users.html:45
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
msgid "here are currently no users for this tenant"
msgstr ""
-#: templates/django_openstack/syspanel/tenants/users.html:49
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
msgid "Add new users"
msgstr ""
-#: templates/django_openstack/syspanel/users/_create_form.html:5
-#: templates/django_openstack/syspanel/users/create.html:12
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
msgid "Create User"
msgstr ""
-#: templates/django_openstack/syspanel/users/_update_form.html:5
-#: templates/django_openstack/syspanel/users/update.html:12
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
#, fuzzy
msgid "Update User"
msgstr "Aktualizuj obraz"
-#: templates/django_openstack/syspanel/users/create.html:23
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
msgid ""
"From here you can create a new user and assign them to a tenant (aka "
"project)."
msgstr ""
-#: templates/django_openstack/syspanel/users/index.html:23
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
msgid "Default Tenant"
msgstr ""
-#: templates/django_openstack/syspanel/users/index.html:42
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
#, fuzzy
msgid "Create New User"
msgstr "Utwórz nowy wolumen."
-#: templates/django_openstack/syspanel/users/update.html:23
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
msgid ""
"From here you can edit users by changing their usernames, emails, passwords, "
"and tenants."
msgstr ""
-#: templatetags/templatetags/sizeformat.py:46
+#: dashboards/syspanel/tenants/forms.py:48
+#, fuzzy, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, fuzzy, python-format
+msgid "Unable to create user association: %s"
+msgstr "Nie można utworzyć grupy bezpieczeństwa: %s"
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, fuzzy, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, fuzzy, python-format
+msgid "Unable to create tenant: %s"
+msgstr "Nie można utworzyć klucza: %s"
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, fuzzy, python-format
+msgid "%s was successfully created."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, fuzzy, python-format
+msgid "%s was successfully updated."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, fuzzy, python-format
+msgid "Unable to update tenant: %s"
+msgstr "Nie można zaktualizować obrazu: %s"
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, fuzzy, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr "Grupa bezpieczeństwa %s została pomyślnie usunięta."
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, fuzzy, python-format
+msgid "Unable to update quotas: %s"
+msgstr "Nie można zaktualizować obrazu: %s"
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, fuzzy, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr "Pomyślnie zmodyfikowano projekt %(proj)s."
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, fuzzy, python-format
+msgid "Error deleting tenant: %s"
+msgstr "Nie można usunąć klucza: %s"
+
+#: dashboards/syspanel/tenants/views.py:51
+#, fuzzy, python-format
+msgid "Unable to get tenant info: %s"
+msgstr "Nie można utworzyć klucza: %s"
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, fuzzy, python-format
+msgid "%(user)s was successfully deleted."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, fuzzy, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr "Nie można usunąć klucza: %s"
+
+#: dashboards/syspanel/users/views.py:49
+#, fuzzy, python-format
+msgid "Unable to list users: %s"
+msgstr "Nie można usunąć klucza: %s"
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+#, fuzzy
+msgid "Unable to update user, please try again."
+msgstr "Nie można zaktualizować obrazu: %s"
+
+#: dashboards/syspanel/users/views.py:113
+#, fuzzy, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr "Nie można utworzyć klucza: %s"
+
+#: dashboards/syspanel/users/views.py:131
+#, fuzzy, python-format
+msgid "User \"%s\" was successfully created."
+msgstr "Klucz %s został pomyślnie usunięty."
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, fuzzy, python-format
+msgid "Error creating user: %s"
+msgstr "tworzenie użytkownika %s..."
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] ""
msgstr[1] ""
-#: templatetags/templatetags/sizeformat.py:50
+#: templatetags/sizeformat.py:50
#, python-format
msgid "%(size)d"
msgid_plural "%(size)d"
msgstr[0] ""
msgstr[1] ""
-#: templatetags/templatetags/sizeformat.py:53
+#: templatetags/sizeformat.py:53
#, python-format
msgid "%s KB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:56
+#: templatetags/sizeformat.py:56
#, python-format
msgid "%s MB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:59
+#: templatetags/sizeformat.py:59
#, python-format
msgid "%s GB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:62
+#: templatetags/sizeformat.py:62
#, python-format
msgid "%s TB"
msgstr ""
-#: templatetags/templatetags/sizeformat.py:64
+#: templatetags/sizeformat.py:64
#, python-format
msgid "%s PB"
msgstr ""
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, fuzzy, python-format
+msgid "Error authenticating: %s"
+msgstr "Użytkownik nie jest uwierzytelniony"
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
+
#~ msgid "Creates nova users for all users in the django auth database."
#~ msgstr "Tworzy użytkowników nova dla wszystkich użytkowników w baze django."
@@ -2012,9 +2037,6 @@ msgstr ""
#~ msgid "A security group named %s already exists."
#~ msgstr "Grupa bezpieczeństwa %s juz istnieje."
-#~ msgid "Project %s does not exist."
-#~ msgstr "Projekt %s nie istnieje."
-
#~ msgid "Successfully started VPN for project %(proj)s."
#~ msgstr "Pomyślnie uruchomiono VPN dla projektu %(proj)s."
diff --git a/django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.mo b/horizon/horizon/locale/pt/LC_MESSAGES/django.mo
index 8cc8b156..0e45aeca 100644
--- a/django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/pt/LC_MESSAGES/django.mo
Binary files differ
diff --git a/horizon/horizon/locale/pt/LC_MESSAGES/django.po b/horizon/horizon/locale/pt/LC_MESSAGES/django.po
new file mode 100644
index 00000000..85e941a1
--- /dev/null
+++ b/horizon/horizon/locale/pt/LC_MESSAGES/django.po
@@ -0,0 +1,1970 @@
+# Translations of Dashboard for OpenStack User Interface.
+# Copyright 2011 Midokura KK
+# This file is distributed under the same license as the Dashboard for OpenStack.
+# FIRST AUTHOR Jeffrey Wilcox, 2011.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: openstack-dashboard\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-11-01 23:07-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: context_processors.py:35
+#, python-format
+msgid ""
+"Unable to retrieve tenant list from "
+"keystone: %s"
+msgstr ""
+
+#: forms.py:180
+#, python-format
+msgid "Unexpected error: %s"
+msgstr ""
+
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
+msgstr ""
+
+#: api/keystone.py:199
+#, python-format
+msgid "Role does not exist: %s"
+msgstr ""
+
+#: api/keystone.py:207
+#, python-format
+msgid "Role \"%s\" does not exist for that user on this tenant."
+msgstr ""
+
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+msgid "Network"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:22
+#, python-format
+msgid "Unable to delete non-empty container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:28
+#, python-format
+msgid "Successfully deleted container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:34
+msgid "Container Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:38
+msgid "Container was successfully created."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, python-format
+msgid "Successfully deleted object: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+msgid "Object was successfully uploaded."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
+#, python-format
+msgid "Successfully released Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:47
+#, python-format
+msgid "Error releasing Floating IP from tenant: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
+msgid "Instance"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:72
+#, python-format
+msgid ""
+"Successfully associated Floating IP: "
+"%(ip)s with Instance: %(inst)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:78
+#, python-format
+msgid "Error associating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:95
+#, python-format
+msgid "Successfully disassociated Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:99
+#, python-format
+msgid "Error disassociating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:114
+#, python-format
+msgid ""
+"Successfully allocated Floating IP \"%(ip)s\" "
+"to tenant \"%(tenant)s\""
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:120
+#, python-format
+msgid ""
+"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
+"\": %(msg)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/views.py:53
+#, python-format
+msgid "Error fetching floating ips: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
+msgid "Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
+msgid "Kernel ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
+msgid "Ramdisk ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
+msgid "Architecture"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
+msgid "Container Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
+msgid "Disk Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
+#, python-format
+msgid "Unable to retreive image info from glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:57
+#, python-format
+msgid "Error updating image with id: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
+msgid "Error connecting to glance"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
+msgid "Image was successfully updated."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:97
+msgid "Unspecified Exception in image update"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:101
+msgid ""
+"Unable to update image. You are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:107
+msgid "Server Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:111
+msgid "User Data"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
+msgid "Flavor"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:126
+msgid "Key Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
+msgid "Security Groups"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:165
+msgid "Instance was successfully launched"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:174
+#, python-format
+msgid "Unable to launch instance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:188
+msgid ""
+"Unable to delete image, you are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
+#, python-format
+msgid "Error connecting to glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:198
+msgid "Error deleting image: %(image)s: %i(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
+msgid "There are currently no images."
+msgstr ""
+
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
+#, python-format
+msgid "Error retrieving image list: %s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:118
+#, python-format
+msgid "Error parsing quota for %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
+#, python-format
+msgid "Error retrieving image %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:25
+#, python-format
+msgid "ApiException while terminating instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:28
+#, python-format
+msgid "Unable to terminate %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:31
+#, python-format
+msgid "Instance %s has been terminated."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:45
+msgid "Instance rebooting"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:47
+#, python-format
+msgid "ApiException while rebooting instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:50
+#, python-format
+msgid "Unable to reboot instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:53
+#, python-format
+msgid "Instance %s has been rebooted."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:75
+#, python-format
+msgid "Instance '%s' updated"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:79
+#, python-format
+msgid "Unable to update instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:55
+msgid "Exception in instance index"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
+#, python-format
+msgid "Unable to get instance list: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:110
+msgid "ApiException in instance usage"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, python-format
+msgid "Unable to get usage info: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:174
+msgid "ApiException while fetching instance console"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:176
+#, python-format
+msgid "Unable to get log for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:190
+msgid "ApiException while fetching instance vnc connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
+msgid "ApiException while fetching instance info"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:235
+msgid ""
+"ApiException while fetching instance vnc "
+"connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:238
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:244
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:24
+#, python-format
+msgid "Successfully deleted keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:29
+#, python-format
+msgid "Error deleting keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
+msgid "Keypair Name"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:50
+#, python-format
+msgid "Error Creating Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:58
+msgid "Public Key"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:64
+#, python-format
+msgid "Successfully imported public key: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:70
+#, python-format
+msgid "Error Importing Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/views.py:53
+#, python-format
+msgid "Error fetching keypairs: %s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:15
+msgid "Network Name"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:26
+#, python-format
+msgid "Unable to create network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:30
+#, python-format
+msgid "Network %s has been created."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:45
+#, python-format
+msgid "Unable to delete network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:48
+#, python-format
+msgid "Network %s has been deleted."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:67
+#, python-format
+msgid "Unable to rename network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:70
+#, python-format
+msgid "Network %(net)s has been renamed to %(new_name)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:80
+msgid "Number of Ports"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:90
+#, python-format
+msgid "Unable to create ports on network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:93
+#, python-format
+msgid "%(num_ports)s ports created on network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:112
+#, python-format
+msgid "Unable to delete port %(port)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:115
+#, python-format
+msgid "Port %(port)s deleted from network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:126
+msgid "Select VIF to connect"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:137
+#, python-format
+msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:142
+#, python-format
+msgid "Port %(port)s connected to VIF %(vif)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:159
+#, python-format
+msgid "Unable to detach port %(port)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:162
+#, python-format
+msgid "Port %s detached."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:181
+#, python-format
+msgid "Unable to set port state to %(state)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:184
+#, python-format
+msgid "Port %(port)s state set to %(state)s."
+msgstr ""
+
+#: dashboards/dash/networks/views.py:68
+#, python-format
+msgid "Unable to get network list: %s"
+msgstr ""
+
+#: dashboards/dash/networks/views.py:104
+#, python-format
+msgid "Unable to get network details: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:48
+#, python-format
+msgid "Successfully created security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:53
+#, python-format
+msgid "Error creating security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:67
+#, python-format
+msgid "Successfully deleted security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:71
+#, python-format
+msgid "Error deleting security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:100
+#, python-format
+msgid "Successfully added rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:104
+#, python-format
+msgid "Error adding rule security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:122
+#, python-format
+msgid "Successfully deleted rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:126
+#, python-format
+msgid "Error authorizing security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:54
+#, python-format
+msgid "Error fetching security_groups: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:82
+#, python-format
+msgid "Error getting security_group: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:19
+msgid "Snapshot Name"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:30
+#, python-format
+msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:34
+#, python-format
+msgid "Error Creating Snapshot: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:76
+#, python-format
+msgid "Unable to retreive instance: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:83
+#, python-format
+msgid ""
+"To snapshot, instance state must be one of "
+"the following: %s"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
+msgid "Dashboard Settings"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
+msgid "Dashboard User Interface Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
+msgid "Select Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
+msgid "Delete"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_form.html:10
+msgid "Create Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
+msgid "Actions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:17
+msgid "List Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
+msgid "Upload Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
+msgid "Create Tenant"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:22
+msgid ""
+"A container is a storage compartment for your data and provides a way for "
+"you to organize your data. You can think of a container as a folder in "
+"Windows® or a directory in UNIX®. The primary difference between a container "
+"and these other file system concepts is that containers cannot be nested. "
+"You can, however, create an unlimited number of containers within your "
+"account. Data must be stored in a container so you must have at least one "
+"container defined in your account prior to uploading data."
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/index.html:18
+msgid "Create New Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
+msgid "Allocate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
+msgid "Associate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
+msgid "Disassociate"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
+msgid "Instance ID:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
+msgid "Fixed IP:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
+msgid "Associate to instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
+msgid "Release"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
+msgid "Associate Floating IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
+msgid "Description:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
+msgid "Associate a floating ip with an instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
+msgid "Info"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
+msgid "There are currently no floating ips assigned to your tenant."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
+msgid "Update Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
+msgid "Launch Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
+msgid "Created"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
+msgid "Updated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
+msgid "Status"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
+msgid "Edit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:24
+msgid "Launch"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:22
+msgid ""
+"Specify the details for launching an instance. Also please make note of the "
+"table below; all tenants have quotas which define the limit of resources you "
+"are allowed to provision."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
+msgid "Quota Name"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
+msgid "Limit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:29
+msgid "RAM (MB)"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
+msgid "From here you can modify different properties of an image."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
+msgid "Update Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:8
+msgid "Groups"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
+msgid "Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
+msgid "Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
+msgid "IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
+msgid "State"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:66
+msgid "Log"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
+msgid "VNC Console"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:69
+msgid "Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:19
+msgid "Return to Instances List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:24
+msgid "Update the name and description of your instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
+msgid "Download CSV"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:50
+msgid "Hide Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:52
+msgid "Show Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
+msgid "User"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
+msgid "Ram Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
+msgid "Disk Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
+msgid "Uptime"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:89
+msgid "No active instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:98
+#, python-format
+msgid ""
+"There are currently no instances.<br/><br/>You can launch an instance from "
+"the <a href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
+msgid "Add Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
+msgid "Fingerprint"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
+msgid "Create Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:30
+msgid "Your private key is being downloaded."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
+msgid "Return to keypairs list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
+msgid ""
+"Keypairs are ssh credentials which are injected into images when they are "
+"launched. Creating a new key pair registers the public key and downloads the "
+"private key (a .pem file)."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
+msgid "Protect and use the key as you would any normal ssh private key."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
+msgid "Add New Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
+msgid "Import Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:24
+msgid "There are currently no keypairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
+msgid "Detach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:6
+msgid "Attachment"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:8
+msgid "Extensions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:20
+msgid "VIF Id"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:36
+msgid "Attach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
+msgid "Create Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:6
+msgid "Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:7
+msgid "Available"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:8
+msgid "Used"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:9
+msgid "Action"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
+msgid "Rename"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
+msgid "Rename Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
+msgid "Port UP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
+msgid "Port DOWN"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
+msgid "Return to networks list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:24
+msgid "Networks provide layer 2 connectivity to your instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "Create Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "There are currently no ports in this network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
+msgid "Create New Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "There are currently no networks."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "Create A Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/rename.html:32
+msgid "Enter a new name for your network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
+msgid "Copy Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_filter.html:7
+msgid "Filter"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:16
+msgid "Copy"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:18
+msgid "Download"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
+msgid "Return to objects list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:26
+msgid ""
+"You may make a new copy of an existing object to store in this or another "
+"container."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
+#, python-format
+msgid ""
+"There are currently no objects in the container %(container_name)s. You can "
+"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
+"Page &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:34
+msgid "Upload New Object &gt;&gt;"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:11
+msgid "Upload Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:25
+msgid ""
+"An object is the basic storage entity and any optional metadata that "
+"represents the files you store in the OpenStack Object Storage system. When "
+"you upload data to OpenStack Object Storage, the data is stored as-is (no "
+"compression or encryption) and consists of a location (container), the "
+"object's name, and any metadata consisting of key/value pairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:12
+msgid "Attach Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
+msgid "Return to network detail"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:42
+msgid ""
+"<p>Select an interface from the list on the left to attach it to this port.</"
+"p>\n"
+" <p>Only interfaces that are not connected to any existing port are "
+"shown</p>\n"
+" <p>If you want to reconnect a connected interface, please detach it "
+"first</p>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/create.html:24
+msgid ""
+"You can plug virtual interfaces from your instances to ports created in the "
+"network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
+msgid "Create Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
+msgid "Edit Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/create.html:22
+msgid "From here you can create a new security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
+msgid "Edit Security Group Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
+msgid "Rules for Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
+msgid "IP Protocol"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
+msgid "From Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
+msgid "To Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
+msgid "CIDR"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
+msgid "No rules for this security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
+msgid "Add a rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
+msgid "Add Rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/index.html:25
+#, python-format
+msgid ""
+"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
+"Security Group &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
+msgid "Create Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:19
+msgid "Create a Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:25
+msgid "Choose a name for your snapshot."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:27
+msgid "Return to snapshots list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:32
+msgid "Snapshots preserve the disk state of a running instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
+#, python-format
+msgid ""
+"There are currently no snapshots. You can create snapshots from running "
+"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/syspanel/dashboard.py:25
+msgid "System Panel"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, python-format
+msgid "%s was successfully added to flavors."
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, python-format
+msgid "Unable to delete flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, python-format
+msgid "Error updating image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+msgid "Image was successfully uploaded."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, python-format
+msgid "Unable to get service info: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, python-format
+msgid "Service '%s' has been enabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:49
+#, python-format
+msgid "Service '%s' has been disabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:55
+#, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
+msgid "Create Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
+msgid "Id"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
+msgid "Memory"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
+msgid "Disk"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
+msgid "From here you can define the sizing of a new flavor."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
+msgid "Create New Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
+msgid "Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
+msgid "Location"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
+msgid "Project ID"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
+msgid "Toggle Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
+msgid "Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
+msgid "Host"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
+msgid "Console Log"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_image_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
+msgid "System Panel Overview"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
+msgid "Active Instances"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
+msgid "This month's VCPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
+msgid "This month's GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
+msgid "Tenant Usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
+msgid "Monitoring"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
+msgid "Select a month to query its usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
+msgid "Server Usage Summary"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
+msgid "RAM"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
+msgid "VCPU CPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
+msgid "Disk GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
+msgid "Default Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
+msgid "Service"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
+msgid "System Stats"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
+msgid "Up"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
+msgid "Hypervisor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
+msgid "Allocable Cores"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
+msgid "Allocable Storage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
+msgid "System Ram"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
+msgid "Enable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
+msgid "Disable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
+msgid "Add"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
+msgid "Options"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
+msgid "View Members"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
+msgid "Modify Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
+msgid "Remove"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
+msgid "Update Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
+msgid "Update Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
+msgid "From here you can create a new tenant (aka project) to organize users."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
+msgid "Create New Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
+msgid "Update Tenant Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
+msgid "From here you can edit a tenant."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
+msgid "Users for Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
+msgid "here are currently no users for this tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
+msgid "Add new users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
+msgid "Create User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
+msgid "Update User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
+msgid ""
+"From here you can create a new user and assign them to a tenant (aka "
+"project)."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
+msgid "Default Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
+msgid "Create New User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
+msgid ""
+"From here you can edit users by changing their usernames, emails, passwords, "
+"and tenants."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:48
+#, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, python-format
+msgid "Unable to create user association: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, python-format
+msgid "Unable to create tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, python-format
+msgid "%s was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, python-format
+msgid "%s was successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, python-format
+msgid "Unable to update tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, python-format
+msgid "Unable to update quotas: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, python-format
+msgid "Error deleting tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/views.py:51
+#, python-format
+msgid "Unable to get tenant info: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, python-format
+msgid "%(user)s was successfully deleted."
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:49
+#, python-format
+msgid "Unable to list users: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+msgid "Unable to update user, please try again."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:113
+#, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:131
+#, python-format
+msgid "User \"%s\" was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, python-format
+msgid "Error creating user: %s"
+msgstr ""
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:50
+#, python-format
+msgid "%(size)d"
+msgid_plural "%(size)d"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:53
+#, python-format
+msgid "%s KB"
+msgstr ""
+
+#: templatetags/sizeformat.py:56
+#, python-format
+msgid "%s MB"
+msgstr ""
+
+#: templatetags/sizeformat.py:59
+#, python-format
+msgid "%s GB"
+msgstr ""
+
+#: templatetags/sizeformat.py:62
+#, python-format
+msgid "%s TB"
+msgstr ""
+
+#: templatetags/sizeformat.py:64
+#, python-format
+msgid "%s PB"
+msgstr ""
+
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, python-format
+msgid "Error authenticating: %s"
+msgstr ""
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
diff --git a/django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.mo b/horizon/horizon/locale/zh-cn/LC_MESSAGES/django.mo
index 8cc8b156..f2936816 100644
--- a/django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/zh-cn/LC_MESSAGES/django.mo
Binary files differ
diff --git a/horizon/horizon/locale/zh-cn/LC_MESSAGES/django.po b/horizon/horizon/locale/zh-cn/LC_MESSAGES/django.po
new file mode 100644
index 00000000..8a229336
--- /dev/null
+++ b/horizon/horizon/locale/zh-cn/LC_MESSAGES/django.po
@@ -0,0 +1,1970 @@
+# Translations of Dashboard for OpenStack User Interface.
+# Copyright 2011 Midokura KK
+# This file is distributed under the same license as the Dashboard for OpenStack.
+# FIRST AUTHOR Jeffrey Wilcox, 2011.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: openstack-dashboard\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-11-01 23:08-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: context_processors.py:35
+#, python-format
+msgid ""
+"Unable to retrieve tenant list from "
+"keystone: %s"
+msgstr ""
+
+#: forms.py:180
+#, python-format
+msgid "Unexpected error: %s"
+msgstr ""
+
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
+msgstr ""
+
+#: api/keystone.py:199
+#, python-format
+msgid "Role does not exist: %s"
+msgstr ""
+
+#: api/keystone.py:207
+#, python-format
+msgid "Role \"%s\" does not exist for that user on this tenant."
+msgstr ""
+
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+msgid "Network"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:22
+#, python-format
+msgid "Unable to delete non-empty container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:28
+#, python-format
+msgid "Successfully deleted container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:34
+msgid "Container Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:38
+msgid "Container was successfully created."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, python-format
+msgid "Successfully deleted object: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+msgid "Object was successfully uploaded."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
+#, python-format
+msgid "Successfully released Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:47
+#, python-format
+msgid "Error releasing Floating IP from tenant: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
+msgid "Instance"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:72
+#, python-format
+msgid ""
+"Successfully associated Floating IP: "
+"%(ip)s with Instance: %(inst)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:78
+#, python-format
+msgid "Error associating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:95
+#, python-format
+msgid "Successfully disassociated Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:99
+#, python-format
+msgid "Error disassociating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:114
+#, python-format
+msgid ""
+"Successfully allocated Floating IP \"%(ip)s\" "
+"to tenant \"%(tenant)s\""
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:120
+#, python-format
+msgid ""
+"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
+"\": %(msg)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/views.py:53
+#, python-format
+msgid "Error fetching floating ips: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
+msgid "Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
+msgid "Kernel ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
+msgid "Ramdisk ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
+msgid "Architecture"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
+msgid "Container Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
+msgid "Disk Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
+#, python-format
+msgid "Unable to retreive image info from glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:57
+#, python-format
+msgid "Error updating image with id: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
+msgid "Error connecting to glance"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
+msgid "Image was successfully updated."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:97
+msgid "Unspecified Exception in image update"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:101
+msgid ""
+"Unable to update image. You are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:107
+msgid "Server Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:111
+msgid "User Data"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
+msgid "Flavor"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:126
+msgid "Key Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
+msgid "Security Groups"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:165
+msgid "Instance was successfully launched"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:174
+#, python-format
+msgid "Unable to launch instance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:188
+msgid ""
+"Unable to delete image, you are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
+#, python-format
+msgid "Error connecting to glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:198
+msgid "Error deleting image: %(image)s: %i(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
+msgid "There are currently no images."
+msgstr ""
+
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
+#, python-format
+msgid "Error retrieving image list: %s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:118
+#, python-format
+msgid "Error parsing quota for %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
+#, python-format
+msgid "Error retrieving image %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:25
+#, python-format
+msgid "ApiException while terminating instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:28
+#, python-format
+msgid "Unable to terminate %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:31
+#, python-format
+msgid "Instance %s has been terminated."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:45
+msgid "Instance rebooting"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:47
+#, python-format
+msgid "ApiException while rebooting instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:50
+#, python-format
+msgid "Unable to reboot instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:53
+#, python-format
+msgid "Instance %s has been rebooted."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:75
+#, python-format
+msgid "Instance '%s' updated"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:79
+#, python-format
+msgid "Unable to update instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:55
+msgid "Exception in instance index"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
+#, python-format
+msgid "Unable to get instance list: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:110
+msgid "ApiException in instance usage"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, python-format
+msgid "Unable to get usage info: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:174
+msgid "ApiException while fetching instance console"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:176
+#, python-format
+msgid "Unable to get log for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:190
+msgid "ApiException while fetching instance vnc connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
+msgid "ApiException while fetching instance info"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:235
+msgid ""
+"ApiException while fetching instance vnc "
+"connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:238
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:244
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:24
+#, python-format
+msgid "Successfully deleted keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:29
+#, python-format
+msgid "Error deleting keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
+msgid "Keypair Name"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:50
+#, python-format
+msgid "Error Creating Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:58
+msgid "Public Key"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:64
+#, python-format
+msgid "Successfully imported public key: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:70
+#, python-format
+msgid "Error Importing Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/views.py:53
+#, python-format
+msgid "Error fetching keypairs: %s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:15
+msgid "Network Name"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:26
+#, python-format
+msgid "Unable to create network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:30
+#, python-format
+msgid "Network %s has been created."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:45
+#, python-format
+msgid "Unable to delete network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:48
+#, python-format
+msgid "Network %s has been deleted."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:67
+#, python-format
+msgid "Unable to rename network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:70
+#, python-format
+msgid "Network %(net)s has been renamed to %(new_name)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:80
+msgid "Number of Ports"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:90
+#, python-format
+msgid "Unable to create ports on network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:93
+#, python-format
+msgid "%(num_ports)s ports created on network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:112
+#, python-format
+msgid "Unable to delete port %(port)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:115
+#, python-format
+msgid "Port %(port)s deleted from network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:126
+msgid "Select VIF to connect"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:137
+#, python-format
+msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:142
+#, python-format
+msgid "Port %(port)s connected to VIF %(vif)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:159
+#, python-format
+msgid "Unable to detach port %(port)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:162
+#, python-format
+msgid "Port %s detached."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:181
+#, python-format
+msgid "Unable to set port state to %(state)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:184
+#, python-format
+msgid "Port %(port)s state set to %(state)s."
+msgstr ""
+
+#: dashboards/dash/networks/views.py:68
+#, python-format
+msgid "Unable to get network list: %s"
+msgstr ""
+
+#: dashboards/dash/networks/views.py:104
+#, python-format
+msgid "Unable to get network details: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:48
+#, python-format
+msgid "Successfully created security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:53
+#, python-format
+msgid "Error creating security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:67
+#, python-format
+msgid "Successfully deleted security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:71
+#, python-format
+msgid "Error deleting security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:100
+#, python-format
+msgid "Successfully added rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:104
+#, python-format
+msgid "Error adding rule security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:122
+#, python-format
+msgid "Successfully deleted rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:126
+#, python-format
+msgid "Error authorizing security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:54
+#, python-format
+msgid "Error fetching security_groups: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:82
+#, python-format
+msgid "Error getting security_group: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:19
+msgid "Snapshot Name"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:30
+#, python-format
+msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:34
+#, python-format
+msgid "Error Creating Snapshot: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:76
+#, python-format
+msgid "Unable to retreive instance: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:83
+#, python-format
+msgid ""
+"To snapshot, instance state must be one of "
+"the following: %s"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
+msgid "Dashboard Settings"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
+msgid "Dashboard User Interface Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
+msgid "Select Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
+msgid "Delete"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_form.html:10
+msgid "Create Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
+msgid "Actions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:17
+msgid "List Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
+msgid "Upload Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
+msgid "Create Tenant"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:22
+msgid ""
+"A container is a storage compartment for your data and provides a way for "
+"you to organize your data. You can think of a container as a folder in "
+"Windows® or a directory in UNIX®. The primary difference between a container "
+"and these other file system concepts is that containers cannot be nested. "
+"You can, however, create an unlimited number of containers within your "
+"account. Data must be stored in a container so you must have at least one "
+"container defined in your account prior to uploading data."
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/index.html:18
+msgid "Create New Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
+msgid "Allocate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
+msgid "Associate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
+msgid "Disassociate"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
+msgid "Instance ID:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
+msgid "Fixed IP:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
+msgid "Associate to instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
+msgid "Release"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
+msgid "Associate Floating IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
+msgid "Description:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
+msgid "Associate a floating ip with an instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
+msgid "Info"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
+msgid "There are currently no floating ips assigned to your tenant."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
+msgid "Update Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
+msgid "Launch Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
+msgid "Created"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
+msgid "Updated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
+msgid "Status"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
+msgid "Edit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:24
+msgid "Launch"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:22
+msgid ""
+"Specify the details for launching an instance. Also please make note of the "
+"table below; all tenants have quotas which define the limit of resources you "
+"are allowed to provision."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
+msgid "Quota Name"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
+msgid "Limit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:29
+msgid "RAM (MB)"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
+msgid "From here you can modify different properties of an image."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
+msgid "Update Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:8
+msgid "Groups"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
+msgid "Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
+msgid "Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
+msgid "IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
+msgid "State"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:66
+msgid "Log"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
+msgid "VNC Console"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:69
+msgid "Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:19
+msgid "Return to Instances List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:24
+msgid "Update the name and description of your instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
+msgid "Download CSV"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:50
+msgid "Hide Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:52
+msgid "Show Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
+msgid "User"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
+msgid "Ram Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
+msgid "Disk Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
+msgid "Uptime"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:89
+msgid "No active instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:98
+#, python-format
+msgid ""
+"There are currently no instances.<br/><br/>You can launch an instance from "
+"the <a href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
+msgid "Add Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
+msgid "Fingerprint"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
+msgid "Create Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:30
+msgid "Your private key is being downloaded."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
+msgid "Return to keypairs list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
+msgid ""
+"Keypairs are ssh credentials which are injected into images when they are "
+"launched. Creating a new key pair registers the public key and downloads the "
+"private key (a .pem file)."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
+msgid "Protect and use the key as you would any normal ssh private key."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
+msgid "Add New Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
+msgid "Import Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:24
+msgid "There are currently no keypairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
+msgid "Detach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:6
+msgid "Attachment"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:8
+msgid "Extensions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:20
+msgid "VIF Id"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:36
+msgid "Attach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
+msgid "Create Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:6
+msgid "Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:7
+msgid "Available"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:8
+msgid "Used"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:9
+msgid "Action"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
+msgid "Rename"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
+msgid "Rename Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
+msgid "Port UP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
+msgid "Port DOWN"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
+msgid "Return to networks list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:24
+msgid "Networks provide layer 2 connectivity to your instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "Create Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "There are currently no ports in this network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
+msgid "Create New Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "There are currently no networks."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "Create A Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/rename.html:32
+msgid "Enter a new name for your network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
+msgid "Copy Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_filter.html:7
+msgid "Filter"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:16
+msgid "Copy"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:18
+msgid "Download"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
+msgid "Return to objects list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:26
+msgid ""
+"You may make a new copy of an existing object to store in this or another "
+"container."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
+#, python-format
+msgid ""
+"There are currently no objects in the container %(container_name)s. You can "
+"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
+"Page &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:34
+msgid "Upload New Object &gt;&gt;"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:11
+msgid "Upload Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:25
+msgid ""
+"An object is the basic storage entity and any optional metadata that "
+"represents the files you store in the OpenStack Object Storage system. When "
+"you upload data to OpenStack Object Storage, the data is stored as-is (no "
+"compression or encryption) and consists of a location (container), the "
+"object's name, and any metadata consisting of key/value pairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:12
+msgid "Attach Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
+msgid "Return to network detail"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:42
+msgid ""
+"<p>Select an interface from the list on the left to attach it to this port.</"
+"p>\n"
+" <p>Only interfaces that are not connected to any existing port are "
+"shown</p>\n"
+" <p>If you want to reconnect a connected interface, please detach it "
+"first</p>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/create.html:24
+msgid ""
+"You can plug virtual interfaces from your instances to ports created in the "
+"network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
+msgid "Create Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
+msgid "Edit Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/create.html:22
+msgid "From here you can create a new security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
+msgid "Edit Security Group Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
+msgid "Rules for Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
+msgid "IP Protocol"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
+msgid "From Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
+msgid "To Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
+msgid "CIDR"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
+msgid "No rules for this security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
+msgid "Add a rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
+msgid "Add Rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/index.html:25
+#, python-format
+msgid ""
+"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
+"Security Group &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
+msgid "Create Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:19
+msgid "Create a Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:25
+msgid "Choose a name for your snapshot."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:27
+msgid "Return to snapshots list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:32
+msgid "Snapshots preserve the disk state of a running instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
+#, python-format
+msgid ""
+"There are currently no snapshots. You can create snapshots from running "
+"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/syspanel/dashboard.py:25
+msgid "System Panel"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, python-format
+msgid "%s was successfully added to flavors."
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, python-format
+msgid "Unable to delete flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, python-format
+msgid "Error updating image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+msgid "Image was successfully uploaded."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, python-format
+msgid "Unable to get service info: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, python-format
+msgid "Service '%s' has been enabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:49
+#, python-format
+msgid "Service '%s' has been disabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:55
+#, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
+msgid "Create Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
+msgid "Id"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
+msgid "Memory"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
+msgid "Disk"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
+msgid "From here you can define the sizing of a new flavor."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
+msgid "Create New Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
+msgid "Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
+msgid "Location"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
+msgid "Project ID"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
+msgid "Toggle Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
+msgid "Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
+msgid "Host"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
+msgid "Console Log"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_image_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
+msgid "System Panel Overview"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
+msgid "Active Instances"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
+msgid "This month's VCPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
+msgid "This month's GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
+msgid "Tenant Usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
+msgid "Monitoring"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
+msgid "Select a month to query its usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
+msgid "Server Usage Summary"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
+msgid "RAM"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
+msgid "VCPU CPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
+msgid "Disk GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
+msgid "Default Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
+msgid "Service"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
+msgid "System Stats"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
+msgid "Up"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
+msgid "Hypervisor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
+msgid "Allocable Cores"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
+msgid "Allocable Storage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
+msgid "System Ram"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
+msgid "Enable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
+msgid "Disable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
+msgid "Add"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
+msgid "Options"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
+msgid "View Members"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
+msgid "Modify Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
+msgid "Remove"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
+msgid "Update Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
+msgid "Update Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
+msgid "From here you can create a new tenant (aka project) to organize users."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
+msgid "Create New Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
+msgid "Update Tenant Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
+msgid "From here you can edit a tenant."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
+msgid "Users for Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
+msgid "here are currently no users for this tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
+msgid "Add new users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
+msgid "Create User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
+msgid "Update User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
+msgid ""
+"From here you can create a new user and assign them to a tenant (aka "
+"project)."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
+msgid "Default Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
+msgid "Create New User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
+msgid ""
+"From here you can edit users by changing their usernames, emails, passwords, "
+"and tenants."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:48
+#, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, python-format
+msgid "Unable to create user association: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, python-format
+msgid "Unable to create tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, python-format
+msgid "%s was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, python-format
+msgid "%s was successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, python-format
+msgid "Unable to update tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, python-format
+msgid "Unable to update quotas: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, python-format
+msgid "Error deleting tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/views.py:51
+#, python-format
+msgid "Unable to get tenant info: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, python-format
+msgid "%(user)s was successfully deleted."
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:49
+#, python-format
+msgid "Unable to list users: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+msgid "Unable to update user, please try again."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:113
+#, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:131
+#, python-format
+msgid "User \"%s\" was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, python-format
+msgid "Error creating user: %s"
+msgstr ""
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:50
+#, python-format
+msgid "%(size)d"
+msgid_plural "%(size)d"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:53
+#, python-format
+msgid "%s KB"
+msgstr ""
+
+#: templatetags/sizeformat.py:56
+#, python-format
+msgid "%s MB"
+msgstr ""
+
+#: templatetags/sizeformat.py:59
+#, python-format
+msgid "%s GB"
+msgstr ""
+
+#: templatetags/sizeformat.py:62
+#, python-format
+msgid "%s TB"
+msgstr ""
+
+#: templatetags/sizeformat.py:64
+#, python-format
+msgid "%s PB"
+msgstr ""
+
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, python-format
+msgid "Error authenticating: %s"
+msgstr ""
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
diff --git a/django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.mo b/horizon/horizon/locale/zh-tw/LC_MESSAGES/django.mo
index 8cc8b156..0e45aeca 100644
--- a/django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.mo
+++ b/horizon/horizon/locale/zh-tw/LC_MESSAGES/django.mo
Binary files differ
diff --git a/horizon/horizon/locale/zh-tw/LC_MESSAGES/django.po b/horizon/horizon/locale/zh-tw/LC_MESSAGES/django.po
new file mode 100644
index 00000000..85e941a1
--- /dev/null
+++ b/horizon/horizon/locale/zh-tw/LC_MESSAGES/django.po
@@ -0,0 +1,1970 @@
+# Translations of Dashboard for OpenStack User Interface.
+# Copyright 2011 Midokura KK
+# This file is distributed under the same license as the Dashboard for OpenStack.
+# FIRST AUTHOR Jeffrey Wilcox, 2011.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: openstack-dashboard\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-11-01 23:07-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: context_processors.py:35
+#, python-format
+msgid ""
+"Unable to retrieve tenant list from "
+"keystone: %s"
+msgstr ""
+
+#: forms.py:180
+#, python-format
+msgid "Unexpected error: %s"
+msgstr ""
+
+#: middleware.py:85
+msgid "Your token has expired. Please log in again"
+msgstr ""
+
+#: api/keystone.py:199
+#, python-format
+msgid "Role does not exist: %s"
+msgstr ""
+
+#: api/keystone.py:207
+#, python-format
+msgid "Role \"%s\" does not exist for that user on this tenant."
+msgstr ""
+
+#: dashboards/dash/dashboard.py:25
+msgid "Manage Compute"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:28
+msgid "Network"
+msgstr ""
+
+#: dashboards/dash/dashboard.py:29
+msgid "Object Store"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:22
+#, python-format
+msgid "Unable to delete non-empty container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:28
+#, python-format
+msgid "Successfully deleted container: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:34
+msgid "Container Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:38
+msgid "Container was successfully created."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:55
+#, python-format
+msgid "There are no objects matching that prefix in %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:71
+#, python-format
+msgid "Successfully deleted object: %s"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:77
+msgid "Object Name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:78
+msgid "File"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:88
+msgid "Object was successfully uploaded."
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:94
+msgid "Container to store object in"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:97
+msgid "New object name"
+msgstr ""
+
+#: dashboards/dash/containers/forms.py:119
+#, python-format
+msgid "Object was successfully copied to %(container)s\\%(obj)s"
+msgstr ""
+
+#: dashboards/dash/containers/panel.py:8
+#: dashboards/dash/templates/dash/containers/index.html:13
+msgid "Containers"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:43
+#, python-format
+msgid "Successfully released Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:47
+#, python-format
+msgid "Error releasing Floating IP from tenant: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:63
+#: dashboards/dash/templates/dash/networks/_detail.html:19
+msgid "Instance"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:72
+#, python-format
+msgid ""
+"Successfully associated Floating IP: "
+"%(ip)s with Instance: %(inst)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:78
+#, python-format
+msgid "Error associating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:95
+#, python-format
+msgid "Successfully disassociated Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:99
+#, python-format
+msgid "Error disassociating Floating IP: %s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:114
+#, python-format
+msgid ""
+"Successfully allocated Floating IP \"%(ip)s\" "
+"to tenant \"%(tenant)s\""
+msgstr ""
+
+#: dashboards/dash/floating_ips/forms.py:120
+#, python-format
+msgid ""
+"Error allocating Floating IP \"%(ip)s\" to tenant \"%(tenant)s"
+"\": %(msg)s"
+msgstr ""
+
+#: dashboards/dash/floating_ips/views.py:53
+#, python-format
+msgid "Error fetching floating ips: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:42
+#: dashboards/dash/templates/dash/containers/_list.html:6
+#: dashboards/dash/templates/dash/images/_list.html:6
+#: dashboards/dash/templates/dash/instances/_list.html:7
+#: dashboards/dash/templates/dash/instances/usage.html:61
+#: dashboards/dash/templates/dash/keypairs/_list.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:5
+#: dashboards/dash/templates/dash/objects/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/_list.html:4
+#: dashboards/syspanel/flavors/forms.py:37
+#: dashboards/syspanel/images/forms.py:72
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:5
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:67
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:23
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:53
+#: dashboards/syspanel/templates/syspanel/users/index.html:21
+#: dashboards/syspanel/tenants/forms.py:79
+#: dashboards/syspanel/tenants/forms.py:107
+#: dashboards/syspanel/users/forms.py:42
+msgid "Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:43 dashboards/syspanel/images/forms.py:73
+#: dashboards/syspanel/templates/syspanel/images/_list.html:37
+msgid "Kernel ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:45 dashboards/syspanel/images/forms.py:75
+#: dashboards/syspanel/templates/syspanel/images/_list.html:38
+msgid "Ramdisk ID"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:47 dashboards/syspanel/images/forms.py:77
+#: dashboards/syspanel/templates/syspanel/images/_list.html:39
+msgid "Architecture"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:48 dashboards/syspanel/images/forms.py:79
+#: dashboards/syspanel/templates/syspanel/images/_list.html:41
+msgid "Container Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:50 dashboards/syspanel/images/forms.py:81
+#: dashboards/syspanel/templates/syspanel/images/_list.html:42
+msgid "Disk Format"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:55 dashboards/dash/images/views.py:63
+#, python-format
+msgid "Unable to retreive image info from glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:57
+#, python-format
+msgid "Error updating image with id: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:62 dashboards/dash/images/forms.py:91
+msgid "Error connecting to glance"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:88 dashboards/syspanel/images/views.py:106
+msgid "Image was successfully updated."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:97
+msgid "Unspecified Exception in image update"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:101
+msgid ""
+"Unable to update image. You are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:107
+msgid "Server Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:111
+msgid "User Data"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:121
+#: dashboards/dash/templates/dash/instances/usage.html:66
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:72
+msgid "Flavor"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:126
+msgid "Key Name"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:134
+#: dashboards/dash/templates/dash/security_groups/index.html:13
+msgid "Security Groups"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:165
+msgid "Instance was successfully launched"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:174
+#, python-format
+msgid "Unable to launch instance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:188
+msgid ""
+"Unable to delete image, you are not "
+"its owner."
+msgstr ""
+
+#: dashboards/dash/images/forms.py:193 dashboards/dash/images/views.py:58
+#: dashboards/dash/images/views.py:144 dashboards/dash/snapshots/views.py:51
+#: dashboards/syspanel/images/forms.py:46
+#: dashboards/syspanel/images/forms.py:64
+#: dashboards/syspanel/images/views.py:57
+#: dashboards/syspanel/images/views.py:77
+#: dashboards/syspanel/images/views.py:110
+#: dashboards/syspanel/images/views.py:173
+#, python-format
+msgid "Error connecting to glance: %s"
+msgstr ""
+
+#: dashboards/dash/images/forms.py:198
+msgid "Error deleting image: %(image)s: %i(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:55
+#: dashboards/dash/templates/dash/images/index.html:22
+#: dashboards/syspanel/images/views.py:53
+msgid "There are currently no images."
+msgstr ""
+
+#: dashboards/dash/images/views.py:61 dashboards/dash/snapshots/views.py:55
+#: dashboards/syspanel/images/views.py:61
+#, python-format
+msgid "Error retrieving image list: %s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:118
+#, python-format
+msgid "Error parsing quota for %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/images/views.py:149 dashboards/syspanel/images/views.py:81
+#, python-format
+msgid "Error retrieving image %(image)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:25
+#, python-format
+msgid "ApiException while terminating instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:28
+#, python-format
+msgid "Unable to terminate %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:31
+#, python-format
+msgid "Instance %s has been terminated."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:45
+msgid "Instance rebooting"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:47
+#, python-format
+msgid "ApiException while rebooting instance \"%s\""
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:50
+#, python-format
+msgid "Unable to reboot instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:53
+#, python-format
+msgid "Instance %s has been rebooted."
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:75
+#, python-format
+msgid "Instance '%s' updated"
+msgstr ""
+
+#: dashboards/dash/instances/forms.py:79
+#, python-format
+msgid "Unable to update instance: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:55
+msgid "Exception in instance index"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:56 dashboards/dash/instances/views.py:79
+#: dashboards/syspanel/instances/views.py:270
+#: dashboards/syspanel/instances/views.py:296
+#, python-format
+msgid "Unable to get instance list: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:110
+msgid "ApiException in instance usage"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:112
+#: dashboards/syspanel/flavors/views.py:53
+#: dashboards/syspanel/instances/views.py:93
+#: dashboards/syspanel/instances/views.py:225
+#, python-format
+msgid "Unable to get usage info: %s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:174
+msgid "ApiException while fetching instance console"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:176
+#, python-format
+msgid "Unable to get log for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:190
+msgid "ApiException while fetching instance vnc connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:192
+#: dashboards/syspanel/instances/views.py:323
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:203
+#: dashboards/dash/instances/views.py:242
+msgid "ApiException while fetching instance info"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:205
+#: dashboards/syspanel/instances/views.py:329
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:235
+msgid ""
+"ApiException while fetching instance vnc "
+"connection"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:238
+#, python-format
+msgid "Unable to get vnc console for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/instances/views.py:244
+#, python-format
+msgid "Unable to get information for instance %(inst)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:24
+#, python-format
+msgid "Successfully deleted keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:29
+#, python-format
+msgid "Error deleting keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:35 dashboards/dash/keypairs/forms.py:56
+msgid "Keypair Name"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:50
+#, python-format
+msgid "Error Creating Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:58
+msgid "Public Key"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:64
+#, python-format
+msgid "Successfully imported public key: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/forms.py:70
+#, python-format
+msgid "Error Importing Keypair: %s"
+msgstr ""
+
+#: dashboards/dash/keypairs/views.py:53
+#, python-format
+msgid "Error fetching keypairs: %s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:15
+msgid "Network Name"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:26
+#, python-format
+msgid "Unable to create network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:30
+#, python-format
+msgid "Network %s has been created."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:45
+#, python-format
+msgid "Unable to delete network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:48
+#, python-format
+msgid "Network %s has been deleted."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:67
+#, python-format
+msgid "Unable to rename network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:70
+#, python-format
+msgid "Network %(net)s has been renamed to %(new_name)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:80
+msgid "Number of Ports"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:90
+#, python-format
+msgid "Unable to create ports on network %(network)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:93
+#, python-format
+msgid "%(num_ports)s ports created on network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:112
+#, python-format
+msgid "Unable to delete port %(port)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:115
+#, python-format
+msgid "Port %(port)s deleted from network %(network)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:126
+msgid "Select VIF to connect"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:137
+#, python-format
+msgid "Unable to attach port %(port)s to VIF %(vif)s: %(msg)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:142
+#, python-format
+msgid "Port %(port)s connected to VIF %(vif)s."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:159
+#, python-format
+msgid "Unable to detach port %(port)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:162
+#, python-format
+msgid "Port %s detached."
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:181
+#, python-format
+msgid "Unable to set port state to %(state)s: %(message)s"
+msgstr ""
+
+#: dashboards/dash/networks/forms.py:184
+#, python-format
+msgid "Port %(port)s state set to %(state)s."
+msgstr ""
+
+#: dashboards/dash/networks/views.py:68
+#, python-format
+msgid "Unable to get network list: %s"
+msgstr ""
+
+#: dashboards/dash/networks/views.py:104
+#, python-format
+msgid "Unable to get network details: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:48
+#, python-format
+msgid "Successfully created security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:53
+#, python-format
+msgid "Error creating security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:67
+#, python-format
+msgid "Successfully deleted security_group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:71
+#, python-format
+msgid "Error deleting security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:100
+#, python-format
+msgid "Successfully added rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:104
+#, python-format
+msgid "Error adding rule security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:122
+#, python-format
+msgid "Successfully deleted rule: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/forms.py:126
+#, python-format
+msgid "Error authorizing security group: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:54
+#, python-format
+msgid "Error fetching security_groups: %s"
+msgstr ""
+
+#: dashboards/dash/security_groups/views.py:82
+#, python-format
+msgid "Error getting security_group: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:19
+msgid "Snapshot Name"
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:30
+#, python-format
+msgid "Snapshot \"%(name)s\" created for instance \"%(inst)s\""
+msgstr ""
+
+#: dashboards/dash/snapshots/forms.py:34
+#, python-format
+msgid "Error Creating Snapshot: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:76
+#, python-format
+msgid "Unable to retreive instance: %s"
+msgstr ""
+
+#: dashboards/dash/snapshots/views.py:83
+#, python-format
+msgid ""
+"To snapshot, instance state must be one of "
+"the following: %s"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:20
+#: dashboards/settings/templates/settings/user/settings.html:6
+msgid "Dashboard Settings"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:26
+#: dashboards/settings/templates/settings/user/settings.html:13
+msgid "Dashboard User Interface Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/settings.html:38
+#: dashboards/settings/templates/settings/user/settings.html:25
+msgid "Select Language"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_delete.html:8
+#: dashboards/dash/templates/dash/images/_delete.html:8
+#: dashboards/dash/templates/dash/keypairs/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete.html:8
+#: dashboards/dash/templates/dash/networks/_delete_port.html:9
+#: dashboards/dash/templates/dash/objects/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete.html:8
+#: dashboards/dash/templates/dash/security_groups/_delete_rule.html:8
+#: dashboards/syspanel/templates/syspanel/flavors/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/images/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/tenants/_delete.html:8
+#: dashboards/syspanel/templates/syspanel/users/_delete.html:8
+msgid "Delete"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_form.html:10
+msgid "Create Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:7
+#: dashboards/dash/templates/dash/instances/_list.html:13
+#: dashboards/dash/templates/dash/keypairs/_list.html:6
+#: dashboards/dash/templates/dash/networks/_detail.html:7
+#: dashboards/dash/templates/dash/objects/_list.html:7
+#: dashboards/dash/templates/dash/security_groups/_list.html:6
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:24
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:13
+#: dashboards/syspanel/templates/syspanel/services/_list.html:9
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:25
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:54
+msgid "Actions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:17
+msgid "List Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/_list.html:18
+#: dashboards/dash/templates/dash/objects/_form.html:10
+msgid "Upload Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:11
+#: dashboards/syspanel/templates/syspanel/tenants/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:11
+msgid "Create Tenant"
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/create.html:22
+msgid ""
+"A container is a storage compartment for your data and provides a way for "
+"you to organize your data. You can think of a container as a folder in "
+"Windows® or a directory in UNIX®. The primary difference between a container "
+"and these other file system concepts is that containers cannot be nested. "
+"You can, however, create an unlimited number of containers within your "
+"account. Data must be stored in a container so you must have at least one "
+"container defined in your account prior to uploading data."
+msgstr ""
+
+#: dashboards/dash/templates/dash/containers/index.html:18
+msgid "Create New Container"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_allocate.html:7
+msgid "Allocate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_associate.html:14
+msgid "Associate IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_disassociate.html:8
+msgid "Disassociate"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:14
+msgid "Instance ID:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:15
+msgid "Fixed IP:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_list.html:28
+msgid "Associate to instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/_release.html:8
+msgid "Release"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:12
+msgid "Associate Floating IP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:22
+#: dashboards/dash/templates/dash/images/launch.html:21
+#: dashboards/dash/templates/dash/images/update.html:21
+#: dashboards/dash/templates/dash/instances/update.html:23
+msgid "Description:"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/associate.html:23
+msgid "Associate a floating ip with an instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:13
+#: dashboards/dash/templates/dash/images/launch.html:33
+#: dashboards/syspanel/tenants/forms.py:146
+msgid "Floating IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:21
+#: dashboards/dash/templates/dash/images/index.html:21
+#: dashboards/dash/templates/dash/instances/index.html:22
+#: dashboards/dash/templates/dash/instances/usage.html:97
+#: dashboards/dash/templates/dash/keypairs/index.html:23
+#: dashboards/dash/templates/dash/networks/detail.html:27
+#: dashboards/dash/templates/dash/networks/index.html:23
+#: dashboards/dash/templates/dash/security_groups/index.html:24
+#: dashboards/dash/templates/dash/snapshots/index.html:22
+#: dashboards/syspanel/templates/syspanel/instances/index.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:44
+msgid "Info"
+msgstr ""
+
+#: dashboards/dash/templates/dash/floating_ips/index.html:22
+msgid "There are currently no floating ips assigned to your tenant."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_form.html:10
+#: dashboards/dash/templates/dash/images/update.html:11
+#: dashboards/syspanel/templates/syspanel/images/_form.html:10
+#: dashboards/syspanel/templates/syspanel/images/update.html:11
+msgid "Update Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_launch.html:5
+#: dashboards/dash/templates/dash/images/_launch_form.html:14
+#: dashboards/dash/templates/dash/images/launch.html:12
+msgid "Launch Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:5
+#: dashboards/dash/templates/dash/instances/_list.html:6
+#: dashboards/dash/templates/dash/instances/usage.html:60
+#: dashboards/dash/templates/dash/networks/_detail.html:4
+#: dashboards/dash/templates/dash/networks/_list.html:4
+#: dashboards/syspanel/templates/syspanel/images/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:66
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:22
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:52
+#: dashboards/syspanel/templates/syspanel/users/index.html:20
+#: dashboards/syspanel/tenants/forms.py:105
+#: dashboards/syspanel/users/forms.py:57
+msgid "ID"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:7
+#: dashboards/syspanel/templates/syspanel/images/_list.html:10
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:9
+msgid "Created"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:8
+#: dashboards/syspanel/templates/syspanel/images/_list.html:11
+msgid "Updated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:9
+#: dashboards/dash/templates/dash/instances/usage.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:12
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:74
+msgid "Status"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:22
+#: dashboards/dash/templates/dash/instances/_list.html:68
+#: dashboards/syspanel/templates/syspanel/images/_list.html:28
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:19
+#: dashboards/syspanel/templates/syspanel/users/index.html:36
+msgid "Edit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/_list.html:24
+msgid "Launch"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/index.html:12
+#: dashboards/syspanel/templates/syspanel/images/index.html:13
+msgid "Images"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:22
+msgid ""
+"Specify the details for launching an instance. Also please make note of the "
+"table below; all tenants have quotas which define the limit of resources you "
+"are allowed to provision."
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:25
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:19
+msgid "Quota Name"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:26
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:20
+msgid "Limit"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:29
+msgid "RAM (MB)"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:37
+#: dashboards/dash/templates/dash/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/index.html:13
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:77
+#: dashboards/syspanel/tenants/forms.py:142
+msgid "Instances"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:41
+#: dashboards/syspanel/tenants/forms.py:143
+msgid "Volumes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/launch.html:45
+#: dashboards/syspanel/tenants/forms.py:144
+msgid "Gigabytes"
+msgstr ""
+
+#: dashboards/dash/templates/dash/images/update.html:22
+#: dashboards/syspanel/templates/syspanel/images/update.html:22
+msgid "From here you can modify different properties of an image."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_form.html:10
+#: dashboards/dash/templates/dash/instances/update.html:12
+msgid "Update Instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:8
+msgid "Groups"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:9
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:10
+msgid "Image"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:10
+#: dashboards/syspanel/templates/syspanel/images/_list.html:8
+msgid "Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:11
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:11
+msgid "IPs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:12
+#: dashboards/dash/templates/dash/networks/_detail.html:5
+#: dashboards/syspanel/templates/syspanel/images/_list.html:36
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:12
+msgid "State"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:66
+msgid "Log"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:67
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:49
+msgid "VNC Console"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/_list.html:69
+msgid "Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:19
+msgid "Return to Instances List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/update.html:24
+msgid "Update the name and description of your instance"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:14
+msgid "Overview"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:46
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:60
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:70
+msgid "Download CSV"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:50
+msgid "Hide Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:52
+msgid "Show Terminated"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:62
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:7
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:68
+msgid "User"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:63
+#: dashboards/syspanel/flavors/forms.py:38
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:69
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:78
+#: dashboards/syspanel/tenants/forms.py:141
+msgid "VCPUs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:64
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:70
+msgid "Ram Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:65
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:71
+msgid "Disk Size"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:67
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:73
+msgid "Uptime"
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:89
+msgid "No active instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/instances/usage.html:98
+#, python-format
+msgid ""
+"There are currently no instances.<br/><br/>You can launch an instance from "
+"the <a href='%(dash_img_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_form.html:10
+msgid "Add Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/_list.html:5
+msgid "Fingerprint"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:24
+#: dashboards/dash/templates/dash/keypairs/import.html:15
+msgid "Create Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:30
+msgid "Your private key is being downloaded."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:32
+#: dashboards/dash/templates/dash/keypairs/import.html:22
+msgid "Return to keypairs list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:36
+#: dashboards/dash/templates/dash/keypairs/import.html:26
+#: dashboards/dash/templates/dash/networks/create.html:23
+#: dashboards/dash/templates/dash/objects/copy.html:25
+#: dashboards/dash/templates/dash/objects/upload.html:24
+#: dashboards/dash/templates/dash/ports/create.html:23
+#: dashboards/dash/templates/dash/security_groups/_list.html:5
+#: dashboards/dash/templates/dash/security_groups/create.html:21
+#: dashboards/dash/templates/dash/snapshots/create.html:31
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:36
+#: dashboards/syspanel/templates/syspanel/images/update.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:6
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:21
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:21
+#: dashboards/syspanel/templates/syspanel/users/create.html:22
+#: dashboards/syspanel/templates/syspanel/users/update.html:22
+#: dashboards/syspanel/tenants/forms.py:81
+#: dashboards/syspanel/tenants/forms.py:110
+msgid "Description"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:37
+#: dashboards/dash/templates/dash/keypairs/import.html:27
+msgid ""
+"Keypairs are ssh credentials which are injected into images when they are "
+"launched. Creating a new key pair registers the public key and downloads the "
+"private key (a .pem file)."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/create.html:38
+#: dashboards/dash/templates/dash/keypairs/import.html:28
+msgid "Protect and use the key as you would any normal ssh private key."
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:13
+msgid "Keypairs"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:19
+#: dashboards/dash/templates/dash/keypairs/index.html:26
+msgid "Add New Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:20
+#: dashboards/dash/templates/dash/keypairs/index.html:27
+msgid "Import Keypair"
+msgstr ""
+
+#: dashboards/dash/templates/dash/keypairs/index.html:24
+msgid "There are currently no keypairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detach_port.html:9
+msgid "Detach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:6
+msgid "Attachment"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:8
+msgid "Extensions"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:20
+msgid "VIF Id"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_detail.html:36
+msgid "Attach"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_form.html:10
+#: dashboards/dash/templates/dash/networks/create.html:12
+#: dashboards/dash/templates/dash/ports/create.html:12
+msgid "Create Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:6
+msgid "Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:7
+msgid "Available"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:8
+msgid "Used"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:9
+msgid "Action"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_list.html:22
+#: dashboards/dash/templates/dash/networks/_rename.html:11
+#: dashboards/dash/templates/dash/networks/_rename.html:15
+#: dashboards/dash/templates/dash/networks/rename.html:31
+msgid "Rename"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_rename_form.html:11
+#: dashboards/dash/templates/dash/networks/rename.html:12
+msgid "Rename Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:11
+msgid "Port UP"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/_toggle_port.html:14
+msgid "Port DOWN"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:19
+#: dashboards/dash/templates/dash/networks/rename.html:27
+msgid "Return to networks list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/create.html:24
+msgid "Networks provide layer 2 connectivity to your instances."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:24
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "Create Ports"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/detail.html:28
+msgid "There are currently no ports in this network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:13
+msgid "Networks"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:20
+msgid "Create New Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "There are currently no networks."
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/index.html:24
+msgid "Create A Network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/networks/rename.html:32
+msgid "Enter a new name for your network."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_copy.html:10
+#: dashboards/dash/templates/dash/objects/copy.html:11
+msgid "Copy Object"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_filter.html:7
+msgid "Filter"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:16
+msgid "Copy"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/_list.html:18
+msgid "Download"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:21
+#: dashboards/dash/templates/dash/objects/upload.html:20
+msgid "Return to objects list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/copy.html:26
+msgid ""
+"You may make a new copy of an existing object to store in this or another "
+"container."
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:17
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh List"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:31
+#, python-format
+msgid ""
+"There are currently no objects in the container %(container_name)s. You can "
+"upload a new object from the <a href='%(dash_obj_up_url)s'>Object Upload "
+"Page &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/index.html:34
+msgid "Upload New Object &gt;&gt;"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:11
+msgid "Upload Objects"
+msgstr ""
+
+#: dashboards/dash/templates/dash/objects/upload.html:25
+msgid ""
+"An object is the basic storage entity and any optional metadata that "
+"represents the files you store in the OpenStack Object Storage system. When "
+"you upload data to OpenStack Object Storage, the data is stored as-is (no "
+"compression or encryption) and consists of a location (container), the "
+"object's name, and any metadata consisting of key/value pairs."
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:12
+msgid "Attach Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:38
+#: dashboards/dash/templates/dash/ports/create.html:19
+msgid "Return to network detail"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/attach.html:42
+msgid ""
+"<p>Select an interface from the list on the left to attach it to this port.</"
+"p>\n"
+" <p>Only interfaces that are not connected to any existing port are "
+"shown</p>\n"
+" <p>If you want to reconnect a connected interface, please detach it "
+"first</p>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/ports/create.html:24
+msgid ""
+"You can plug virtual interfaces from your instances to ports created in the "
+"network"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_form.html:11
+#: dashboards/dash/templates/dash/security_groups/create.html:11
+#: dashboards/dash/templates/dash/security_groups/index.html:20
+msgid "Create Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/_list.html:14
+msgid "Edit Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/create.html:22
+msgid "From here you can create a new security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:11
+msgid "Edit Security Group Rules"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:17
+msgid "Rules for Security Group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:20
+msgid "IP Protocol"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:21
+msgid "From Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:22
+msgid "To Port"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:23
+msgid "CIDR"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:41
+msgid "No rules for this security group"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:49
+msgid "Add a rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/edit_rules.html:60
+msgid "Add Rule"
+msgstr ""
+
+#: dashboards/dash/templates/dash/security_groups/index.html:25
+#, python-format
+msgid ""
+"There are currently no security groups. <a href='%(dash_sec_url)s'>Create A "
+"Security Group &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/_form.html:11
+msgid "Create Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:19
+msgid "Create a Snapshot"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:25
+msgid "Choose a name for your snapshot."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:27
+msgid "Return to snapshots list"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/create.html:32
+msgid "Snapshots preserve the disk state of a running instance."
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:13
+msgid "Snapshots"
+msgstr ""
+
+#: dashboards/dash/templates/dash/snapshots/index.html:23
+#, python-format
+msgid ""
+"There are currently no snapshots. You can create snapshots from running "
+"instances. <a href='%(inst_url)s'>View Running Instances &gt;&gt;</a>"
+msgstr ""
+
+#: dashboards/syspanel/dashboard.py:25
+msgid "System Panel"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:36
+msgid "Flavor ID"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:39
+msgid "Memory MB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:40
+msgid "Disk GB"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:49
+#, python-format
+msgid "%s was successfully added to flavors."
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:64
+#, python-format
+msgid "Successfully deleted flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/flavors/forms.py:67
+#, python-format
+msgid "Unable to delete flavor: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:49
+#, python-format
+msgid "Error deleting image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/forms.py:67
+#: dashboards/syspanel/images/views.py:114
+#, python-format
+msgid "Error updating image: %s"
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:118
+msgid "Image could not be updated, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:123
+#: dashboards/syspanel/images/views.py:181
+msgid "Image could not be uploaded, please try agian."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:161
+msgid "Image was successfully uploaded."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:165
+msgid "Image could not be uploaded, please try again."
+msgstr ""
+
+#: dashboards/syspanel/images/views.py:177
+#, python-format
+msgid "Error adding image: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:67
+#: dashboards/syspanel/services/views.py:52
+#, python-format
+msgid "Unable to get service info: %s"
+msgstr ""
+
+#: dashboards/syspanel/instances/views.py:172
+#: dashboards/syspanel/instances/views.py:210
+msgid "No data for the selected period"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:46
+#, python-format
+msgid "Service '%s' has been enabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:49
+#, python-format
+msgid "Service '%s' has been disabled"
+msgstr ""
+
+#: dashboards/syspanel/services/forms.py:55
+#, python-format
+msgid "Unable to update service '%(name)s': %(msg)s"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_create.html:5
+#: dashboards/syspanel/templates/syspanel/flavors/_form.html:14
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:11
+msgid "Create Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:4
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:4
+msgid "Id"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:7
+msgid "Memory"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/_list.html:8
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:79
+msgid "Disk"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/create.html:37
+msgid "From here you can define the sizing of a new flavor."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:13
+msgid "Flavors"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/flavors/index.html:18
+msgid "Create New Flavor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:9
+msgid "Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:35
+msgid "Location"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_list.html:40
+msgid "Project ID"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/images/_toggle.html:8
+msgid "Toggle Public"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:6
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:76
+msgid "Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:8
+msgid "Host"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/_list.html:48
+msgid "Console Log"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/index.html:23
+#, python-format
+msgid ""
+"There are currently no instances. You can launch an instance from the <a "
+"href='%(dash_image_url)s'>Images Page.</a>"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:14
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:16
+msgid "System Panel Overview"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:52
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:61
+msgid "Active Instances"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:53
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:62
+msgid "This month's VCPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:54
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:63
+msgid "This month's GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/tenant_usage.html:61
+msgid "Tenant Usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:23
+msgid "Monitoring"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:34
+msgid "Select a month to query its usage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:71
+msgid "Server Usage Summary"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:80
+msgid "RAM"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:81
+msgid "VCPU CPU-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/instances/usage.html:82
+msgid "Disk GB-Hours"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/quotas/index.html:13
+msgid "Default Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:5
+msgid "Service"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:6
+msgid "System Stats"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:7
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:7
+#: dashboards/syspanel/tenants/forms.py:82
+#: dashboards/syspanel/tenants/forms.py:111
+msgid "Enabled"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:8
+msgid "Up"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:22
+msgid "Hypervisor"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:25
+msgid "Allocable Cores"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:30
+msgid "Allocable Storage"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_list.html:35
+msgid "System Ram"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:10
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:18
+msgid "Enable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/_toggle.html:20
+#: dashboards/syspanel/templates/syspanel/users/_toggle_enabled.html:9
+msgid "Disable"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/services/index.html:13
+msgid "Services"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_add_user.html:9
+msgid "Add"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:8
+#: dashboards/syspanel/templates/syspanel/users/index.html:24
+msgid "Options"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:20
+msgid "View Members"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_list.html:21
+msgid "Modify Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_remove_user.html:9
+msgid "Remove"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:11
+msgid "Update Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html:5
+msgid "Update Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/create.html:22
+msgid "From here you can create a new tenant (aka project) to organize users."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:13
+msgid "Tenants"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/index.html:18
+msgid "Create New Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:11
+msgid "Update Tenant Quotas"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/quotas.html:22
+msgid "From here you can edit quotas (max limits) for the tenant "
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/update.html:22
+msgid "From here you can edit a tenant."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:12
+msgid "Users for Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:24
+#: dashboards/syspanel/templates/syspanel/users/index.html:22
+#: dashboards/syspanel/users/forms.py:43 dashboards/syspanel/users/forms.py:61
+msgid "Email"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:45
+msgid "here are currently no users for this tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/tenants/users.html:49
+msgid "Add new users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_create_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/create.html:12
+msgid "Create User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/_update_form.html:5
+#: dashboards/syspanel/templates/syspanel/users/update.html:12
+msgid "Update User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/create.html:23
+msgid ""
+"From here you can create a new user and assign them to a tenant (aka "
+"project)."
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:13
+msgid "Users"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:23
+msgid "Default Tenant"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/index.html:42
+msgid "Create New User"
+msgstr ""
+
+#: dashboards/syspanel/templates/syspanel/users/update.html:23
+msgid ""
+"From here you can edit users by changing their usernames, emails, passwords, "
+"and tenants."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:48
+#, python-format
+msgid "%(user)s was successfully added to %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:51
+#, python-format
+msgid "Unable to create user association: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:69
+#, python-format
+msgid "%(user)s was successfully removed from %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:72
+#: dashboards/syspanel/tenants/forms.py:99
+#, python-format
+msgid "Unable to create tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:93
+#, python-format
+msgid "%s was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:122
+#, python-format
+msgid "%s was successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:130
+#: dashboards/syspanel/tenants/views.py:86
+#, python-format
+msgid "Unable to update tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:135
+msgid "ID (name)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:137
+msgid "Metadata Items"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:138
+msgid "Injected Files"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:139
+msgid "Injected File Content Bytes"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:145
+msgid "RAM (in MB)"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:162
+#, python-format
+msgid "Quotas for %s were successfully updated."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:166
+#, python-format
+msgid "Unable to update quotas: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:177
+#, python-format
+msgid "Successfully deleted tenant %(tenant)s."
+msgstr ""
+
+#: dashboards/syspanel/tenants/forms.py:182
+#, python-format
+msgid "Error deleting tenant: %s"
+msgstr ""
+
+#: dashboards/syspanel/tenants/views.py:51
+#, python-format
+msgid "Unable to get tenant info: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:44 dashboards/syspanel/users/forms.py:62
+#: views/auth.py:57
+msgid "Password"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:47 dashboards/syspanel/users/forms.py:65
+msgid "Primary Tenant"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:75
+#, python-format
+msgid "%(user)s was successfully deleted."
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:81
+msgid "ID (username)"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:82
+msgid "enabled"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:93
+#, python-format
+msgid "User %(user)s %(state)s"
+msgstr ""
+
+#: dashboards/syspanel/users/forms.py:98
+#, python-format
+msgid "Unable to %(state)s user %(user)s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:49
+#, python-format
+msgid "Unable to list users: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:80
+#, python-format
+msgid "Updated %(attrib)s for %(user)s."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:86
+msgid "Unable to update user, please try again."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:113
+#, python-format
+msgid "Unable to retrieve tenant list: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:131
+#, python-format
+msgid "User \"%s\" was successfully created."
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:141
+#, python-format
+msgid "Error assigning role to user: %s"
+msgstr ""
+
+#: dashboards/syspanel/users/views.py:151
+#, python-format
+msgid "Error creating user: %s"
+msgstr ""
+
+#: templates/horizon/auth/_login.html:14
+#: templates/horizon/auth/_switch.html:14
+msgid "Login"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/horizon/common/_page_header.html:17
+msgid "Refresh"
+msgstr ""
+
+#: templates/horizon/common/instances/_reboot.html:8
+msgid "Reboot"
+msgstr ""
+
+#: templates/horizon/common/instances/_terminate.html:8
+msgid "Terminate"
+msgstr ""
+
+#: templatetags/sizeformat.py:46
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:50
+#, python-format
+msgid "%(size)d"
+msgid_plural "%(size)d"
+msgstr[0] ""
+msgstr[1] ""
+
+#: templatetags/sizeformat.py:53
+#, python-format
+msgid "%s KB"
+msgstr ""
+
+#: templatetags/sizeformat.py:56
+#, python-format
+msgid "%s MB"
+msgstr ""
+
+#: templatetags/sizeformat.py:59
+#, python-format
+msgid "%s GB"
+msgstr ""
+
+#: templatetags/sizeformat.py:62
+#, python-format
+msgid "%s TB"
+msgstr ""
+
+#: templatetags/sizeformat.py:64
+#, python-format
+msgid "%s PB"
+msgstr ""
+
+#: views/auth.py:56
+msgid "User Name"
+msgstr ""
+
+#: views/auth.py:90
+#, python-format
+msgid "No tenants present for user: %(user)s"
+msgstr ""
+
+#: views/auth.py:110
+msgid "You are not authorized for any available tenants."
+msgstr ""
+
+#: views/auth.py:119
+#, python-format
+msgid "Error authenticating: %s"
+msgstr ""
+
+#: views/auth.py:124
+#, python-format
+msgid "Error authenticating with keystone: %s"
+msgstr ""
+
+#: views/auth.py:164
+msgid "You are not authorized for that tenant."
+msgstr ""
diff --git a/django-openstack/django_openstack/middleware/keystone.py b/horizon/horizon/middleware.py
index 17643717..dfb47a7e 100644
--- a/django-openstack/django_openstack/middleware/keystone.py
+++ b/horizon/horizon/middleware.py
@@ -17,6 +17,9 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+"""
+Middleware provided and used by Horizon.
+"""
from django.contrib import messages
from django import shortcuts
@@ -25,48 +28,30 @@ from django.utils.translation import ugettext as _
import openstackx
import openstack
+from horizon import exceptions
+from horizon import users
-class User(object):
- def __init__(self, token=None, user=None, tenant_id=None, admin=None,
- service_catalog=None, tenant_name=None):
- self.token = token
- self.username = user
- self.tenant_id = tenant_id
- self.tenant_name = tenant_name
- self.admin = admin
- self.service_catalog = service_catalog
- def is_authenticated(self):
- # TODO: deal with token expiration
- return self.token
+class HorizonMiddleware(object):
+ """ The main Horizon middleware class. Required for use of Horizon. """
- def is_admin(self):
- return self.admin
-
-
-def get_user_from_request(request):
- if 'user' not in request.session:
- return User()
- return User(token=request.session['token'],
- user=request.session['user'],
- tenant_id=request.session['tenant_id'],
- tenant_name=request.session['tenant'],
- admin=request.session['admin'],
- service_catalog=request.session['serviceCatalog'])
-
-
-class LazyUser(object):
- def __get__(self, request, obj_type=None):
- if not hasattr(request, '_cached_user'):
- request._cached_user = get_user_from_request(request)
- return request._cached_user
+ def process_request(self, request):
+ """ Adds data necessary for Horizon to function to the request.
+ Adds the current "active" :class:`~horizon.Dashboard` and
+ :class:`~horizon.Panel` to ``request.horizon``.
-class AuthenticationMiddleware(object):
- def process_request(self, request):
- request.__class__.user = LazyUser()
+ Adds a :class:`~horizon.users.User` object to ``request.user``.
+ """
+ request.__class__.user = users.LazyUser()
+ request.horizon = {'dashboard': None, 'panel': None}
def process_exception(self, request, exception):
+ """ Catch NotAuthorized and handle it gracefully. """
+ if issubclass(exception.__class__, exceptions.NotAuthorized):
+ messages.error(request, _(unicode(exception)))
+ return shortcuts.redirect('/auth/logout')
+
if type(exception) in [openstack.compute.exceptions.Forbidden,
openstackx.api.exceptions.Forbidden]:
# flush other error messages, which are collateral damage
diff --git a/horizon/horizon/models.py b/horizon/horizon/models.py
new file mode 100644
index 00000000..300ba4b3
--- /dev/null
+++ b/horizon/horizon/models.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
+"""
diff --git a/horizon/horizon/site_urls.py b/horizon/horizon/site_urls.py
new file mode 100644
index 00000000..e940a740
--- /dev/null
+++ b/horizon/horizon/site_urls.py
@@ -0,0 +1,31 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django.conf.urls.defaults import patterns, url, include
+from django.views.generic import TemplateView
+
+urlpatterns = patterns('horizon.views.auth',
+ url(r'auth/login/$', 'login', name='auth_login'),
+ url(r'auth/logout/$', 'logout', name='auth_logout'),
+ url(r'auth/switch/(?P<tenant_id>[^/]+)/$', 'switch_tenants',
+ name='auth_switch'),)
+
+urlpatterns += patterns('',
+ url(r'^i18n/', include('django.conf.urls.i18n')))
diff --git a/horizon/horizon/templates/horizon/_nav_list.html b/horizon/horizon/templates/horizon/_nav_list.html
new file mode 100644
index 00000000..b10c9a4e
--- /dev/null
+++ b/horizon/horizon/templates/horizon/_nav_list.html
@@ -0,0 +1,10 @@
+{% load horizon %}
+
+{% for component in components %}
+ {% if user|can_haz:component %}
+ <li>
+ <a href="{{ component.get_absolute_url }}" {% if current == component.slug %}class="active"{% endif %}>{{ component.name }}</a>
+ </li>
+ {% endif %}
+{% endfor %}
+
diff --git a/horizon/horizon/templates/horizon/_subnav_list.html b/horizon/horizon/templates/horizon/_subnav_list.html
new file mode 100644
index 00000000..5327e8eb
--- /dev/null
+++ b/horizon/horizon/templates/horizon/_subnav_list.html
@@ -0,0 +1,14 @@
+{% load horizon %}
+
+{% for heading, panels in components.iteritems %}
+<h3>{{ heading }}</h3>
+<ul class="sub_nav">
+{% for panel in panels %}
+ {% if user|can_haz:panel %}
+ <li>
+ <a href="{{ panel.get_absolute_url }}" {% if current == panel.slug %}class="active"{% endif %}>{{ panel.name }}</a>
+ </li>
+ {% endif %}
+{% endfor %}
+</ul>
+{% endfor %}
diff --git a/horizon/horizon/templates/horizon/auth/_login.html b/horizon/horizon/templates/horizon/auth/_login.html
new file mode 100644
index 00000000..3c7f8abb
--- /dev/null
+++ b/horizon/horizon/templates/horizon/auth/_login.html
@@ -0,0 +1,17 @@
+{% load i18n %}
+<form action="{% url horizon:auth_login %}" method="post">
+ {% csrf_token %}
+ <fieldset>
+ {% for hidden in form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ {% for field in form.visible_fields %}
+ {{ field.label_tag }}
+ {{ field.errors }}
+ {{ field }}
+ {% endfor %}
+ {% block submit %}
+ <input type="submit" value="{% trans "Login" %}" />
+ {% endblock %}
+ </fieldset>
+</form>
diff --git a/django-openstack/django_openstack/templates/django_openstack/auth/_switch.html b/horizon/horizon/templates/horizon/auth/_switch.html
index af8d4d20..7be5450a 100644
--- a/django-openstack/django_openstack/templates/django_openstack/auth/_switch.html
+++ b/horizon/horizon/templates/horizon/auth/_switch.html
@@ -1,17 +1,17 @@
-{%load i18n%}
+{% load i18n %}
<form action="" method="post">
{% csrf_token %}
<fieldset>
{% for hidden in form.hidden_fields %}
- {{hidden}}
+ {{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
- {{field.label_tag}}
- {{field.errors}}
- {{field}}
+ {{ field.label_tag }}
+ {{ field.errors }}
+ {{ field }}
{% endfor %}
{% block submit %}
- <input type="submit" value="{%trans "Login"%}" />
+ <input type="submit" value="{% trans "Login" %}" />
{% endblock %}
</fieldset>
</form>
diff --git a/django-openstack/django_openstack/templates/django_openstack/common/_page_header.html b/horizon/horizon/templates/horizon/common/_page_header.html
index 277c289b..28199218 100644
--- a/django-openstack/django_openstack/templates/django_openstack/common/_page_header.html
+++ b/horizon/horizon/templates/horizon/common/_page_header.html
@@ -1,4 +1,4 @@
-{%load i18n%}
+{% load i18n %}
{% block page_header %}
<div id='page_header'>
<h2>{{title}}</h2>
@@ -9,12 +9,12 @@
<div class='search'>
<form action='' method='post' onsubmit='return false;'>
<fieldset>
- <label for='table_search'>{%trans "Search"%}</label>
+ <label for='table_search'>{% trans "Search" %}</label>
<input id='table_search' name='search' type='text' value='' />
</fieldset>
</form>
</div>
- <a class="refresh" title="{%trans "Refresh"%}" href="{{refresh_link}}">{%trans "Refresh List"%}</a>
+ <a class="refresh" title="{% trans "Refresh" %}" href="{{ refresh_link }}">{% trans "Refresh List" %}</a>
</div>
{% endif %}
</div>
diff --git a/horizon/horizon/templates/horizon/common/_sidebar.html b/horizon/horizon/templates/horizon/common/_sidebar.html
new file mode 100644
index 00000000..a9b06ada
--- /dev/null
+++ b/horizon/horizon/templates/horizon/common/_sidebar.html
@@ -0,0 +1,5 @@
+{% load horizon i18n %}
+
+<div id='sidebar'>
+ {% horizon_dashboard_nav %}
+</div>
diff --git a/django-openstack/django_openstack/templates/django_openstack/common/_sidebar_module.html b/horizon/horizon/templates/horizon/common/_sidebar_module.html
index 661108dc..2b9739ce 100644
--- a/django-openstack/django_openstack/templates/django_openstack/common/_sidebar_module.html
+++ b/horizon/horizon/templates/horizon/common/_sidebar_module.html
@@ -1,9 +1,9 @@
{% for module in modules %}
- <h3>{{module.title}}</h3>
+ <h3>{{ module.title }}</h3>
<ul class="sub_nav">
{% for link in module.links %}
- <li><a {% if request.get_full_path == link.url %} class="active" {% endif %} href="{{link.url}}">{{link.text}}</a></li>
+ <li><a {% if request.get_full_path == link.url %} class="active" {% endif %} href="{{ link.url }}">{{ link.text }}</a></li>
{% endfor %}
</ul>
{% endfor %}
diff --git a/horizon/horizon/templates/horizon/common/instances/_reboot.html b/horizon/horizon/templates/horizon/common/instances/_reboot.html
new file mode 100644
index 00000000..2fa3e537
--- /dev/null
+++ b/horizon/horizon/templates/horizon/common/instances/_reboot.html
@@ -0,0 +1,9 @@
+{% load i18n %}
+<form id="form_reboot_{{ instance.id }}" class="form-reboot" method="post">
+ {% csrf_token %}
+ {% for hidden in form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ <input name="instance" type="hidden" value="{{ instance.id }}" />
+ <input id="reboot_{{ instance.id }}" class="reboot" title="Instance: {{ instance.name }}" type="submit" value="{% trans "Reboot" %}" />
+</form>
diff --git a/horizon/horizon/templates/horizon/common/instances/_terminate.html b/horizon/horizon/templates/horizon/common/instances/_terminate.html
new file mode 100644
index 00000000..054c64ea
--- /dev/null
+++ b/horizon/horizon/templates/horizon/common/instances/_terminate.html
@@ -0,0 +1,9 @@
+{% load i18n %}
+<form id="form_terminate_{{ instance.id }}" class="form-terminate" method="post">
+ {% csrf_token %}
+ {% for hidden in form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ <input name="instance" type="hidden" value="{{ instance.id }}" />
+ <input id="terminate_{{instance.id}}" class="terminate" title="{{ instance.name }}" type="submit" value="{% trans "Terminate" %}" />
+</form>
diff --git a/horizon/horizon/templatetags/__init__.py b/horizon/horizon/templatetags/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/templatetags/__init__.py
diff --git a/django-openstack/django_openstack/templatetags/templatetags/branding.py b/horizon/horizon/templatetags/branding.py
index 79e5a91d..d62c79bd 100644
--- a/django-openstack/django_openstack/templatetags/templatetags/branding.py
+++ b/horizon/horizon/templatetags/branding.py
@@ -19,7 +19,7 @@
# under the License.
"""
-Template tags for working with django_openstack.
+Template tags for customizing Horizon.
"""
from django import template
diff --git a/horizon/horizon/templatetags/horizon.py b/horizon/horizon/templatetags/horizon.py
new file mode 100644
index 00000000..9df91a80
--- /dev/null
+++ b/horizon/horizon/templatetags/horizon.py
@@ -0,0 +1,79 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+import copy
+
+from django import template
+
+from horizon.base import Horizon
+
+
+register = template.Library()
+
+
+@register.filter
+def can_haz(user, component):
+ """ Checks if the given user has the necessary roles for the component. """
+ if hasattr(user, 'roles'):
+ user_roles = set([role['name'].lower() for role in user.roles])
+ else:
+ user_roles = set([])
+ if set(getattr(component, 'roles', [])) <= user_roles:
+ return True
+ return False
+
+
+@register.inclusion_tag('horizon/_nav_list.html', takes_context=True)
+def horizon_main_nav(context):
+ """ Generates top-level dashboard navigation entries. """
+ if 'request' not in context:
+ return {}
+ dashboards = []
+ for dash in Horizon.get_dashboards():
+ if callable(dash.nav) and dash.nav(context):
+ dashboards.append(dash)
+ elif dash.nav:
+ dashboards.append(dash)
+ return {'components': dashboards,
+ 'user': context['request'].user,
+ 'current': context['request'].horizon['dashboard'].slug}
+
+
+@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
+def horizon_dashboard_nav(context):
+ """ Generates sub-navigation entries for the current dashboard. """
+ if 'request' not in context:
+ return {}
+ dashboard = context['request'].horizon['dashboard']
+ if type(dashboard.panels) is dict:
+ panels = copy.copy(dashboard.get_panels())
+ else:
+ panels = {dashboard.name: dashboard.get_panels()}
+
+ for heading, items in panels.iteritems():
+ temp_panels = []
+ for panel in items:
+ if callable(panel.nav) and panel.nav(context):
+ temp_panels.append(panel)
+ elif not callable(panel.nav) and panel.nav:
+ temp_panels.append(panel)
+ panels[heading] = temp_panels
+ non_empty_panels = dict([(k, v) for k, v in panels.items() if len(v) > 0])
+ return {'components': non_empty_panels,
+ 'user': context['request'].user,
+ 'current': context['request'].horizon['panel'].slug}
diff --git a/django-openstack/django_openstack/templatetags/templatetags/parse_date.py b/horizon/horizon/templatetags/parse_date.py
index 6adff07b..6adff07b 100644
--- a/django-openstack/django_openstack/templatetags/templatetags/parse_date.py
+++ b/horizon/horizon/templatetags/parse_date.py
diff --git a/django-openstack/django_openstack/templatetags/templatetags/sizeformat.py b/horizon/horizon/templatetags/sizeformat.py
index 6e7e9ecc..6e7e9ecc 100644
--- a/django-openstack/django_openstack/templatetags/templatetags/sizeformat.py
+++ b/horizon/horizon/templatetags/sizeformat.py
diff --git a/horizon/horizon/templatetags/swift_paging.py b/horizon/horizon/templatetags/swift_paging.py
new file mode 100644
index 00000000..5c79c4c1
--- /dev/null
+++ b/horizon/horizon/templatetags/swift_paging.py
@@ -0,0 +1,35 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from django import template
+from django.conf import settings
+from django.utils import http
+
+register = template.Library()
+
+
+@register.inclusion_tag('nova/objects/_paging.html')
+def object_paging(objects):
+ marker = None
+ if objects and not \
+ len(objects) < getattr(settings, 'SWIFT_PAGINATE_LIMIT', 10000):
+ last_object = objects[-1]
+ marker = http.urlquote_plus(last_object.name)
+ return {'marker': marker}
diff --git a/django-openstack/django_openstack/templatetags/templatetags/truncate_filter.py b/horizon/horizon/templatetags/truncate_filter.py
index c8b4e4a3..c8b4e4a3 100644
--- a/django-openstack/django_openstack/templatetags/templatetags/truncate_filter.py
+++ b/horizon/horizon/templatetags/truncate_filter.py
diff --git a/horizon/horizon/test.py b/horizon/horizon/test.py
new file mode 100644
index 00000000..97f512af
--- /dev/null
+++ b/horizon/horizon/test.py
@@ -0,0 +1,212 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import datetime
+
+from django import http
+from django import shortcuts
+from django import test as django_test
+from django import template as django_template
+from django.conf import settings
+import mox
+
+from horizon import context_processors
+from horizon import middleware
+from horizon import users
+
+
+def time():
+ '''Overrideable version of datetime.datetime.today'''
+ if time.override_time:
+ return time.override_time
+ return datetime.time()
+
+time.override_time = None
+
+
+def today():
+ '''Overridable version of datetime.datetime.today'''
+ if today.override_time:
+ return today.override_time
+ return datetime.datetime.today()
+
+today.override_time = None
+
+
+def utcnow():
+ '''Overridable version of datetime.datetime.utcnow'''
+ if utcnow.override_time:
+ return utcnow.override_time
+ return datetime.datetime.utcnow()
+
+utcnow.override_time = None
+
+
+class TestCase(django_test.TestCase):
+ TEST_STAFF_USER = 'staffUser'
+ TEST_TENANT = '1'
+ TEST_TENANT_NAME = 'aTenant'
+ TEST_TOKEN = 'aToken'
+ TEST_USER = 'test'
+ TEST_ROLES = [{'name': 'admin', 'id': '1'}]
+
+ TEST_SERVICE_CATALOG = [
+ {"endpoints": [{
+ "adminURL": "http://cdn.admin-nets.local:8774/v1.0",
+ "region": "RegionOne",
+ "internalURL": "http://127.0.0.1:8774/v1.0",
+ "publicURL": "http://cdn.admin-nets.local:8774/v1.0/"}],
+ "type": "nova_compat",
+ "name": "nova_compat"},
+ {"endpoints": [{
+ "adminURL": "http://nova/novapi/admin",
+ "region": "RegionOne",
+ "internalURL": "http://nova/novapi/internal",
+ "publicURL": "http://nova/novapi/public"}],
+ "type": "compute",
+ "name": "nova"},
+ {"endpoints": [{
+ "adminURL": "http://glance/glanceapi/admin",
+ "region": "RegionOne",
+ "internalURL": "http://glance/glanceapi/internal",
+ "publicURL": "http://glance/glanceapi/public"}],
+ "type": "image",
+ "name": "glance"},
+ {"endpoints": [{
+ "adminURL": "http://cdn.admin-nets.local:35357/v2.0",
+ "region": "RegionOne",
+ "internalURL": "http://127.0.0.1:5000/v2.0",
+ "publicURL": "http://cdn.admin-nets.local:5000/v2.0"}],
+ "type": "identity",
+ "name": "identity"},
+ {"endpoints": [{
+ "adminURL": "http://swift/swiftapi/admin",
+ "region": "RegionOne",
+ "internalURL": "http://swift/swiftapi/internal",
+ "publicURL": "http://swift/swiftapi/public"}],
+ "type": "object-store",
+ "name": "swift"}]
+
+ def setUp(self):
+ self.mox = mox.Mox()
+
+ context_dict = {'tenants': [],
+ 'object_store_configured': False,
+ 'network_configured': False}
+
+ self._real_horizon_context_processor = context_processors.horizon
+ context_processors.horizon = lambda request: context_dict
+
+ self._real_get_user_from_request = users.get_user_from_request
+ self.setActiveUser(token=self.TEST_TOKEN,
+ username=self.TEST_USER,
+ tenant_id=self.TEST_TENANT,
+ service_catalog=self.TEST_SERVICE_CATALOG)
+ self.request = http.HttpRequest()
+ middleware.HorizonMiddleware().process_request(self.request)
+
+ def tearDown(self):
+ self.mox.UnsetStubs()
+ context_processors.horizon = self._real_horizon_context_processor
+ users.get_user_from_request = self._real_get_user_from_request
+
+ def setActiveUser(self, token=None, username=None, tenant_id=None,
+ service_catalog=None, tenant_name=None, roles=None):
+ users.get_user_from_request = lambda x: \
+ users.User(token=token,
+ user=username,
+ tenant_id=tenant_id,
+ service_catalog=service_catalog)
+
+ def override_times(self):
+ now = datetime.datetime.utcnow()
+ time.override_time = \
+ datetime.time(now.hour, now.minute, now.second)
+ today.override_time = datetime.date(now.year, now.month, now.day)
+ utcnow.override_time = now
+
+ return now
+
+ def reset_times(self):
+ time.override_time = None
+ today.override_time = None
+ utcnow.override_time = None
+
+
+def fake_render_to_response(template_name, context, context_instance=None,
+ mimetype='text/html'):
+ """Replacement for render_to_response so that views can be tested
+ without having to stub out templates that belong in the frontend
+ implementation.
+
+ Should be able to be tested using the django unit test assertions like a
+ normal render_to_response return value can be.
+ """
+ class Template(object):
+ def __init__(self, name):
+ self.name = name
+
+ if context_instance is None:
+ context_instance = django_template.Context(context)
+ else:
+ context_instance.update(context)
+
+ resp = http.HttpResponse()
+ template = Template(template_name)
+
+ resp.write('<html><body><p>'
+ 'This is a fake httpresponse for testing purposes only'
+ '</p></body></html>')
+
+ # Allows django.test.client to populate fields on the response object
+ django_test.signals.template_rendered.send(template, template=template,
+ context=context_instance)
+
+ return resp
+
+
+class BaseViewTests(TestCase):
+ """
+ Base class for view based unit tests.
+ """
+ def setUp(self):
+ super(BaseViewTests, self).setUp()
+ self._real_render_to_response = shortcuts.render_to_response
+ shortcuts.render_to_response = fake_render_to_response
+
+ def tearDown(self):
+ super(BaseViewTests, self).tearDown()
+ shortcuts.render_to_response = self._real_render_to_response
+
+ def assertRedirectsNoFollow(self, response, expected_url):
+ self.assertEqual(response._headers['location'],
+ ('Location', settings.TESTSERVER + expected_url))
+ self.assertEqual(response.status_code, 302)
+
+
+class BaseAdminViewTests(BaseViewTests):
+ def setActiveUser(self, token=None, username=None, tenant_id=None,
+ service_catalog=None, tenant_name=None, roles=None):
+ users.get_user_from_request = lambda x: \
+ users.User(token=self.TEST_TOKEN,
+ user=self.TEST_USER,
+ tenant_id=self.TEST_TENANT,
+ service_catalog=self.TEST_SERVICE_CATALOG,
+ roles=self.TEST_ROLES)
diff --git a/django-openstack/django_openstack/tests/__init__.py b/horizon/horizon/tests/__init__.py
index 8dc4fb67..31e69bd4 100644
--- a/django-openstack/django_openstack/tests/__init__.py
+++ b/horizon/horizon/tests/__init__.py
@@ -18,4 +18,4 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testsettings import *
+from horizon.tests.testsettings import *
diff --git a/horizon/horizon/tests/api_tests/__init__.py b/horizon/horizon/tests/api_tests/__init__.py
new file mode 100644
index 00000000..b3fc6e5b
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/__init__.py
@@ -0,0 +1,29 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from horizon.tests.api_tests.base import (APIResourceWrapperTests,
+ APIDictWrapperTests, ApiHelperTests)
+from horizon.tests.api_tests.glance import GlanceApiTests, ImageWrapperTests
+from horizon.tests.api_tests.keystone import (KeystoneAdminApiTests,
+ TokenApiTests, RoleAPITests, TenantAPITests, UserAPITests)
+from horizon.tests.api_tests.nova import (ServerWrapperTests,
+ NovaAdminApiTests, ComputeApiTests, ExtrasApiTests, VolumeTests,
+ APIExtensionTests)
+from horizon.tests.api_tests.swift import SwiftApiTests
diff --git a/horizon/horizon/tests/api_tests/base.py b/horizon/horizon/tests/api_tests/base.py
new file mode 100644
index 00000000..71daae4f
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/base.py
@@ -0,0 +1,112 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+from django import http
+from django.conf import settings
+from mox import IsA
+
+from horizon import exceptions
+from horizon.tests.api_tests.utils import *
+
+
+# Wrapper classes that only define _attrs don't need extra testing.
+class APIResourceWrapperTests(test.TestCase):
+ def test_get_attribute(self):
+ resource = APIResource.get_instance()
+ self.assertEqual(resource.foo, 'foo')
+
+ def test_get_invalid_attribute(self):
+ resource = APIResource.get_instance()
+ self.assertNotIn('missing', resource._attrs,
+ msg="Test assumption broken. Find new missing attribute")
+ with self.assertRaises(AttributeError):
+ resource.missing
+
+ def test_get_inner_missing_attribute(self):
+ resource = APIResource.get_instance()
+ with self.assertRaises(AttributeError):
+ resource.baz
+
+
+class APIDictWrapperTests(test.TestCase):
+ # APIDict allows for both attribute access and dictionary style [element]
+ # style access. Test both
+ def test_get_item(self):
+ resource = APIDict.get_instance()
+ self.assertEqual(resource.foo, 'foo')
+ self.assertEqual(resource['foo'], 'foo')
+
+ def test_get_invalid_item(self):
+ resource = APIDict.get_instance()
+ self.assertNotIn('missing', resource._attrs,
+ msg="Test assumption broken. Find new missing attribute")
+ with self.assertRaises(AttributeError):
+ resource.missing
+ with self.assertRaises(KeyError):
+ resource['missing']
+
+ def test_get_inner_missing_attribute(self):
+ resource = APIDict.get_instance()
+ with self.assertRaises(AttributeError):
+ resource.baz
+ with self.assertRaises(KeyError):
+ resource['baz']
+
+ def test_get_with_default(self):
+ resource = APIDict.get_instance()
+
+ self.assertEqual(resource.get('foo'), 'foo')
+
+ self.assertIsNone(resource.get('baz'))
+
+ self.assertEqual('retValue', resource.get('baz', 'retValue'))
+
+
+class ApiHelperTests(test.TestCase):
+ """ Tests for functions that don't use one of the api objects """
+
+ def test_url_for(self):
+ GLANCE_URL = 'http://glance/glanceapi/'
+ NOVA_URL = 'http://nova/novapi/'
+
+ url = api.url_for(self.request, 'image')
+ self.assertEqual(url, GLANCE_URL + 'internal')
+
+ url = api.url_for(self.request, 'image', admin=False)
+ self.assertEqual(url, GLANCE_URL + 'internal')
+
+ url = api.url_for(self.request, 'image', admin=True)
+ self.assertEqual(url, GLANCE_URL + 'admin')
+
+ url = api.url_for(self.request, 'compute')
+ self.assertEqual(url, NOVA_URL + 'internal')
+
+ url = api.url_for(self.request, 'compute', admin=False)
+ self.assertEqual(url, NOVA_URL + 'internal')
+
+ url = api.url_for(self.request, 'compute', admin=True)
+ self.assertEqual(url, NOVA_URL + 'admin')
+
+ self.assertNotIn('notAnApi', self.request.user.service_catalog,
+ 'Select a new nonexistent service catalog key')
+ with self.assertRaises(exceptions.ServiceCatalogException):
+ url = api.url_for(self.request, 'notAnApi')
diff --git a/horizon/horizon/tests/api_tests/glance.py b/horizon/horizon/tests/api_tests/glance.py
new file mode 100644
index 00000000..dea27d12
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/glance.py
@@ -0,0 +1,174 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+from django import http
+from glance import client as glance_client
+from mox import IsA
+
+from horizon.tests.api_tests.utils import *
+
+
+class GlanceApiTests(APITestCase):
+ def stub_glance_api(self, count=1):
+ self.mox.StubOutWithMock(api.glance, 'glance_api')
+ glance_api = self.mox.CreateMock(glance_client.Client)
+ glance_api.token = TEST_TOKEN
+ for i in range(count):
+ api.glance.glance_api(IsA(http.HttpRequest)).AndReturn(glance_api)
+ return glance_api
+
+ def test_get_glance_api(self):
+ self.mox.StubOutClassWithMocks(glance_client, 'Client')
+ client_instance = glance_client.Client(TEST_HOSTNAME, TEST_PORT,
+ auth_tok=TEST_TOKEN)
+ # Normally ``auth_tok`` is set in ``Client.__init__``, but mox doesn't
+ # duplicate that behavior so we set it manually.
+ client_instance.auth_tok = TEST_TOKEN
+
+ self.mox.StubOutWithMock(api.glance, 'url_for')
+ api.glance.url_for(IsA(http.HttpRequest), 'image').AndReturn(TEST_URL)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.glance.glance_api(self.request)
+ self.assertIsNotNone(ret_val)
+ self.assertEqual(ret_val.auth_tok, TEST_TOKEN)
+
+ self.mox.VerifyAll()
+
+ def test_image_create(self):
+ IMAGE_FILE = 'someData'
+ IMAGE_META = {'metadata': 'foo'}
+
+ glance_api = self.stub_glance_api()
+ glance_api.add_image(IMAGE_META, IMAGE_FILE).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.image_create(self.request, IMAGE_META, IMAGE_FILE)
+
+ self.assertIsInstance(ret_val, api.Image)
+ self.assertEqual(ret_val._apidict, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_image_delete(self):
+ IMAGE_ID = '1'
+
+ glance_api = self.stub_glance_api()
+ glance_api.delete_image(IMAGE_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.image_delete(self.request, IMAGE_ID)
+
+ self.assertEqual(ret_val, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_image_get(self):
+ IMAGE_ID = '1'
+
+ glance_api = self.stub_glance_api()
+ glance_api.get_image(IMAGE_ID).AndReturn([TEST_RETURN])
+
+ self.mox.ReplayAll()
+
+ ret_val = api.image_get(self.request, IMAGE_ID)
+
+ self.assertIsInstance(ret_val, api.Image)
+ self.assertEqual(ret_val._apidict, TEST_RETURN)
+
+ def test_image_list_detailed(self):
+ images = (TEST_RETURN, TEST_RETURN + '2')
+ glance_api = self.stub_glance_api()
+ glance_api.get_images_detailed().AndReturn(images)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.image_list_detailed(self.request)
+
+ self.assertEqual(len(ret_val), len(images))
+ for image in ret_val:
+ self.assertIsInstance(image, api.Image)
+ self.assertIn(image._apidict, images)
+
+ self.mox.VerifyAll()
+
+ def test_image_update(self):
+ IMAGE_ID = '1'
+ IMAGE_META = {'metadata': 'foobar'}
+
+ glance_api = self.stub_glance_api(count=2)
+ glance_api.update_image(IMAGE_ID, image_meta={}).AndReturn(TEST_RETURN)
+ glance_api.update_image(IMAGE_ID,
+ image_meta=IMAGE_META).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.image_update(self.request, IMAGE_ID)
+
+ self.assertIsInstance(ret_val, api.Image)
+ self.assertEqual(ret_val._apidict, TEST_RETURN)
+
+ ret_val = api.image_update(self.request,
+ IMAGE_ID,
+ image_meta=IMAGE_META)
+
+ self.assertIsInstance(ret_val, api.Image)
+ self.assertEqual(ret_val._apidict, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+
+# Wrapper classes that have other attributes or methods need testing
+class ImageWrapperTests(test.TestCase):
+ dict_with_properties = {
+ 'properties':
+ {'image_state': 'running'},
+ 'size': 100,
+ }
+ dict_without_properties = {
+ 'size': 100,
+ }
+
+ def test_get_properties(self):
+ image = api.Image(self.dict_with_properties)
+ image_props = image.properties
+ self.assertIsInstance(image_props, api.ImageProperties)
+ self.assertEqual(image_props.image_state, 'running')
+
+ def test_get_other(self):
+ image = api.Image(self.dict_with_properties)
+ self.assertEqual(image.size, 100)
+
+ def test_get_properties_missing(self):
+ image = api.Image(self.dict_without_properties)
+ with self.assertRaises(AttributeError):
+ image.properties
+
+ def test_get_other_missing(self):
+ image = api.Image(self.dict_without_properties)
+ with self.assertRaises(AttributeError):
+ self.assertNotIn('missing', image._attrs,
+ msg="Test assumption broken. Find new missing attribute")
+ image.missing
diff --git a/horizon/horizon/tests/api_tests/keystone.py b/horizon/horizon/tests/api_tests/keystone.py
new file mode 100644
index 00000000..3af463f3
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/keystone.py
@@ -0,0 +1,366 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+from django import http
+from django.conf import settings
+from mox import IsA
+from openstackx import admin as OSAdmin
+
+from horizon.tests.api_tests.utils import *
+
+
+class Token(object):
+ """ More or less fakes what the api is looking for """
+ def __init__(self, id, username, tenant_id,
+ tenant_name, serviceCatalog=None):
+ self.id = id
+ self.user = {'name': username}
+ self.tenant = {'id': tenant_id, 'name': tenant_name}
+ self.serviceCatalog = serviceCatalog
+
+ def __eq__(self, other):
+ return self.id == other.id and \
+ self.user['name'] == other.user['name'] and \
+ self.tenant_id == other.tenant_id and \
+ self.serviceCatalog == other.serviceCatalog
+
+ def __ne__(self, other):
+ return not self == other
+
+
+class KeystoneAdminApiTests(APITestCase):
+ def stub_admin_api(self, count=1):
+ self.mox.StubOutWithMock(api.keystone, 'admin_api')
+ admin_api = self.mox.CreateMock(OSAdmin.Admin)
+ for i in range(count):
+ api.keystone.admin_api(IsA(http.HttpRequest)) \
+ .AndReturn(admin_api)
+ return admin_api
+
+ def test_service_get(self):
+ NAME = 'serviceName'
+
+ admin_api = self.stub_admin_api()
+ admin_api.services = self.mox.CreateMockAnything()
+ admin_api.services.get(NAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.service_get(self.request, NAME)
+
+ self.assertIsInstance(ret_val, api.Services)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_service_list(self):
+ services = (TEST_RETURN, TEST_RETURN + '2')
+
+ admin_api = self.stub_admin_api()
+ admin_api.services = self.mox.CreateMockAnything()
+ admin_api.services.list().AndReturn(services)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.service_list(self.request)
+
+ for service in ret_val:
+ self.assertIsInstance(service, api.Services)
+ self.assertIn(service._apiresource, services)
+
+ self.mox.VerifyAll()
+
+ def test_service_update(self):
+ ENABLED = True
+ NAME = 'serviceName'
+
+ admin_api = self.stub_admin_api()
+ admin_api.services = self.mox.CreateMockAnything()
+ admin_api.services.update(NAME, ENABLED).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.service_update(self.request, NAME, ENABLED)
+
+ self.assertIsInstance(ret_val, api.Services)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+
+class TokenApiTests(APITestCase):
+ def setUp(self):
+ super(TokenApiTests, self).setUp()
+ self._prev_OPENSTACK_KEYSTONE_URL = getattr(settings,
+ 'OPENSTACK_KEYSTONE_URL',
+ None)
+ settings.OPENSTACK_KEYSTONE_URL = TEST_URL
+
+ def tearDown(self):
+ super(TokenApiTests, self).tearDown()
+ settings.OPENSTACK_KEYSTONE_URL = self._prev_OPENSTACK_KEYSTONE_URL
+
+ def test_token_create(self):
+ catalog = {
+ 'access': {
+ 'token': {
+ 'id': TEST_TOKEN_ID,
+ },
+ 'user': {
+ 'roles': [],
+ }
+ }
+ }
+ test_token = Token(TEST_TOKEN_ID, TEST_USERNAME,
+ TEST_TENANT_ID, TEST_TENANT_NAME)
+
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.tokens = self.mox.CreateMockAnything()
+ keystoneclient.tokens.authenticate(username=TEST_USERNAME,
+ password=TEST_PASSWORD,
+ tenant=TEST_TENANT_ID)\
+ .AndReturn(test_token)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.token_create(self.request, TEST_TENANT_ID,
+ TEST_USERNAME, TEST_PASSWORD)
+
+ self.assertEqual(test_token.tenant['id'], ret_val.tenant['id'])
+
+ self.mox.VerifyAll()
+
+
+class RoleAPITests(APITestCase):
+ def test_role_add_for_tenant_user(self):
+ keystoneclient = self.stub_keystoneclient()
+
+ role = api.Role(APIResource.get_instance())
+ role.id = TEST_RETURN
+ role.name = TEST_RETURN
+
+ keystoneclient.roles = self.mox.CreateMockAnything()
+ keystoneclient.roles.add_user_to_tenant(TEST_TENANT_ID,
+ TEST_USERNAME,
+ TEST_RETURN).AndReturn(role)
+ api.keystone._get_role = self.mox.CreateMockAnything()
+ api.keystone._get_role(IsA(http.HttpRequest), IsA(str)).AndReturn(role)
+
+ self.mox.ReplayAll()
+ ret_val = api.role_add_for_tenant_user(self.request,
+ TEST_TENANT_ID,
+ TEST_USERNAME,
+ TEST_RETURN)
+ self.assertEqual(ret_val, role)
+
+ self.mox.VerifyAll()
+
+
+class TenantAPITests(APITestCase):
+ def test_tenant_create(self):
+ DESCRIPTION = 'aDescription'
+ ENABLED = True
+
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.tenants = self.mox.CreateMockAnything()
+ keystoneclient.tenants.create(TEST_TENANT_ID, DESCRIPTION,
+ ENABLED).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.tenant_create(self.request, TEST_TENANT_ID,
+ DESCRIPTION, ENABLED)
+
+ self.assertIsInstance(ret_val, api.Tenant)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_tenant_get(self):
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.tenants = self.mox.CreateMockAnything()
+ keystoneclient.tenants.get(TEST_TENANT_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.tenant_get(self.request, TEST_TENANT_ID)
+
+ self.assertIsInstance(ret_val, api.Tenant)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_tenant_list(self):
+ tenants = (TEST_RETURN, TEST_RETURN + '2')
+
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.tenants = self.mox.CreateMockAnything()
+ keystoneclient.tenants.list().AndReturn(tenants)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.tenant_list(self.request)
+
+ self.assertEqual(len(ret_val), len(tenants))
+ for tenant in ret_val:
+ self.assertIsInstance(tenant, api.Tenant)
+ self.assertIn(tenant._apiresource, tenants)
+
+ self.mox.VerifyAll()
+
+ def test_tenant_update(self):
+ DESCRIPTION = 'aDescription'
+ ENABLED = True
+
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.tenants = self.mox.CreateMockAnything()
+ keystoneclient.tenants.update(TEST_TENANT_ID, TEST_TENANT_NAME,
+ DESCRIPTION, ENABLED).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.tenant_update(self.request, TEST_TENANT_ID,
+ TEST_TENANT_NAME, DESCRIPTION, ENABLED)
+
+ self.assertIsInstance(ret_val, api.Tenant)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+
+class UserAPITests(APITestCase):
+ def test_user_create(self):
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.create(TEST_USERNAME, TEST_PASSWORD, TEST_EMAIL,
+ TEST_TENANT_ID, True).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_create(self.request, TEST_USERNAME, TEST_EMAIL,
+ TEST_PASSWORD, TEST_TENANT_ID, True)
+
+ self.assertIsInstance(ret_val, api.User)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_user_delete(self):
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.delete(TEST_USERNAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_delete(self.request, TEST_USERNAME)
+
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_user_get(self):
+ keystoneclient = self.stub_keystoneclient()
+
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.get(TEST_USERNAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_get(self.request, TEST_USERNAME)
+
+ self.assertIsInstance(ret_val, api.User)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_user_list(self):
+ users = (TEST_USERNAME, TEST_USERNAME + '2')
+
+ keystoneclient = self.stub_keystoneclient()
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.list(tenant_id=None).AndReturn(users)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_list(self.request)
+
+ self.assertEqual(len(ret_val), len(users))
+ for user in ret_val:
+ self.assertIsInstance(user, api.User)
+ self.assertIn(user._apiresource, users)
+
+ self.mox.VerifyAll()
+
+ def test_user_update_email(self):
+ keystoneclient = self.stub_keystoneclient()
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.update_email(TEST_USERNAME,
+ TEST_EMAIL).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_update_email(self.request, TEST_USERNAME,
+ TEST_EMAIL)
+
+ self.assertIsInstance(ret_val, api.User)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_user_update_password(self):
+ keystoneclient = self.stub_keystoneclient()
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.update_password(TEST_USERNAME,
+ TEST_PASSWORD).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_update_password(self.request, TEST_USERNAME,
+ TEST_PASSWORD)
+
+ self.assertIsInstance(ret_val, api.User)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_user_update_tenant(self):
+ keystoneclient = self.stub_keystoneclient()
+ keystoneclient.users = self.mox.CreateMockAnything()
+ keystoneclient.users.update_tenant(TEST_USERNAME,
+ TEST_TENANT_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.user_update_tenant(self.request, TEST_USERNAME,
+ TEST_TENANT_ID)
+
+ self.assertIsInstance(ret_val, api.User)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
diff --git a/horizon/horizon/tests/api_tests/nova.py b/horizon/horizon/tests/api_tests/nova.py
new file mode 100644
index 00000000..92dac4ae
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/nova.py
@@ -0,0 +1,697 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+from django import http
+from django.conf import settings
+from mox import IsA
+from openstack import compute as OSCompute
+from openstackx import admin as OSAdmin
+from openstackx import auth as OSAuth
+from openstackx import extras as OSExtras
+
+
+from horizon.tests.api_tests.utils import *
+
+
+class Server(object):
+ """ More or less fakes what the api is looking for """
+ def __init__(self, id, image, attrs=None):
+ self.id = id
+
+ self.image = image
+ if attrs is not None:
+ self.attrs = attrs
+
+ def __eq__(self, other):
+ if self.id != other.id or \
+ self.image['id'] != other.image['id']:
+ return False
+
+ for k in self.attrs:
+ if other.attrs.__getattr__(k) != v:
+ return False
+
+ return True
+
+ def __ne__(self, other):
+ return not self == other
+
+
+class ServerWrapperTests(test.TestCase):
+ HOST = 'hostname'
+ ID = '1'
+ IMAGE_NAME = 'imageName'
+ IMAGE_OBJ = {'id': '3', 'links': [{'href': '3', u'rel': u'bookmark'}]}
+
+ def setUp(self):
+ super(ServerWrapperTests, self).setUp()
+
+ # these are all objects "fetched" from the api
+ self.inner_attrs = {'host': self.HOST}
+
+ self.inner_server = Server(self.ID, self.IMAGE_OBJ, self.inner_attrs)
+ self.inner_server_no_attrs = Server(self.ID, self.IMAGE_OBJ)
+
+ #self.request = self.mox.CreateMock(http.HttpRequest)
+
+ def test_get_attrs(self):
+ server = api.Server(self.inner_server, self.request)
+ attrs = server.attrs
+ # for every attribute in the "inner" object passed to the api wrapper,
+ # see if it can be accessed through the api.ServerAttribute instance
+ for k in self.inner_attrs:
+ self.assertEqual(attrs.__getattr__(k), self.inner_attrs[k])
+
+ def test_get_other(self):
+ server = api.Server(self.inner_server, self.request)
+ self.assertEqual(server.id, self.ID)
+
+ def test_get_attrs_missing(self):
+ server = api.Server(self.inner_server_no_attrs, self.request)
+ with self.assertRaises(AttributeError):
+ server.attrs
+
+ def test_get_other_missing(self):
+ server = api.Server(self.inner_server, self.request)
+ with self.assertRaises(AttributeError):
+ self.assertNotIn('missing', server._attrs,
+ msg="Test assumption broken. Find new missing attribute")
+ server.missing
+
+ def test_image_name(self):
+ image = api.Image({'name': self.IMAGE_NAME})
+ self.mox.StubOutWithMock(api.glance, 'image_get')
+ api.glance.image_get(IsA(http.HttpRequest),
+ self.IMAGE_OBJ['id']).AndReturn(image)
+
+ server = api.Server(self.inner_server, self.request)
+
+ self.mox.ReplayAll()
+
+ image_name = server.image_name
+
+ self.assertEqual(image_name, self.IMAGE_NAME)
+
+ self.mox.VerifyAll()
+
+
+class NovaAdminApiTests(APITestCase):
+ def stub_admin_api(self, count=1):
+ self.mox.StubOutWithMock(api.nova, 'admin_api')
+ admin_api = self.mox.CreateMock(OSAdmin.Admin)
+ for i in range(count):
+ api.nova.admin_api(IsA(http.HttpRequest)) \
+ .AndReturn(admin_api)
+ return admin_api
+
+ def test_get_admin_api(self):
+ self.mox.StubOutClassWithMocks(OSAdmin, 'Admin')
+ OSAdmin.Admin(auth_token=TEST_TOKEN, management_url=TEST_URL)
+
+ self.mox.StubOutWithMock(api.deprecated, 'url_for')
+ api.deprecated.url_for(IsA(http.HttpRequest),
+ 'compute', True).AndReturn(TEST_URL)
+
+ self.mox.ReplayAll()
+
+ self.assertIsNotNone(api.nova.admin_api(self.request))
+
+ self.mox.VerifyAll()
+
+ def test_flavor_create(self):
+ FLAVOR_DISK = 1000
+ FLAVOR_ID = 6
+ FLAVOR_MEMORY = 1024
+ FLAVOR_NAME = 'newFlavor'
+ FLAVOR_VCPU = 2
+
+ admin_api = self.stub_admin_api()
+
+ admin_api.flavors = self.mox.CreateMockAnything()
+ admin_api.flavors.create(FLAVOR_NAME, FLAVOR_MEMORY, FLAVOR_VCPU,
+ FLAVOR_DISK, FLAVOR_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.flavor_create(self.request, FLAVOR_NAME,
+ str(FLAVOR_MEMORY), str(FLAVOR_VCPU),
+ str(FLAVOR_DISK), FLAVOR_ID)
+
+ self.assertIsInstance(ret_val, api.Flavor)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_flavor_delete(self):
+ FLAVOR_ID = 6
+
+ admin_api = self.stub_admin_api(count=2)
+
+ admin_api.flavors = self.mox.CreateMockAnything()
+ admin_api.flavors.delete(FLAVOR_ID, False).AndReturn(TEST_RETURN)
+ admin_api.flavors.delete(FLAVOR_ID, True).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.flavor_delete(self.request, FLAVOR_ID)
+ self.assertIsNone(ret_val)
+
+ ret_val = api.flavor_delete(self.request, FLAVOR_ID, purge=True)
+ self.assertIsNone(ret_val)
+
+
+class ComputeApiTests(APITestCase):
+ def stub_compute_api(self, count=1):
+ self.mox.StubOutWithMock(api.nova, 'compute_api')
+ compute_api = self.mox.CreateMock(OSCompute.Compute)
+ for i in range(count):
+ api.nova.compute_api(IsA(http.HttpRequest)) \
+ .AndReturn(compute_api)
+ return compute_api
+
+ def test_get_compute_api(self):
+ class ComputeClient(object):
+ __slots__ = ['auth_token', 'management_url']
+
+ self.mox.StubOutClassWithMocks(OSCompute, 'Compute')
+ compute_api = OSCompute.Compute(auth_token=TEST_TOKEN,
+ management_url=TEST_URL)
+
+ compute_api.client = ComputeClient()
+
+ self.mox.StubOutWithMock(api.deprecated, 'url_for')
+ api.deprecated.url_for(IsA(http.HttpRequest),
+ 'compute').AndReturn(TEST_URL)
+
+ self.mox.ReplayAll()
+
+ compute_api = api.nova.compute_api(self.request)
+
+ self.assertIsNotNone(compute_api)
+ self.assertEqual(compute_api.client.auth_token, TEST_TOKEN)
+ self.assertEqual(compute_api.client.management_url, TEST_URL)
+
+ self.mox.VerifyAll()
+
+ def test_flavor_get(self):
+ FLAVOR_ID = 6
+
+ novaclient = self.stub_novaclient()
+
+ novaclient.flavors = self.mox.CreateMockAnything()
+ novaclient.flavors.get(FLAVOR_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.flavor_get(self.request, FLAVOR_ID)
+ self.assertIsInstance(ret_val, api.Flavor)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_server_delete(self):
+ INSTANCE = 'anInstance'
+
+ compute_api = self.stub_compute_api()
+
+ compute_api.servers = self.mox.CreateMockAnything()
+ compute_api.servers.delete(INSTANCE).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.server_delete(self.request, INSTANCE)
+
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_server_reboot(self):
+ INSTANCE_ID = '2'
+ HARDNESS = 'diamond'
+
+ self.mox.StubOutWithMock(api.nova, 'server_get')
+
+ server = self.mox.CreateMock(OSCompute.Server)
+ server.reboot(OSCompute.servers.REBOOT_HARD).AndReturn(TEST_RETURN)
+ api.nova.server_get(IsA(http.HttpRequest),
+ INSTANCE_ID).AndReturn(server)
+
+ server = self.mox.CreateMock(OSCompute.Server)
+ server.reboot(HARDNESS).AndReturn(TEST_RETURN)
+ api.nova.server_get(IsA(http.HttpRequest),
+ INSTANCE_ID).AndReturn(server)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.server_reboot(self.request, INSTANCE_ID)
+ self.assertIsNone(ret_val)
+
+ ret_val = api.server_reboot(self.request, INSTANCE_ID,
+ hardness=HARDNESS)
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_server_create(self):
+ NAME = 'server'
+ IMAGE = 'anImage'
+ FLAVOR = 'cherry'
+ USER_DATA = {'nuts': 'berries'}
+ KEY = 'user'
+ SECGROUP = self.mox.CreateMock(api.SecurityGroup)
+
+ server = self.mox.CreateMock(OSCompute.Server)
+ novaclient = self.stub_novaclient()
+ novaclient.servers = self.mox.CreateMockAnything()
+ novaclient.servers.create(NAME, IMAGE, FLAVOR, userdata=USER_DATA,
+ security_groups=[SECGROUP], key_name=KEY)\
+ .AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.server_create(self.request, NAME, IMAGE, FLAVOR,
+ KEY, USER_DATA, [SECGROUP])
+
+ self.assertIsInstance(ret_val, api.Server)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+
+class ExtrasApiTests(APITestCase):
+
+ def stub_extras_api(self, count=1):
+ self.mox.StubOutWithMock(api.nova, 'extras_api')
+ extras_api = self.mox.CreateMock(OSExtras.Extras)
+ for i in range(count):
+ api.nova.extras_api(IsA(http.HttpRequest)) \
+ .AndReturn(extras_api)
+ return extras_api
+
+ def test_get_extras_api(self):
+ self.mox.StubOutClassWithMocks(OSExtras, 'Extras')
+ OSExtras.Extras(auth_token=TEST_TOKEN, management_url=TEST_URL)
+
+ self.mox.StubOutWithMock(api.deprecated, 'url_for')
+ api.deprecated.url_for(IsA(http.HttpRequest),
+ 'compute').AndReturn(TEST_URL)
+
+ self.mox.ReplayAll()
+
+ self.assertIsNotNone(api.nova.extras_api(self.request))
+
+ self.mox.VerifyAll()
+
+ def test_console_create(self):
+ extras_api = self.stub_extras_api(count=2)
+ extras_api.consoles = self.mox.CreateMockAnything()
+ extras_api.consoles.create(
+ TEST_INSTANCE_ID, TEST_CONSOLE_KIND).AndReturn(TEST_RETURN)
+ extras_api.consoles.create(
+ TEST_INSTANCE_ID, 'text').AndReturn(TEST_RETURN + '2')
+
+ self.mox.ReplayAll()
+
+ ret_val = api.console_create(self.request,
+ TEST_INSTANCE_ID,
+ TEST_CONSOLE_KIND)
+ self.assertIsInstance(ret_val, api.Console)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ ret_val = api.console_create(self.request, TEST_INSTANCE_ID)
+ self.assertIsInstance(ret_val, api.Console)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN + '2')
+
+ self.mox.VerifyAll()
+
+ def test_flavor_list(self):
+ flavors = (TEST_RETURN, TEST_RETURN + '2')
+ novaclient = self.stub_novaclient()
+ novaclient.flavors = self.mox.CreateMockAnything()
+ novaclient.flavors.list().AndReturn(flavors)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.flavor_list(self.request)
+
+ self.assertEqual(len(ret_val), len(flavors))
+ for flavor in ret_val:
+ self.assertIsInstance(flavor, api.Flavor)
+ self.assertIn(flavor._apiresource, flavors)
+
+ self.mox.VerifyAll()
+
+ def test_server_list(self):
+ servers = (TEST_RETURN, TEST_RETURN + '2')
+
+ extras_api = self.stub_extras_api()
+
+ extras_api.servers = self.mox.CreateMockAnything()
+ extras_api.servers.list().AndReturn(servers)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.server_list(self.request)
+
+ self.assertEqual(len(ret_val), len(servers))
+ for server in ret_val:
+ self.assertIsInstance(server, api.Server)
+ self.assertIn(server._apiresource, servers)
+
+ self.mox.VerifyAll()
+
+ def test_usage_get(self):
+ extras_api = self.stub_extras_api()
+
+ extras_api.usage = self.mox.CreateMockAnything()
+ extras_api.usage.get(TEST_TENANT_ID, 'start',
+ 'end').AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.usage_get(self.request, TEST_TENANT_ID, 'start', 'end')
+
+ self.assertIsInstance(ret_val, api.Usage)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_usage_list(self):
+ usages = (TEST_RETURN, TEST_RETURN + '2')
+
+ extras_api = self.stub_extras_api()
+
+ extras_api.usage = self.mox.CreateMockAnything()
+ extras_api.usage.list('start', 'end').AndReturn(usages)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.usage_list(self.request, 'start', 'end')
+
+ self.assertEqual(len(ret_val), len(usages))
+ for usage in ret_val:
+ self.assertIsInstance(usage, api.Usage)
+ self.assertIn(usage._apiresource, usages)
+
+ self.mox.VerifyAll()
+
+ def test_server_get(self):
+ INSTANCE_ID = '2'
+
+ extras_api = self.stub_extras_api()
+ extras_api.servers = self.mox.CreateMockAnything()
+ extras_api.servers.get(INSTANCE_ID).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.server_get(self.request, INSTANCE_ID)
+
+ self.assertIsInstance(ret_val, api.Server)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+
+class APIExtensionTests(APITestCase):
+
+ def setUp(self):
+ super(APIExtensionTests, self).setUp()
+ keypair = api.KeyPair(APIResource.get_instance())
+ keypair.id = 1
+ keypair.name = TEST_RETURN
+
+ self.keypair = keypair
+ self.keypairs = [keypair, ]
+
+ floating_ip = api.FloatingIp(APIResource.get_instance())
+ floating_ip.id = 1
+ floating_ip.fixed_ip = '10.0.0.4'
+ floating_ip.instance_id = 1
+ floating_ip.ip = '58.58.58.58'
+
+ self.floating_ip = floating_ip
+ self.floating_ips = [floating_ip, ]
+
+ server = api.Server(APIResource.get_instance(), self.request)
+ server.id = 1
+
+ self.server = server
+ self.servers = [server, ]
+
+ def test_server_snapshot_create(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.servers = self.mox.CreateMockAnything()
+ novaclient.servers.create_image(IsA(int), IsA(str)).\
+ AndReturn(self.server)
+ self.mox.ReplayAll()
+
+ server = api.snapshot_create(self.request, 1, 'test-snapshot')
+
+ self.assertIsInstance(server, api.Server)
+ self.mox.VerifyAll()
+
+ def test_tenant_floating_ip_list(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+ novaclient.floating_ips.list().AndReturn(self.floating_ips)
+ self.mox.ReplayAll()
+
+ floating_ips = api.tenant_floating_ip_list(self.request)
+
+ self.assertEqual(len(floating_ips), len(self.floating_ips))
+ self.assertIsInstance(floating_ips[0], api.FloatingIp)
+ self.mox.VerifyAll()
+
+ def test_tenant_floating_ip_get(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+ novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
+ self.mox.ReplayAll()
+
+ floating_ip = api.tenant_floating_ip_get(self.request, 1)
+
+ self.assertIsInstance(floating_ip, api.FloatingIp)
+ self.mox.VerifyAll()
+
+ def test_tenant_floating_ip_allocate(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+ novaclient.floating_ips.create().AndReturn(self.floating_ip)
+ self.mox.ReplayAll()
+
+ floating_ip = api.tenant_floating_ip_allocate(self.request)
+
+ self.assertIsInstance(floating_ip, api.FloatingIp)
+ self.mox.VerifyAll()
+
+ def test_tenant_floating_ip_release(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+ novaclient.floating_ips.delete(1).AndReturn(self.floating_ip)
+ self.mox.ReplayAll()
+
+ floating_ip = api.tenant_floating_ip_release(self.request, 1)
+
+ self.assertIsInstance(floating_ip, api.FloatingIp)
+ self.mox.VerifyAll()
+
+ def test_server_remove_floating_ip(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.servers = self.mox.CreateMockAnything()
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+
+ novaclient.servers.get(IsA(int)).AndReturn(self.server)
+ novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
+ novaclient.servers.remove_floating_ip(IsA(self.server.__class__),
+ IsA(self.floating_ip.__class__)) \
+ .AndReturn(self.server)
+ self.mox.ReplayAll()
+
+ server = api.server_remove_floating_ip(self.request, 1, 1)
+
+ self.assertIsInstance(server, api.Server)
+ self.mox.VerifyAll()
+
+ def test_server_add_floating_ip(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.floating_ips = self.mox.CreateMockAnything()
+ novaclient.servers = self.mox.CreateMockAnything()
+
+ novaclient.servers.get(IsA(int)).AndReturn(self.server)
+ novaclient.floating_ips.get(IsA(int)).AndReturn(self.floating_ip)
+ novaclient.servers.add_floating_ip(IsA(self.server.__class__),
+ IsA(self.floating_ip.__class__)) \
+ .AndReturn(self.server)
+ self.mox.ReplayAll()
+
+ server = api.server_add_floating_ip(self.request, 1, 1)
+
+ self.assertIsInstance(server, api.Server)
+ self.mox.VerifyAll()
+
+ def test_keypair_create(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.keypairs = self.mox.CreateMockAnything()
+ novaclient.keypairs.create(IsA(str)).AndReturn(self.keypair)
+ self.mox.ReplayAll()
+
+ ret_val = api.keypair_create(self.request, TEST_RETURN)
+ self.assertIsInstance(ret_val, api.KeyPair)
+ self.assertEqual(ret_val.name, self.keypair.name)
+
+ self.mox.VerifyAll()
+
+ def test_keypair_import(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.keypairs = self.mox.CreateMockAnything()
+ novaclient.keypairs.create(IsA(str), IsA(str)).AndReturn(self.keypair)
+ self.mox.ReplayAll()
+
+ ret_val = api.keypair_import(self.request, TEST_RETURN, TEST_RETURN)
+ self.assertIsInstance(ret_val, api.KeyPair)
+ self.assertEqual(ret_val.name, self.keypair.name)
+
+ self.mox.VerifyAll()
+
+ def test_keypair_delete(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.keypairs = self.mox.CreateMockAnything()
+ novaclient.keypairs.delete(IsA(int))
+
+ self.mox.ReplayAll()
+
+ ret_val = api.keypair_delete(self.request, self.keypair.id)
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_keypair_list(self):
+ novaclient = self.stub_novaclient()
+
+ novaclient.keypairs = self.mox.CreateMockAnything()
+ novaclient.keypairs.list().AndReturn(self.keypairs)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.keypair_list(self.request)
+
+ self.assertEqual(len(ret_val), len(self.keypairs))
+ for keypair in ret_val:
+ self.assertIsInstance(keypair, api.KeyPair)
+
+ self.mox.VerifyAll()
+
+
+class VolumeTests(APITestCase):
+ def setUp(self):
+ super(VolumeTests, self).setUp()
+ volume = api.Volume(APIResource.get_instance())
+ volume.id = 1
+ volume.displayName = "displayName"
+ volume.attachments = [{"device": "/dev/vdb",
+ "serverId": 1,
+ "id": 1,
+ "volumeId": 1}]
+ self.volume = volume
+ self.volumes = [volume, ]
+
+ self.novaclient = self.stub_novaclient()
+ self.novaclient.volumes = self.mox.CreateMockAnything()
+
+ def test_volume_list(self):
+ self.novaclient.volumes.list().AndReturn(self.volumes)
+ self.mox.ReplayAll()
+
+ volumes = api.volume_list(self.request)
+
+ self.assertIsInstance(volumes[0], api.Volume)
+ self.mox.VerifyAll()
+
+ def test_volume_get(self):
+ self.novaclient.volumes.get(IsA(int)).AndReturn(self.volume)
+ self.mox.ReplayAll()
+
+ volume = api.volume_get(self.request, 1)
+
+ self.assertIsInstance(volume, api.Volume)
+ self.mox.VerifyAll()
+
+ def test_volume_instance_list(self):
+ self.novaclient.volumes.get_server_volumes(IsA(int)).AndReturn(
+ self.volume.attachments)
+ self.mox.ReplayAll()
+
+ attachments = api.volume_instance_list(self.request, 1)
+
+ self.assertEqual(attachments, self.volume.attachments)
+ self.mox.VerifyAll()
+
+ def test_volume_create(self):
+ self.novaclient.volumes.create(IsA(int), IsA(str), IsA(str)).AndReturn(
+ self.volume)
+ self.mox.ReplayAll()
+
+ new_volume = api.volume_create(self.request,
+ 10,
+ "new volume",
+ "new description")
+
+ self.assertIsInstance(new_volume, api.Volume)
+ self.mox.VerifyAll()
+
+ def test_volume_delete(self):
+ self.novaclient.volumes.delete(IsA(int))
+ self.mox.ReplayAll()
+
+ ret_val = api.volume_delete(self.request, 1)
+
+ self.assertIsNone(ret_val)
+ self.mox.VerifyAll()
+
+ def test_volume_attach(self):
+ self.novaclient.volumes.create_server_volume(
+ IsA(int), IsA(int), IsA(str))
+ self.mox.ReplayAll()
+
+ ret_val = api.volume_attach(self.request, 1, 1, "/dev/vdb")
+
+ self.assertIsNone(ret_val)
+ self.mox.VerifyAll()
+
+ def test_volume_detach(self):
+ self.novaclient.volumes.delete_server_volume(IsA(int), IsA(int))
+ self.mox.ReplayAll()
+
+ ret_val = api.volume_detach(self.request, 1, 1)
+
+ self.assertIsNone(ret_val)
+ self.mox.VerifyAll()
diff --git a/horizon/horizon/tests/api_tests/swift.py b/horizon/horizon/tests/api_tests/swift.py
new file mode 100644
index 00000000..77c667e0
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/swift.py
@@ -0,0 +1,260 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from __future__ import absolute_import
+
+import cloudfiles
+from django import http
+from mox import IsA
+
+from horizon.tests.api_tests.utils import *
+
+
+class SwiftApiTests(APITestCase):
+ def setUp(self):
+ super(SwiftApiTests, self).setUp()
+ self.request = http.HttpRequest()
+ self.request.session = dict()
+ self.request.session['token'] = TEST_TOKEN
+
+ def stub_swift_api(self, count=1):
+ self.mox.StubOutWithMock(api.swift, 'swift_api')
+ swift_api = self.mox.CreateMock(cloudfiles.connection.Connection)
+ for i in range(count):
+ api.swift.swift_api(IsA(http.HttpRequest)).AndReturn(swift_api)
+ return swift_api
+
+ def test_swift_get_containers(self):
+ containers = (TEST_RETURN, TEST_RETURN + '2')
+
+ swift_api = self.stub_swift_api()
+
+ swift_api.get_all_containers(limit=10000,
+ marker=None).AndReturn(containers)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_get_containers(self.request)
+
+ self.assertEqual(len(ret_val), len(containers))
+ for container in ret_val:
+ self.assertIsInstance(container, api.Container)
+ self.assertIn(container._apiresource, containers)
+
+ self.mox.VerifyAll()
+
+ def test_swift_create_container(self):
+ NAME = 'containerName'
+
+ swift_api = self.stub_swift_api()
+ self.mox.StubOutWithMock(api.swift, 'swift_container_exists')
+
+ api.swift.swift_container_exists(self.request,
+ NAME).AndReturn(False)
+ swift_api.create_container(NAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_create_container(self.request, NAME)
+
+ self.assertIsInstance(ret_val, api.Container)
+ self.assertEqual(ret_val._apiresource, TEST_RETURN)
+
+ self.mox.VerifyAll()
+
+ def test_swift_delete_container(self):
+ NAME = 'containerName'
+
+ swift_api = self.stub_swift_api()
+
+ swift_api.delete_container(NAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_delete_container(self.request, NAME)
+
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_swift_get_objects(self):
+ NAME = 'containerName'
+
+ swift_objects = (TEST_RETURN, TEST_RETURN + '2')
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ container.get_objects(limit=10000,
+ marker=None,
+ prefix=None).AndReturn(swift_objects)
+
+ swift_api = self.stub_swift_api()
+
+ swift_api.get_container(NAME).AndReturn(container)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_get_objects(self.request, NAME)
+
+ self.assertEqual(len(ret_val), len(swift_objects))
+ for swift_object in ret_val:
+ self.assertIsInstance(swift_object, api.SwiftObject)
+ self.assertIn(swift_object._apiresource, swift_objects)
+
+ self.mox.VerifyAll()
+
+ def test_swift_get_objects_with_prefix(self):
+ NAME = 'containerName'
+ PREFIX = 'prefacedWith'
+
+ swift_objects = (TEST_RETURN, TEST_RETURN + '2')
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ container.get_objects(limit=10000,
+ marker=None,
+ prefix=PREFIX).AndReturn(swift_objects)
+
+ swift_api = self.stub_swift_api()
+
+ swift_api.get_container(NAME).AndReturn(container)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_get_objects(self.request,
+ NAME,
+ prefix=PREFIX)
+
+ self.assertEqual(len(ret_val), len(swift_objects))
+ for swift_object in ret_val:
+ self.assertIsInstance(swift_object, api.SwiftObject)
+ self.assertIn(swift_object._apiresource, swift_objects)
+
+ self.mox.VerifyAll()
+
+ def test_swift_upload_object(self):
+ CONTAINER_NAME = 'containerName'
+ OBJECT_NAME = 'objectName'
+ OBJECT_DATA = 'someData'
+
+ swift_api = self.stub_swift_api()
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ swift_object = self.mox.CreateMock(cloudfiles.storage_object.Object)
+
+ swift_api.get_container(CONTAINER_NAME).AndReturn(container)
+ container.create_object(OBJECT_NAME).AndReturn(swift_object)
+ swift_object.write(OBJECT_DATA).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_upload_object(self.request,
+ CONTAINER_NAME,
+ OBJECT_NAME,
+ OBJECT_DATA)
+
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_swift_delete_object(self):
+ CONTAINER_NAME = 'containerName'
+ OBJECT_NAME = 'objectName'
+
+ swift_api = self.stub_swift_api()
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+
+ swift_api.get_container(CONTAINER_NAME).AndReturn(container)
+ container.delete_object(OBJECT_NAME).AndReturn(TEST_RETURN)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_delete_object(self.request,
+ CONTAINER_NAME,
+ OBJECT_NAME)
+
+ self.assertIsNone(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_swift_get_object_data(self):
+ CONTAINER_NAME = 'containerName'
+ OBJECT_NAME = 'objectName'
+ OBJECT_DATA = 'objectData'
+
+ swift_api = self.stub_swift_api()
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ swift_object = self.mox.CreateMock(cloudfiles.storage_object.Object)
+
+ swift_api.get_container(CONTAINER_NAME).AndReturn(container)
+ container.get_object(OBJECT_NAME).AndReturn(swift_object)
+ swift_object.stream().AndReturn(OBJECT_DATA)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_get_object_data(self.request,
+ CONTAINER_NAME,
+ OBJECT_NAME)
+
+ self.assertEqual(ret_val, OBJECT_DATA)
+
+ self.mox.VerifyAll()
+
+ def test_swift_object_exists(self):
+ CONTAINER_NAME = 'containerName'
+ OBJECT_NAME = 'objectName'
+
+ swift_api = self.stub_swift_api()
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ swift_object = self.mox.CreateMock(cloudfiles.Object)
+
+ swift_api.get_container(CONTAINER_NAME).AndReturn(container)
+ container.get_object(OBJECT_NAME).AndReturn(swift_object)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_object_exists(self.request,
+ CONTAINER_NAME,
+ OBJECT_NAME)
+ self.assertTrue(ret_val)
+
+ self.mox.VerifyAll()
+
+ def test_swift_copy_object(self):
+ CONTAINER_NAME = 'containerName'
+ OBJECT_NAME = 'objectName'
+
+ swift_api = self.stub_swift_api()
+ container = self.mox.CreateMock(cloudfiles.container.Container)
+ self.mox.StubOutWithMock(api.swift, 'swift_object_exists')
+
+ swift_object = self.mox.CreateMock(cloudfiles.Object)
+
+ swift_api.get_container(CONTAINER_NAME).AndReturn(container)
+ api.swift.swift_object_exists(self.request,
+ CONTAINER_NAME,
+ OBJECT_NAME).AndReturn(False)
+
+ container.get_object(OBJECT_NAME).AndReturn(swift_object)
+ swift_object.copy_to(CONTAINER_NAME, OBJECT_NAME)
+
+ self.mox.ReplayAll()
+
+ ret_val = api.swift_copy_object(self.request, CONTAINER_NAME,
+ OBJECT_NAME, CONTAINER_NAME,
+ OBJECT_NAME)
+
+ self.assertIsNone(ret_val)
+ self.mox.VerifyAll()
diff --git a/horizon/horizon/tests/api_tests/utils.py b/horizon/horizon/tests/api_tests/utils.py
new file mode 100644
index 00000000..37dcd2b3
--- /dev/null
+++ b/horizon/horizon/tests/api_tests/utils.py
@@ -0,0 +1,99 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from keystoneclient.v2_0 import client as keystone_client
+from novaclient.v1_1 import client as nova_client
+
+from horizon import api
+from horizon import test
+
+
+TEST_CONSOLE_KIND = 'vnc'
+TEST_EMAIL = 'test@test.com'
+TEST_HOSTNAME = 'hostname'
+TEST_INSTANCE_ID = '2'
+TEST_PASSWORD = '12345'
+TEST_PORT = 8000
+TEST_RETURN = 'retValue'
+TEST_TENANT_DESCRIPTION = 'tenantDescription'
+TEST_TENANT_ID = '1234'
+TEST_TENANT_NAME = 'foo'
+TEST_TOKEN = 'aToken'
+TEST_TOKEN_ID = 'userId'
+TEST_URL = 'http://%s:%s/something/v1.0' % (TEST_HOSTNAME, TEST_PORT)
+TEST_USERNAME = 'testUser'
+
+
+class APIResource(api.APIResourceWrapper):
+ """ Simple APIResource for testing """
+ _attrs = ['foo', 'bar', 'baz']
+
+ @staticmethod
+ def get_instance(innerObject=None):
+ if innerObject is None:
+
+ class InnerAPIResource(object):
+ pass
+
+ innerObject = InnerAPIResource()
+ innerObject.foo = 'foo'
+ innerObject.bar = 'bar'
+ return APIResource(innerObject)
+
+
+class APIDict(api.APIDictWrapper):
+ """ Simple APIDict for testing """
+ _attrs = ['foo', 'bar', 'baz']
+
+ @staticmethod
+ def get_instance(innerDict=None):
+ if innerDict is None:
+ innerDict = {'foo': 'foo',
+ 'bar': 'bar'}
+ return APIDict(innerDict)
+
+
+class APITestCase(test.TestCase):
+ def setUp(self):
+ def fake_keystoneclient(request, username=None, password=None,
+ tenant_id=None, token_id=None, endpoint=None):
+ return self.stub_keystoneclient()
+ super(APITestCase, self).setUp()
+ self._original_keystoneclient = api.keystone.keystoneclient
+ self._original_novaclient = api.nova.novaclient
+ api.keystone.keystoneclient = fake_keystoneclient
+ api.nova.novaclient = lambda request: self.stub_novaclient()
+
+ def stub_novaclient(self):
+ if not hasattr(self, "novaclient"):
+ self.mox.StubOutWithMock(nova_client, 'Client')
+ self.novaclient = self.mox.CreateMock(nova_client.Client)
+ return self.novaclient
+
+ def stub_keystoneclient(self):
+ if not hasattr(self, "keystoneclient"):
+ self.mox.StubOutWithMock(keystone_client, 'Client')
+ self.keystoneclient = self.mox.CreateMock(keystone_client.Client)
+ return self.keystoneclient
+
+ def tearDown(self):
+ super(APITestCase, self).tearDown()
+ api.nova.novaclient = self._original_novaclient
+ api.keystone.keystoneclient = self._original_keystoneclient
diff --git a/django-openstack/django_openstack/tests/view_tests/auth_tests.py b/horizon/horizon/tests/auth_tests.py
index 1c637f27..50333f12 100644
--- a/django-openstack/django_openstack/tests/view_tests/auth_tests.py
+++ b/horizon/horizon/tests/auth_tests.py
@@ -21,35 +21,33 @@
from django import http
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django_openstack import api
-from django_openstack.tests.view_tests import base
from openstackx.api import exceptions as api_exceptions
from mox import IsA
+from horizon import api
+from horizon import test
-class AuthViewTests(base.BaseViewTests):
+
+SYSPANEL_INDEX_URL = reverse('horizon:syspanel:overview:index')
+DASH_INDEX_URL = reverse('horizon:nova:overview:index')
+
+
+class AuthViewTests(test.BaseViewTests):
def setUp(self):
super(AuthViewTests, self).setUp()
self.setActiveUser()
self.PASSWORD = 'secret'
def test_login_index(self):
- res = self.client.get(reverse('auth_login'))
+ res = self.client.get(reverse('horizon:auth_login'))
self.assertTemplateUsed(res, 'splash.html')
def test_login_user_logged_in(self):
self.setActiveUser(self.TEST_TOKEN, self.TEST_USER, self.TEST_TENANT,
False, self.TEST_SERVICE_CATALOG)
- res = self.client.get(reverse('auth_login'))
- self.assertRedirectsNoFollow(res, reverse('dash_overview'))
-
- def test_login_admin_logged_in(self):
- self.setActiveUser(self.TEST_TOKEN, self.TEST_USER, self.TEST_TENANT,
- True, self.TEST_SERVICE_CATALOG)
-
- res = self.client.get(reverse('auth_login'))
- self.assertRedirectsNoFollow(res, reverse('syspanel_overview'))
+ res = self.client.get(reverse('horizon:auth_login'))
+ self.assertRedirectsNoFollow(res, DASH_INDEX_URL)
def test_login_no_tenants(self):
NEW_TENANT_ID = '6'
@@ -84,7 +82,7 @@ class AuthViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('auth_login'), form_data)
+ res = self.client.post(reverse('horizon:auth_login'), form_data)
self.assertTemplateUsed(res, 'splash.html')
@@ -128,9 +126,9 @@ class AuthViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('auth_login'), form_data)
+ res = self.client.post(reverse('horizon:auth_login'), form_data)
- self.assertRedirectsNoFollow(res, reverse('dash_overview'))
+ self.assertRedirectsNoFollow(res, DASH_INDEX_URL)
self.mox.VerifyAll()
@@ -146,7 +144,7 @@ class AuthViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('auth_login'), form_data)
+ res = self.client.post(reverse('horizon:auth_login'), form_data)
self.assertTemplateUsed(res, 'splash.html')
@@ -165,14 +163,15 @@ class AuthViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('auth_login'), form_data)
+ res = self.client.post(reverse('horizon:auth_login'), form_data)
self.assertTemplateUsed(res, 'splash.html')
self.mox.VerifyAll()
def test_switch_tenants_index(self):
- res = self.client.get(reverse('auth_switch', args=[self.TEST_TENANT]))
+ res = self.client.get(reverse('horizon:auth_switch',
+ args=[self.TEST_TENANT]))
self.assertTemplateUsed(res, 'switch_tenants.html')
@@ -210,10 +209,10 @@ class AuthViewTests(base.BaseViewTests):
self.mox.ReplayAll()
- res = self.client.post(reverse('auth_switch', args=[NEW_TENANT_ID]),
- form_data)
+ res = self.client.post(reverse('horizon:auth_switch',
+ args=[NEW_TENANT_ID]), form_data)
- self.assertRedirectsNoFollow(res, reverse('dash_overview'))
+ self.assertRedirectsNoFollow(res, DASH_INDEX_URL)
self.assertEqual(self.client.session['tenant'], NEW_TENANT_NAME)
self.mox.VerifyAll()
@@ -224,7 +223,7 @@ class AuthViewTests(base.BaseViewTests):
self.assertNotIn(KEY, self.client.session)
self.client.session[KEY] = VALUE
- res = self.client.get(reverse('auth_logout'))
+ res = self.client.get(reverse('horizon:auth_logout'))
self.assertRedirectsNoFollow(res, reverse('splash'))
self.assertNotIn(KEY, self.client.session)
diff --git a/horizon/horizon/tests/base_tests.py b/horizon/horizon/tests/base_tests.py
new file mode 100644
index 00000000..fbef3149
--- /dev/null
+++ b/horizon/horizon/tests/base_tests.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import copy
+
+import horizon
+from horizon import base
+from horizon import exceptions
+from horizon import test
+from horizon.base import Horizon
+from horizon.users import User
+
+
+class MyDash(horizon.Dashboard):
+ name = "My Dashboard"
+ slug = "mydash"
+
+
+class MyPanel(horizon.Panel):
+ name = "My Panel"
+ slug = "myslug"
+
+
+class HorizonTests(test.TestCase):
+ def setUp(self):
+ super(HorizonTests, self).setUp()
+ self._orig_horizon = copy.deepcopy(base.Horizon)
+
+ def tearDown(self):
+ super(HorizonTests, self).tearDown()
+ base.Horizon = self._orig_horizon
+
+ def test_registry(self):
+ """ Verify registration and autodiscovery work correctly.
+
+ Please note that this implicitly tests that autodiscovery works
+ by virtue of the fact that the dashboards listed in
+ ``settings.INSTALLED_APPS`` are loaded from the start.
+ """
+
+ # Registration
+ self.assertEqual(len(Horizon._registry), 3)
+ horizon.register(MyDash)
+ self.assertEqual(len(Horizon._registry), 4)
+ with self.assertRaises(ValueError):
+ horizon.register(MyPanel)
+ with self.assertRaises(ValueError):
+ horizon.register("MyPanel")
+
+ # Retrieval
+ my_dash_instance_by_name = horizon.get_dashboard("mydash")
+ self.assertTrue(isinstance(my_dash_instance_by_name, MyDash))
+ my_dash_instance_by_class = horizon.get_dashboard(MyDash)
+ self.assertEqual(my_dash_instance_by_name, my_dash_instance_by_class)
+ with self.assertRaises(base.NotRegistered):
+ horizon.get_dashboard("fake")
+ self.assertQuerysetEqual(horizon.get_dashboards(),
+ ['<Dashboard: User Dashboard>',
+ '<Dashboard: System Dashboard>',
+ '<Dashboard: Settings>',
+ '<Dashboard: My Dashboard>'])
+
+ # Removal
+ self.assertEqual(len(Horizon._registry), 4)
+ horizon.unregister(MyDash)
+ self.assertEqual(len(Horizon._registry), 3)
+ with self.assertRaises(base.NotRegistered):
+ horizon.get_dashboard(MyDash)
+
+ def test_site(self):
+ self.assertEqual(unicode(Horizon), "Horizon")
+ self.assertEqual(repr(Horizon), "<Site: Horizon>")
+ dash = Horizon.get_dashboard('nova')
+ self.assertEqual(Horizon.get_default_dashboard(), dash)
+ user = User()
+ self.assertEqual(Horizon.get_user_home(user), dash.get_absolute_url())
+
+ def test_dashboard(self):
+ syspanel = horizon.get_dashboard("syspanel")
+ self.assertEqual(syspanel._registered_with, Horizon)
+ self.assertQuerysetEqual(syspanel.get_panels()['System Panel'],
+ ['<Panel: Overview>',
+ '<Panel: Instances>',
+ '<Panel: Services>',
+ '<Panel: Flavors>',
+ '<Panel: Images>',
+ '<Panel: Tenants>',
+ '<Panel: Users>',
+ '<Panel: Quotas>'])
+ self.assertEqual(syspanel.get_absolute_url(), "/syspanel/")
+ # Test registering a module with a dashboard that defines panels
+ # as a dictionary.
+ syspanel.register(MyPanel)
+ self.assertQuerysetEqual(syspanel.get_panels()['Other'],
+ ['<Panel: My Panel>'])
+
+ # Test registering a module with a dashboard that defines panels
+ # as a tuple.
+ settings_dash = horizon.get_dashboard("settings")
+ settings_dash.register(MyPanel)
+ self.assertQuerysetEqual(settings_dash.get_panels(),
+ ['<Panel: User Settings>',
+ '<Panel: My Panel>'])
+
+ def test_panels(self):
+ syspanel = horizon.get_dashboard("syspanel")
+ instances = syspanel.get_panel("instances")
+ self.assertEqual(instances._registered_with, syspanel)
+ self.assertEqual(instances.get_absolute_url(), "/syspanel/instances/")
+
+ def test_lazy_urls(self):
+ urlpatterns = horizon.urls[0]
+ self.assertTrue(isinstance(urlpatterns, base.LazyURLPattern))
+ # The following two methods simply should not raise any exceptions
+ iter(urlpatterns)
+ reversed(urlpatterns)
diff --git a/horizon/horizon/tests/context_processor_tests.py b/horizon/horizon/tests/context_processor_tests.py
new file mode 100644
index 00000000..b4e507d1
--- /dev/null
+++ b/horizon/horizon/tests/context_processor_tests.py
@@ -0,0 +1,45 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+from horizon import context_processors
+from horizon import test
+
+
+class ContextProcessorTests(test.TestCase):
+ def setUp(self):
+ super(ContextProcessorTests, self).setUp()
+ self._prev_catalog = self.request.user.service_catalog
+ context_processors.horizon = self._real_horizon_context_processor
+
+ def tearDown(self):
+ super(ContextProcessorTests, self).tearDown()
+ self.request.user.service_catalog = self._prev_catalog
+
+ def test_object_store(self):
+ # Returns the object store service data when it's in the catalog
+ context = context_processors.horizon(self.request)
+ self.assertNotEqual(None, context['object_store_configured'])
+
+ # Returns None when the object store is not in the catalog
+ new_catalog = [service for service in self.request.user.service_catalog
+ if service['type'] != 'object-store']
+ self.request.user.service_catalog = new_catalog
+ context = context_processors.horizon(self.request)
+ self.assertEqual(None, context['object_store_configured'])
diff --git a/horizon/horizon/tests/templates/base-sidebar.html b/horizon/horizon/tests/templates/base-sidebar.html
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/tests/templates/base-sidebar.html
diff --git a/horizon/horizon/tests/templates/base.html b/horizon/horizon/tests/templates/base.html
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/tests/templates/base.html
diff --git a/horizon/horizon/tests/templates/splash.html b/horizon/horizon/tests/templates/splash.html
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/tests/templates/splash.html
diff --git a/horizon/horizon/tests/templates/switch_tenants.html b/horizon/horizon/tests/templates/switch_tenants.html
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/tests/templates/switch_tenants.html
diff --git a/horizon/horizon/tests/templatetag_tests.py b/horizon/horizon/tests/templatetag_tests.py
new file mode 100644
index 00000000..d05c7d89
--- /dev/null
+++ b/horizon/horizon/tests/templatetag_tests.py
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+import re
+
+from django import dispatch, http, template
+from django.utils.text import normalize_newlines
+
+from horizon import test
+
+
+def single_line(text):
+ ''' Quick utility to make comparing template output easier. '''
+ return re.sub(' +',
+ ' ',
+ normalize_newlines(text).replace('\n', '')).strip()
+
+
+class TemplateTagTests(test.TestCase):
+ def setUp(self):
+ super(TemplateTagTests, self).setUp()
diff --git a/django-openstack/django_openstack/tests/testsettings.py b/horizon/horizon/tests/testsettings.py
index 37657015..145f2165 100644
--- a/django-openstack/django_openstack/tests/testsettings.py
+++ b/horizon/horizon/tests/testsettings.py
@@ -26,31 +26,38 @@ TESTSERVER = 'http://testserver'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': '/tmp/django-openstack.db',
- },
- }
-INSTALLED_APPS = ['django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django_openstack',
- 'django_openstack.tests',
- 'django_openstack.templatetags',
- 'mailer',
- ]
+ 'NAME': '/tmp/horizon.db'}}
+
+INSTALLED_APPS = (
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'horizon',
+ 'horizon.tests',
+ 'horizon.dashboards.nova',
+ 'horizon.dashboards.syspanel',
+ 'horizon.dashboards.settings',
+ 'mailer')
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
- 'django_openstack.middleware.keystone.AuthenticationMiddleware',
- )
+ 'django.middleware.doc.XViewMiddleware',
+ 'django.middleware.locale.LocaleMiddleware',
+ 'horizon.middleware.HorizonMiddleware')
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.request',
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ 'django.contrib.messages.context_processors.messages',
+ 'horizon.context_processors.horizon')
-ROOT_URLCONF = 'django_openstack.tests.testurls'
-TEMPLATE_DIRS = (
- os.path.join(ROOT_PATH, 'tests', 'templates')
-)
+ROOT_URLCONF = 'horizon.tests.testurls'
+TEMPLATE_DIRS = (os.path.join(ROOT_PATH, 'tests', 'templates'))
SITE_ID = 1
SITE_BRANDING = 'OpenStack'
SITE_NAME = 'openstack'
@@ -59,26 +66,39 @@ NOVA_DEFAULT_ENDPOINT = None
NOVA_DEFAULT_REGION = 'test'
NOVA_ACCESS_KEY = 'test'
NOVA_SECRET_KEY = 'test'
+
QUANTUM_URL = '127.0.0.1'
QUANTUM_PORT = '9696'
QUANTUM_TENANT = '1234'
QUANTUM_CLIENT_VERSION = '0.1'
+QUANTUM_ENABLED = True
CREDENTIAL_AUTHORIZATION_DAYS = 2
CREDENTIAL_DOWNLOAD_URL = TESTSERVER + '/credentials/'
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
NOSE_ARGS = ['--nocapture',
- '--cover-package=django_openstack',
- '--cover-inclusive',
- ]
+ '--cover-package=horizon',
+ '--cover-inclusive']
# django-mailer uses a different config attribute
# even though it just wraps django.core.mail
MAILER_EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
EMAIL_BACKEND = MAILER_EMAIL_BACKEND
+SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
+
+HORIZON_CONFIG = {
+ 'dashboards': ('nova', 'syspanel', 'settings',),
+ 'default_dashboard': 'nova',
+}
SWIFT_ACCOUNT = 'test'
SWIFT_USER = 'tester'
SWIFT_PASS = 'testing'
SWIFT_AUTHURL = 'http://swift/swiftapi/v1.0'
+
+OPENSTACK_ADDRESS = "localhost"
+OPENSTACK_ADMIN_TOKEN = "openstack"
+OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_ADDRESS
+OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_ADDRESS
+OPENSTACK_KEYSTONE_DEFAULT_ROLE_ID = "2"
diff --git a/horizon/horizon/tests/testurls.py b/horizon/horizon/tests/testurls.py
new file mode 100644
index 00000000..21fa7e36
--- /dev/null
+++ b/horizon/horizon/tests/testurls.py
@@ -0,0 +1,33 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+URL patterns for testing Horizon views.
+"""
+
+from django.conf.urls.defaults import *
+
+import horizon
+
+
+urlpatterns = patterns('',
+ url(r'^$', 'horizon.tests.views.fakeView', name='splash'),
+ url(r'', include(horizon.urls)),
+)
diff --git a/django-openstack/django_openstack/tests/views.py b/horizon/horizon/tests/views.py
index a8a1684a..a8a1684a 100644
--- a/django-openstack/django_openstack/tests/views.py
+++ b/horizon/horizon/tests/views.py
diff --git a/horizon/horizon/users.py b/horizon/horizon/users.py
new file mode 100644
index 00000000..a3b880c1
--- /dev/null
+++ b/horizon/horizon/users.py
@@ -0,0 +1,123 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+"""
+Classes and methods related to user handling in Horizon.
+"""
+
+
+def get_user_from_request(request):
+ """ Checks the current session and returns a :class:`~horizon.users.User`.
+
+ If the session contains user data the User will be treated as
+ authenticated and the :class:`~horizon.users.User` will have all
+ its attributes set.
+
+ If not, the :class:`~horizon.users.User` will have no attributes set.
+
+ If the session contains invalid data,
+ :exc:`~horizon.exceptions.NotAuthorized` will be raised.
+ """
+ if 'user' not in request.session:
+ return User()
+ try:
+ return User(token=request.session['token'],
+ user=request.session['user'],
+ tenant_id=request.session['tenant_id'],
+ tenant_name=request.session['tenant'],
+ service_catalog=request.session['serviceCatalog'],
+ roles=request.session['roles'])
+ except KeyError:
+ # If any of those keys are missing from the session it is
+ # overwhelmingly likely that we're dealing with an outdated session.
+ request.session.clear()
+ raise exceptions.NotAuthorized(_("Your session has expired. "
+ "Please log in again."))
+
+
+class LazyUser(object):
+ def __get__(self, request, obj_type=None):
+ if not hasattr(request, '_cached_user'):
+ request._cached_user = get_user_from_request(request)
+ return request._cached_user
+
+
+class User(object):
+ """ The main user class which Horizon expects.
+
+ .. attribute:: token
+
+ The id of the Keystone token associated with the current user/tenant.
+
+ .. attribute:: username
+
+ The name of the current user.
+
+ .. attribute:: tenant_id
+
+ The id of the Keystone tenant for the current user/token.
+
+ .. attribute:: tenant_name
+
+ The name of the Keystone tenant for the current user/token.
+
+ .. attribute:: service_catalog
+
+ The ``ServiceCatalog`` data returned by Keystone.
+
+ .. attribute:: roles
+
+ A list of dictionaries containing role names and ids as returned
+ by Keystone.
+
+ .. attribute:: admin
+
+ Boolean value indicating whether or not this user has admin
+ privileges. Internally mapped to :meth:`horizon.users.User.is_admin`.
+ """
+ def __init__(self, token=None, user=None, tenant_id=None,
+ service_catalog=None, tenant_name=None, roles=None):
+ self.token = token
+ self.username = user
+ self.tenant_id = tenant_id
+ self.tenant_name = tenant_name
+ self.service_catalog = service_catalog
+ self.roles = roles or []
+
+ def is_authenticated(self):
+ """
+ Evaluates whether this :class:`.User` instance has been authenticated.
+ Returns ``True`` or ``False``.
+ """
+ # TODO: deal with token expiration
+ return self.token
+
+ @property
+ def admin(self):
+ return self.is_admin()
+
+ def is_admin(self):
+ """
+ Evaluates whether this user has admin privileges. Returns
+ ``True`` or ``False``.
+ """
+ for role in self.roles:
+ if role['name'].lower() == 'admin':
+ return True
+ return False
diff --git a/django-openstack/django_openstack/version.py b/horizon/horizon/version.py
index 999ae39f..999ae39f 100644
--- a/django-openstack/django_openstack/version.py
+++ b/horizon/horizon/version.py
diff --git a/horizon/horizon/views/__init__.py b/horizon/horizon/views/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/horizon/horizon/views/__init__.py
diff --git a/django-openstack/django_openstack/auth/views.py b/horizon/horizon/views/auth.py
index 73dc7622..9322b049 100644
--- a/django-openstack/django_openstack/auth/views.py
+++ b/horizon/horizon/views/auth.py
@@ -25,15 +25,14 @@ from django import template
from django import shortcuts
from django.contrib import messages
from django.utils.translation import ugettext as _
-
-from django_openstack import api
-from django_openstack import exceptions
-from django_openstack import forms
from openstackx.api import exceptions as api_exceptions
-from django_openstack import exceptions
+
+from horizon import api
+from horizon import exceptions
+from horizon import forms
-LOG = logging.getLogger('django_openstack.auth')
+LOG = logging.getLogger(__name__)
def _is_admin(token):
@@ -50,6 +49,7 @@ def _set_session_data(request, token):
request.session['tenant_id'] = token.tenant['id']
request.session['token'] = token.id
request.session['user'] = token.user['name']
+ request.session['roles'] = token.user['roles']
class Login(forms.SelfHandlingForm):
@@ -113,7 +113,7 @@ class Login(forms.SelfHandlingForm):
(data['username'], token.serviceCatalog))
_set_session_data(request, token)
- return shortcuts.redirect('dash_overview')
+ return shortcuts.redirect('horizon:nova:overview:index')
except api_exceptions.Unauthorized as e:
msg = _('Error authenticating: %s') % e.message
@@ -134,17 +134,15 @@ class LoginWithTenant(Login):
def login(request):
if request.user and request.user.is_authenticated():
if request.user.is_admin():
- return shortcuts.redirect('syspanel_overview')
+ return shortcuts.redirect('horizon:syspanel:overview:index')
else:
- return shortcuts.redirect('dash_overview')
+ return shortcuts.redirect('horizon:nova:overview:index')
form, handled = Login.maybe_handle(request)
if handled:
return handled
- return shortcuts.render_to_response('splash.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request, 'splash.html', {'form': form})
def switch_tenants(request, tenant_id):
@@ -161,14 +159,14 @@ def switch_tenants(request, tenant_id):
tenant_id,
unscoped_token)
_set_session_data(request, token)
- return shortcuts.redirect('dash_overview')
+ return shortcuts.redirect('horizon:nova:overview:index')
except exceptions.Unauthorized as e:
messages.error(_("You are not authorized for that tenant."))
- return shortcuts.render_to_response('switch_tenants.html', {
- 'to_tenant': tenant_id,
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request,
+ 'switch_tenants.html', {
+ 'to_tenant': tenant_id,
+ 'form': form})
def logout(request):
diff --git a/horizon/horizon/views/auth_forms.py b/horizon/horizon/views/auth_forms.py
new file mode 100644
index 00000000..7664b694
--- /dev/null
+++ b/horizon/horizon/views/auth_forms.py
@@ -0,0 +1,141 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2011 Nebula, Inc.
+#
+# 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.
+
+"""
+Forms used for Horizon's auth mechanisms.
+"""
+
+import logging
+
+from django import shortcuts
+from django.contrib import messages
+from django.utils.translation import ugettext as _
+from openstackx.api import exceptions as api_exceptions
+
+from horizon import api
+from horizon import base
+from horizon import exceptions
+from horizon import forms
+from horizon import users
+
+
+LOG = logging.getLogger(__name__)
+
+
+def _set_session_data(request, token):
+ request.session['serviceCatalog'] = token.serviceCatalog
+ request.session['tenant'] = token.tenant['name']
+ request.session['tenant_id'] = token.tenant['id']
+ request.session['token'] = token.id
+ request.session['user'] = token.user['name']
+ request.session['roles'] = token.user['roles']
+
+
+class Login(forms.SelfHandlingForm):
+ """ Form used for logging in a user.
+
+ Handles authentication with Keystone, choosing a tenant, and fetching
+ a scoped token token for that tenant. Redirects to the URL returned
+ by :meth:`horizon.get_user_home` if successful.
+
+ Subclass of :class:`~horizon.forms.SelfHandlingForm`.
+ """
+ username = forms.CharField(max_length="20", label=_("User Name"))
+ password = forms.CharField(max_length="20", label=_("Password"),
+ widget=forms.PasswordInput(render_value=False))
+
+ def handle(self, request, data):
+ try:
+ if data.get('tenant', None):
+ token = api.token_create(request,
+ data.get('tenant'),
+ data['username'],
+ data['password'])
+
+ tenants = api.tenant_list_for_token(request, token.id)
+ tenant = None
+ for t in tenants:
+ if t.id == data.get('tenant'):
+ tenant = t
+ _set_session_data(request, token)
+ user = users.get_user_from_request(request)
+ return shortcuts.redirect(base.Horizon.get_user_home(user))
+
+ elif data.get('username', None):
+ token = api.token_create(request,
+ '',
+ data['username'],
+ data['password'])
+
+ # Unscoped token
+ request.session['unscoped_token'] = token.id
+ request.user.username = data['username']
+
+ # Get the tenant list, and log in using first tenant
+ # FIXME (anthony): add tenant chooser here?
+ tenants = api.tenant_list_for_token(request, token.id)
+
+ # Abort if there are no valid tenants for this user
+ if not tenants:
+ messages.error(request,
+ _('No tenants present for user: %(user)s') %
+ {"user": data['username']})
+ return
+
+ # Create a token.
+ # NOTE(gabriel): Keystone can return tenants that you're
+ # authorized to administer but not to log into as a user, so in
+ # the case of an Unauthorized error we should iterate through
+ # the tenants until one succeeds or we've failed them all.
+ while tenants:
+ tenant = tenants.pop()
+ try:
+ token = api.token_create_scoped(request,
+ tenant.id,
+ token.id)
+ break
+ except api_exceptions.Unauthorized as e:
+ token = None
+ if token is None:
+ raise exceptions.NotAuthorized(
+ _("You are not authorized for any available tenants."))
+
+ _set_session_data(request, token)
+ user = users.get_user_from_request(request)
+ return shortcuts.redirect(base.Horizon.get_user_home(user))
+
+ except api_exceptions.Unauthorized as e:
+ msg = _('Error authenticating: %s') % e.message
+ LOG.exception(msg)
+ messages.error(request, msg)
+ except api_exceptions.ApiException as e:
+ messages.error(request,
+ _('Error authenticating with keystone: %s') %
+ e.message)
+
+
+class LoginWithTenant(Login):
+ """
+ Exactly like :class:`.Login` but includes the tenant id as a field
+ so that the process of choosing a default tenant is bypassed.
+ """
+ username = forms.CharField(max_length="20",
+ widget=forms.TextInput(attrs={'readonly': 'readonly'}))
+ tenant = forms.CharField(widget=forms.HiddenInput())
diff --git a/django-openstack/setup.py b/horizon/setup.py
index 2e3f46c0..66644ec5 100755..100644
--- a/django-openstack/setup.py
+++ b/horizon/setup.py
@@ -20,13 +20,13 @@
import os
from setuptools import setup, find_packages, findall
-from django_openstack import version
+from horizon import version
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup(
- name = "django-openstack",
+ name = "horizon",
version = version.canonical_version_string(),
url = 'https://github.com/openstack/horizon/',
license = 'Apache 2.0',
@@ -35,9 +35,9 @@ setup(
author = 'Devin Carlen',
author_email = 'devin.carlen@gmail.com',
packages = find_packages(),
- package_data = {'django_openstack':
- [s[len('django_openstack/'):] for s in
- findall('django_openstack/templates')]},
+ package_data = {'horizon':
+ [s[len('horizon/'):] for s in
+ findall('horizon/templates')]},
install_requires = ['setuptools', 'mox>=0.5.3', 'django_nose'],
classifiers = [
'Development Status :: 4 - Beta',
@@ -49,4 +49,3 @@ setup(
'Topic :: Internet :: WWW/HTTP',
]
)
-
diff --git a/openstack-dashboard/README b/openstack-dashboard/README
index 3c9053a2..f902e97d 100644
--- a/openstack-dashboard/README
+++ b/openstack-dashboard/README
@@ -1,53 +1,34 @@
+===================
OpenStack Dashboard
--------------------
+===================
The OpenStack Dashboard is a reference implementation of a Django site that
-uses the Django-Nova project to provide web based interactions with the
-OpenStack Nova cloud controller.
+uses the Horizon project to provide web based interactions with the various
+OpenStack projects.
Getting Started
----------------
+===============
-For local development, first create a virtualenv for local development.
+For local development, first create a virtualenv for the project.
A tool is included to create one for you:
$ python tools/install_venv.py
-
Now that the virtualenv is created, you need to configure your local
-environment. To do this, create a local_settings.py file in the local/
-directory. There is a local_settings.py.example file there that may be used
-as a template.
-
-Finally, issue the django syncdb command:
-
- $ tools/with_venv.sh dashboard/manage.py syncdb
-
-If after you have specified the admin user the script appears to hang, it
-probably means the installation of Nova being referred to in local_settings.py
-is unavailable.
-
+environment. To do this, create a ``local_settings.py`` file in the ``local/``
+directory. There is a ``local_settings.py.example`` file there that may be
+used as a template.
If all is well you should now able to run the server locally:
$ tools/with_venv.sh dashboard/manage.py runserver
-Adding openstackx Extensions to Nova
-------------------------------------
-
-If you are seeing large numbers of 404 exceptions on operations such as listing
-servers, you are probably not running the openstackx extensions that the
-dashboard depends on. You will need to download the openstackx code from
-
-> https://github.com/cloudbuilders/openstackx
-
-and add the following option to your nova instantiation:
-
-> --osapi_extensions_path=/path/to/openstackx/extensions
+Settings Up OpenStack
+=====================
-The rackspace cloudbuilders nova.sh script automates this process and creates a
-full nova installation compatible with the dashboard. You can acquire this
-script from the repository at
+The recommended tool for installing and configuring the core OpenStack
+components is `Devstack`_. Refer to their documentation for getting
+Nova, Keystone, Glance, etc. up and running.
-https://github.com/cloudbuilders/deploy.sh
+.. _Devstack: http://devstack.org/
diff --git a/openstack-dashboard/dashboard/manage.py b/openstack-dashboard/dashboard/manage.py
index 95d00493..73053f39 100755
--- a/openstack-dashboard/dashboard/manage.py
+++ b/openstack-dashboard/dashboard/manage.py
@@ -20,6 +20,8 @@
# under the License.
from django.core.management import execute_manager
+
+
try:
import settings # Assumed to be in the same directory.
except ImportError:
@@ -31,5 +33,6 @@ except ImportError:
"somehow.)\n" % __file__)
sys.exit(1)
+
if __name__ == "__main__":
execute_manager(settings)
diff --git a/openstack-dashboard/dashboard/middleware.py b/openstack-dashboard/dashboard/middleware.py
index d0678953..6a8772f7 100644
--- a/openstack-dashboard/dashboard/middleware.py
+++ b/openstack-dashboard/dashboard/middleware.py
@@ -24,6 +24,7 @@ from django import shortcuts
from django.contrib import messages
from openstackx.api import exceptions as api_exceptions
+
LOG = logging.getLogger('openstack_dashboard')
diff --git a/openstack-dashboard/dashboard/settings.py b/openstack-dashboard/dashboard/settings.py
index 5c43e549..1b5100be 100644
--- a/openstack-dashboard/dashboard/settings.py
+++ b/openstack-dashboard/dashboard/settings.py
@@ -52,10 +52,10 @@ MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
- 'django_openstack.middleware.keystone.AuthenticationMiddleware',
+ 'dashboard.middleware.DashboardLogUnhandledExceptionsMiddleware',
+ 'horizon.middleware.HorizonMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.middleware.locale.LocaleMiddleware',
- 'dashboard.middleware.DashboardLogUnhandledExceptionsMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = (
@@ -65,9 +65,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.contrib.messages.context_processors.messages',
- 'django_openstack.context_processors.object_store',
- 'django_openstack.context_processors.tenants',
- 'django_openstack.context_processors.quantum',
+ 'horizon.context_processors.horizon',
)
TEMPLATE_LOADERS = (
@@ -85,12 +83,13 @@ STATICFILES_DIRS = (
INSTALLED_APPS = (
'dashboard',
- 'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
- 'django_openstack',
- 'django_openstack.templatetags',
+ 'horizon',
+ 'horizon.dashboards.nova',
+ 'horizon.dashboards.syspanel',
+ 'horizon.dashboards.settings',
'mailer',
)
@@ -98,6 +97,7 @@ TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
+SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
TIME_ZONE = None
gettext_noop = lambda s: s
@@ -119,6 +119,9 @@ ACCOUNT_ACTIVATION_DAYS = 7
TOTAL_CLOUD_RAM_GB = 10
+OPENSTACK_KEYSTONE_DEFAULT_ROLE = 'Member'
+LIVE_SERVER_PORT = 8000
+
try:
from local.local_settings import *
except Exception, e:
@@ -136,4 +139,3 @@ if DEBUG:
except ImportError:
logging.info('Running in debug mode without debug_toolbar.')
-OPENSTACK_KEYSTONE_DEFAULT_ROLE = 'Member'
diff --git a/openstack-dashboard/dashboard/static/dashboard/images/favicon.ico b/openstack-dashboard/dashboard/static/dashboard/images/favicon.ico
new file mode 100644
index 00000000..f3b9bf9c
--- /dev/null
+++ b/openstack-dashboard/dashboard/static/dashboard/images/favicon.ico
Binary files differ
diff --git a/openstack-dashboard/dashboard/templates/_login.html b/openstack-dashboard/dashboard/templates/_login.html
index c2a1ead9..db15f938 100644
--- a/openstack-dashboard/dashboard/templates/_login.html
+++ b/openstack-dashboard/dashboard/templates/_login.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/auth/_login.html' %}
+{% extends 'horizon/auth/_login.html' %}
{% load i18n %}
{% block submit %}
<input type="hidden" name="next" value="/" />
diff --git a/openstack-dashboard/dashboard/templates/_switch.html b/openstack-dashboard/dashboard/templates/_switch.html
index 9b6004ae..69945832 100644
--- a/openstack-dashboard/dashboard/templates/_switch.html
+++ b/openstack-dashboard/dashboard/templates/_switch.html
@@ -1,4 +1,4 @@
-{% extends 'django_openstack/auth/_switch.html' %}
+{% extends 'horizon/auth/_switch.html' %}
{%load i18n%}
{% block submit %}
<input type="hidden" name="next" value="/" />
diff --git a/openstack-dashboard/dashboard/templates/_topbar.html b/openstack-dashboard/dashboard/templates/_topbar.html
index ea1729e9..b75d38a5 100644
--- a/openstack-dashboard/dashboard/templates/_topbar.html
+++ b/openstack-dashboard/dashboard/templates/_topbar.html
@@ -1,21 +1,14 @@
-{%load i18n%}
+{% load horizon i18n %}
+
<div id='header'>
<ul id="main_nav">
<li id="home_link"><h1><a href='{% url splash %}'>{% trans "OpenStack Dashboard"%}</a></h1></li>
- {% if request.user %}
- <li><a {% if current_topbar == "dash" %} class="active" {% endif %} href="{% url dash_overview %}">{% trans "User Dashboard"%}</a></li>
-
- {% if request.user.is_admin %}
- <li><a {% if current_topbar == "syspanel" %} class="active" {% endif %} href="{% url syspanel_overview %}">{% trans "System Panel"%}</a></li>
- {% endif %}
- {% else %}
- NOT _LOGGED_IN_TOPBAR
- {% endif %}
- <li><a id="settings_btn" {% if current_topbar == "settings" %} class="active" {% endif %} href="{% url dashboard_settings %}">&nbsp;</a></li>
+ {% horizon_main_nav %}
+ <li><a id="settings_btn" {% if request.horizon.dashboard.slug == "settings" %} class="active" {% endif %} href="{% url horizon:settings:user:index %}">&nbsp;</a></li>
</ul>
<div id="user_bar">
- <a id="current_tenant" href="{% url dash_overview %}">
+ <a id="current_tenant" href="#FIXME">
<h4>{{request.user.tenant_name}}</h4>
<span>as {{request.user.username}}</span>
</a>
@@ -24,11 +17,10 @@
<li class="title"><h4>{% trans "Available Tenants"%}</h4></li>
{% for tenant in tenants %}
{% if tenant.enabled %}
- <li><a href="{% url auth_switch tenant.id %}">{{tenant.name}}</a></li>
+ <li><a href="{% url horizon:auth_switch tenant.id %}">{{tenant.name}}</a></li>
{% endif %}
{% endfor %}
- <li id="sign_out"><a href="{% url auth_logout %}">{% trans "Sign Out"%}</a></li>
+ <li id="sign_out"><a href="{% url horizon:auth_logout %}">{% trans "Sign Out"%}</a></li>
</ul>
</div>
-
</div>
diff --git a/openstack-dashboard/dashboard/templates/base.html b/openstack-dashboard/dashboard/templates/base.html
index 97f92dde..ab136e19 100644
--- a/openstack-dashboard/dashboard/templates/base.html
+++ b/openstack-dashboard/dashboard/templates/base.html
@@ -13,6 +13,7 @@
<script charset='utf-8' src='{{ STATIC_URL }}dashboard/js/application.js' type='text/javascript'></script>
<link href='{{ STATIC_URL }}dashboard/css/style.css' media='screen' rel='stylesheet' />
<link href='{{ STATIC_URL }}dashboard/css/chosen.css' media='screen' rel='stylesheet' />
+ <link rel="shortcut icon" href="{{ STATIC_URL }}dashboard/images/favicon.ico"/>
{% block headerjs %}{% endblock %}
{% block headercss %}{% endblock %}
</head>
diff --git a/openstack-dashboard/dashboard/templates/switch_tenants.html b/openstack-dashboard/dashboard/templates/switch_tenants.html
index e19a9739..f0066431 100644
--- a/openstack-dashboard/dashboard/templates/switch_tenants.html
+++ b/openstack-dashboard/dashboard/templates/switch_tenants.html
@@ -1,4 +1,4 @@
-{%load i18n%}
+{% load i18n %}
<!DOCTYPE html>
<html lang="en" xml:lang="en">
<head>
@@ -9,7 +9,7 @@
<body id="standalone">
<div id="login_wrapper">
<div class='large-rounded' id='login'>
- <h3>{% trans "Log-in to tenant"%}: <i>{{to_tenant}}</i></h3>
+ <h3>{% trans "Log-in to tenant"%}: <i>{{ to_tenant }}</i></h3>
<br/>
{% include "_messages.html" %}
{% include '_login.html' %}
diff --git a/openstack-dashboard/dashboard/tests.py b/openstack-dashboard/dashboard/tests.py
deleted file mode 100644
index a7231056..00000000
--- a/openstack-dashboard/dashboard/tests.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2011 Nebula, Inc.
-#
-# 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.
-
-''' Test for django mailer.
-
-This test is pretty much worthless, and should be removed once real testing of
-views that send emails is implemented
-'''
-
-from django import test
-from django.core import mail
-from mailer import engine
-from mailer import send_mail
-
-
-class DjangoMailerPresenceTest(test.TestCase):
- def test_mailsent(self):
- send_mail('subject', 'message_body', 'from@test.com', ['to@test.com'])
- engine.send_all()
- self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].subject, 'subject')
diff --git a/openstack-dashboard/dashboard/urls.py b/openstack-dashboard/dashboard/urls.py
index 1f2c6bd9..ed60acc5 100644
--- a/openstack-dashboard/dashboard/urls.py
+++ b/openstack-dashboard/dashboard/urls.py
@@ -26,19 +26,13 @@ from django.conf.urls.defaults import *
from django.conf.urls.static import static
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
-from django.views import generic as generic_views
-import django.views.i18n
-from django_openstack import urls as django_openstack_urls
+import horizon
+
urlpatterns = patterns('',
url(r'^$', 'dashboard.views.splash', name='splash'),
- url(r'^dash/$', 'django_openstack.dash.views.instances.usage',
- name='dash_overview'),
- url(r'^syspanel/$', 'django_openstack.syspanel.views.instances.usage',
- name='syspanel_overview'),
- url(r'^i18n/', include('django.conf.urls.i18n')),
-)
+ url(r'', include(horizon.urls)))
# Development static app and project media serving using the staticfiles app.
urlpatterns += staticfiles_urlpatterns()
@@ -47,6 +41,3 @@ urlpatterns += staticfiles_urlpatterns()
# development. Only active if DEBUG==True and the URL prefix is a local
# path. Production media should NOT be served by Django.
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
-
-# NOTE(termie): just append them since we want the routes at the root
-urlpatterns += django_openstack_urls.urlpatterns
diff --git a/openstack-dashboard/dashboard/views.py b/openstack-dashboard/dashboard/views.py
index 0d7fab07..fb06c62d 100644
--- a/openstack-dashboard/dashboard/views.py
+++ b/openstack-dashboard/dashboard/views.py
@@ -25,22 +25,20 @@ from django import template
from django import shortcuts
from django.views.decorators import vary
-from django_openstack import api
-from django_openstack.auth import views as auth_views
+import horizon
+from horizon.views import auth as auth_views
+
+
+def user_home(user):
+ if user.admin:
+ return horizon.get_dashboard('syspanel').get_absolute_url()
+ return horizon.get_dashboard('dash').get_absolute_url()
@vary.vary_on_cookie
def splash(request):
- if request.user:
- if request.user.is_admin():
- return shortcuts.redirect('syspanel_overview')
- else:
- return shortcuts.redirect('dash_overview')
-
form, handled = auth_views.Login.maybe_handle(request)
if handled:
return handled
- return shortcuts.render_to_response('splash.html', {
- 'form': form,
- }, context_instance=template.RequestContext(request))
+ return shortcuts.render(request, 'splash.html', {'form': form})
diff --git a/openstack-dashboard/local/local_settings.py.example b/openstack-dashboard/local/local_settings.py.example
index b6063244..ceebde77 100644
--- a/openstack-dashboard/local/local_settings.py.example
+++ b/openstack-dashboard/local/local_settings.py.example
@@ -13,8 +13,7 @@ DATABASES = {
},
}
-CACHE_BACKEND = 'dummy://'
-
+CACHE_BACKEND = 'locmem://'
# Send email to the console by default
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@@ -30,61 +29,73 @@ MAILER_EMAIL_BACKEND = EMAIL_BACKEND
# EMAIL_HOST_USER = 'djangomail'
# EMAIL_HOST_PASSWORD = 'top-secret!'
+HORIZON_CONFIG = {
+ 'dashboards': ('nova', 'syspanel', 'settings',),
+ 'default_dashboard': 'nova',
+ 'user_home': 'dashboard.views.user_home',
+}
-OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0"
+OPENSTACK_HOST = "127.0.0.1"
+OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_HOST
# FIXME: this is only needed until keystone fixes its GET /tenants call
# so that it doesn't return everything for admins
-OPENSTACK_KEYSTONE_ADMIN_URL = "http://localhost:35357/v2.0"
+OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
SWIFT_PAGINATE_LIMIT = 100
# Configure quantum connection details for networking
QUANTUM_ENABLED = True
-QUANTUM_URL = '127.0.0.1'
+QUANTUM_URL = '%s' % OPENSTACK_HOST
QUANTUM_PORT = '9696'
QUANTUM_TENANT = '1234'
QUANTUM_CLIENT_VERSION='0.1'
-# If you have external monitoring links
-EXTERNAL_MONITORING = [
- ['Nagios','http://foo.com'],
- ['Ganglia','http://bar.com'],
-]
+# If you have external monitoring links, eg:
+# EXTERNAL_MONITORING = [
+# ['Nagios','http://foo.com'],
+# ['Ganglia','http://bar.com'],
+# ]
-# If you do not have external monitoring links
-# EXTERNAL_MONITORING = []
-
-# Uncomment the following segment to silence most logging
-# django.db and boto DEBUG logging is extremely verbose.
-#LOGGING = {
-# 'version': 1,
-# # set to True will disable all logging except that specified, unless
-# # nothing is specified except that django.db.backends will still log,
-# # even when set to True, so disable explicitly
-# 'disable_existing_loggers': False,
-# 'handlers': {
-# 'null': {
-# 'level': 'DEBUG',
-# 'class': 'django.utils.log.NullHandler',
-# },
-# 'console': {
-# 'level': 'DEBUG',
-# 'class': 'logging.StreamHandler',
-# },
-# },
-# 'loggers': {
-# # Comment or Uncomment these to turn on/off logging output
-# 'django.db.backends': {
-# 'handlers': ['null'],
-# 'propagate': False,
-# },
-# 'django_openstack': {
-# 'handlers': ['null'],
-# 'propagate': False,
-# },
-# }
-#}
+LOGGING = {
+ 'version': 1,
+ # When set to True this will disable all logging except
+ # for loggers specified in this configuration dictionary. Note that
+ # if nothing is specified here and disable_existing_loggers is True,
+ # django.db.backends will still log unless it is disabled explicitly.
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ 'null': {
+ 'level': 'DEBUG',
+ 'class': 'django.utils.log.NullHandler',
+ },
+ 'console': {
+ # Set the level to "DEBUG" for verbose output logging.
+ 'level': 'INFO',
+ 'class': 'logging.StreamHandler',
+ },
+ },
+ 'loggers': {
+ # Logging from django.db.backends is VERY verbose, send to null
+ # by default.
+ 'django.db.backends': {
+ 'handlers': ['null'],
+ 'propagate': False,
+ },
+ 'horizon': {
+ 'handlers': ['console'],
+ 'propagate': False,
+ },
+ 'novaclient': {
+ 'handlers': ['console'],
+ 'propagate': False,
+ },
+ 'keystoneclient': {
+ 'handlers': ['console'],
+ 'propagate': False,
+ },
+ }
+}
# How much ram on each compute host?
COMPUTE_HOST_RAM_GB = 16
diff --git a/openstack-dashboard/tools/install_venv.py b/openstack-dashboard/tools/install_venv.py
index 37c35c33..50195979 100644
--- a/openstack-dashboard/tools/install_venv.py
+++ b/openstack-dashboard/tools/install_venv.py
@@ -107,9 +107,10 @@ def create_virtualenv(venv=VENV):
def install_dependencies(venv=VENV):
- print 'Installing dependencies with pip (this can take a while)...'
- run_command([WITH_VENV, 'pip', 'install', '-E', venv, '-r', PIP_REQUIRES],
- redirect_output=False)
+ print "Quietly installing dependencies..."
+ print "(This may take several minutes, don't panic)"
+ run_command([WITH_VENV, 'pip', 'install', '-q', '-E',
+ venv, '-r', PIP_REQUIRES], redirect_output=False)
# Tell the virtual env how to "import dashboard"
py = 'python%d.%d' % (sys.version_info[0], sys.version_info[1])
@@ -119,8 +120,8 @@ def install_dependencies(venv=VENV):
def install_django_openstack():
- print 'Installing django_openstack in development mode...'
- path = os.path.join(ROOT, '..', 'django-openstack')
+ print 'Installing horizon module in development mode...'
+ path = os.path.join(ROOT, '..', 'horizon')
run_command([WITH_VENV, 'python', 'setup.py', 'develop'], cwd=path)
diff --git a/openstack-dashboard/tools/pip-requires b/openstack-dashboard/tools/pip-requires
index 1ac5a74c..17c3481c 100644
--- a/openstack-dashboard/tools/pip-requires
+++ b/openstack-dashboard/tools/pip-requires
@@ -1,27 +1,27 @@
-nose==1.0.0
+coverage
Django==1.3
-django-nose==0.1.2
django-mailer
+django-nose==0.1.2
django-registration==0.7
+eventlet
+glance
kombu
+nose==1.0.0
+paste
+PasteDeploy
python-cloudfiles
python-dateutil
routes
-webob
sqlalchemy
-paste
-PasteDeploy
sqlalchemy-migrate
-eventlet
-xattr
pep8
pylint
-coverage
-glance
sphinx
+webob
+xattr
--e git+https://github.com/openstack/quantum.git#egg=quantum
--e git+https://github.com/jacobian/openstack.compute.git#egg=openstack
-e git+https://github.com/cloudbuilders/openstackx.git#egg=openstackx
+-e git+https://github.com/jacobian/openstack.compute.git#egg=openstack
+-e git+https://github.com/openstack/quantum.git#egg=quantum
-e git+https://github.com/rackspace/python-novaclient.git#egg=python-novaclient
-e git+https://github.com/4P/python-keystoneclient.git#egg=python-keystoneclient
diff --git a/openstack-dashboard/tools/with_venv.sh b/openstack-dashboard/tools/with_venv.sh
index 91299647..51efe29f 100755
--- a/openstack-dashboard/tools/with_venv.sh
+++ b/openstack-dashboard/tools/with_venv.sh
@@ -2,4 +2,3 @@
TOOLS=`dirname $0`
VENV=$TOOLS/../.dashboard-venv
source $VENV/bin/activate && $@
-
diff --git a/run_tests.sh b/run_tests.sh
index 94950878..89e021d8 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -2,17 +2,21 @@
function usage {
echo "Usage: $0 [OPTION]..."
- echo "Run Openstack Dashboard's test suite(s)"
+ echo "Run Horizon's test suite(s)"
echo ""
echo " -V, --virtual-env Always use virtualenv. Install automatically"
echo " if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local"
echo " environment"
+ echo " -c, --coverage Generate reports using Coverage"
echo " -f, --force Force a clean re-build of the virtual"
echo " environment. Useful when dependencies have"
echo " been added."
echo " -p, --pep8 Just run pep8"
echo " -y, --pylint Just run pylint"
+ echo " --runserver Run the Django development server for"
+ echo " openstack-dashboard in the virtual"
+ echo " environment."
echo " --docs Just build the documentation"
echo " -h, --help Print this usage message"
echo ""
@@ -31,14 +35,21 @@ function process_option {
-p|--pep8) let just_pep8=1;;
-y|--pylint) let just_pylint=1;;
-f|--force) let force=1;;
+ -c|--coverage) let with_coverage=1;;
--docs) let just_docs=1;;
+ --runserver) let runserver=1;;
*) testargs="$testargs $1"
esac
}
+function run_server {
+ echo "Starting Django development server..."
+ ${django_wrapper} python openstack-dashboard/dashboard/manage.py runserver
+}
+
function run_pylint {
echo "Running pylint ..."
- PYLINT_INCLUDE="openstack-dashboard/dashboard django-openstack/django_openstack"
+ PYLINT_INCLUDE="openstack-dashboard/dashboard horizon/horizon"
${django_wrapper} pylint --rcfile=.pylintrc -f parseable $PYLINT_INCLUDE > pylint.txt
CODE=$?
grep Global -A2 pylint.txt
@@ -54,7 +65,7 @@ function run_pep8 {
echo "Running pep8 ..."
PEP8_EXCLUDE=vcsversion.py
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat"
- PEP8_INCLUDE="openstack-dashboard/dashboard django-openstack/django_openstack"
+ PEP8_INCLUDE="openstack-dashboard/dashboard horizon/horizon"
echo "${django_wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE > pep8.txt"
#${django_wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE > pep8.txt
#perl string strips out the [ and ] characters
@@ -63,15 +74,12 @@ function run_pep8 {
function run_sphinx {
echo "Building sphinx..."
- echo "${django_wrapper} export DJANGO_SETTINGS_MODULE=local.local_settings"
- ${django_wrapper} export DJANGO_SETTINGS_MODULE=local.local_settings
- echo "${django_wrapper} python doc/generate_autodoc_index.py"
- ${django_wrapper} python doc/generate_autodoc_index.py
- echo "${django_wrapper} sphinx-build -b html doc/source build/sphinx/html"
- ${django_wrapper} sphinx-build -b html doc/source build/sphinx/html
+ echo "export DJANGO_SETTINGS_MODULE=dashboard.settings"
+ export DJANGO_SETTINGS_MODULE=dashboard.settings
+ echo "${django_wrapper} sphinx-build -b html docs/source docs/build/html"
+ ${django_wrapper} sphinx-build -b html docs/source docs/build/html
}
-
# DEFAULTS FOR RUN_TESTS.SH
#
venv=openstack-dashboard/.dashboard-venv
@@ -80,12 +88,14 @@ dashboard_with_venv=tools/with_venv.sh
always_venv=0
never_venv=0
force=0
+with_coverage=0
testargs=""
django_wrapper=""
dashboard_wrapper=""
just_pep8=0
just_pylint=0
just_docs=0
+runserver=0
# PROCESS ARGUMENTS, OVERRIDE DEFAULTS
for arg in "$@"; do
@@ -108,6 +118,10 @@ then
cd openstack-dashboard
python tools/install_venv.py
cd ..
+ cd horizon
+ python bootstrap.py
+ bin/buildout
+ cd ..
django_wrapper="${django_with_venv}"
dashboard_wrapper="${dashboard_with_venv}"
else
@@ -118,6 +132,10 @@ then
cd openstack-dashboard
python tools/install_venv.py
cd ..
+ cd horizon
+ python bootstrap.py
+ bin/buildout
+ cd ..
django_wrapper="${django_with_venv}"
dashboard_wrapper="${dashboard_with_venv}"
fi
@@ -126,29 +144,33 @@ then
fi
function run_tests {
- echo "Running django-openstack (core django) tests"
+ echo "Running Horizon application tests"
${django_wrapper} coverage erase
- cd django-openstack
- python bootstrap.py
- bin/buildout
- cd ..
- ${django_wrapper} coverage run django-openstack/bin/test
- # get results of the django-openstack tests
+ ${django_wrapper} coverage run horizon/bin/test
+ # get results of the Horizon tests
OPENSTACK_RESULT=$?
- echo "Running openstack-dashboard (django website) tests"
+ echo "Running openstack-dashboard (Django project) tests"
cd openstack-dashboard
+ if [ -f local/local_settings.py ]; then
+ cp local/local_settings.py local/local_settings.py.bak
+ fi
cp local/local_settings.py.example local/local_settings.py
${dashboard_wrapper} coverage run dashboard/manage.py test
+ if [ -f local/local_settings.py.bak ]; then
+ cp local/local_settings.py.bak local/local_settings.py
+ rm local/local_settings.py.bak
+ fi
# get results of the openstack-dashboard tests
DASHBOARD_RESULT=$?
cd ..
-
- echo "Generating coverage reports"
- ${django_wrapper} coverage combine
- ${django_wrapper} coverage xml --omit='/usr*,setup.py,*egg*'
- ${django_wrapper} coverage html --omit='/usr*,setup.py,*egg*' -d reports
- exit $(($OPENSTACK_RESULT || $DASHBOARD_RESULT))
+ if [ $with_coverage -eq 1 ]; then
+ echo "Generating coverage reports"
+ ${django_wrapper} coverage combine
+ ${django_wrapper} coverage xml -i --omit='/usr*,setup.py,*egg*'
+ ${django_wrapper} coverage html -i --omit='/usr*,setup.py,*egg*' -d reports
+ exit $(($OPENSTACK_RESULT || $DASHBOARD_RESULT))
+ fi
}
if [ $just_docs -eq 1 ]; then
@@ -166,4 +188,9 @@ if [ $just_pylint -eq 1 ]; then
exit $?
fi
+if [ $runserver -eq 1 ]; then
+ run_server
+ exit $?
+fi
+
run_tests || exit